古詩詞大全網 - 個性簽名 - 每日工作2022.4.19 PackageManager服務掃描APK目錄。

每日工作2022.4.19 PackageManager服務掃描APK目錄。

2022.4.19

明確了witen 5.1升級到bturnc 5.3不綁定imei的用戶選項;

6掃描APK目錄

在PackageManagerService的構造函數中調用scanDirTracedLI方法來掃描壹個目錄的apk文件。

在Android 10.0中,PKMS主要掃描以下路徑的APK信息:

/供應商/覆蓋

/產品/覆蓋

/產品服務/覆蓋

/ODM/覆蓋

/OEM/覆蓋

/系統/框架

/系統/私人應用程序

/系統/應用程序

/供應商/私人應用程序

/供應商/應用程序

/odm/priv-app

/odm/app

/oem/app

/oem/priv-app

/產品/隱私應用程序

/產品/應用程序

/產品服務/隱私應用程序

/產品服務/應用程序

/產品服務/隱私應用程序

我們以scanDirTracedLI()為入口來分析壹下:

6.1[ParallelPackageParser.java]scanDirTracedLI()

從下面的函數可以看出,scanDirTracedLI的入口非常簡單。首先添加systtrace的壹些日誌痕跡,然後調用scanDirLI()進行分析。

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

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

嘗試{

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

}最後{

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

}

}

6.2[ParallelPackageParser.java]斯坎迪裏

ScanDirLI()使用ParallelPackageParser的對象,這是壹個隊列。這裏我們取所有手機系統的apk,然後從這些隊列中取出apk,然後調用PackageParser進行解析。

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

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

if (ArrayUtils.isEmpty(files)) {

Log.d(標簽,“應用目錄中沒有文件”+scanDir);

返回;

}

if(調試包掃描){

Log.d(標簽,"掃描應用目錄"+scanDir+" scan flags = "+scan flags

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

}

//parallelPackageParser是收集系統apk文件的隊列。

//然後從這個隊列中逐個取出apk,調用PackageParser進行解析。

try(ParallelPackageParser ParallelPackageParser = new ParallelPackageParser(

mSeparateProcesses,mOnlyCore,mMetrics,mCacheDir,

mparallelpackaparsercallback)){

//並行提交文件進行解析

int file count = 0;

for(文件文件:文件){

//是Apk文件或目錄。

最終布爾值is package =(isApkFile(file)| | file . is directory())

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

過濾掉非apk文件,如果沒有,跳過繼續掃描。

如果(!isPackage) {

//忽略不是包的條目

繼續;

}

parallelPackageParser中存儲APK信息的對象mQueue,將PackageParser()函數賦給隊列中的pkg成員。

//引用[6.3]

parallelpackageparser . submit(file,parse flags);

filecount++;

}

//逐個處理結果

for(;文件計數& gt0;文件計數- ) {

//從parallelPackageParser中取出隊列apk的信息。

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

throwable throwable = parse result . throwable;

int errorCode = PackageManager。INSTALL _ SUCCEEDED

if (throwable == null) {

// TODO(toddke):在掃描鏈中下移

//靜態共享庫有合成的包名

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

renameStaticSharedLibraryPackage(parse result . pkg);

}

嘗試{

//調用scanPackageChildLI方法掃描特定的apk文件。

//這個類的實例代表壹個apk文件,所以是APK文件對應的數據結構。

//引用[6.4]

scanPackageChildLI(parse result . pkg,parseFlags,scanFlags,

currentTime,null);

} catch(PackageManagerException e){

errorCode = e.error

Slog.w(TAG,"未能掃描"+parse result . scan file+":"+e . getmessage());

}

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

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

可投擲的;

errorCode = e.error

Slog.w(TAG,"未能解析"+parse result . scan file+":"+e . getmessage());

}否則{

拋出新的IllegalStateException("解析時出現意外異常"

+ parseResult.scanFile,throwable);

}

//刪除無效的用戶數據應用程序

//如果是非系統apk,解析失敗。

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

錯誤代碼!= PackageManager。安裝成功){

logCriticalInfo(Log。警告,

”刪除“+ parseResult.scanFile”處的無效包);

//非系統包掃描失敗。刪除文件。

removeCodePathLI(parse result . scan file);

}

}

}

}

