You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

264 lines
8.2 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. import datetime
  2. import json
  3. import os
  4. import re
  5. import shutil
  6. import subprocess
  7. import time
  8. from load_things import loaded
  9. from decode_parcel import decode_parcel
  10. debug = True
  11. # path = os.path.dirname(__file__)
  12. defaults = loaded.defaults
  13. keycodes = loaded.keycodes
  14. exe = defaults.exe
  15. def merge(src, dst,log = False):
  16. if not os.path.exists(dst):
  17. return False
  18. ok = True
  19. for path, dirs, files in os.walk(src):
  20. relPath = os.path.relpath(path, src)
  21. destPath = os.path.join(dst, relPath)
  22. if not os.path.exists(destPath):
  23. os.makedirs(destPath)
  24. for file in files:
  25. destFile = os.path.join(destPath, file)
  26. if os.path.isfile(destFile):
  27. if log:
  28. print("Skipping existing file: " + os.path.join(relPath, file))
  29. ok = False
  30. continue
  31. srcFile = os.path.join(path, file)
  32. shutil.move(srcFile, destFile)
  33. for path, dirs, files in os.walk(src, False):
  34. if len(files) == 0 and len(dirs) == 0:
  35. os.rmdir(path)
  36. return ok
  37. def _adb(*args,out = False):
  38. args = [exe] + list(args)
  39. if out:
  40. return subprocess.check_output(args,shell = False).decode().rstrip('\r\n')
  41. else:
  42. ret = subprocess.call(args,shell = False)
  43. if ret:
  44. raise subprocess.CalledProcessError(ret,args)
  45. def get_info():
  46. thing = _adb("devices","-l",out = True)
  47. formed = list(filter(bool,thing.split("\r\n")))[1:]
  48. main = {}
  49. for device in formed:
  50. categories = re.split(" +",device)
  51. device_dict = {
  52. "serial":categories[0],
  53. "mode":categories[1]
  54. }
  55. device_dict.update(dict(category.split(":") for category in categories[2:]))
  56. main[categories[0]] = device_dict
  57. return main
  58. class Device:
  59. def connect(ip,port=5555):
  60. if not re.match(r'(\d{1,3}\.){3}\d{1,3}',ip):
  61. raise TypeError("Invalid ip")
  62. if not all(int(n) <= 255 and int(n) >= 0 for n in ip.split('.')):
  63. raise TypeError("Invalid ip")
  64. if not (port >= 0 and port <= 2**16-1):
  65. raise TyperError("Port must be in the range 0-65536")
  66. id = '{}:{}'.format(ip,port)
  67. _adb('connect','{}:{}'.format(ip,port))
  68. dev = Device(id)
  69. dev.tcip = True
  70. return dev
  71. def disconnect(self):
  72. if self.tcip:
  73. _adb('disconnect',self.serial)
  74. #init operations
  75. def prim_device():
  76. cont = True
  77. while cont:
  78. try:
  79. d = Device()
  80. cont = False
  81. except IndexError:
  82. time.sleep(1)
  83. return d
  84. def __init__(self,serial=None):
  85. self.tcip = False
  86. if serial:
  87. self.serial = serial
  88. info = get_info()[serial]
  89. else:
  90. serial,info = list(get_info().items())[0]
  91. self.__dict__.update(info)
  92. #end of init operations
  93. #command interface
  94. def adb(self,*args,out = False):
  95. args = ['-s',self.serial]+ list(args)
  96. return _adb(*args,out = out)
  97. def shell(self,*args,out=False):
  98. args = ('shell',)+args
  99. return self.adb(*args,out=out)
  100. def sudo(self,*args,out = False):
  101. if self.mode == 'recovery':
  102. return self.shell(*args,out=out)
  103. else:
  104. args = '"{}"'.format(' '.join(args).replace('"','\\"'))
  105. return self.shell('su','-c',args,out = out)
  106. #end of cammand interface
  107. #file operations
  108. def type(self,file):
  109. exists = '''if [ -e "{file}" ]; then
  110. if [ -d "{file}" ]; then
  111. echo "directory"
  112. elif [ -f "{file}" ]; then
  113. echo "file"
  114. else
  115. echo "error"
  116. fi
  117. else
  118. echo "na"
  119. fi'''
  120. e = exists.format(file = file)
  121. res = self.sudo(e,out=True)
  122. return res
  123. def exists(self,file):
  124. return self.type(file) != "na"
  125. def isfile(self,file):
  126. return self.type(file) == 'file'
  127. def isdir(self,file):
  128. return self.type(file) == 'directory'
  129. def delete(self,path):
  130. return self.sudo("rm","-rf",path,out=True)
  131. def copy(self,remote,local,del_duplicates = True,ignore_error=True):
  132. remote_type = self.type(remote)
  133. if remote_type != "na":
  134. if remote_type == "directory" and not remote.endswith('/'):
  135. remote += '/'
  136. merge_flag = False
  137. if os.path.exists(local):
  138. last = os.path.split(local)[-1]
  139. real_dir = local
  140. local = os.path.join(defaults['local']['temp'],last)
  141. merge_flag = True
  142. try:
  143. self.adb("pull","-a",remote,local)
  144. except subprocess.CalledProcessError as e:
  145. if ignore_error:
  146. pass
  147. else:
  148. raise e
  149. if merge_flag:
  150. merge(local,real_dir)
  151. if os.path.exists(local) and del_duplicates:
  152. shutil.rmtree(local)
  153. else:
  154. print("File not found: {}".format(remote))
  155. def move(self,remote,local,del_duplicates = True,ignore_error=False):
  156. if self.exists(remote):
  157. self.copy(remote,local,del_duplicates = del_duplicates,ignore_error=ignore_error)
  158. self.delete(remote)
  159. else:
  160. print("File not found: {}".format(remote))
  161. def push(self,local,remote):
  162. self.adb('push',local,remote)
  163. #end of file operations
  164. #convenience
  165. def reboot(self,mode = None):
  166. if mode:
  167. if mode == "soft":
  168. if self.mode != 'recovery':
  169. pid = self.shell("pidof","zygote",out = True)
  170. return self.sudo("kill",pid,out=False)
  171. else:
  172. return self.reboot()
  173. else:
  174. self.adb("reboot",mode)
  175. else:
  176. self.adb("reboot")
  177. while True:
  178. infos = get_info()
  179. if len(infos) > 0:
  180. self.__dict__.update(infos[self.serial])
  181. break
  182. time.sleep(1)
  183. def send_keycode(self,code):
  184. try:
  185. keycode = keycodes[code]
  186. except KeyError:
  187. keycode = str(code)
  188. self.shell("input","keyevent",keycode)
  189. def unlock_phone(self,pass):
  190. if self.mode != 'recovery':
  191. if not decode_parcel(self.shell('service','call', 'power','12',out=True),'int'):
  192. self.send_keycode('power')
  193. if decode_parcel(self.shell('service','call','trust','7',out=True),'int'):
  194. self.send_keycode('space')
  195. self.shell("input","text",str(pass))
  196. self.send_keycode('enter')
  197. #end of convenience
  198. #twrp
  199. def backup(self,*partitions,name = None):
  200. if self.mode != 'recovery':
  201. self.reboot('recovery')
  202. backupdir = defaults['local']['TWRP']
  203. options_dict = {
  204. "system": "S",
  205. "data": "D",
  206. "cache": "C",
  207. "recovery": "R",
  208. "spec_part_1": "1",
  209. "spec_part_2": "2",
  210. "spec_part_3": "3",
  211. "boot": "B",
  212. "as": "A"
  213. }
  214. options = "".join(options_dict[option] for option in partitions)
  215. if not name:
  216. name = "backup_"+datetime.datetime.today().strftime(defaults['date_format'])
  217. filename = os.path.join(backupdir,name)
  218. self.shell("twrp","backup",options,name)
  219. phone_dir = "/data/media/0/TWRP/BACKUPS/{serial}/{name}".format(serial = self.serial,name = name)
  220. self.move(phone_dir,filename)
  221. def wipe(self,partition):
  222. if self.mode != 'recovery':
  223. self.reboot('recovery')
  224. self.shell("twrp","wipe",partition)
  225. def install(self,name):
  226. if self.mode != 'recovery':
  227. self.reboot('recovery')
  228. if os.path.exists(name):
  229. local_name = name
  230. name = os.path.split(name)[-1]
  231. update_path = '{}/{}'.format(defaults['remote']['updates'],name)
  232. if not self.exists(update_path):
  233. self.push(local_name,defaults['remote']['updates'])
  234. else:
  235. update_path = '{}/{}'.format(defaults['remote']['updates'],name)
  236. self.shell("twrp","install",update_path)
  237. #end of twrp
  238. if __name__ == "__main__" and debug:
  239. d = Device.prim_device()