APK安裝流程系列文章整體內容如下:
- APK安裝流程詳解0——前言
- APK安裝流程詳解1——有關"安裝ing"的實體類概述
- APK安裝流程詳解2——PackageManager簡介
- APK安裝流程詳解3——PackageManager與PackageManagerService
- APK安裝流程詳解4——安裝中關于so庫的那些事
- APK安裝流程詳解5——PackageInstallerService和Installer
- APK安裝流程詳解6——PackageManagerService啟動前奏
- APK安裝流程詳解7——PackageManagerService的啟動流程(上)
- APK安裝流程詳解8——PackageManagerService的啟動流程(下)
- APK安裝流程詳解9——PackageParser解析APK(上)
- APK安裝流程詳解10——PackageParser解析APK(下)
- APK安裝流程詳解11——普通應用安裝簡介
- APK安裝流程詳解12——PackageManagerService中的新安裝流程上(拷貝)
- APK安裝流程詳解13——PackageManagerService中的新安裝流程下(裝載)
- APK安裝流程詳解14——PMS中的新安裝流程上(拷貝)補充
- APK安裝流程詳解15——PMS中的新安裝流程下(裝載)補充
- APK安裝流程詳解16——Android包管理總結(尚未完結請期待)
本片文章的主要內容如下:
- 1、PackageManagerService的啟動概述
- 2、PackageManagerService的啟動之SystemServer部分
- 3、PackageManagerService的啟動之PackageManagerService部分
- 4、PackageManagerService#scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime)方法解析
一、PackageManagerService的啟動概述
PackageManager在啟動時會掃描所有的APK文件和jar包,然后把他們的信息讀取出來,保存在內存中,這樣系統運行時就能迅速找到各種應用和組件的信息。掃描中如果遇到沒有優化過的文件還要進行優化工作(dex格式轉換成oat格式(Android 5.0以前是odex)),優化后的文件放在/data/dalvik-cache/下面
PackageManagerService的啟動流程如下圖:
我把PackageManagerService分為兩個部分:
- 1、SystemServer部分
- 2、PackageManagerService部分
二、PackageManagerService的啟動之SystemServer部分
在Android系統開機啟動的時候會調用SystemServer的main方法
1、SystemServer#main(String[])方法
代碼在SystemServer.java 176行
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
我們看到在SystemServer的main方法里面主要是做了兩件事
- 第一步:new了一個SystemServer對象
- 第二步:調用這個SystemServer對象的run()方法
2、SystemServer無參構造函數
代碼在SystemServer.java 167行
public SystemServer() {
// Check for factory test mode.
mFactoryTestMode = FactoryTest.getMode();
}
我們看到在SystemServer無參構造函數里面就是初始化mFactoryTestMode
3、SystemServer的run方法
代碼在SystemServer.java 176行
private void run() {
// If a device's clock is before 1970 (before 0), a lot of
// APIs crash dealing with negative numbers, notably
// java.io.File#setLastModified, so instead we fake it and
// hope that time from cell towers or NTP fixes it shortly.
// 時間修復 ,如果設備的時鐘是在1970年之前,則修復它
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}
// If the system has "persist.sys.language" and friends set, replace them with
// "persist.sys.locale". Note that the default locale at this point is calculated
// using the "-Duser.locale" command line flag. That flag is usually populated by
// AndroidRuntime using the same set of system properties, but only the system_server
// and system apps are allowed to set them.
//
// NOTE: Most changes made here will need an equivalent change to
// core/jni/AndroidRuntime.cpp
// 系統語言設置
if (!SystemProperties.get("persist.sys.language").isEmpty()) {
final String languageTag = Locale.getDefault().toLanguageTag();
SystemProperties.set("persist.sys.locale", languageTag);
SystemProperties.set("persist.sys.language", "");
SystemProperties.set("persist.sys.country", "");
SystemProperties.set("persist.sys.localevar", "");
}
// Here we go!
Slog.i(TAG, "Entered the Android system server!");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
// In case the runtime switched since last boot (such as when
// the old runtime was removed in an OTA), set the system
// property so that it is in sync. We can't do this in
// libnativehelper's JniInvocation::Init code where we already
// had to fallback to a different runtime because it is
// running as root and we need to be the system user to set
// the property. http://b/11463182
// 設置系統屬性
SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
// Enable the sampling profiler.
// 啟動采樣分析器
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
mProfilerSnapshotTimer = new Timer();
mProfilerSnapshotTimer.schedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server", null);
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
// Mmmmmm... more memory!
// 清空內存
VMRuntime.getRuntime().clearGrowthLimit();
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
// 由于system server一直在運行,所以它需要更多的內存
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
// Some devices rely on runtime fingerprint generation, so make sure
// we've defined it before booting further.
// 確保指紋識別初始化
Build.ensureFingerprintProperty();
// Within the system server, it is an error to access Environment paths without
// explicitly specifying a user.
// 設置用戶權限設置,如果沒有顯示指定用戶,則無法訪問System Server
Environment.setUserRequired(true);
// Ensure binder calls into the system always run at foreground priority.
// 確保 binder 請求 進入系統后,一直在前臺運行。
BinderInternal.disableBackgroundScheduling(true);
// Prepare the main looper thread (this thread).
// 設置 優先級
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
Looper.prepareMainLooper();
// Initialize native services.
// 初始化 native 服務
System.loadLibrary("android_servers");
// Check whether we failed to shut down last time we tried.
// This call may not return.
// 檢查上次的關機是否失敗
performPendingShutdown();
// Initialize the system context.
// 初始化系統的Context
createSystemContext();
// Create the system service manager.
// 創建SystemServiceManager
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Start services.
try {
// 這里會開啟PackageManagerService,下面會詳解
startBootstrapServices();
// 開啟系統核心服務,里面會開啟BatteryService和UsageStatsService和WebViewUpdateService
startCoreServices();
// 開啟一系列Service
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
// For debug builds, log event loop stalls to dropbox for analysis.
if (StrictMode.conditionallyEnableDebugLogging()) {
Slog.i(TAG, "Enabled StrictMode for system server main thread.");
}
// Loop forever.
// 開啟循環
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
這個方法內部我已經添加注釋了,這里面主要是調用startBootstrapServices()方法,那我們就來看下這里面的具體實現
4、SystemServer的startBootstrapServices方法
代碼在SystemServer.java 322行
/**
* Starts the small tangle of critical services that are needed to get
* the system off the ground. These services have complex mutual dependencies
* which is why we initialize them all in one place here. Unless your service
* is also entwined in these dependencies, it should be initialized in one of
* the other functions.
*/
private void startBootstrapServices() {
// Wait for installd to finish starting up so that it has a chance to
// create critical directories such as /data/user with the appropriate
// permissions. We need this to complete before we initialize other services.
// 等待intalld完成啟動,這樣就有創建適當權限的的關鍵目錄。比如
// /data/user,所以我們要在初始化其他服務之前,進行這個操作。
// 第一塊
Installer installer = mSystemServiceManager.startService(Installer.class);
// Activity manager runs the show.
// 第二塊
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
// Power manager needs to be started early because other services need it.
// Native daemons may be watching for it to be registered so it must be ready
// to handle incoming binder calls immediately (including being able to verify
// the permissions for those calls).
// 第三塊
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
// Now that the power manager has been started, let the activity manager
// initialize power management features.
mActivityManagerService.initPowerManagement();
// Manages LEDs and display backlight so we need it to bring up the display.
// 第四塊
mSystemServiceManager.startService(LightsService.class);
// Display manager is needed to provide display metrics before package manager
// starts up.
// 第五塊
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
// We need the default display before we can initialize the package manager.
// 第六塊——開啟PackageManagerService
mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
// Only run "core" apps if we're encrypting the device.
String cryptState = SystemProperties.get("vold.decrypt");
if (ENCRYPTING_STATE.equals(cryptState)) {
Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
mOnlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
Slog.w(TAG, "Device encrypted - only parsing core apps");
mOnlyCore = true;
}
// Start the package manager.
Slog.i(TAG, "Package Manager");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
// 判斷是不是第一次開機啟動
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
Slog.i(TAG, "User Service");
// 第七塊
ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
// Initialize attribute cache used to cache resources from packages.
AttributeCache.init(mSystemContext);
// Set up the Application instance for the system process and get started.
// 第八塊
mActivityManagerService.setSystemProcess();
// The sensor service needs access to package manager service, app ops
// service, and permissions service, therefore we start it after them.
// 第九塊
startSensorService();
}
有必要先講解下注釋,翻譯如下:
開啟一小戳重要的系統服務,因為這些系統服務相互之前有這個強耦合性,這就是我們在一個地方初始化的原因。如果你的服務和這些系統沒有非常強的依賴性,建議應該在其他方法里面進行初始化。
我將startBootstrapServices方法里面的主要內容分為9塊,如下圖:
- 第一塊:開啟Installer這個Service
- 第二塊:開啟ActivityManagerService(Activity管理)這個Service
- 第三塊:開啟PowerManagerService(電力管理)這個Service
- 第四塊:開啟LightsService(燈光管理)這個Service
- 第五塊:開啟DisplayManagerService(顯示器管理)這個Service
- 第六塊:開啟PackageManagerService(包管理)這個Service
- 第七塊:SystemManager添加UserManagerService(用戶管理)
- 第八塊:給mActivityManagerService設置為系統進程
- 第九塊:開啟SensorService(傳感器管理)這個Service
這里我們重點看下PackageManagerService的啟動流程,如下:
// Only run "core" apps if we're encrypting the device.
// 第一步
String cryptState = SystemProperties.get("vold.decrypt");
if (ENCRYPTING_STATE.equals(cryptState)) {
Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
mOnlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
Slog.w(TAG, "Device encrypted - only parsing core apps");
mOnlyCore = true;
}
// Start the package manager.
Slog.i(TAG, "Package Manager");
// 第二步
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
啟動PackageManagerService,我將其又分為兩步
- 第一步:獲取mOnlyCore,mOnlyCore表示僅僅是核心,因為如果我們在加密設備的時候,僅僅能跑"核心"程序。
- 第二步:調用PackageManagerService的靜態main方法,這里注意傳入的mOnlyCore是true。
那我們就繼續看下PackageManagerService的main方法具體實現
三、PackageManagerService的啟動之PackageManagerService部分
我們先來看下PackageManagerService的main方法的實現
1、PackageManagerService的main方法
代碼在PackageManagerService.java 322行
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// 第一步
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
// 第二步
ServiceManager.addService("package", m);
return m;
}
通過上面代碼我們知道main方法里面主要是做了兩件事:
- 第一件事情:構造一個PackageManagerService對象
- 第二件事情:調用ServiceManager.addService()方法
2、PackageManagerService的構造函數
代碼在PackageManagerService.java 1801行
PackageManagerService構造函數的主要功能是,掃描Android系統中幾個目標文件夾中的APK,從而建立合適的數據結構以管理諸如Package信息、四大組件信息、權限信息等信息。抽象的看,PackageManagerService就像一個加工廠,它解析實際的物理文件(APK文件)以生成符合自己要求的產品。例如,PackageManagerService將解析APK包中的AndroidManifest.xml,并根據其中聲明的Activity標簽來創建與此對應的對象并加以保管。
PackageManagerService的工作流程相對簡單,復雜的是其中用于保存各種信息的數據結構和它們之間的關系,以及影響最終結果的策略控制(比如前面代碼中的onlyCore變量,用于判斷是否只掃描系統目錄)。
這里代碼太多了,我粘貼以后就滿了。所以我就不粘貼了,我把PackageManagerService的構造函數里面的主要內容分為8個步驟
- 1、new Setting()對象,添加用戶組信息
- 2、獲取默認的設備展示信息
- 3、創建PackageHandler()
- 4、創建UserManagerService對象,解析User相關信息
- 5、獲取權限信息
- 6、調用Settings.readLPW(),解析/data/system/的4個文件
- 7、進行dex優化操作
- 8、調用scanDirLI掃描文件
我們就來詳細分析下:
2.1、new Setting()對象,添加用戶組信息
代碼在PackageManagerService.java 1806行
// mSdkVersion是PackageManagerService的成員變量,定義的時候進行賦值,其值取自系統屬性"ro.build.version.sdk",
// 即編譯的SDK版本。如果沒有定義,則APK就無法知道自己運行在Android那個版本上了。
if (mSdkVersion <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
}
mContext = context;
// 設置運行模式,工廠模式是一種測試模式
mFactoryTest = factoryTest;
// onlyCore為true表示只處理系統應用,通常為false
mOnlyCore = onlyCore;
// 如果此系統是eng版,則掃描Package后,不對package做dex優化
mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
// 初始化mMetrics,存儲與顯示屏幕相關的一些屬性,例如屏幕的寬/高尺寸,分辨率等信息
mMetrics = new DisplayMetrics();
//設置UID,添加SharedUserSetting對象到Settings中,UID相同的包可以運行在同一個進程中,或者可以相互讀取資源。這里添加6種系統的UID:
// system、radio、log、nfc、bluetooth和shell
mSettings = new Settings(mPackages);
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
2.2、獲取默認的設備展示信息
代碼在PackageManagerService.java 1830行
//dexopt緩存的時間
long dexOptLRUThresholdInMinutes;
if (mLazyDexOpt) {
// 30分鐘
dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds.
} else {
// 7天
dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users.
}
// 把以分鐘為單位改成毫秒級別的單位
mDexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000;
// 該值和調試有關,一般不設置該屬性
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
if ("*".equals(separateProcesses)) {
mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
mSeparateProcesses = null;
Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
} else {
mDefParseFlags = 0;
mSeparateProcesses = separateProcesses.split(",");
Slog.w(TAG, "Running with debug.separate_processes: "
+ separateProcesses);
}
} else {
mDefParseFlags = 0;
mSeparateProcesses = null;
}
// 創建一個Installer對象,該對象和Native進程installd交互,后面會一篇文章專門講解它的作用,Installer為應用安裝器
mInstaller = installer;
// 構造mPackageDexOptimizer 對象
mPackageDexOptimizer = new PackageDexOptimizer(this);
// 構造MoveCallbacks對象
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
// 構造OnPermissionChangeListeners對象
mOnPermissionChangeListeners = new OnPermissionChangeListeners(
FgThread.get().getLooper());
// 用系統屬性來設置DisplayMetrics對象
getDefaultDisplayMetrics(context, mMetrics);
2.3、new Setting()對象,添加用戶組信息
代碼在PackageManagerService.java 1864行
// SystemConfig用于獲取系統的全局配置信息,初始化mGlobalGids、mSystemPermissions和mAvailableFeatures
SystemConfig systemConfig = SystemConfig.getInstance();
//取出全局的groupId 保存在PackageManagerService中
mGlobalGids = systemConfig.getGlobalGids();
// 取出系統權限保存到PackageManagerService的全局變量中
mSystemPermissions = systemConfig.getSystemPermissions();
// 取出可用的feature保存在PackageManagerService的全局變量中
mAvailableFeatures = systemConfig.getAvailableFeatures();
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
// 初始化mHandlerThread
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
// 初始化mHandler
mHandler = new PackageHandler(mHandlerThread.getLooper());
//將mHandler加入到Watchdog檢測中,安裝應用可能會有大量的I/O操作會比較耗時
// 因此這里的WATCHDOG_TIMEOUT設置為10min,一般為60s或者30s
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
// 為/data 目錄下子目錄生成文件對象
File dataDir = Environment.getDataDirectory();
// 對應 /data/data 目錄: 用于存放應用數據的目錄
mAppDataDir = new File(dataDir, "data");
// 對應 /data/data 目錄:用于存放安裝的應用
mAppInstallDir = new File(dataDir, "app");
// 對應 /data/app-lib 目錄:用于存放 應用的native庫
mAppLib32InstallDir = new File(dataDir, "app-lib");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
// 對應 /data/user 目錄: 用于存放用戶的數據文件
mUserAppDataDir = new File(dataDir, "user");
// 對應 /data/app-private 目錄:存放drm保護的應用
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
2.4、創建UserManagerService對象,解析User相關信息
代碼在PackageManagerService.java 1886行
// 創建用戶管理服務,管理多用戶
sUserManager = new UserManagerService(context, this,mInstallLock, mPackages);
創建一個UserManager對象,目前沒有什么作用,但前途不可限量。根據谷歌的設想,未來手機將支持多個User,每個User將安裝自己的應用,該功能的目的是Android手機推向企業用戶打下基礎。
2.5、獲取權限信息
代碼在PackageManagerService.java 1889行
// Propagate permission configuration in to package manager.
// 獲取系統中定義的permissions,這些permissions從/etc/permissions目錄下面讀取的。
ArrayMap<String, SystemConfig.PermissionEntry> permConfig
= systemConfig.getPermissions();
for (int i=0; i<permConfig.size(); i++) {
SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
BasePermission bp = mSettings.mPermissions.get(perm.name);
if (bp == null) {
bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
// 保存到mSettings.mPermissions中
mSettings.mPermissions.put(perm.name, bp);
}
if (perm.gids != null) {
bp.setGids(perm.gids, perm.perUser);
}
}
// 通過SystemConfig得到系統中的共享庫列表
ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
for (int i=0; i<libConfig.size(); i++) {
mSharedLibraries.put(libConfig.keyAt(i),
new SharedLibraryEntry(libConfig.valueAt(i), null));
}
// 打開SELinux的policy文件/security/current/mac_permissions.xml或者/etc/security/mac_permissions.xml
mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
2.6、調用Settings.readLPW(),解析/data/system/的4個文件
代碼在PackageManagerService.java 1912行
// 讀取文件 package.xml內容,解析后插到mSettings的mPackages等變量中
mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false), mSdkVersion, mOnlyCore);
// 設置模塊來代替framework-res.apk中缺省的ResolverActivity
String customResolverActivity = Resources.getSystem().getString(
R.string.config_customResolverActivity);
if (TextUtils.isEmpty(customResolverActivity)) {
customResolverActivity = null;
} else {
mCustomResolverComponentName = ComponentName.unflattenFromString(
customResolverActivity);
}
// 記錄開始掃描的時間
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
// Set flag to monitor and not change apk file paths when
// scanning install directories.
// 配置掃描的參數
final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING | SCAN_INITIAL;
// 保存一些已經進行dex優化過的apk,比如"framework-res.apk"、Java啟動類庫、framework所有核心庫,這部分不需要再優化
final ArraySet<String> alreadyDexOpted = new ArraySet<String>();
/**
* Add everything in the in the boot class path to the
* list of process files because dexopt will have been run
* if necessary during zygote startup.
*/
// 獲取Java 啟動類庫、framework所有核心庫,在init.rc文件配置
final String bootClassPath = System.getenv("BOOTCLASSPATH");
final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
// 把它們加入到已經優化集合中去
if (bootClassPath != null) {
String[] bootClassPathElements = splitString(bootClassPath, ':');
for (String element : bootClassPathElements) {
alreadyDexOpted.add(element);
}
} else {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
// 把環境變量SYSTEMSERVERCLASSPATH中定義的包加入到已優化集合alreadyDexOpted
if (systemServerClassPath != null) {
String[] systemServerClassPathElements = splitString(systemServerClassPath, ':');
for (String element : systemServerClassPathElements) {
alreadyDexOpted.add(element);
}
} else {
Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
}
final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();
final String[] dexCodeInstructionSets =
getDexCodeInstructionSets(
allInstructionSets.toArray(new String[allInstructionSets.size()]));
2.7、進行dex優化操作
代碼在PackageManagerService.java 1969行
/**
* Ensure all external libraries have had dexopt run on them.
*/
// 對比當前系統的指令集,檢查mSharedLibraries中記錄的jar包是否需要轉化成odex格式
// mSharedLibraries 變量中的動態庫是通過SystemConfig.getSharedLibraries()從/etc/permissions/platform.xml中讀取出來的
if (mSharedLibraries.size() > 0) {
// NOTE: For now, we're compiling these system "shared libraries"
// (and framework jars) into all available architectures. It's possible
// to compile them only when we come across an app that uses them (there's
// already logic for that in scanPackageLI) but that adds some complexity.
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {
final String lib = libEntry.path;
if (lib == null) {
continue;
}
try {
int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
alreadyDexOpted.add(lib);
// 調用install的dexopt命令,優化后的文件放在/data/dalvik-cache/下面
mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
} catch (IOException e) {
Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
+ e.getMessage());
}
}
}
}
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
// Gross hack for now: we know this file doesn't contain any
// code, so don't dexopt it to avoid the resulting log spew.
// 把framwork-res.apk加入到已優化的列表中
alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");
// Gross hack for now: we know this file is only part of
// the boot class path for art, so don't dexopt it to
// avoid the resulting log spew.
// 把 core-libart.jar加入到已優化的列表中
alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");
/**
* There are a number of commands implemented in Java, which
* we currently need to do the dexopt on so that they can be
* run from a non-root shell.
*/
// 對framework目錄下面的文件執行dex到odex優化
String[] frameworkFiles = frameworkDir.list();
if (frameworkFiles != null) {
// TODO: We could compile these only for the most preferred ABI. We should
// first double check that the dex files for these commands are not referenced
// by other system apps.
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (int i=0; i<frameworkFiles.length; i++) {
File libPath = new File(frameworkDir, frameworkFiles[i]);
String path = libPath.getPath();
// Skip the file if we already did it.
// 忽略已經在alreadyDexOpted列表中的文件
if (alreadyDexOpted.contains(path)) {
continue;
}
// Skip the file if it is not a type we want to dexopt.
// 忽略apk和jar意外的文件
if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
continue;
}
try {
int dexoptNeeded = DexFile.getDexOptNeeded(path, null, dexCodeInstructionSet, false);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
// 調用 install的dexopt命令,優化后的文件放在/data/dalvik-cache/下面
mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
} catch (IOException e) {
Slog.w(TAG, "Exception reading jar: " + path, e);
}
}
}
}
final VersionInfo ver = mSettings.getInternalVersion();
mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
// when upgrading from pre-M, promote system app permissions from install to runtime
mPromoteSystemApps =
mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;
// save off the names of pre-existing system packages prior to scanning; we don't
// want to automatically grant runtime permissions for new system apps
if (mPromoteSystemApps) {
Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
while (pkgSettingIter.hasNext()) {
PackageSetting ps = pkgSettingIter.next();
if (isSystemApp(ps)) {
mExistingSystemPackages.add(ps.name);
}
}
}
2.8、調用scanDirLI掃描文件
下面到PackageManagerService初始化過程的重頭戲,PackageManagerService在開機后需要將系統中所有的package信息統計管理起來,首先掃描文件夾
代碼在PackageManagerService.java 2066行
// ************** 第一塊 **************
// Collect vendor overlay packages.
// (Do this before scanning any apps.)
// For security and version matching reason, only consider
// overlay packages if they reside in VENDOR_OVERLAY_DIR.
// 掃描 /vendor/overlay目錄,收集目錄中文件的信息
File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
// Find base frameworks (resource packages without code).
// 掃描/system/framework目錄,收集目錄中文件的信息
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);
// Collected privileged system packages.
// 掃描 /system/priv-app 目錄,收集目錄中文件的信息,這個是Android 4.4出現的
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
// Collect ordinary system packages.
// 掃描 /system/app 目錄, 收集目錄中文件信息
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// Collect all vendor packages.
// 掃描 /vendor/app目錄, 收集目錄中文件信息
File vendorAppDir = new File("/vendor/app");
try {
vendorAppDir = vendorAppDir.getCanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// Collect all OEM packages.
// 掃描 /oem/app 目錄, 收集目錄中文件信息
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
// 調用installd執行movefiles命令,執行/system/etc/updatecmds下的命令腳本
mInstaller.moveFiles();
// Prune any system packages that no longer exist.
// 這類List表示的是有可能有升級包的系統應用
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
if (!mOnlyCore) {
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
// 遍歷mSettings.mPackages中保存的應用
while (psit.hasNext()) {
PackageSetting ps = psit.next();
/*
* If this is not a system app, it can't be a
* disable system app.
*/
// 忽略掉非系統應用
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
continue;
}
/*
* If the package is scanned, it's not erased.
*/
// 下面的mPackages是PackageManangerService的成員變量,
// 保存的是上面調用scanDirLI方法掃描目錄得到的應用信息,不要和mSettings.mPackages弄混了
final PackageParser.Package scannedPkg = mPackages.get(ps.name);
if (scannedPkg != null) {
/*
* If the system app is both scanned and in the
* disabled packages list, then it must have been
* added via OTA. Remove it from the currently
* scanned package so the previously user-installed
* application can be scanned.
*/
// 如果某個掃描過的系統應用是帶升級包的系統應用,把它從mPackages中移除,
// “disable” 列表是package.xml中<update-package>標簽標示的應用
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
logCriticalInfo(Log.WARN, "Expecting better updated system app for "
+ ps.name + "; removing system app. Last known codePath="
+ ps.codePathString + ", installStatus=" + ps.installStatus
+ ", versionCode=" + ps.versionCode + "; scanned versionCode="
+ scannedPkg.mVersionCode);
// 從掃描列表mPackages中移除
removePackageLI(ps, true);
// 放入mExpectingBetter列表,后面會進行處理的。
mExpectingBetter.put(ps.name, ps.codePath);
}
// 忽略在掃描列表mPackages中的文件
continue;
}
// 運行到這里說明ps表示的應用不在掃描列表mPackages中,也就是在系統中不存在
if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
// 如果這個文件不屬于<update-package>標識的應用,說明這個應用是殘留在packages.xml中的,
// 可能還有數據目錄,因此要刪除
psit.remove();
logCriticalInfo(Log.WARN, "System package " + ps.name
+ " no longer exists; wiping its data");
// 刪除數據目錄,內部也是通過installd來執行的
removeDataDirsLI(null, ps.name);
} else {
// 如果這個應用不在系統中,但是被標記了<update-package>,
// 則加入到possiblyDeletedUpdatedSystemApps列表
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
possiblyDeletedUpdatedSystemApps.add(ps.name);
}
}
}
}
//look for any incomplete package installations
// 掃描并刪除未安裝成功的apk包
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
//clean up list
for(int i = 0; i < deletePkgsList.size(); i++) {
//clean up here
cleanupInstallFailedPackage(deletePkgsList.get(i));
}
//delete tmp files
// 刪除臨時文件
deleteTempPackageFiles();
// Remove any shared userIDs that have no associated packages
// 刪除掉Settings中的沒有關聯任何應用的SharedUserSetting對象
mSettings.pruneSharedUsersLPw();
// ************** 第二塊 **************
// 開始處理非系統應用
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
//掃描 /data/app 目錄,保存到mPackages中
scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
// 掃描 /data/app-private目錄,收集目錄中文件信息
scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
scanFlags | SCAN_REQUIRE_KNOWN, 0);
/**
* Remove disable package settings for any updated system
* apps that were removed via an OTA. If they're not a
* previously-updated app, remove them completely.
* Otherwise, just revoke their system-level permissions.
*/
// 放在possiblyDeletedUpdatedSystemApps中的應用是在packge.xml中被標記成了待升級的系統應用
// 但是文件卻不存在了,因此這里檢查用戶目錄下升級文件是否還存在,然后進行處理
for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
// 從mSettings.mDisabledSysPackages變量中移除去此應用
mSettings.removeDisabledSystemPackageLPw(deletedAppName);
String msg;
if (deletedPkg == null) {
// 用戶目錄中也沒有升級包,則肯定是殘留的應用信息,則把它的數據目錄刪除掉
msg = "Updated system package " + deletedAppName
+ " no longer exists; wiping its data";
// 刪除應用數據目錄
removeDataDirsLI(null, deletedAppName);
} else {
// 如果 在用戶空間找到了文件,則說明系統目錄下的文件可能被刪除了
// 因此,把應用的系統屬性去掉,以普通應用的方式運行
msg = "Updated system app + " + deletedAppName
+ " no longer present; removing system privileges for "
+ deletedAppName;
deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
}
// 報告系統發生了不一致的情況
logCriticalInfo(Log.WARN, msg);
}
/**
* Make sure all system apps that we expected to appear on
* the userdata partition actually showed up. If they never
* appeared, crawl back and revive the system version.
*/
// 現在來處理mExpectingBetter列表,這個列表的應用是帶有升級包的系統的應用,
// 前面把他們從mPackages列表中清除了并放到mExpectingBetter列表
// 最后也對他們進行掃描處理,但不會放到mPackages中
for (int i = 0; i < mExpectingBetter.size(); i++) {
final String packageName = mExpectingBetter.keyAt(i);
if (!mPackages.containsKey(packageName)) {
final File scanFile = mExpectingBetter.valueAt(i);
logCriticalInfo(Log.WARN, "Expected better " + packageName
+ " but never showed up; reverting to system");
final int reparseFlags;
// 確保應用位于下面4個系統應用目錄,如果不在,不需要處理
if (FileUtils.contains(privilegedAppDir, scanFile)) {
reparseFlags = PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED;
} else if (FileUtils.contains(systemAppDir, scanFile)) {
reparseFlags = PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARS } else if (FileUtils.contains(vendorAppDir, scanFile)) {
reparseFlags = PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR;
} else if (FileUtils.contains(oemAppDir, scanFile)) {
reparseFlags = PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR;
} else {
Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
// 如果應用不在上面這些目錄,繼續循環,不要處理
continue;
}
// 現在把這個apk標示為系統應用,從mSettings.mDisabledSysPackages中刪除,
//因為在scanDirLI->scanPackageLI中會執行mSettings.disableSystemPackageLPw
// 所以此時包名的標簽是只有<update-package>,執行到這步之后變成<package>標簽,
// 在下面的scanPackageLI中又會添加一個<update-package>標簽的
mSettings.enableSystemPackageLPw(packageName);
try {
// 重新掃描一下這個文件,會添加一個<update-package>標簽
scanPackageLI(scanFile, reparseFlags, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse original system package: "
+ e.getMessage());
}
}
}
}
// 清空目錄
mExpectingBetter.clear();
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
// 更新所有應用的動態庫路徑
updateAllSharedLibrariesLPw();
for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
// NOTE: We ignore potential failures here during a system scan (like
// the rest of the commands above) because there's precious little we
// can do about it. A settings error is reported, though.
adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */,
false /* force dexopt */, false /* defer dexopt */,
false /* boot complete */);
}
// Now that we know all the packages we are keeping,
// read and update their last usage times.
mPackageUsage.readLP();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
// If the platform SDK has changed since the last time we booted,
// we need to re-grant app permission to catch any new ones that
// appear. This is really a hack, and means that apps can in some
// cases get permissions that the user didn't initially explicitly
// allow... it would be nice to have some better way to handle
// this situation.
// 如果平臺的SDK版本和上次啟動時候發生了變化,可能permission的定義也發生了變化,因此需要重新賦予應用權限
int updateFlags = UPDATE_PERMISSIONS_ALL;
if (ver.sdkVersion != mSdkVersion) {
Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to "
+ mSdkVersion + "; regranting permissions for internal storage");
updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
}
updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);
ver.sdkVersion = mSdkVersion;
// If this is the first boot or an update from pre-M, and it is a normal
// boot, then we need to initialize the default preferred apps across
// all defined users.
// 如果是第一次啟動或者是Android M升級后的第一次啟動,需要執行一些初始化工作
if (!onlyCore && (mPromoteSystemApps || !mRestoredSettings)) {
for (UserInfo user : sUserManager.getUsers(true)) {
mSettings.applyDefaultPreferredAppsLPw(this, user.id);
applyFactoryDefaultBrowserLPw(user.id);
primeDomainVerificationsLPw(user.id);
}
}
// ************** 第三塊 **************
// If this is first boot after an OTA, and a normal boot, then
// we need to clear code cache directories.
// 如果是執行OTA后的第一次啟動,需要清除cache
if (mIsUpgrade && !onlyCore) {
Slog.i(TAG, "Build fingerprint changed; clearing code caches");
for (int i = 0; i < mSettings.mPackages.size(); i++) {
final PackageSetting ps = mSettings.mPackages.valueAt(i);
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
deleteCodeCacheDirsLI(ps.volumeUuid, ps.name);
}
}
ver.fingerprint = Build.FINGERPRINT;
}
checkDefaultBrowser();
// clear only after permissions and other defaults have been updated
mExistingSystemPackages.clear();
mPromoteSystemApps = false;
// All the changes are done during package scanning.
ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;
// can downgrade to reader
// 把Settings的內容保存到packages.xml中去
mSettings.writeLPr();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
mRequiredVerifierPackage = getRequiredVerifierLPr();
mRequiredInstallerPackage = getRequiredInstallerLPr();
mInstallerService = new PackageInstallerService(context, this);
mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
mIntentFilterVerifier = new IntentVerifierProxy(mContext,
mIntentFilterVerifierComponent);
} // synchronized (mPackages)
} // synchronized (mInstallLock)
// ************** 第四塊 **************
// Now after opening every single application zip, make sure they
// are all flushed. Not really needed, but keeps things nice and
// tidy.
//啟動一次內存垃圾回收
Runtime.getRuntime().gc();
// Expose private service for system components to use.
LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
}
整體時序圖如下:
我將本方法的內部分為3個部分
- 1、掃描系統文件夾
- 2、掃描第三方應用目錄
- 3、OTA換粗處理
- 4|、清理內存收尾
這里重點說下第一個,掃描系統文件夾
2.8.1、掃描系統文件夾
這一部分是PackageManagerService初始化的重量級部分,從code中可以看到這里掃描的文件夾有:
- "/vendor/overlay"
- "framework"
- "system/priv-app"
- "system/app"
- "/vendor/app"
- "oem/app"
掃描文件夾的操作會一步一步最終調用到scanPackageDirtyLI()方法,這個方法中PackageManagerService將package中的組件管理起來從而實現系統應用的安裝過程,如圖:
從上圖中我們主要知道兩點,第一,PackageParser將package進行徹底的解析,第二,PackageManagerService將上面解析得到的數據統計到自身變量中用于管理。
四、PackageManagerService#scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime)方法解析
代碼在PackageManagerService.java 5624行
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
//拿到文件的所有目錄
final File[] files = dir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + dir);
return;
}
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
+ " flags=0x" + Integer.toHexString(parseFlags));
}
for (File file : files) {
// 過濾掉非apk文件
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
try {
//如果是 APK則進行掃描
scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
scanFlags, currentTime, null);
} catch (PackageManagerException e) {
// 如果掃描APK過程中發生異常
Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
// Delete invalid userdata apps
// 如果解析失敗,并且是非系統APP
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
// 刪除APP
if (file.isDirectory()) {
mInstaller.rmPackageDir(file.getAbsolutePath());
} else {
file.delete();
}
}
}
}
}
其實這個方法的邏輯非常簡單,首先拿到指定目錄下面的所有文件,并過濾掉非apk文件,然后調用scanPackageLI方法進行解析,注意這里的scanPackageLI方法的第一個參數是File嗎,它還有一個重載的方法,這個重載的方法第一個參數是PackageParser.Package。我們看下scanPackageLI做了什么吧,代碼里面首先創建了PackageParser.Package對象,并調用了parsePackage方法,這里同樣要注意的一點就是這個parsePackage方法,這里也要注意parsePackage方法的第一個參數是File類型,我們看下parsePackage方法里面做了什么,parsePackage的邏輯其實也很簡單,就是通過AssertManager拿到apk文件的Resource文件,然后拿到Androidmanifest.xml文件,并進行解析,并將結果以PackageParser.Package的形式返回給PackageManagerService,PackageManagerService為了方便以后的訪問,需要將這個Package對象保存起來,于是調用了第一個scanPackageLI方法。
這里說下PackageManagerService掃描文件目錄的目的:
PackageManagerService在掃描APK的目錄時會使用PackageParser類對APK的androidManifest.xml文件進行解析,保存到Package類型的變量中,然后通過PackageManagerService的scanPackageDirtyLI()將解析后組件數據統計到PackageManagerService本地變量中,用于管理查詢調用,當系統中任意某個apk的package發生改變時,如卸載,升級等操作都會更新package的統計數據到PackageManagerService,PackageManagerService正式基于擁有系統中所有Package的信息才能勝任Package管理者的角色。
PS:注意不同目錄下掃描規則不同,PackageParser在解析apk包的時候對于不同安裝目錄下的apk解析規則是不同的,其中很多重要的解析,這也正式adb push 和adb install 不同方式的安裝應用可能有不同效果的原因所在。
這個方法里面的核心方法是scanPackageLI,那我們就來跟蹤下scanPackageLI方法的執行
scanPackageLI是有一對重載方法,一個方法的首參數為File,另一個方法的首參數為PackageParser.Package。上面調用的方法為首參數為File的方法。
上一篇文章 APK安裝流程詳解6——PackageManagerService啟動前奏
下一篇文章 APK安裝流程詳解8——PackageManagerService的啟動流程(下)