Current location - Quotes Website - Signature design - Daily work 2022.4. 19 PackageManager service scans the APK directory.
Daily work 2022.4. 19 PackageManager service scans the APK directory.
2022.4. 19

The user option of upgrading witen 5. 1 to bturnc 5.3 without binding imei is clarified.

6 scan APK directory

Call the scanDirTracedLI method in the constructor of PackageManagerService to scan the apk file of a directory.

In Android 10.0, PKMS mainly scans the APK information of the following paths:

/Supplier/Coverage

/product/coverage

/product service/coverage

/ODM/ overlay

/OEM/ coverage

/system/framework

/System/Private Applications

/system/application

/Vendor/Private Applications

/vendor/application

/odm/priv-app

/odm/app

/oem/app

/oem/priv-app

/Products/Privacy Applications

/products/applications

/Product Services/Privacy Applications

/products, services/applications

/Product Services/Privacy Applications

Let's take scanDirTracedLI () as the entrance to analyze:

6. 1[ParallelPackageParser.java]scanDirTracedLI()

As can be seen from the following function, the entry of scanDirTracedLI is very simple. First, add some log traces of systtrace, and then call scanDirLI () for analysis.

private void scanDirTracedLI(File scanDir,final int parseFlags,int scanFlags,long currentTime) {

TRACE . TRACE begin(TRACE _ TAG _ PACKAGE _ MANAGER," scanDir["+scanDir . getabsolutepath()+"]");

Try {

scanDirLI(scanDir,parseFlags,scanFlags,current time);

} Finally {

TRACE . TRACE end(TRACE _ TAG _ PACKAGE _ MANAGER);

}

}

6.2 [Parallelpackageparser.java] Scandi

ScanDirLI () uses the object of ParallelPackageParser, which is a queue. Here we take apk of all mobile phone systems, then take apk from these queues, and then call PackageParser for parsing.

private void scanDirLI(File scanDir,int parseFlags,int scanFlags,long currentTime) {

final File[]files = scandir . list files();

if (ArrayUtils.isEmpty(files)) {

Log.d (label, "No file in application directory"+scandir);

Return;

}

If (debug package scan)

Log.d (label, "scan application directory"+scandir+"scanflags ="+scanflags.

+" flags = 0x "+integer . tohexstring(parse flags));

}

//parallelPackageParser is the queue for collecting system apk files.

//Then take out apk from this queue one by one and call PackageParser for parsing.

try(ParallelPackageParser ParallelPackageParser = new ParallelPackageParser(

mSeparateProcesses,mOnlyCore,mMetrics,mCacheDir,

mparallelpackaparsercallback)){

//Submit files in parallel for parsing.

int file count = 0;

For (file file: file)

//is an Apk file or directory.

The final boolean value ispackage = (isapkfile (file) || file.isdirectory ())

& amp& amp! package installer service . isstagename(file . getname());

Filter out non-apk files, if not, skip and continue scanning.

If (! isPackage) {

//Ignore entries that are not packages

Continue;

}

The mQueue, the object that stores APK information in parallelPackageParser, assigns the PackageParser () function to the pkg members in the queue.

//Reference [6.3]

parallelpackageparser . submit(file,parse flags);

filecount++;

}

//Process the results one by one

