|  |  |  | import os
 | 
					
						
							|  |  |  | import subprocess
 | 
					
						
							|  |  |  | import glob
 | 
					
						
							|  |  |  | import hashlib
 | 
					
						
							|  |  |  | import shutil
 | 
					
						
							|  |  |  | from common.basedir import BASEDIR
 | 
					
						
							|  |  |  | from selfdrive.swaglog import cloudlog
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | android_packages = ("ai.comma.plus.offroad",)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_installed_apks():
 | 
					
						
							|  |  |  |   dat = subprocess.check_output(["pm", "list", "packages", "-f"], encoding='utf8').strip().split("\n")
 | 
					
						
							|  |  |  |   ret = {}
 | 
					
						
							|  |  |  |   for x in dat:
 | 
					
						
							|  |  |  |     if x.startswith("package:"):
 | 
					
						
							|  |  |  |       v, k = x.split("package:")[1].split("=")
 | 
					
						
							|  |  |  |       ret[k] = v
 | 
					
						
							|  |  |  |   return ret
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def install_apk(path):
 | 
					
						
							|  |  |  |   # can only install from world readable path
 | 
					
						
							|  |  |  |   install_path = "/sdcard/%s" % os.path.basename(path)
 | 
					
						
							|  |  |  |   shutil.copyfile(path, install_path)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ret = subprocess.call(["pm", "install", "-r", install_path])
 | 
					
						
							|  |  |  |   os.remove(install_path)
 | 
					
						
							|  |  |  |   return ret == 0
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def start_offroad():
 | 
					
						
							|  |  |  |   set_package_permissions()
 | 
					
						
							|  |  |  |   system("am start -n ai.comma.plus.offroad/.MainActivity")
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def set_package_permissions():
 | 
					
						
							|  |  |  |   try:
 | 
					
						
							|  |  |  |     output = subprocess.check_output(['dumpsys', 'package', 'ai.comma.plus.offroad'], encoding="utf-8")
 | 
					
						
							|  |  |  |     given_permissions = output.split("runtime permissions")[1]
 | 
					
						
							|  |  |  |   except Exception:
 | 
					
						
							|  |  |  |     given_permissions = ""
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   wanted_permissions = ["ACCESS_FINE_LOCATION", "READ_PHONE_STATE", "READ_EXTERNAL_STORAGE"]
 | 
					
						
							|  |  |  |   for permission in wanted_permissions:
 | 
					
						
							|  |  |  |     if permission not in given_permissions:
 | 
					
						
							|  |  |  |       pm_grant("ai.comma.plus.offroad", "android.permission."+permission)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   appops_set("ai.comma.plus.offroad", "SU", "allow")
 | 
					
						
							|  |  |  |   appops_set("ai.comma.plus.offroad", "WIFI_SCAN", "allow")
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def appops_set(package, op, mode):
 | 
					
						
							|  |  |  |   system(f"LD_LIBRARY_PATH= appops set {package} {op} {mode}")
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def pm_grant(package, permission):
 | 
					
						
							|  |  |  |   system(f"pm grant {package} {permission}")
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def system(cmd):
 | 
					
						
							|  |  |  |   try:
 | 
					
						
							|  |  |  |     cloudlog.info("running %s" % cmd)
 | 
					
						
							|  |  |  |     subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
 | 
					
						
							|  |  |  |   except subprocess.CalledProcessError as e:
 | 
					
						
							|  |  |  |     cloudlog.event("running failed",
 | 
					
						
							|  |  |  |       cmd=e.cmd,
 | 
					
						
							|  |  |  |       output=e.output[-1024:],
 | 
					
						
							|  |  |  |       returncode=e.returncode)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # *** external functions ***
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def update_apks():
 | 
					
						
							|  |  |  |   # install apks
 | 
					
						
							|  |  |  |   installed = get_installed_apks()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   install_apks = glob.glob(os.path.join(BASEDIR, "apk/*.apk"))
 | 
					
						
							|  |  |  |   for apk in install_apks:
 | 
					
						
							|  |  |  |     app = os.path.basename(apk)[:-4]
 | 
					
						
							|  |  |  |     if app not in installed:
 | 
					
						
							|  |  |  |       installed[app] = None
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cloudlog.info("installed apks %s" % (str(installed), ))
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for app in installed.keys():
 | 
					
						
							|  |  |  |     apk_path = os.path.join(BASEDIR, "apk/"+app+".apk")
 | 
					
						
							|  |  |  |     if not os.path.exists(apk_path):
 | 
					
						
							|  |  |  |       continue
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     h1 = hashlib.sha1(open(apk_path, 'rb').read()).hexdigest()
 | 
					
						
							|  |  |  |     h2 = None
 | 
					
						
							|  |  |  |     if installed[app] is not None:
 | 
					
						
							|  |  |  |       h2 = hashlib.sha1(open(installed[app], 'rb').read()).hexdigest()
 | 
					
						
							|  |  |  |       cloudlog.info("comparing version of %s  %s vs %s" % (app, h1, h2))
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if h2 is None or h1 != h2:
 | 
					
						
							|  |  |  |       cloudlog.info("installing %s" % app)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       success = install_apk(apk_path)
 | 
					
						
							|  |  |  |       if not success:
 | 
					
						
							|  |  |  |         cloudlog.info("needing to uninstall %s" % app)
 | 
					
						
							|  |  |  |         system("pm uninstall %s" % app)
 | 
					
						
							|  |  |  |         success = install_apk(apk_path)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       assert success
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def pm_apply_packages(cmd):
 | 
					
						
							|  |  |  |   for p in android_packages:
 | 
					
						
							|  |  |  |     system("pm %s %s" % (cmd, p))
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__":
 | 
					
						
							|  |  |  |   update_apks()
 |