6.3[ParallelPackageParser.java]提交

將掃描路徑中的APK和其他內容放入隊列mQueue中,並將parsePackage()賦給ParseResult以供後續調用。

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+"]");

嘗試{

package parser PP = new package parser();

PP . setseparateprocesses(mSeparateProcesses);

PP . setonlycoresses(monly core);

pp.setDisplayMetrics(公制);

PP . setcachedir(mCacheDir);

PP . set callback(mPackageParserCallback);

pr . scan file = scan file;

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

} catch(可投擲e) {

pr . throwable = e;

}最後{

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

}

嘗試{

mqueue . put(pr);

} catch (InterruptedException e) {

Thread.currentThread()。中斷();

//將結果傳播給take()的調用方。

//這有助於防止主線程在等待時被卡住

// ParallelPackageParser在中斷時結束

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

}

});

}

通過parsePackage分析apk。如果傳入的packageFile是壹個目錄,則調用parseClusterPackage()進行解析。

如果調用了傳入的APK文件,則調用parseMonolithicPackage()進行解析。

公共包解析包(文件包文件,整數標誌,布爾使用緩存)

拋出PackageParserException {

...

if (packageFile.isDirectory()) {

//如果傳遞的packageFile是目錄,則調用parseClusterPackage()進行解析。

parsed = parseClusterPackage(package file,flags);

}否則{

//如果是APK文件,調用parseMonolithicPackage()進行解析。

parsed = parsimonolicipackage(package file,flags);

}

...

返回已解析的;

}

讓我們來看看parseClusterPackage()

函數:解析給定目錄中包含的所有apk,並將它們作為單個包處理。這也可以執行完整性檢查,例如要求相同的包名和版本代碼、單個基本APK和唯壹的分割名。

首先用parseClusterPackageLite()解析目錄中的apk文件,主要區別在於是核心應用還是非核心應用。核心應用只有壹個,非核心應用可以沒有,也可以有多個。非核心應用的功能主要是節省資源和代碼。然後在核心應用上調用parseBaseApk分析,生成包。非核心應用調用parseSplitApk,分析結果放在前面的包對象中。

私有包parseClusterPackage(文件packageDir,int flags)拋出PackageParserException {

//獲取應用程序目錄的PackageLite對象,該對象在目錄中分別存儲核心應用程序和非核心應用程序的名稱。

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

//如果lite中沒有核心應用,退出。

如果(mOnlyCoreApps & amp& amp!lite.coreApp) {

拋出新的PackageParserException(INSTALL _ PARSE _ FAILED _ MANIFEST _ formattered,

"不是core app:"+package dir);

}

//生成拆分依賴關系樹。

//建立分區依賴關系樹

SparseArray split dependencies = null;

最終SplitAssetLoader assetLoader

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

嘗試{

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

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

} catch(SplitAssetDependencyLoader。IllegalDependencyException e) {

拋出新的PackageParserException(INSTALL _ PARSE _ FAILED _ BAD _ MANIFEST,e . getmessage());

}

}否則{

asset loader = new DefaultSplitAssetLoader(lite,flags);

}

嘗試{

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

最終文件baseApk =新文件(lite . base code path);

//分析核心應用程序

最終包pkg = parseBaseApk(baseApk,assets,flags);

if (pkg == null) {

拋出新的PackageParserException(INSTALL _ PARSE _ FAILED _ NOT _ APK

無法解析基本APK:“+base apk”);

}

如果(!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;我& ltnumi++) {

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

//非核心應用程序的處理

parsplitapk(pkg,I,splitAssets,flags);

}

}

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

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