for(; File Count & gt0; File Count-) {

//Take out the information of queue apk from parallelPackageParser.

ParallelPackageParser。 parse result parse result = parallelpackageparser . take();

throwable throwable = parse result . throwable;

int errorCode = PackageManager。 INSTALL _ SUCCEEDED

if (throwable == null) {

// TODO(toddke): Move down in the scan chain.

//The static shared library has a composite package name.

if(parse result . pkg . application info . isstaticsharedlibrary()){

renameStaticSharedLibraryPackage(parse result . pkg);

}

Try {

//Call the scanPackageChildLI method to scan a specific apk file.

//The instance of this class represents an apk file, so it is the data structure corresponding to the APK file.

//Reference [6.4]

scanPackageChildLI(parse result . pkg,parseFlags,scanFlags,

currentTime,null);

} catch(PackageManagerException e){

errorCode = e.error

Slog.w(TAG, "failed to scan"+parseresult.scanfile+":"+e.getmessage ());

}

} else if(throwable instance of package parser。 PackageParserException) {

PackageParser。 package parser exception e =(package parser。 PackageParserException)

Throwing;

errorCode = e.error

Slog.w(TAG, "failed to parse"+parseresult.scanfile+":"+e.getmessage ());

} Otherwise {

Throws a new IllegalStateException ("Unexpected exception while parsing"

+ parseResult.scanFile,throwable);

}

//Delete invalid user data application.

//If it is a non-system apk, the parsing fails.

if((scan flags & amp; SCAN_AS_SYSTEM) == 0。 & amp

Error code! = PackageManager。 Installation successful) {

logCriticalInfo(Log。 Warning,

"Delete the invalid package at"+parseResult.scanFile ");

//Non-system package scan failed. Delete files.

removeCodePathLI(parse result . scan file);

}

}

}

}

6.3 [parallelpackageparser.java] submission

Put the APK and other contents in the scanning path into the queue mQueue, and assign parsePackage () to ParseResult for subsequent call.

