def initAlreadyInstrApkEnv(self, pathToInstrApk, resultsDir, pathToInstrManifestFile=None): if not apk_utils.checkInputApkFile(pathToInstrApk): logger.error("Provided file [%s] is not a valid apk file!" % pathToInstrApk) return if not os.path.isdir(resultsDir): logger.error( "Provided path to results dir [%s] do not point to dir!" % resultsDir) return coverageMetadataFolderPath = os.path.join( resultsDir, self.config.getCoverageMetadataRelativeDir()) if not os.path.isdir(coverageMetadataFolderPath): logger.error( "In the results dir [%s] there is no folder with coverage metadata!" % resultsDir) return self.coverageMetadataFolder = coverageMetadataFolderPath if self.config.getCoverageMetadataFilename() not in os.listdir( coverageMetadataFolderPath): logger.error( "Cannot find metadata filename in the coverage metadata folder: %s!" % self.coverageMetadataFolder) return self.coverageMetadataFile = os.path.join( self.coverageMetadataFolder, self.config.getCoverageMetadataFilename()) #by default trying to look for a file in the if pathToInstrManifestFile: androidManifestPath = pathToInstrManifestFile else: androidManifestPath = os.path.join(resultsDir, "AndroidManifest.xml") if not os.path.isfile(androidManifestPath): logger.warning( "Path [%s] is not pointing to a real file! Leaving pointer to AndroidManifest.xml empty!" % androidManifestPath) return self.instrumentedApk = pathToInstrApk self.apkResultsDir = resultsDir self.runtimeReportsRootDir = self._createDir( resultsDir, self.config.getRuntimeReportsRelativeDir(), False, False) self.androidManifestFile = androidManifestPath self.androidManifest = AndroidManifest(self.androidManifestFile) self.packageName = self.androidManifest.getInstrumentationTargetPackage( ) self.runnerName = self.androidManifest.getInstrumentationRunnerName() self._bboxStateMachine.start(STATE_VALID_SETTINGS_PROVIDED)
def __init__(self, adbDevice, pathToAndroidManifest): self.adbDevice = adbDevice self.androidManifest = AndroidManifest(pathToAndroidManifest)
def instrumentApkForCoverage(self, pathToOrigApk, resultsDir=None, tmpDir=None, removeApkTmpDirAfterInstr=True, copyApkToRes=True): ''' Args: :param pathToOrigApk: :param resultsDir: :param tmpDir: Returns: :ret True - if instrumentation was successful, False otherwise ''' self._bboxStateMachine.start(STATE_UNINITIALIZED) valid = self._checkProvidedApk(pathToOrigApk) if not valid: return False self._bboxStateMachine.transitToState(STATE_APK_VALID) resultsRootDir = None if not resultsDir: resultsRootDir = os.path.join(os.getcwd(), RESULTS_RELATIVE_DIR) else: resultsRootDir = os.path.abspath(resultsDir) tmpRootDir = None if not tmpDir: tmpRootDir = os.path.join(os.getcwd(), TMP_RELATIVE_DIR) else: tmpRootDir = os.path.abspath(tmpDir) apkFileName = os.path.splitext(os.path.basename(pathToOrigApk))[0] self.apkTmpDir = self._createDir(tmpDir, apkFileName, False, True) self.apkResultsDir = self._createDir(resultsRootDir, apkFileName, False, True) self.coverageMetadataFolder = self._createDir( self.apkResultsDir, self.config.getCoverageMetadataRelativeDir(), False, True) self.runtimeReportsRootDir = self._createDir( self.apkResultsDir, self.config.getRuntimeReportsRelativeDir(), False, True) self._bboxStateMachine.transitToState(STATE_FOLDERS_CREATED) #coping initial apk file if required if copyApkToRes: shutil.copy2(pathToOrigApk, self.apkResultsDir) #decompiling apk into a folder decompileDir = os.path.join(self.apkTmpDir, self.config.getDecompiledApkRelativeDir()) success = self._decompileApk(self.bboxInstrumenter, pathToOrigApk, decompileDir) if not success: return False self._bboxStateMachine.transitToState(STATE_APK_DECOMPILED) #getting all available dex files dexFilesRelativePaths = self._getDexFilePathsRelativeToDir( decompileDir) if not dexFilesRelativePaths: logger.error("There is no dex files to convert!") return False if "classes.dex" not in dexFilesRelativePaths: # "classes.dex" must be in the decompile root directory logger.error( "There is no classes.dex file found in the list of dex files") return False #converting dex to jar files rawJarFilesRootDir = os.path.join(self.apkTmpDir, self.config.getTmpJarRelativeDir()) jarFilesRelativePaths = self._convertDex2JarFiles( converter=self.bboxInstrumenter, dexFilesRootDir=decompileDir, dexFilesRelativePaths=dexFilesRelativePaths, jarFilesRootDir=rawJarFilesRootDir, proceedOnError=True) self._bboxStateMachine.transitToState(STATE_DEX_CONVERTED_TO_JAR) if "classes.jar" not in jarFilesRelativePaths: #main file is not converted logger.error( "Conversion from classes.dex to classes.jar was not successful!" ) return False #instrumenting available jar files self.coverageMetadataFile = os.path.join( self.coverageMetadataFolder, self.config.getCoverageMetadataFilename()) emmaInstrJarFilesRootDir = os.path.join( self.apkTmpDir, self.config.getInstrumentedFilesRelativeDir()) emmaInstrJarFileRelativePaths = self._instrFilesWithEmma( instrumenter=self.bboxInstrumenter, jarFilesRootDir=rawJarFilesRootDir, jarFilesRelativePaths=jarFilesRelativePaths, instrJarsRootDir=emmaInstrJarFilesRootDir, coverageMetadataFile=self.coverageMetadataFile, proceedOnError=True) self._bboxStateMachine.transitToState(STATE_JARS_INSTRUMENTED) if "classes.jar" not in emmaInstrJarFileRelativePaths: #main file is not instrumented logger.error("Instrumentation of classes.jar was not successful!") return False #converting jar files back to dex files instrDexFilesRelativePaths = self._convertJar2DexWithInstr( converter=self.bboxInstrumenter, instrJarsRootDir=emmaInstrJarFilesRootDir, instrJarFilesRelativePaths=emmaInstrJarFileRelativePaths, finalDexFilesRootDir=decompileDir, proceedOnError=True) self._bboxStateMachine.transitToState(STATE_JAR_CONVERTED_TO_DEX) if "classes.dex" not in instrDexFilesRelativePaths: logger.error( "There is no classes.dex file found in the list of dex files") return False #checking what files have not been converted uninstrumentedFiles = self._getUnInstrFilesRelativePaths( dexFilesRelativePaths, instrDexFilesRelativePaths) if uninstrumentedFiles: logger.debug("The following files were not instrumented: %s" + str(uninstrumentedFiles)) #instrument AndroidManifest.xml decompiledAndroidManifestPath = os.path.join(decompileDir, "AndroidManifest.xml") success = self._instrAndroidManifest(self.bboxInstrumenter, decompiledAndroidManifestPath) if not success: logger.error("Cannot instrument AndroidManifest.xml file!") return False #coping instrumented AndroidManifest.xml to result folder shutil.copy2(decompiledAndroidManifestPath, self.apkResultsDir) self.androidManifestFile = os.path.join(self.apkResultsDir, "AndroidManifest.xml") self._bboxStateMachine.transitToState(STATE_MANIFEST_INSTRUMENTED) compiledApkFilePath = os.path.join( self.apkResultsDir, "%s%s.apk" % (apkFileName, self.config.getInstrFileSuffix())) success = self._compileApk(self.bboxInstrumenter, decompileDir, compiledApkFilePath) if not success: logger.error("Cannot build apk!") return False self._bboxStateMachine.transitToState(STATE_INSTRUMENTED_APK_BUILD) #need to copy resources into file compiledApkFilePathWithEmmaRes = os.path.join( self.apkResultsDir, "%s%s.apk" % (apkFileName, self.config.getFinalInstrFileSuffix())) shutil.copy2(compiledApkFilePath, compiledApkFilePathWithEmmaRes) self._putAdditionalResources( apk=compiledApkFilePathWithEmmaRes, resources=self.config.getEmmaResourcesDir()) self._bboxStateMachine.transitToState( STATE_FINAL_INSTRUMENTED_APK_BUILD) signedApkFilePath = os.path.join( self.apkResultsDir, "%s%s.apk" % (apkFileName, self.config.getSignedFileSuffix())) success = self._signApk(self.bboxInstrumenter, compiledApkFilePathWithEmmaRes, signedApkFilePath) if not success: logger.error("Cannot sign apk!") return False self._bboxStateMachine.transitToState(STATE_INSTRUMENTED_APK_SIGNED) alignedApkFilePath = os.path.join( self.apkResultsDir, "%s%s.apk" % (apkFileName, self.config.getAlignedFileSuffix())) success = self._alignApk(self.bboxInstrumenter, signedApkFilePath, alignedApkFilePath) if not success: logger.error("Cannot align apk!") return False self._bboxStateMachine.transitToState(STATE_INSTRUMENTED_APK_ALIGNED) #cleaning: if tmp dir needs to be removed after instrumentation if removeApkTmpDirAfterInstr: shutil.rmtree(self.apkTmpDir) self.instrumentedApk = alignedApkFilePath self.androidManifest = AndroidManifest(self.androidManifestFile) self.packageName = self.androidManifest.getInstrumentationTargetPackage( ) self.runnerName = self.androidManifest.getInstrumentationRunnerName() #Final node transition self._bboxStateMachine.transitToState(STATE_APK_INSTRUMENTED) return True