def combineFrameworkPartitions(frameworkDir): """ Combine framework partitions into framework.jar.out. """ # For Android 5.0, handle dex partitions. dst = os.path.join(frameworkDir, "framework.jar.out", "smali") partitionPath = os.path.join(frameworkDir, "framework.jar.out", "smali_classes2") if os.path.exists(partitionPath): Log.i(TAG, "Combine %s into framework.jar.out/smali" % partitionPath) for subDir in os.listdir(partitionPath): src = os.path.join(partitionPath, subDir) Utils.run(["cp", "-r", src, dst], stdout=subprocess.PIPE).communicate() shutil.rmtree(partitionPath) # For Android Handle framework partitions for partition in PARTITIONS: if partition == "framework.jar.out": continue partitionPath = os.path.join(frameworkDir, partition) if os.path.exists(partitionPath): Log.i(TAG, "Combine %s into framework.jar.out" % partition) src = os.path.join(partitionPath, "smali") dst = os.path.join(frameworkDir, "framework.jar.out") Utils.run(["cp", "-r", src, dst], stdout=subprocess.PIPE).communicate() shutil.rmtree(partitionPath)
def getBasePath(base): try: devices = os.path.join(os.environ["PORT_ROOT"], "devices") return os.path.join(devices, base) except KeyError: Log.e(TAG, "device %s not found" % base) sys.exit(155)
def decode(baiduZip, out): """ Decode FRAMEWORK_JARS in baidu.zip into out directory. """ Log.i(TAG, "Generating %s from %s" % (out, baiduZip)) # Phase 1: deodex deodexZip = Utils.deodex(baiduZip) if deodexZip == None: return # Phase 2: decode framework jars temp = tempfile.mkdtemp() Log.i(TAG, "unzip %s to %s" % (deodexZip, temp)) subp = Utils.run(["unzip", "-q", "-o", deodexZip, "-d", temp], stdout=subprocess.PIPE) subp.communicate() if not os.path.exists(out): os.makedirs(out) Utils.decodeAPKandJAR(temp, out) shutil.rmtree(temp) # Phase 3: combine framework partitions Utils.combineFrameworkPartitions(out)
def portingFiles(self, commit, filesChanged, dstDir): """ Generate patch files for porting """ # Reset to the commit self.reset(commit) Log.i( TAG, "Generating %s from %s at commit %s" % (dstDir, self.basePath, commit)) if not os.path.exists(dstDir): os.makedirs(dstDir) # Copy changed items from source for item in filesChanged: src = os.path.join(self.basePath, item) dst = os.path.join(dstDir, item) if os.path.exists(src): # Only copy files in FRAMEWORK_JARS if not Utils.isInFramework(item): continue # We need to format the SMALI file. # Copy all the sub classes even if no change. Utils.copyWholly(src, os.path.dirname(dst)) Utils.combineFrameworkPartitions(dstDir)
def printSubprocessOut(subp): while True: buff = subp.stdout.readline().strip('\n') if buff == '' and subp.poll() != None: break Log.i(TAG, buff)
def porting(self): """ Porting changes from commit1 to commit2 commit is 7 bits """ # Phase 1: get the lower and upper commit commitModel = CommitModel(self.baseDevice) (lowerCommit, upperCommit) = commitModel.getCommitRange(OPTIONS.commit1, OPTIONS.commit2) Log.d( TAG, "Porting.prepare(). lowerCommit = %s, upperCommit = %s" % (lowerCommit, upperCommit)) # Phase 2: Prepare the older and newer root if OPTIONS.patchXml == Config.PORTING_XML: OPTIONS.newerRoot = os.path.join( Config.AUTOPATCH, "%s_newer_%s" % (self.baseDevice.name(), upperCommit)) OPTIONS.olderRoot = os.path.join( Config.AUTOPATCH, "%s_older_%s" % (self.baseDevice.name(), lowerCommit)) filesChanged = self.baseDevice.getFilesChanged(lowerCommit, upperCommit) self.baseDevice.portingFiles(upperCommit, filesChanged, OPTIONS.newerRoot) self.baseDevice.portingFiles(lowerCommit, filesChanged, OPTIONS.olderRoot) # Phase 3: Restore the commit model commitModel.restore() # Phase 4: prepare patch XML ChangeList(OPTIONS.olderRoot, OPTIONS.newerRoot, OPTIONS.patchXml).make(force=True)
def dump(self): Log.d(TAG, "prepare = %s" % str(self.prepare)) Log.d( TAG, "baseName = %s, patchXml = %s, olderRoot = %s, newerRoot = %s, commit1 = %s, commit2 = %s" % (self.baseName, self.patchXml, self.olderRoot, self.newerRoot, self.commit1, self.commit2))
def out(self, outDir=None): if outDir is None: outDir = self.mOutDir for itype in self.mImgDict.keys(): outFile = os.path.join(outDir, "%s.img" % (itype)) shutil.copyfile(self.mImgDict[itype], outFile) Log.i(LOG_TAG, "Out: %s" % (outFile)) shutil.rmtree(self.mWorkdir)
def appendPart(self, part): """ Append a part to list if not exist """ try: self.mPartList.index(part) except: Log.d(TAG, " [Add new part %s ] " % part) self.mPartList.append(part)
def __init__(self): """ baseName is the short device name """ Log.i(TAG, "Start preparing essential files in %s" % Config.AUTOPATCH) self.baseDevice = BaseDevice(OPTIONS.baseName) if OPTIONS.patchXml == Config.PATCHALL_XML: self.patchall() elif OPTIONS.patchXml == Config.UPGRADE_XML: self.upgrade() elif OPTIONS.patchXml == Config.PORTING_XML: self.porting()
def deletePart(self, part): """ Delete a part """ try: self.mPartList.remove(part) Log.d(TAG, " [Delete part %s ] " % part) except: Log.e(TAG, "SmaliSpliiter.deltePart(): can not find part %s" % part)
def writeXML(dom): # tree = ET.ElementTree(root) # tree.write(ChangeList.PATCH_XML, #pretty_print=True, # xml_declaration=True, encoding='utf-8') f = open(ChangeList.PATCH_XML, 'w') dom.writexml(f, addindent=' ', newl='\n', encoding='utf-8') f.close() Log.i(TAG, "%s is generated" % ChangeList.PATCH_XML)
def isInFramework(filepath): """ Is the file path in jars defined in FRAMEWORK_JARS """ relRoot = filepath.split("/")[0] result = relRoot[0:-4] in FRAMEWORK_JARS Log.d( TAG, "Utils.isInFramework(): %s, %s -> %s" % (result, filepath, relRoot)) return result
def bosp(self, bospDst, force=True): """ Prepare BOSP, set force to be False to not generate again if exists. """ if force: subp = Utils.run(["rm", "-rf", bospDst], stdout=subprocess.PIPE) subp.communicate() Log.i(TAG, "Generating %s from %s" % (bospDst, self.basePath)) Utils.copyAPKandJAR(self.basePath, bospDst, self.target_is_ab_system())
def replacePart(self, targetPart, newerPart): """ Replace the target with the newer. """ try: index = self.mPartList.index(targetPart) self.mPartList[index] = newerPart Log.d(TAG, " [Replace %s by %s] " % (targetPart, newerPart)) except: Log.e( TAG, "SmaliSplitter.replacePart() can not find part %s" % targetPart)
def __pull__(self): bootEntry = mtkEntry(imagetype.BOOT, self.mFstab.getEntry(imagetype.BOOT)) Log.i(LOG_TAG, "Try to pull boot partition from device ...") adBoot = AndroidFile(bootEntry.mMp) adBoot.pull(self.mBootImg, bootEntry.mStart, bootEntry.mSize) recoveryEntry = mtkEntry(imagetype.RECOVERY, self.mFstab.getEntry(imagetype.RECOVERY)) Log.i(LOG_TAG, "Try to pull recovery partition from device ...") adRecovery = AndroidFile(recoveryEntry.mMp) adRecovery.pull(self.mRecoveryImg, recoveryEntry.mStart, recoveryEntry.mSize)
def make(self, force=True): """ Generate the change list into XML. Set force as False not to generate again if exists. """ if not force and os.path.exists(ChangeList.PATCH_XML): Log.d(TAG, "Using the existing %s" % ChangeList.PATCH_XML) return True Log.i(TAG, "Generating %s" % ChangeList.PATCH_XML) hasChange = ChangeList.XMLFromDiff() return hasChange
def __init__(self): ''' Constructor ''' super(mtkpull, self).__init__() self.mFstabConfig = fstabconfig(mtkpull.getFstabconfigFile()) self.mFstab = fstab(AndroidFile(mtkpull.MTK_DUMCHAR_INFO), self.mFstabConfig) Log.d(LOG_TAG, "work dir: %s" % (self.mWorkdir)) self.mBootImg = os.path.join(self.mWorkdir, "boot.img") self.mRecoveryImg = os.path.join(self.mWorkdir, "recovery.img")
def aosp(self, aospDst): """ Prepare AOSP to asopDst """ aospSrc = os.path.join(self.basePath, "vendor/aosp") # If no AOSP under vendor/ , decode them out if not os.path.exists(aospSrc): os.makedirs(aospSrc) vendorRoot = os.path.join(self.basePath, "vendor") Utils.decodeAPKandJAR(vendorRoot, aospSrc) if not os.path.exists(aospDst): Log.i(TAG, "Generating %s from %s" % (aospDst, aospSrc)) Utils.copyAPKandJAR(aospSrc, aospDst, self.target_is_ab_system())
def conflictPart(self, olderPart, newerPart): """ If older and newer are the same content, no conflict happen. Otherwise, mark out conflict. """ # Get older part content olderHandle = open(olderPart, "rb") olderContent = olderHandle.read() olderHandle.close() # Get newer part content newerHandle = open(newerPart, "r+") newerContent = newerHandle.read() # Compare older and newer content if olderContent == newerContent: # No need to handle access any more # # BOSP has no change on AOSP. # # Still handle this case: "access$" method # if newerPart.find("access$") >= 0: # Log.d(TAG, " [Might useful access part %s ] " % newerPart) # # lines = [] # lines.append("\n# Remove the first '#' if you want to enable this method. It might be invoked from codes of BOSP.\n") # for line in newerContent.splitlines(): # if len(line) > 0: line = "#%s\n" % line # lines.append(line) # # newerHandle.seek(0) # newerHandle.truncate() # newerHandle.writelines(lines) # newerHandle.close() # self.mPartList.append(newerPart) # else: # newerHandle.close() newerHandle.close() else: # BOSP has changes on AOSP. # Conflict happened Log.d(TAG, " [Conflict part %s ] " % newerPart) # Mark out the conflict newerContent = "\n<<<<<<< VENDOR\n=======%s\n>>>>>>> BOSP\n" % newerContent newerHandle.seek(0) newerHandle.truncate() newerHandle.write(newerContent) newerHandle.close() self.mPartList.append(newerPart)
def porting(self): """ Porting changes from commit1 to commit2 commit is 7 bits """ # Phase 1: get the lower and upper commit commitModel = CommitModel(self.baseDevice) (lowerCommit, upperCommit) = commitModel.getCommitRange(OPTIONS.commit1, OPTIONS.commit2) Log.d( TAG, "Porting.prepare(). lowerCommit = %s, upperCommit = %s" % (lowerCommit, upperCommit)) # Phase 2: Prepare the older and newer root if OPTIONS.patchXml == Config.PORTING_XML: OPTIONS.newerRoot = os.path.join( Config.AUTOPATCH, "%s_newer_%s" % (self.baseDevice.name(), upperCommit)) OPTIONS.olderRoot = os.path.join( Config.AUTOPATCH, "%s_older_%s" % (self.baseDevice.name(), lowerCommit)) filesChanged = self.baseDevice.getFilesChanged(lowerCommit, upperCommit) self.baseDevice.portingFiles(upperCommit, filesChanged, OPTIONS.newerRoot) self.baseDevice.portingFiles(lowerCommit, filesChanged, OPTIONS.olderRoot) # Phase 3: Restore the commit model commitModel.restore() # Phase 4: prepare patch XML # TODO Fix upgrade no wifi-service.jar.out # Temporary solution, remove the following code later wifi_service = os.path.join(OPTIONS.olderRoot, "wifi-service.jar.out") if not os.path.exists(wifi_service): src = os.path.join(self.baseDevice.basePath, "vendor/aosp/wifi-service.jar.out") if os.path.exists(src): subp = Utils.run(["cp", "-r", src, OPTIONS.olderRoot], stdout=subprocess.PIPE) subp.communicate() # Temporary solution, remove the above code later ChangeList(OPTIONS.olderRoot, OPTIONS.newerRoot, OPTIONS.patchXml).make(force=True)
def combineFrameworkPartitions(frameworkDir): """ Combine framework partitions into framework.jar.out. """ for partition in PARTITIONS: if partition == "framework.jar.out": continue partitionPath = os.path.join(frameworkDir, partition) if os.path.exists(partitionPath): Log.i(TAG, "Combine %s into framework.jar.out" % partition) src = os.path.join(partitionPath, "smali") dst = os.path.join(frameworkDir, "framework.jar.out") subp = Utils.run(["cp", "-r", src, dst], stdout=subprocess.PIPE) subp.communicate() shutil.rmtree(partitionPath)
def otaNormalize(boardZip): """ Normalize the OTA package zip, return the root directory of unziped files """ if not os.path.exists(boardZip): Log.e(TAG, "oatNormalize() % not exists" % boardZip) return None zipFormatter = ZipFormatter.create(ZipFormatter.genOptions(boardZip)) # Do not need to zip back zipFormatter.format(zipBack=False) root = zipFormatter.getFilesRoot() if not os.path.exists(root): Log.e(TAG, "otaNormalize() normalize %s failed!" % boardZip) return None return root
def pull(outDir): ret = False Log.i( LOG_TAG, "Begin pull boot and recovery, make sure your phone was connected and adb devices is fine!" ) Log.i(LOG_TAG, "It may take a few minutes, please wait....") check() Log.i(LOG_TAG, "adb connect success.") if mtkpull.isMtkDevice() and mtkpull.do(outDir): Log.d("pull_boot_recovery", "Success use mtkpull to pull images....") ret = True else: if pull.do(outDir): Log.d("pull_boot_recovery", "Success to pull images....") ret = True assert ret == True, "Failed to pull images....."
def copyAPKandJAR(src, dst, targetAbSystem): if not os.path.exists(dst): os.makedirs(dst) baseRootPath = os.path.join(src, "ROOT") baseBootPath = os.path.join(src, "boot.img.out") baseRamDisk = os.path.join(baseBootPath, "RAMDISK") dstRootPath = os.path.join(dst, "ROOT") dstBootPath = os.path.join(dst, "boot.img.out") dstRamDisk = os.path.join(dstBootPath, "RAMDISK") baseAbSystem = os.path.exists(baseRootPath) if baseAbSystem: if targetAbSystem: subp = Utils.run(["cp", "-r", baseRootPath, dst], stdout=subprocess.PIPE) else: os.makedirs(dstBootPath) subp = Utils.run(["cp", "-r", baseRootPath, dstRamDisk], stdout=subprocess.PIPE) else: if targetAbSystem: subp = Utils.run(["cp", "-r", baseRamDisk, dstRootPath], stdout=subprocess.PIPE) else: subp = Utils.run(["cp", "-r", baseBootPath, dst], stdout=subprocess.PIPE) subp.communicate() frwRes = os.path.join(src, "framework-res") subp = Utils.run(["cp", "-r", frwRes, dst], stdout=subprocess.PIPE) subp.communicate() for jarname in FRAMEWORK_JARS: jarname += ".out" srcJar = os.path.join(src, jarname) if os.path.exists(srcJar): Log.d( TAG, "Utils.copyAPKandJAR(). copying %s to %s" % (srcJar, dst)) subp = Utils.run(["cp", "-r", srcJar, dst], stdout=subprocess.PIPE) subp.communicate() Utils.combineFrameworkPartitions(dst)
def handle(self, argv): if len(argv) == 1: Options.usage() try: (opts, args) = getopt.getopt(argv[1:], "hlputb:c1:c2:", \ [ "help", "loosely", "patchall", "upgrade", "porting", "base=", "commit1=", "commit2=" ]) Log.d(TAG, "Program args = %s" % args) except getopt.GetoptError: Options.usage() for name, value in opts: if name in ("--help", "-h"): Options.usage() elif name in ("--loosely", "-l"): self.prepare = False elif name in ("--patchall", "-p"): self.patchXml = Config.PATCHALL_XML self.olderRoot = Config.AOSP_ROOT self.newerRoot = Config.BOSP_ROOT elif name in ("--upgrade", "-u"): self.patchXml = Config.UPGRADE_XML self.olderRoot = Config.LAST_BOSP_ROOT self.newerRoot = Config.BOSP_ROOT elif name in ("--porting", "-t"): # The older and newer root are generated by the commit1 and commit2 self.patchXml = Config.PORTING_XML elif name in ("--base", "-b"): if len(value) > 0: self.baseName = value elif name in ("--commit1", "-1"): if len(value) > 0: self.commit1 = value elif name in ("--commit2", "-2"): if len(value) > 0: self.commit2 = value self.dump() return self
def copyWholly(srcFilePath, dstDirname): """ Copy whole SMALI files which are in the same JAVA file Especially for the case of inner class, it has '$' in file path """ if not os.path.exists(dstDirname): os.makedirs(dstDirname) # Copy all the sub classes even if no change. # We need to format the SMALI file pos = srcFilePath.find("$") if pos > 0: srcFilePath = srcFilePath[0:pos] + "*" elif srcFilePath.endswith(".smali"): srcFilePath = srcFilePath.rstrip(".smali") + "*" # Note: Do not use commands.mkarg here cmd = "cp %s %s" % (srcFilePath, dstDirname) Log.d(TAG, "Utils.copyWholly(): %s" % cmd) commands.getstatusoutput(cmd)
def run(cmd): """ Run command in shell. Set `isMakeCommand` to True if command is a `make` command """ subp = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output = None while True: buff = subp.stdout.readline().strip('\n') print buff if buff == '' and subp.poll() != None: break output = buff Log.d(TAG, "Shell.run() %s return %s" %(cmd, subp.returncode)) status = Shell.parseHelpStatus(subp.returncode, "%s" %output) return status
def copyAPKandJAR(src, dst): if not os.path.exists(dst): os.makedirs(dst) frwRes = os.path.join(src, "framework-res") subp = Utils.run(["cp", "-r", frwRes, dst], stdout=subprocess.PIPE) subp.communicate() for jarname in FRAMEWORK_JARS: jarname += ".out" srcJar = os.path.join(src, jarname) if os.path.exists(srcJar): Log.d( TAG, "Utils.copyAPKandJAR(). copying %s to %s" % (srcJar, dst)) subp = Utils.run(["cp", "-r", srcJar, dst], stdout=subprocess.PIPE) subp.communicate() Utils.combineFrameworkPartitions(dst)
def __getRootShell__(): subp = subprocess.Popen(["check-su"], stdout=subprocess.PIPE) subp.communicate() if subp.returncode == 0: Log.i("AdbShell", "use su to root") return SuShell() else: Log.i("AdbShell", "Can not use su to root, assume your phone has already been root with modify default.prop in boot!") Log.i("AdbShell", "Try adb root, it may be blocked!") subp = subprocess.Popen(["adb", "root"], stdout=subprocess.PIPE) subp.communicate() Log.i("AdbShell", "Root successfull") return AdbShell()