Public void submit (int parseFlags) {

mservice . submit(()-& gt; {

parse result pr = new parse result();

TRACE . TRACE begin(TRACE _ TAG _ PACKAGE _ MANAGER," parallel parse PACKAGE["+scan file+"]");

Try {

package parser PP = new package parser();

PP . setseparateprocesses(mSeparateProcesses);

PP . setonlycoresses(monly core);

Pp.setDisplayMetrics (metric);

PP . setcachedir(mCacheDir);

PP . set callback(mPackageParserCallback);

pr . scan file = scan file;

pr.pkg = parsePackage(pp,scanFile,parse flags);

Catch (e can be thrown e) {

pr . throwable = e;

} Finally {

TRACE . TRACE end(TRACE _ TAG _ PACKAGE _ MANAGER);

}

Try {

mqueue . put(pr);

} catch (InterruptedException e) {

Thread.currentThread()。 Interrupt ();

//Propagate the result to the caller of take ().

//This helps prevent the main thread from getting stuck while waiting.

// ParallelPackageParser ends when interrupted.

mInterruptedInThread = thread . current thread()。 getName();

}

});

}

Analyze apk through parsePackage. If the packageFile passed in is a directory, call parseClusterPackage () for parsing.

If the incoming APK file is called, it is called parseMonolithicPackage () for parsing.

Common package parsing package (package file, integer flag, Boolean use cache)

Throwing PackageParserException {

...

if (packageFile.isDirectory()) {

//If the passed packageFile is a directory, call parseClusterPackage () for parsing.

parsed = parseClusterPackage(package file,flags);

} Otherwise {

//If it is an APK file, call parseMonolithicPackage () to parse it.

parsed = parsimonolicipackage(package file,flags);

}

...

Returns a parsed;

}

Let's take a look at parseClusterPackage ()

Function: Parses all apk contained in a given directory and treats them as a single package. This can also perform integrity checks, such as requiring the same package name and version code, a single basic APK and a unique partition name.

Firstly, the apk file in the directory is parsed by parseClusterPackageLite (), and the main difference is whether it is a core application or a non-core application. There is only one core application, and non-core applications can be absent or multiple. The function of non-core applications is mainly to save resources and code. Then call parseBaseApk analysis on the core application to generate the package. The non-core application calls parseSplitApk, and the analysis result is placed in the previous package object.

Private package parseClusterPackage (file packageDir, int flags) throws PackageParserException {

//Get the PackageLite object of the application directory, which stores the names of core applications and non-core applications in the directory respectively.

final package lite = parseClusterPackageLite(package dir,0);

//If there is no core application in lite, exit.

If (mOnlyCoreApps & amp& amp lite.coreApp) {

Throw a new packageparseexception (install _ parse _ failed _ manifest _ for mattered,

"not coreapp:"+packagedir);

}

//Generate a split dependency tree.

//Establish partition dependency tree

SparseArray split dependencies = null;

Eventually SplitAssetLoader assetLoader

if(lite . isolated splits & amp; & amp! array utils . isempty(lite . split names)){

Try {

split dependencies = splitassetdependencyloader . createdependencies from package(lite);

asset loader = new SplitAssetDependencyLoader(lite,splitDependencies,flags);

} catch(SplitAssetDependencyLoader。 IllegalDependencyException e) {

Throw a new packageparseexception (install _ parse _ failed _ bad _ manifest, e.getmessage ());

}

} Otherwise {

asset loader = new DefaultSplitAssetLoader(lite,flags);

}

Try {

final asset manager assets = asset loader . getbase asset manager();

The final file baseApk = new file (lite. basecodepath);

//Analyze core applications

The final package pkg = parseBaseApk(baseApk, assets, flags);

if (pkg == null) {

Throw a new packageparseexception (install _ parse _ failed _ not _ apk

Unable to parse the basic apk:'+baseapk');

}

If (! array utils . isempty(lite . split names)){

final int num = lite . split names . length;

pkg . split names = lite . split names;

pkg . splitcodepaths = lite . splitcodepaths;

pkg . splitrevisioncodes = lite . splitrevisioncodes;

pkg . split flags = new int[num];

pkg . splitprivateflags = new int[num];

pkg . application info . split names = pkg . split names;

pkg . application info . split dependencies = split dependencies;

pkg . application info . splitclassloadernames = new String[num];

for(int I = 0; I & ltnumi++) {

final asset manager split assets = asset loader . getsplitassetmanager(I);

//Handling of non-core applications

parsplitapk(pkg,I,splitAssets,flags);

}

}

pkg . setcodepath(package dir . getcanonicalpath());

pkg . setuse 32 bitabi(lite . use 32 bitabi);

Return to pkg

} catch (IOException e) {

Throw a new packageparseexception (install _ parse _ failed _ unexpected _ exception,

Unable to get the path:'+lite.baseCodePath, e');

} Finally {

iou tils . closequietly(asset loader);

}

}

Let's take a look at parseMonolithicPackage (). Its function is to parse a given APK file and treat it as a single software package.

ParseBaseApk () is also called for parsing. Next, let's take a look at parsebasepk ().

Public package parseMonolithicPackage (file apkFile, int flag) throws PackageParserException {

final package lite = parsimonolicipackagelite(apk file,flags);

If (monlycrepse){

If (! lite.coreApp) {

Throw a new packageparseexception (install _ parse _ failed _ manifest _ for mattered,

"not coreapp:"+apkfile);

}

}

final SplitAssetLoader asset loader = new DefaultSplitAssetLoader(lite,flags);

Try {

//Analyze core applications

The final package pkg = parseBaseApk(apkFile, assetloader. getbaseassetmanager (), flags);

pkg . setcodepath(apk file . getcanonicalpath());

pkg . setuse 32 bitabi(lite . use 32 bitabi);

Return to pkg

} catch (IOException e) {

Throw a new packageparseexception (install _ parse _ failed _ unexpected _ exception,

Unable to get the path:'+apkFile, e');

} Finally {

iou tils . closequietly(asset loader);

}

}

ParseBaseApk () mainly parses AndroidManifest.xml, and all the parsed information is put in the Package object.

Private package parseBaseApk (file apkFile, asset manager asset, int flag)

Throwing PackageParserException {

The final string apkpath = apkfile.getaabsolutepath ();

...

XmlResourceParser parser = null

...

final int cookie = assets . findcookieforpath(apk path);

if (cookie == 0) {

Throw a new packageparseexception (install _ parse _ failed _ bad _ manifest,

Failed to add asset path:'+apkpath';

}

//Get the XML resource parsing object and parse the AndroidManifest.xml file of APK.

parser = assets . openxmlresourceparser(cookie,ANDROID _ MANIFEST _ FILENAME);

Final resource res = new resource (asset, matrix, empty);

final String[]out error = new String[ 1];

//Call the overloaded function parseBaseApk () to finally get parseBaseApkCommon (), and get a Package object after parsing AndroidManifest.xml

The final package pkg = parseBaseApk(apkPath, res, parser, flags, outerror);

...

pkg . setvolumeuuid(volume uuid);

pkg . setapplicationvolumeuuid(volume uuid);

pkg . setbasecodepath(apk path);

pkg . set signing details(signing details。 Unknown);

Return to pkg

...

}

Get the tag name from AndroidManifest.xml, parse the content of each item in the tag, and store it in the Package object.

For example, get the labels "Application", "Permission"

Private package parseBaseApkCommon (package pkg, set acceptedTags, resource res,

XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,

IOException {

Typedarraysa = Res. ObtainAttributes (parser,

com . Android . internal . r . styleable . Android manifest);

//Obtaining the sharedUserId in AndroidManifest.xml generally includes information such as "android.uid.system".

string str = sa . getnonconfigurationstring(

com . Android . internal . r . styleable . Android manifest _ shared userid,0);

while ((type = parser.next())! = XmlPullParser。 End _ Document

&&(type! = XmlPullParser。 END _ TAG | | parser . get depth()& gt; outerDepth)) {

//Get the tagname from AndroidManifest.xml

string tagName = parser . getname();

//If you read that the tag in AndroidManifest.xml is "application", perform parseBaseApplication () parsing.

if(tagname . equals(TAG _ APPLICATION)){

if (foundApp) {

...

}

foundApp = true

//Parse the information of "Application" and assign it to pkg.

If (! parseBaseApplication(pkg,res,parser,flags,outError)) {

Returns null

}

...

//If the label is "Permission"

else if(tagname . equals(TAG _ PERMISSION)){

//Analyze "Permission"

If (! parsePermission(pkg,res,parser,outError)) {

Returns null

}

....

}

}

}

}

AndroidManifest.xml is parsed above.

You will get information such as "application", "coverage", "license" and "use-license".

Let's analyze the "application" and enter the parseBaseApplication () function.

Private boolean parseBaseApplication (package owner, resource res,

XmlResourceParser, int flag, String[] outError)

while ((type = parser.next())! = XmlPullParser。 End _ Document

&&(type! = XmlPullParser。 END _ TAG | | parser . get depth()& gt; innerDepth)) {

//Get the label content of the Application subtab.

string tagName = parser . getname();

//If the label is "Active"

if(tagname . equals(" activity "){

//Parse the activity information and add the activity to the package object.

Activity a = parseActivity(owner,res,parser,flags,outError,cachedArgs,false,

owner . base hardware accelerated);

if (a == null) {

mParseError = PackageManager。 INSTALL _ PARSE _ FAILED _ MANIFEST _ malformed;

Returns false

}

hasActivityOrder |= (a.order! = 0);

owner . activities . add(a);

} else if(tagname . equals(" receiver "){

//If the label is "receiver", get the receiver information and add the Package object.

Activity a = parseActivity(owner,res,parser,flags,outError,cachedArgs,

True or false);

if (a == null) {

mParseError = PackageManager。 INSTALL _ PARSE _ FAILED _ MANIFEST _ malformed;

Returns false

}

hasReceiverOrder |= (a.order! = 0);

owner . receivers . add(a);

} else if(tagname . equals(" service ")){

//If the label is "Service", get the service information and add the package object.

Service s = parseService(owner,res,parser,flags,outError,cache dargs);

if (s == null) {

mParseError = PackageManager。 INSTALL _ PARSE _ FAILED _ MANIFEST _ malformed;

Returns false

}

hasServiceOrder |= (s.order! = 0);

owner . services . add;

} else if(tagname . equals(" provider "){

//If the label is "Provider", get the provider information and add the package object.

Provider p = parseProvider(owner,res,parser,flags,outError,cache dargs);

if (p == null) {

mParseError = PackageManager。 INSTALL _ PARSE _ FAILED _ MANIFEST _ malformed;

Returns false

}

owner . providers . add(p);

}

...

}

}

After the PackageParser scans the APK, the system creates a complete package object according to AndroidManifest.xml in the APK.

The next step is to add the package to the system. The function called at this time is another scanPackageChildLI.

6.4[PackageManagerService.java]scanPackageChildLI()

When the platform is initialized, call addForInitLI () to add the package contents to the internal data structure.

Private PackageParser. Package scanpackagechildli (package parser. Packaging, packaging,

final @ParseFlags int parseFlags,@ScanFlags int scanFlags,long currentTime,

@Nullable UserHandle user)

Throw PackageManagerException {

...

//Scan the parent item

PackageParser。 package scanned pkg = addForInitLI(pkg,parseFlags,

scanFlags,currentTime,user);

//Scan children

final int child count =(pkg . child packages! = null)? pkg . child packages . size():0;

for(int I = 0; I< children count; i++) {

PackageParser。 package child package = pkg . child packages . get(I);

//Add a new package to the internal data structure during platform initialization.

//When the platform is initialized, the package content is added to the internal data structure.

AddForInitLI (subpackage, parsing flag, scanning flag,

CurrentTime, user);

}

if((scan flags & amp; Scan only)! = 0) {

Returns scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);

}

}

In addForInitLI (), check the installation package, check the signature, update apk, and add the package to the system.

Private PackageParser. package addForInitLI(package parser。 Packaging, packaging,

@ParseFlags int parseFlags,@ScanFlags int scanFlags,long currentTime

@Nullable UserHandle user)

Throw PackageManagerException {

//Judge whether the system application needs to be updated.

Synchronization (multi-packet) {

//Update the sub-application

if (isSystemPkgUpdated) {

...

}

if (isSystemPkgBetter) {

//Update the installation package to the system partition.

Synchronization (multi-packet) {

//Only delete the loaded entry from the package list.

m packages . remove(pkg setting . name);

}

...

//Create the installation parameter InstallArgs

final install args args = createInstallArgsForExisting(

pkgSetting.codePathString,

pkgSetting.resourcePathString,getAppDexInstructionSets(pkg setting));

args . cleanupresourcesli();

Synchronization (multi-packet) {

m settings . enablesystempackagelpw(pkg setting . name);

}

}

//Installation package verification

collectCertificatesLI(pkg setting,pkg,forceCollect,skip verify);

...

try(package freezer freezer = freeze package(pkg . package name,

" scanPackageInternalLI "){

//If the two apk signatures do not match, call the deletePackageLIF method to clear the apk file and its data.

deletePackageLIF(pkg . package name,null,true,null,0,null,false,null);

}

...

//Update the system apk program

install args args = createInstallArgsForExisting(

pkgSetting.codePathString,

pkgSetting.resourcePathString,getAppDexInstructionSets(pkg setting));

Synchronization (Minimum Lock)

args . cleanupresourcesli();

}

}

//If the newly installed system APP will be overwritten by the old APP data, you need to hide the system app and rescan the /data/app directory.

if (shouldHideSystemApp) {

Synchronization (multi-packet) {

m settings . disablesystempackagelpw(pkg . package name,true);

}

}

}

Review the whole scanning process of APK:

According to the core app > system app>, other applications scan APK first, parse the AndroidManifest.xml file, and get the content of each tag.

After the PackageParser scans an APK, the system has created a complete Package object according to AndroidManifest.xml in the APK. The next step is to add the package to the system.

Non-system package scan failed, deleting files.