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)
示例#2
0
 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