返回pkg

} catch (IOException e) {

拋出新的PackageParserException(INSTALL _ PARSE _ FAILED _ UNEXPECTED _ EXCEPTION,

無法獲取路徑:“+ lite.baseCodePath,e”);

}最後{

iou tils . closequietly(asset loader);

}

}

再來看看parseMonolithicPackage()。它的功能是解析壹個給定的APK文件,並把它當作壹個單壹的軟件包。

ParseBaseApk()也被調用來進行解析。接下來我們來看看parsebasepk()。

公共包parseMonolithicPackage(文件apkFile,int標誌)拋出PackageParserException {

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

如果(monlycrepse){

如果(!lite.coreApp) {

拋出新的PackageParserException(INSTALL _ PARSE _ FAILED _ MANIFEST _ formattered,

"不是core app:"+apk file);

}

}

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

嘗試{

//分析核心應用程序

最終包pkg = parseBaseApk(apkFile,asset loader . getbaseassetmanager(),flags);

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

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

返回pkg

} catch (IOException e) {

拋出新的PackageParserException(INSTALL _ PARSE _ FAILED _ UNEXPECTED _ EXCEPTION,

無法獲取路徑:“+ apkFile,e”);

}最後{

iou tils . closequietly(asset loader);

}

}

ParseBaseApk()主要解析AndroidManifest.xml,解析後的所有信息都放在Package對象中。

私有包parseBaseApk(文件apkFile,資產管理器資產,int標誌)

拋出PackageParserException {

最終字符串apk path = apk file . getabsolutepath();

...

XmlResourceParser parser = null

...

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

if (cookie == 0) {

拋出新的PackageParserException(INSTALL _ PARSE _ FAILED _ BAD _ MANIFEST,

添加資產路徑失敗:“+apk path”;

}

//獲取XML資源解析對象,解析APK的AndroidManifest.xml文件。

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

最終資源res =新資源(資產,矩陣,空);

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

//調用重載函數parseBaseApk()最後得到parseBaseApkCommon(),解析AndroidManifest.xml後得到壹個Package對象

最終包pkg = parseBaseApk(apkPath,res,parser,flags,out error);

...

pkg . setvolumeuuid(volume uuid);

pkg . setapplicationvolumeuuid(volume uuid);

pkg . setbasecodepath(apk path);

pkg . set signing details(signing details。未知);

返回pkg

...

}

從AndroidManifest.xml中獲取標記名,解析標記中每壹項的內容,並將其存儲在Package對象中。

例如,獲取標簽“應用程序”、“權限”

私有包parseBaseApkCommon(包pkg,集acceptedTags,資源res,

XmlResourceParser parser,int flags,String[] outError)拋出XmlPullParserException,

IOException {

typed array sa = RES . obtain attributes(解析器,

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

//獲取AndroidManifest.xml中的sharedUserId壹般有“android.uid.system”等信息。

string str = sa . getnonconfigurationstring(

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

while ((type = parser.next())!= XmlPullParser。結束_文檔

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

//從AndroidManifest.xml獲取標記名

string tagName = parser . getname();

//如果讀到AndroidManifest.xml中的標簽是“application”,執行parseBaseApplication()解析。

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

if (foundApp) {

...

}

foundApp = true

//解析“應用”的信息,賦給pkg。

如果(!parseBaseApplication(pkg,res,parser,flags,outError)) {

返回null

}

...

//如果標簽是“權限”

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

//分析“權限”

如果(!parsePermission(pkg,res,parser,outError)) {

返回null

}

....

}

}

}

}

上面解析了AndroidManifest.xml。

妳會得到諸如“申請”、“覆蓋”、“許可”、“使用-許可”等信息。

我們來分析壹下“應用”,進入parseBaseApplication()函數。

私有布爾parseBaseApplication(包所有者,資源res,

XmlResourceParser解析器,int標誌,String[] outError)

while ((type = parser.next())!= XmlPullParser。結束_文檔

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

//獲取“應用程序”子選項卡的標簽內容。

string tagName = parser . getname();

//如果標簽是“活動”

if(tagname . equals(" activity "){

//解析活動信息,將活動添加到包對象中。

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

owner . base hardware accelerated);

if (a == null) {

mParseError = PackageManager。INSTALL _ PARSE _ FAILED _ MANIFEST _畸形;

返回false

}

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

owner . activities . add(a);

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

//如果標簽為“receiver”,則獲取接收者信息,添加Package對象。

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

真,假);

if (a == null) {

mParseError = PackageManager。INSTALL _ PARSE _ FAILED _ MANIFEST _畸形;

返回false

}

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

owner . receivers . add(a);

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

//如果標簽為“服務”,則獲取服務信息,添加包對象。

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

if (s == null) {

mParseError = PackageManager。INSTALL _ PARSE _ FAILED _ MANIFEST _畸形;

返回false

}

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

owner . services . add;

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

//如果標簽為“提供者”,則獲取提供者信息,添加包對象。

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

if (p == null) {

mParseError = PackageManager。INSTALL _ PARSE _ FAILED _ MANIFEST _畸形;

返回false

}

owner . providers . add(p);

}

...

}

}

在PackageParser掃描APK後,系統根據APK中的AndroidManifest.xml創建了壹個完整的包對象。

下壹步是將包添加到系統中。此時調用的函數是另壹個scanPackageChildLI。

6.4[PackageManagerService.java]scanPackageChildLI()

當平臺初始化時,調用addForInitLI()將包內容添加到內部數據結構中。

私有PackageParser。包scanPackageChildLI(package parser。包裝包裝,

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

@Nullable UserHandle用戶)

拋出PackageManagerException {

...

//掃描父項

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

scanFlags,currentTime,user);

//掃描孩子

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

for(int I = 0;我& lt兒童計數;i++) {

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

//在平臺初始化期間向內部數據結構添加新的包。

//平臺初始化時,將包內容添加到內部數據結構中。

addForInitLI(子包,解析標誌,掃描標誌,

currentTime,用戶);

}

if((scan flags & amp;僅掃描檢查)!= 0) {

返回scanPackageChildLI(pkg,parseFlags,scanFlags,currentTime,user);

}

}

在addForInitLI()中,檢查安裝包,檢查簽名,更新apk,並將包添加到系統中。

私有PackageParser。package addForInitLI(package parser。包裝包裝,

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

@Nullable UserHandle用戶)

拋出PackageManagerException {

//判斷系統應用是否需要更新。

同步(多包){

//更新子應用程序

if (isSystemPkgUpdated) {

...

}

if (isSystemPkgBetter) {

//將安裝包更新到系統分區。

同步(多包){

//只從包列表中刪除加載的條目

m packages . remove(pkg setting . name);

}

...

//創建安裝參數InstallArgs

final install args args = createInstallArgsForExisting(

pkgSetting.codePathString,

pkgSetting.resourcePathString,getAppDexInstructionSets(pkg setting));

args . cleanupresourcesli();

同步(多包){

m settings . enablesystempackagelpw(pkg setting . name);

}

}

//安裝包驗證

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

...

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

" scanPackageInternalLI "){

//如果兩個apk簽名不匹配,則調用deletePackageLIF方法清除apk文件及其數據。

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

}

...

//更新系統apk程序

install args args = createInstallArgsForExisting(

pkgSetting.codePathString,

pkgSetting.resourcePathString,getAppDexInstructionSets(pkg setting));

同步(最小鎖定){

args . cleanupresourcesli();

}

}

//如果新安裝的系統app會被舊的APP數據覆蓋,就需要隱藏系統APP,重新掃描/data/app目錄。

if (shouldHideSystemApp) {

同步(多包){

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

}

}

}

回顧APK的整個掃描過程:

根據核心app >系統app & gt其他應用優先掃描APK,解析AndroidManifest.xml文件,獲取每個標簽的內容。

在PackageParser掃描壹個APK後,系統已經根據APK中的AndroidManifest.xml創建了壹個完整的Package對象,下壹步就是將包添加到系統中。

非系統包掃描失敗,正在刪除文件。