這個(gè)系列會(huì)分成《App的安裝過(guò)程》、《App桌面圖標(biāo)顯示過(guò)程》、《Activity的啟動(dòng)過(guò)程》和《Activity渲染過(guò)程》四篇文章扛拨,來(lái)分析從整個(gè)應(yīng)用安裝耘分,到用戶點(diǎn)擊圖標(biāo)并顯示首頁(yè)举塔,整個(gè)源碼流程是如何調(diào)用的绑警。
我們應(yīng)用程序包的安裝需要通過(guò)PackageManagerService來(lái)操作,而它早在系統(tǒng)啟動(dòng)SystemServer時(shí)便注冊(cè)好了央渣,SystemServer則由init進(jìn)程啟動(dòng)计盒。
public static void main(String[] args) {
new SystemServer().run();//執(zhí)行run
}
//運(yùn)行
private void run() {
......
//創(chuàng)建系統(tǒng)上下文
createSystemContext();
//創(chuàng)建SystemServiceManager,用來(lái)管理各種系統(tǒng)service
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// 啟動(dòng)服務(wù)
try {
//啟動(dòng)服務(wù)芽丹,創(chuàng)建PMS北启,AMS等
startBootstrapServices();
// 啟動(dòng)核心服務(wù)
startCoreServices();
//啟動(dòng)IputManagerService等
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
}
//創(chuàng)建系統(tǒng)上下文
private void createSystemContext() {
ActivityThread activityThread = ActivityThread.systemMain();
mSystemContext = activityThread.getSystemContext();
mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
}
初始化系統(tǒng)上下文時(shí),生成了ActivityThread 拔第,它相當(dāng)于系統(tǒng)的主線程咕村,我們看systemMain方法。
public static ActivityThread systemMain() {
if (!ActivityManager.isHighEndGfx()) {
HardwareRenderer.disable(true);
} else {
HardwareRenderer.enableForegroundTrimming();
}
//構(gòu)造ActivityThread
ActivityThread thread = new ActivityThread();
//true表示系統(tǒng)應(yīng)用
thread.attach(true);
return thread;
}
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
//不是系統(tǒng)進(jìn)程
if (!system) {
......
} else {
android.ddm.DdmHandleAppName.setAppName("system_process",UserHandle.myUserId());
try {
//創(chuàng)建Instrumentation
mInstrumentation = new Instrumentation();
//創(chuàng)建上下文
ContextImpl context = ContextImpl.createAppContext(this, getSystemContext().mPackageInfo);
//創(chuàng)建Application
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}
當(dāng)調(diào)用為系統(tǒng)線程時(shí)蚊俺,attach會(huì)執(zhí)行else代碼懈涛,創(chuàng)建Instrumentation和上下文,我們接著看啟動(dòng)包管理器服務(wù)的方法startBootstrapServices泳猬。
private void startBootstrapServices() {
//該對(duì)象負(fù)責(zé)與底層通信批钠,進(jìn)行具體安裝卸載等操作
mInstaller = mSystemServiceManager.startService(Installer.class);
//開(kāi)啟ActivityManagerService,對(duì)比PowerManagerService等得封,實(shí)際上ActivityManagerService不是一個(gè)SystemService埋心,而是Binder,ActivityManagerService.Lifecycle才是SystemService
mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
mActivityManagerService.initPowerManagement();
//開(kāi)啟mDisplayManagerService
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
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;
}
//構(gòu)建PackageManagerService
mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
AttributeCache.init(mSystemContext);
mActivityManagerService.setSystemProcess();
}
SystemServer啟動(dòng)了許多服務(wù)忙上,PackageManagerService通過(guò)main方法創(chuàng)建拷呆,并將系統(tǒng)上下文和mInstaller工具類(lèi)傳遞進(jìn)去。
public static final PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
//構(gòu)造PMS對(duì)象
PackageManagerService m = new PackageManagerService(context, installer,factoryTest, onlyCore);
//注冊(cè)到ServiceManager中
ServiceManager.addService("package", m);
return m;
}
構(gòu)造PMS對(duì)象晨横,并將服務(wù)對(duì)象添加到ServiceManager中洋腮。PackageManagerService的構(gòu)造方法代碼比較多田弥,我們分塊分析趾徽。
//pms啟動(dòng)后對(duì)系統(tǒng)中的特定目錄進(jìn)行掃描,獲取信息以便進(jìn)行應(yīng)用程序安裝
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
//向事件日志寫(xiě)入事件奶段,標(biāo)識(shí)PackageManagerService啟動(dòng)時(shí)間
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());
//版本檢查
if (mSdkVersion <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
}
mContext = context;
//開(kāi)機(jī)是否工廠模式
mFactoryTest = factoryTest;
//是否啟動(dòng)內(nèi)核
mOnlyCore = onlyCore;
//如果編譯版本為eng库糠,則不要進(jìn)行dex優(yōu)化
mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
//構(gòu)造DisplayMetrics以便獲得尺寸數(shù)據(jù)
mMetrics = new DisplayMetrics();
//構(gòu)造Settings存儲(chǔ)系統(tǒng)安裝時(shí)的信息
mSettings = new Settings(context);
//添加一些用戶id
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
//是否在不同的進(jìn)程中
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;
}
當(dāng)一個(gè)新應(yīng)用程序伙狐,要安裝并運(yùn)行在Linux中時(shí),系統(tǒng)需要先為其開(kāi)辟一個(gè)用戶空間瞬欧,并分配Linux獨(dú)立用戶id或共享用戶id贷屎,而這個(gè)創(chuàng)建和分配的業(yè)務(wù)操作,由PackageMangerService來(lái)完成艘虎。
每當(dāng)系統(tǒng)重啟時(shí)唉侄,都需要對(duì)程序做一次重新安裝,為了提高效率野建,程序在第一次安裝時(shí)属划,PackageMangerService會(huì)將安裝信息進(jìn)行保存恬叹,以便再次安裝時(shí)進(jìn)行快速恢復(fù)。Settings就是用來(lái)保存這些信息的對(duì)象同眯。
//賦值mInstaller
mInstaller = installer;
//測(cè)量顯示對(duì)象
getDefaultDisplayMetrics(context, mMetrics);
SystemConfig systemConfig = SystemConfig.getInstance();
mGlobalGids = systemConfig.getGlobalGids();
mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
//啟動(dòng)處理線程
mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
//啟動(dòng)PackageHandler
mHandler = new PackageHandler(mHandlerThread.getLooper());
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
//獲取data目錄
File dataDir = Environment.getDataDirectory();
//獲取到/data/data目錄
mAppDataDir = new File(dataDir, "data");
//獲取到/data/app目錄绽昼,即第三方應(yīng)用的安裝目錄
mAppInstallDir = new File(dataDir, "app");
//獲取到/data/app-lib目錄
mAppLib32InstallDir = new File(dataDir, "app-lib");
//獲取到/data/app-asec目錄
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
//獲取到/data/user目錄
mUserAppDataDir = new File(dataDir, "user");
//獲取到/data/app-private目錄,受DRM保護(hù)
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
//構(gòu)造UserManagerService,mPackages是一個(gè)Map须蜗,存儲(chǔ)了Package
sUserManager = new UserManagerService(context, this,mInstallLock, mPackages);
//讀取設(shè)置的權(quán)限
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.put(perm.name, bp);
}
if (perm.gids != null) {
bp.gids = appendInts(bp.gids, perm.gids);
}
}
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));
}
//讀取并解析mac_permissions.xml
mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
//讀取到程序上一次的安裝信息
mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
mSdkVersion, mOnlyCore);
首先掃描了各類(lèi)型的安裝目錄硅确,以備后面程序的安裝,我們看到構(gòu)造UserManagerService對(duì)象時(shí)明肮,傳入了mPackages對(duì)象菱农,它是一個(gè)Map,保存了安裝應(yīng)用的信息柿估,在readLPw傳給mSettings進(jìn)行讀取恢復(fù)大莫,如果讀取解析失敗,則重新解析安裝并保存以便下一次啟動(dòng)恢復(fù)官份,readLPw讀取只厘,而后面的mSettings.writeLPr則是保存。
那么我們看readLPw是如何來(lái)解析安裝包數(shù)據(jù)的舅巷。先看mSettings的構(gòu)造方法羔味。
Settings(Context context) {
//dada/data
this(context, Environment.getDataDirectory());
}
Settings(Context context, File dataDir) {
mSystemDir = new File(dataDir, "system");
mSystemDir.mkdirs();
FileUtils.setPermissions(mSystemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
//packages.xml保存了上一次的應(yīng)用安裝信息
mSettingsFilename = new File(mSystemDir, "packages.xml");
//對(duì)mSettingsFilename的備份
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
//存儲(chǔ)包名
mPackageListFilename = new File(mSystemDir, "packages.list");
FileUtils.setPermissions(mPackageListFilename, 0660, SYSTEM_UID, PACKAGE_INFO_GID);
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}
安裝包的信息數(shù)據(jù)是通過(guò)xml來(lái)進(jìn)行存儲(chǔ)的,由代碼知道钠右,源文件和備份文件完整的相對(duì)路徑為dada/dada/system/xxx.xml赋元。這里對(duì)緩存又進(jìn)行了一次備份,是起到了雙次檢測(cè)的效果飒房。
//讀取上一次保存的應(yīng)用安裝信息
boolean readLPw(PackageManagerService service, List<UserInfo> users, int sdkVersion, boolean onlyCore) {
FileInputStream str = null;
//備份文件存在搁凸,即packages-backup.xml文件
if (mBackupSettingsFilename.exists()) {
try {
str = new FileInputStream(mBackupSettingsFilename);//讀取備份文件
mReadMessages.append("Reading from backup settings file\n");
PackageManagerService.reportSettingsProblem(Log.INFO, "Need to read from backup settings file");
//清除源文件,即packages.xml文件
if (mSettingsFilename.exists()) {
mSettingsFilename.delete();
}
} catch (java.io.IOException e) {
// We'll try for the normal settings file.
}
}
mPendingPackages.clear();
mPastSignatures.clear();
try {
//備份文件不存在
if (str == null) {
//源文件不存在
if (!mSettingsFilename.exists()) {
mReadMessages.append("No settings file found\n");
PackageManagerService.reportSettingsProblem(Log.INFO, "No settings file; creating initial state");
mInternalSdkPlatform = mExternalSdkPlatform = sdkVersion;
mFingerprint = Build.FINGERPRINT;
return false;
}
str = new FileInputStream(mSettingsFilename);//讀取源文件存在
}
XmlPullParser parser = Xml.newPullParser();//開(kāi)始pull解析
parser.setInput(str, null);
對(duì)緩存文件的檢測(cè)可以分為3種情況:
- 如果備份存在狠毯,源文件也存在护糖,則讀取備份文件并且刪除源文件,后面writeLPr會(huì)重新保存一份新的源文件嚼松;
- 如果備份不存在嫡良,源文件不存在,則恢復(fù)上一次失敗献酗,結(jié)束事件寝受;
- 如果備份不存在,源文件存在罕偎,則讀取源文件很澄;
文件讀取成功,會(huì)構(gòu)造XmlPullParser 對(duì)象來(lái)解析xml文件。xml保存了上一次安裝的許多數(shù)據(jù)甩苛,這里貼些關(guān)鍵的標(biāo)簽忙干,其中package和shared-user標(biāo)簽,保存了應(yīng)用程序和LInux用戶Id相關(guān)的信息浪藻。
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
;
}
//開(kāi)始標(biāo)簽
if (type != XmlPullParser.START_TAG) {
mReadMessages.append("No start tag found in settings file\n");
PackageManagerService.reportSettingsProblem(Log.WARN,
"No start tag found in package manager settings");
Slog.wtf(PackageManagerService.TAG,
"No start tag found in package manager settings");
return false;
}
//開(kāi)始解析
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
//以包名為根標(biāo)簽,保存了每個(gè)應(yīng)用上次安裝的信息
if (tagName.equals("package")) {
//讀取包信息乾翔,獲取上一次分配的Linux用戶id
readPackageLPw(parser);
} else if (tagName.equals("permissions")) {
readPermissionsLPw(mPermissions, parser);
} else if (tagName.equals("permission-trees")) {
readPermissionsLPw(mPermissionTrees, parser);
//shared-user上一次分配的共享linux用戶
} else if (tagName.equals("shared-user")) {
//獲取上一次分配的共享Linux用戶id
readSharedUserLPw(parser);
} else if (tagName.equals("preferred-packages")) {
// no longer used.
} else if (tagName.equals("preferred-activities")) {
xml以package為根標(biāo)簽保存了一個(gè)應(yīng)用的完整信息爱葵,所以,readPackageLPw從package標(biāo)簽開(kāi)始解析包數(shù)據(jù)反浓。
//解析package標(biāo)簽
private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
String name = null;
String realName = null;
String idStr = null;
String sharedIdStr = null;
String codePathStr = null;
String resourcePathStr = null;
String legacyCpuAbiString = null;
String legacyNativeLibraryPathStr = null;
String primaryCpuAbiString = null;
String secondaryCpuAbiString = null;
String cpuAbiOverrideString = null;
String systemStr = null;
String installerPackageName = null;
String uidError = null;
int pkgFlags = 0;
long timeStamp = 0;
long firstInstallTime = 0;
long lastUpdateTime = 0;
PackageSettingBase packageSetting = null;
String version = null;
int versionCode = 0;
try {
name = parser.getAttributeValue(null, ATTR_NAME);//ATTR_NAME為name萌丈,應(yīng)用包名
realName = parser.getAttributeValue(null, "realName");
idStr = parser.getAttributeValue(null, "userId");//獨(dú)立Linux用戶Id
uidError = parser.getAttributeValue(null, "uidError");
sharedIdStr = parser.getAttributeValue(null, "sharedUserId");//共享Linux用戶Id
codePathStr = parser.getAttributeValue(null, "codePath");
resourcePathStr = parser.getAttributeValue(null, "resourcePath");
......
if (name == null) { //名字為空,拋出異常雷则,說(shuō)明包名必須有
PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings: <package> has no name at "
+ parser.getPositionDescription());
} else if (codePathStr == null) {
PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings: <package> has no codePath at "
+ parser.getPositionDescription());
} else if (userId > 0) {//說(shuō)明上一次分配了一個(gè)獨(dú)立的Linux用戶Id
//則將上一次分配的Linux用戶Id保存下來(lái)
packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags);
if (PackageManagerService.DEBUG_SETTINGS)
Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId=" + userId + " pkg=" + packageSetting);
if (packageSetting == null) {
PackageManagerService.reportSettingsProblem(Log.ERROR, "Failure adding uid "
+ userId + " while parsing settings at "
+ parser.getPositionDescription());
} else {
packageSetting.setTimeStamp(timeStamp);
packageSetting.firstInstallTime = firstInstallTime;
packageSetting.lastUpdateTime = lastUpdateTime;
}
} else if (sharedIdStr != null) {//說(shuō)明上一次沒(méi)有分配獨(dú)立的Linux用戶Id辆雾,而是和其他程序共享一個(gè)Linux用戶Id
userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
if (userId > 0) {
//PendingPackage描述一個(gè)還未確定的應(yīng)用程序
packageSetting = new PendingPackage(name.intern(), realName, new File(
codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
userId, versionCode, pkgFlags);
packageSetting.setTimeStamp(timeStamp);
packageSetting.firstInstallTime = firstInstallTime;
packageSetting.lastUpdateTime = lastUpdateTime;
//將這個(gè)描述對(duì)象保存在mPendingPackages中
mPendingPackages.add((PendingPackage) packageSetting);
if (PackageManagerService.DEBUG_SETTINGS)
Log.i(PackageManagerService.TAG, "Reading package " + name
+ ": sharedUserId=" + userId + " pkg=" + packageSetting);
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Error in package manager settings: package " + name
+ " has bad sharedId " + sharedIdStr + " at "
+ parser.getPositionDescription());
}
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Error in package manager settings: package " + name + " has bad userId "
+ idStr + " at " + parser.getPositionDescription());
}
} catch (NumberFormatException e) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Error in package manager settings: package " + name + " has bad userId "
+ idStr + " at " + parser.getPositionDescription());
}
Linux用戶id分為共享和獨(dú)立,如果此應(yīng)用userId > 0月劈,說(shuō)明上一次分配了一個(gè)獨(dú)立的Linux用戶id度迂,則會(huì)調(diào)用addPackageLPw將獨(dú)立id保存下來(lái),如果不是獨(dú)立的猜揪,而sharedIdStr !=null惭墓,則說(shuō)明是分配的是共享id,則暫時(shí)不保留這個(gè)id而姐,因?yàn)檫@可能是一個(gè)無(wú)效的id腊凶,mPendingPackages會(huì)將此類(lèi)應(yīng)用保存起來(lái),表示還未確定的應(yīng)用拴念。要等到解析完所有安裝信息后才能確定钧萍。
接著看addPackageLPw是如何將Linux用戶id保存下來(lái)的。
PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
String cpuAbiOverrideString, int uid, int vc, int pkgFlags) {
//緩存Map中獲取PackageSetting
PackageSetting p = mPackages.get(name);
//存在這個(gè)包名的應(yīng)用PackageSetting
if (p != null) {
//Linux用戶id和appid相同政鼠,說(shuō)明已分配過(guò)风瘦,直接返回PackageSetting
if (p.appId == uid) {
return p;
}
PackageManagerService.reportSettingsProblem(Log.ERROR, "Adding duplicate package, keeping first: " + name);
return null;
}
//不存在說(shuō)明是第一次安裝,新建一個(gè)PackageSetting對(duì)象
p = new PackageSetting(name, realName, codePath, resourcePath,
legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
cpuAbiOverrideString, vc, pkgFlags);
//將Linux用戶id賦值給appid
p.appId = uid;
//保存此用戶id公般,如果保留成功弛秋,則將PackageSetting存到mPackages中
if (addUserIdLPw(uid, p, name)) {
mPackages.put(name, p);
return p;
}
return null;
}
每個(gè)應(yīng)用程序的安裝信息都是用PackageSetting對(duì)象來(lái)存儲(chǔ),并以包名為key俐载,保存在mPackages這個(gè)HashMap中蟹略,如果程序已安裝過(guò),直接從mPackages獲取遏佣。如果第一次安裝挖炬,將構(gòu)建一個(gè)PackageSetting對(duì)象來(lái)保存信息。
addUserIdLPw方法用于在系統(tǒng)中保留分配的uid状婶,如果保留成功意敛,則將PackageSetting保存到mPackages中馅巷,說(shuō)明PMS已經(jīng)為此應(yīng)用分配了Linux用戶id了。
//保存Linux用戶id
private boolean addUserIdLPw(int uid, Object obj, Object name) {
//Process.LAST_APPLICATION_UID是19999
if (uid > Process.LAST_APPLICATION_UID) {
return false;
}
//LAST_APPLICATION_UID是10000
if (uid >= Process.FIRST_APPLICATION_UID) {
int N = mUserIds.size();//mUserIds為用戶id列表
final int index = uid - Process.FIRST_APPLICATION_UID;//當(dāng)前申請(qǐng)的角標(biāo)
while (index >= N) {//是否超過(guò)列表的角標(biāo)
mUserIds.add(null);//將中間的置為null
N++;
}
//這個(gè)id被用了草姻,保留失敗
if (mUserIds.get(index) != null) {
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate user id: " + uid
+ " name=" + name);
return false;
}
//以pid為角標(biāo)钓猬,添加應(yīng)用程序的PackageSetting
mUserIds.set(index, obj);
} else {
//10000以下給特權(quán)用戶使用
if (mOtherUserIds.get(uid) != null) {
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared id: " + uid
+ " name=" + name);
return false;
}
mOtherUserIds.put(uid, obj);
}
return true;
}
用戶類(lèi)型的pid都在10000到19999之間,說(shuō)明Android系統(tǒng)只分配9999個(gè)給用戶類(lèi)型的程序撩独,小于10000保留給特權(quán)用戶使用敞曹,但這些id也可以通過(guò)共享的方式給用戶程序使用。獨(dú)立用戶的流程分配完成综膀,我們回到xml解析澳迫,看標(biāo)簽為shared-user的共享用戶,它緊接著調(diào)用了Settings的readSharedUserLPw方法剧劝。
//獲取上一次分配的共享Linux用戶id
private void readSharedUserLPw(XmlPullParser parser) throws XmlPullParserException,IOException {
String name = null;
String idStr = null;
int pkgFlags = 0;
SharedUserSetting su = null;
try {
name = parser.getAttributeValue(null, ATTR_NAME);//共享用戶名
idStr = parser.getAttributeValue(null, "userId");//用戶id
int userId = idStr != null ? Integer.parseInt(idStr) : 0;
if ("true".equals(parser.getAttributeValue(null, "system"))) {//是給系統(tǒng)類(lèi)型的應(yīng)用還是用戶類(lèi)型的應(yīng)用
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;//系統(tǒng)用戶為1
}
//name,userId必須存在
if (name == null) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Error in package manager settings: <shared-user> has no name at "
+ parser.getPositionDescription());
} else if (userId == 0) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Error in package manager settings: shared-user " + name
+ " has bad userId " + idStr + " at "
+ parser.getPositionDescription());
} else {
//保存這個(gè)共享用戶的id
if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags)) == null) {
PackageManagerService
.reportSettingsProblem(Log.ERROR, "Occurred while parsing settings at "
+ parser.getPositionDescription());
}
}
} catch (NumberFormatException e) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Error in package manager settings: package " + name + " has bad userId "
+ idStr + " at " + parser.getPositionDescription());
}
;
......
}
這里有三個(gè)元素橄登,name、userId和system讥此,前兩個(gè)是共享Linux用戶的名稱(chēng)和id拢锹,最后一個(gè)則用于描述此程序是系統(tǒng)類(lèi)型,還是用戶類(lèi)型的萄喳。
和獨(dú)立用戶流程相似面褐,共享用戶是通過(guò)addSharedUserLPw方法,保存userId為L(zhǎng)inux用戶id的取胎。
//保存共享用戶的id
SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {
//SharedUserSetting即一個(gè)共享用戶對(duì)象
SharedUserSetting s = mSharedUsers.get(name);
if (s != null) {
if (s.userId == uid) {
return s;
}
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared user, keeping first: " + name);
return null;
}
s = new SharedUserSetting(name, pkgFlags);
s.userId = uid;
//保存共享用戶的id
if (addUserIdLPw(uid, s, name)) {
mSharedUsers.put(name, s);//保存起來(lái)
return s;
}
return null;
}
獨(dú)立用戶使用PackageSetting對(duì)象來(lái)描述應(yīng)用的安裝信息展哭,而共享用戶則使用SharedUserSetting ,分配和安裝成功的用戶同樣保存到一個(gè)Map中闻蛀,即mSharedUsers匪傍。
同樣,需要調(diào)用addUserIdLPw方法觉痛,來(lái)判斷這個(gè)id是否在系統(tǒng)規(guī)定的范圍役衡,這個(gè)方法上面已做了分析。這個(gè)時(shí)候PMS通過(guò)Settings就已將上一次應(yīng)用程序的安裝信息恢復(fù)完成了薪棒。我們回頭看到PMS的構(gòu)造方法手蝎,它會(huì)掃描各個(gè)安裝目錄。
//Environment.getRootDirectory()為system目錄
//獲取/system/famework目錄俐芯,保存的是資源型的文件棵介,不包含執(zhí)行代碼
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
//加載framework資源
alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");
//加載核心庫(kù)
alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");
String[] frameworkFiles = frameworkDir.list();
if (frameworkFiles != null) {
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.
//跳過(guò)已優(yōu)化的文件
if (alreadyDexOpted.contains(path)) {
continue;
}
// Skip the file if it is not a type we want to dexopt.
//跳過(guò)不是apk或jar的文件
if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
continue;
}
try {
byte dexoptRequired = DexFile.isDexOptNeededInternal(path, null, dexCodeInstructionSet, false);
if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
didDexOptLibraryOrTool = true;
} else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {
mInstaller.patchoat(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
didDexOptLibraryOrTool = true;
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
} catch (IOException e) {
Slog.w(TAG, "Exception reading jar: " + path, e);
}
}
}
}
File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
//根據(jù)上面讀取到的安裝信息,通過(guò)scanDirLI來(lái)安裝各個(gè)目錄的程序
scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);
//系統(tǒng)私有的應(yīng)用程序吧史,如Launcher邮辽、systemui、settings
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);
// /system/app系統(tǒng)的應(yīng)用程序
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
//掃描系統(tǒng)應(yīng)用的安裝路徑
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
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);
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");
mInstaller.moveFiles();
顯然scanDirLI是最關(guān)鍵的方法,通過(guò)掃描5個(gè)安裝目錄吨述,判斷是否存在以".apk"為后綴的文件岩睁,如果存在則對(duì)文件進(jìn)行解析。
//掃描安裝路徑
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));
}
//取出所有apk文件進(jìn)行解析
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
continue;
}
try {
//解析apk
scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
scanFlags, currentTime, null);
} catch (PackageManagerException e) {
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
if (file.isDirectory()) {
FileUtils.deleteContents(file);
}
file.delete();
}
}
}
}
scanPackageLI方法用來(lái)解析.apk文件揣云,解析完會(huì)返回一個(gè)Package對(duì)象pkg給調(diào)用者捕儒。
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
//設(shè)置解析標(biāo)志mDefParseFlags默認(rèn)為0
parseFlags |= mDefParseFlags;
//創(chuàng)建一個(gè)包解析器
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
}
//定義包對(duì)象Package
final PackageParser.Package pkg;
try {
//解析apk文件,獲得Package
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
PackageSetting ps = null;
PackageSetting updatedPkg;
synchronized (mPackages) {
String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
ps = mSettings.peekPackageLPr(oldName);
}
if (ps == null) {
ps = mSettings.peekPackageLPr(pkg.packageName);
}
updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);
}
boolean updatedPkgBetter = false;
if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
if (ps != null && !ps.codePath.equals(scanFile)) {
if (pkg.mVersionCode < ps.versionCode) {
if (!updatedPkg.codePath.equals(scanFile)) {
updatedPkg.codePath = scanFile;
updatedPkg.codePathString = scanFile.toString();
if (locationIsPrivileged(scanFile)) {
updatedPkg.pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
}
}
updatedPkg.pkg = pkg;
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, null);
} else {
synchronized (mPackages) {
mPackages.remove(ps.name);
}
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
getAppDexInstructionSets(ps));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
synchronized (mPackages) {
mSettings.enableSystemPackageLPw(ps.name);
}
updatedPkgBetter = true;
}
}
}
if (updatedPkg != null) {
parseFlags |= PackageParser.PARSE_IS_SYSTEM;
if ((updatedPkg.pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
}
}
collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);
boolean shouldHideSystemApp = false;
if (updatedPkg == null && ps != null
&& (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
} else {
if (pkg.mVersionCode < ps.versionCode) {
shouldHideSystemApp = true;
} else {
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
getAppDexInstructionSets(ps));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
}
}
}
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
}
}
String resourcePath = null;
String baseResourcePath = null;
if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) {
if (ps != null && ps.resourcePathString != null) {
resourcePath = ps.resourcePathString;
baseResourcePath = ps.resourcePathString;
} else {
}
} else {
resourcePath = pkg.codePath;
baseResourcePath = pkg.baseCodePath;
}
pkg.applicationInfo.setCodePath(pkg.codePath);
pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
pkg.applicationInfo.setResourcePath(resourcePath);
pkg.applicationInfo.setBaseResourcePath(baseResourcePath);
pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
//解析Package
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags| SCAN_UPDATE_SIGNATURE, currentTime, user);
if (shouldHideSystemApp) {
synchronized (mPackages) {
grantPermissionsLPw(pkg, true, pkg.packageName);
mSettings.disableSystemPackageLPw(pkg.packageName);
}
}
return scannedPkg;
}
這里分兩步看邓夕,第一步是創(chuàng)建PackageParser解析器刘莹,通過(guò)parsePackage方法,將apk文件解析成Package對(duì)象翎迁;第二步是使用另一個(gè)重載方法scanPackageLI來(lái)處理這個(gè)Package并返回。我們先看第一步净薛,進(jìn)入PackageParser這個(gè)類(lèi)的parsePackage方法汪榔。
//解析.apk文件
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {
//解析多個(gè)apk
return parseClusterPackage(packageFile, flags);
} else {
//解析單個(gè)
return parseMonolithicPackage(packageFile, flags);
}
}
如果傳入的是一個(gè)目錄文件,被拆分成多個(gè)apk肃拜,由一個(gè)base APK和一個(gè)或多個(gè)split APK痴腌,稱(chēng)為Cluster,單個(gè)稱(chēng)為Monolithic燃领。
兩者解析流程差別不大士聪,我們以parseMonolithicPackage為例分析。
@Deprecated
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
//是否核心應(yīng)用
if (mOnlyCoreApps) {
//輕量級(jí)解析
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
if (!lite.coreApp) {
throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"Not a coreApp: " + apkFile);
}
}
//構(gòu)建AssetManager
final AssetManager assets = new AssetManager();
try {
//開(kāi)始解析
final Package pkg = parseBaseApk(apkFile, assets, flags);
pkg.codePath = apkFile.getAbsolutePath();
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}
輕量級(jí)解析是因?yàn)榻馕鯽pk是復(fù)雜耗時(shí)的操作猛蔽,這里的邏輯并不需要所有的信息剥悟,coreApp指的是AndroidManifest中屬性coreApp值為true。繼續(xù)看解析方法parseBaseApk曼库,注意它接收了一個(gè)AssetManager 對(duì)象区岗。
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
mParseError = PackageManager.INSTALL_SUCCEEDED;
mArchiveSourcePath = apkFile.getAbsolutePath();
final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
//構(gòu)建Resources
Resources res = null;
XmlResourceParser parser = null;
try {
//將AssetManager封裝在Resources中
res = new Resources(assets, mMetrics, null);
assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Build.VERSION.RESOURCES_SDK_INT);
//打開(kāi)manifest,構(gòu)造解析器
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final String[] outError = new String[1];
//調(diào)用重載方法parseBaseApk
final Package pkg = parseBaseApk(res, parser, flags, outError);
if (pkg == null) {
throw new PackageParserException(mParseError,
apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
}
pkg.baseCodePath = apkPath;
pkg.mSignatures = null;
return pkg;
} catch (PackageParserException e) {
throw e;
} catch (Exception e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
}
}
XmlResourceParser 用于解析編譯后的AndroidManifest毁枯,通過(guò)重載方法parseBaseApk來(lái)解析慈缔。因?yàn)榻馕鰳?biāo)簽很多,所以代碼非常長(zhǎng)种玛,這里貼部分作為示例藐鹤。
private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
final boolean trustedOverlay = (flags & PARSE_TRUSTED_OVERLAY) != 0;
AttributeSet attrs = parser;
mParseInstrumentationArgs = null;
mParseActivityArgs = null;
mParseServiceArgs = null;
mParseProviderArgs = null;
final String pkgName;
final String splitName;
try {
Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);
pkgName = packageSplit.first;//包名
splitName = packageSplit.second;
} catch (PackageParserException e) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
return null;
}
int type;
if (!TextUtils.isEmpty(splitName)) {
outError[0] = "Expected base APK, but found split " + splitName;
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
return null;
}
//根據(jù)包名構(gòu)建Package對(duì)象,將解析manifest后的信息存到這個(gè)對(duì)象中
final Package pkg = new Package(pkgName);
boolean foundApp = false;
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifest);
pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_versionCode, 0);//版本號(hào)
pkg.mVersionName = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_versionName, 0);//版本名
if (pkg.mVersionName != null) {
pkg.mVersionName = pkg.mVersionName.intern();
}
String str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
if (str != null && str.length() > 0) {
String nameError = validateName(str, true);
if (nameError != null && !"android".equals(pkgName)) {
outError[0] = "<manifest> specifies bad sharedUserId name \""
+ str + "\": " + nameError;
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
return null;
}
pkg.mSharedUserId = str.intern();
pkg.mSharedUserLabel = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
}
pkg.installLocation = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_installLocation,
PARSE_DEFAULT_INSTALL_LOCATION);
pkg.applicationInfo.installLocation = pkg.installLocation;
pkg.coreApp = attrs.getAttributeBooleanValue(null, "coreApp", false);
sa.recycle();
if ((flags & PARSE_FORWARD_LOCK) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK;
}
if ((flags & PARSE_ON_SDCARD) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
}
int supportsSmallScreens = 1;
int supportsNormalScreens = 1;
int supportsLargeScreens = 1;
int supportsXLargeScreens = 1;
int resizeable = 1;
int anyDensity = 1;
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
//解析application標(biāo)簽
if (tagName.equals("application")) {
if (foundApp) {
if (RIGID_PARSER) {
//一個(gè)xml只能包含一個(gè)<application>標(biāo)簽
outError[0] = "<manifest> has more than one <application>";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
} else {
Slog.w(TAG, "<manifest> has more than one <application>");
XmlUtils.skipCurrentTag(parser);
continue;
}
}
foundApp = true;
//解析Application標(biāo)簽
if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {
return null;
}
} else if (tagName.equals("overlay")) {
pkg.mTrustedOverlay = trustedOverlay;
sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestResourceOverlay);
pkg.mOverlayTarget = sa.getString(
com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
pkg.mOverlayPriority = sa.getInt(
com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
-1);
sa.recycle();
if (pkg.mOverlayTarget == null) {
outError[0] = "<overlay> does not specify a target package";
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
}
if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
outError[0] = "<overlay> priority must be between 0 and 9999";
mParseError =
PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
}
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("key-sets")) {
if (!parseKeySets(pkg, res, parser, attrs, outError)) {
return null;
}
} else if (tagName.equals("permission-group")) {
if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) {
return null;
}
} else if (tagName.equals("permission")) {
if (parsePermission(pkg, res, parser, attrs, outError) == null) {
return null;
}
} else if (tagName.equals("permission-tree")) {
if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {
return null;
}
//權(quán)限
} else if (tagName.equals("uses-permission")) {
if (!parseUsesPermission(pkg, res, parser, attrs, outError)) {
return null;
}
我們看到parseBaseApplication開(kāi)始解析application標(biāo)簽赂韵,它同樣非常長(zhǎng)娱节。
private boolean parseBaseApplication(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
throws XmlPullParserException, IOException {
//應(yīng)用信息
final ApplicationInfo ai = owner.applicationInfo;
//包名
final String pkgName = owner.applicationInfo.packageName;
//標(biāo)簽屬性
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestApplication);
//應(yīng)用名
String name = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestApplication_name, 0);
if (name != null) {
ai.className = buildClassName(pkgName, name, outError);
if (ai.className == null) {
sa.recycle();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
}
String manageSpaceActivity = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity,
Configuration.NATIVE_CONFIG_VERSION);
if (manageSpaceActivity != null) {
ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
outError);
}
boolean allowBackup = sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
if (allowBackup) {
ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
String backupAgent = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
Configuration.NATIVE_CONFIG_VERSION);
if (backupAgent != null) {
ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore,
true)) {
ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
}
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion,
false)) {
ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
}
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_fullBackupOnly,
false)) {
ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
}
}
}
TypedValue v = sa.peekValue(
com.android.internal.R.styleable.AndroidManifestApplication_label);
if (v != null && (ai.labelRes=v.resourceId) == 0) {
ai.nonLocalizedLabel = v.coerceToString();
}
//應(yīng)用圖標(biāo)等
ai.icon = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
ai.logo = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestApplication_logo, 0);
ai.banner = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestApplication_banner, 0);
ai.theme = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
ai.descriptionRes = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestApplication_description, 0);
if ((flags&PARSE_IS_SYSTEM) != 0) {
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_persistent,
false)) {
ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
}
}
......
final int innerDepth = parser.getDepth();
int type;
//循環(huán)解析Application元素下所有子元素,如activity,service等
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("activity")) {//解析activity
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,
owner.baseHardwareAccelerated);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
//將Activity添加到管理的列表當(dāng)中
owner.activities.add(a);
} else if (tagName.equals("receiver")) {//解析receiver
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.receivers.add(a);
} else if (tagName.equals("service")) {//解析service
Service s = parseService(owner, res, parser, attrs, flags, outError);
if (s == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.services.add(s);
} else if (tagName.equals("provider")) {//解析provider
Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
if (p == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.providers.add(p);
我們看到包名祭示、應(yīng)用名還有4大組件都被解析出來(lái)了括堤。這里注意到有個(gè)owner,它是在parseBaseApk里根據(jù)包名生成的Package對(duì)象,Manifest標(biāo)簽解析后的數(shù)據(jù)都存在此對(duì)象中悄窃。
Package是PackageParser解析器的內(nèi)部類(lèi)讥电,Package用了四個(gè)列表分別保存四大組件。
public final static class Package {
public String packageName;
public String[] splitNames;
public String codePath;
public String baseCodePath;
public String[] splitCodePaths;
public int[] splitFlags;
public boolean baseHardwareAccelerated;
public final ApplicationInfo applicationInfo = new ApplicationInfo();
public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
//保存四大組件
public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
public final ArrayList<Service> services = new ArrayList<Service>(0);
到這里第一步就完成了轧抗,得到一個(gè)Package對(duì)象恩敌,它包含了Manifest的所有信息。如上面所提横媚,第二步是調(diào)用重載的scanPackageLI方法纠炮,解析這個(gè)Package。
我們先看下PMS的5個(gè)成員變量灯蝴。
//保存已安裝的程序
final HashMap<String, PackageParser.Package> mPackages =
new HashMap<String, PackageParser.Package>();
//保存每個(gè)應(yīng)用的Activity節(jié)點(diǎn)恢口,一個(gè)應(yīng)用一個(gè)節(jié)點(diǎn),一個(gè)節(jié)點(diǎn)用一個(gè)HashMap存了改應(yīng)用的所有activity
final ActivityIntentResolver mActivities =
new ActivityIntentResolver();
//保存所有receiver節(jié)點(diǎn)
final ActivityIntentResolver mReceivers =
new ActivityIntentResolver();
//保存所有Service節(jié)點(diǎn)
final ServiceIntentResolver mServices = new ServiceIntentResolver();
//保存所有Provider節(jié)點(diǎn)
final ProviderIntentResolver mProviders = new ProviderIntentResolver();
這些屬性類(lèi)型都采用了自定義類(lèi)去保存相關(guān)信息穷躁,從類(lèi)名上看耕肩,類(lèi)結(jié)構(gòu)都很相似。順便提一下问潭,我們通過(guò)getPackageManager()方法獲得的PackageManager對(duì)象猿诸,只是PackageManagerService的客戶端,PackageManager的子類(lèi)ApplicationPackageManager狡忙,顯然該類(lèi)存在于用戶空間中梳虽。關(guān)于跨進(jìn)程通訊可以看<Binder系列>的分析。
系統(tǒng)中所有已安裝的程序都用Package來(lái)描述灾茁,而這些Package就保存在mPackages 中窜觉,而每一個(gè)應(yīng)用的四大組件都分別保存在mActivities 、mReceivers 北专、mServices 和mProviders 中竖螃。
我們接下去看重載scanPackageLI方法。
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
boolean success = false;
try {
//scanPackageDirtyLI進(jìn)行掃描
final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,
currentTime, user);
success = true;
return res;
} finally {
if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
removeDataDirsLI(pkg.packageName);
}
}
}
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
......
SharedUserSetting suid = null;
PackageSetting pkgSetting = null;
if (!isSystemApp(pkg)) {
pkg.mOriginalPackages = null;
pkg.mRealPackage = null;
pkg.mAdoptPermissions = null;
}
synchronized (mPackages) {
//根據(jù)mSettings保存的分配Linux用戶id
if (pkg.mSharedUserId != null) {
suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, true);
if (suid == null) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Creating application package " + pkg.packageName
+ " for shared user failed");
}
}
......
// writer
synchronized (mPackages) {
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
//將Package添加到成員變量mPackages中
mPackages.put(pkg.applicationInfo.packageName, pkg);
final Iterator<PackageCleanItem> iter = mSettings.mPackagesToBeCleaned.iterator();
while (iter.hasNext()) {
PackageCleanItem item = iter.next();
if (pkgName.equals(item.packageName)) {
iter.remove();
}
}
if (currentTime != 0) {
if (pkgSetting.firstInstallTime == 0) {
pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
} else if ((scanFlags&SCAN_UPDATE_TIME) != 0) {
pkgSetting.lastUpdateTime = currentTime;
}
} else if (pkgSetting.firstInstallTime == 0) {
pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;
} else if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
if (scanFileTime != pkgSetting.timeStamp) {
pkgSetting.lastUpdateTime = scanFileTime;
}
}
KeySetManagerService ksms = mSettings.mKeySetManagerService;
try {
ksms.removeAppKeySetDataLPw(pkg.packageName);
ksms.addSigningKeySetToPackageLPw(pkg.packageName, pkg.mSigningKeys);
if (pkg.mKeySetMapping != null) {
for (Map.Entry<String, ArraySet<PublicKey>> entry :
pkg.mKeySetMapping.entrySet()) {
if (entry.getValue() != null) {
ksms.addDefinedKeySetToPackageLPw(pkg.packageName,
entry.getValue(), entry.getKey());
}
}
if (pkg.mUpgradeKeySets != null) {
for (String upgradeAlias : pkg.mUpgradeKeySets) {
ksms.addUpgradeKeySetToPackageLPw(pkg.packageName, upgradeAlias);
}
}
}
} catch (NullPointerException e) {
Slog.e(TAG, "Could not add KeySet to " + pkg.packageName, e);
} catch (IllegalArgumentException e) {
Slog.e(TAG, "Could not add KeySet to malformed package" + pkg.packageName, e);
}
int N = pkg.providers.size();
StringBuilder r = null;
int i;
for (i=0; i<N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
p.info.processName, pkg.applicationInfo.uid);
//將Provider添加到mProviders
mProviders.addProvider(p);
p.syncable = p.info.isSyncable;
if (p.info.authority != null) {
String names[] = p.info.authority.split(";");
p.info.authority = null;
for (int j = 0; j < names.length; j++) {
if (j == 1 && p.syncable) {
p = new PackageParser.Provider(p);
p.syncable = false;
}
if (!mProvidersByAuthority.containsKey(names[j])) {
mProvidersByAuthority.put(names[j], p);
if (p.info.authority == null) {
p.info.authority = names[j];
} else {
p.info.authority = p.info.authority + ";" + names[j];
}
if (DEBUG_PACKAGE_SCANNING) {
if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
}
} else {
PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
}
}
}
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(p.info.name);
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Providers: " + r);
}
N = pkg.services.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Service s = pkg.services.get(i);
s.info.processName = fixProcessName(pkg.applicationInfo.processName,
s.info.processName, pkg.applicationInfo.uid);
//將Service添加到mServices
mServices.addService(s);
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(s.info.name);
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Services: " + r);
}
N = pkg.receivers.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.receivers.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
//將Receiver添加到mReceivers
mReceivers.addActivity(a, "receiver");
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(a.info.name);
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r);
}
N = pkg.activities.size();
r = null;
//將Package所有activity添加到成員變量mActivities的HashMap中
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.activities.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
//將Activity添加到mActivities
mActivities.addActivity(a, "activity");
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(a.info.name);
}
}
......
return pkg;
}
對(duì)Package的掃描主要任務(wù)是分配Linux用戶id逗余,以及將Package和四大組件分別添加到上面說(shuō)的5成員變量中特咆,前面說(shuō)過(guò)共享用戶都使用一個(gè)SharedUserSetting 對(duì)象來(lái)描述,因此根據(jù)name去mSharedUsers中查找录粱,如果不存在則新建腻格。
SharedUserSetting getSharedUserLPw(String name,
int pkgFlags, boolean create) {
SharedUserSetting s = mSharedUsers.get(name);
//不存在根據(jù)create判斷是否新建
if (s == null) {
if (!create) {
return null;
}
s = new SharedUserSetting(name, pkgFlags);
s.userId = newUserIdLPw(s);
//加到mSharedUsers中
if (s.userId >= 0) {
mSharedUsers.put(name, s);
}
}
return s;
}
此時(shí)PMS便為應(yīng)用分配好了Linux用戶id,并把它們緩存到成員變量中啥繁。但成員數(shù)據(jù)會(huì)隨著類(lèi)的回收而銷(xiāo)毀菜职,前面分析時(shí)我們知道,這些數(shù)據(jù)對(duì)應(yīng)的信息會(huì)保存到packages.xml和packages-backup.xml中旗闽,以便下次啟動(dòng)恢復(fù)酬核,這個(gè)保存操作也在PMS構(gòu)造函數(shù)執(zhí)行蜜另,我們?cè)俅位氐絇MS的構(gòu)造方法。
.....
//權(quán)限設(shè)置嫡意,檢查sdk版本
final boolean regrantPermissions = mSettings.mInternalSdkPlatform
!= mSdkVersion;
if (regrantPermissions) Slog.i(TAG, "Platform changed from "
+ mSettings.mInternalSdkPlatform + " to " + mSdkVersion
+ "; regranting permissions for internal storage");
mSettings.mInternalSdkPlatform = mSdkVersion;
//分配權(quán)限
updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
| (regrantPermissions
? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
: 0));
if (!mRestoredSettings && !onlyCore) {
mSettings.readDefaultPreferredAppsLPw(this, 0);
}
if (!Build.FINGERPRINT.equals(mSettings.mFingerprint) && !onlyCore) {
Slog.i(TAG, "Build fingerprint changed; clearing code caches");
for (String pkgName : mSettings.mPackages.keySet()) {
deleteCodeCacheDirsLI(pkgName);
}
mSettings.mFingerprint = Build.FINGERPRINT;
}
mSettings.updateInternalDatabaseVersion();
//將上面讀取到的信息保存成配置举瑰,以便下次啟動(dòng)恢復(fù)
mSettings.writeLPr();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
mRequiredVerifierPackage = getRequiredVerifierLPr();
}
}
mInstallerService = new PackageInstallerService(context, this, mAppInstallDir);
//GC回收資源
Runtime.getRuntime().gc();
}
我們?cè)俅芜M(jìn)到Settings類(lèi),看writeLPr方法是如何保存的蔬螟。
//保存上一次的應(yīng)用安裝信息
void writeLPr() {
//Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
// Keep the old settings around until we know the new ones have
// been successfully written.
//源文件是否存在
if (mSettingsFilename.exists()) {
// Presence of backup settings file indicates that we failed
// to persist settings earlier. So preserve the older
// backup for future reference since the current settings
// might have been corrupted.
//備份文件不存存在
if (!mBackupSettingsFilename.exists()) {
//將源文件重命名為備份文件
if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
Slog.wtf(PackageManagerService.TAG,
"Unable to backup package manager settings, "
+ " current changes will be lost at reboot");
return;
}
} else {
//刪掉源文件
mSettingsFilename.delete();
Slog.w(PackageManagerService.TAG, "Preserving older settings backup");
}
}
mPastSignatures.clear();
try {
//初始化文件的一些標(biāo)簽
FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
BufferedOutputStream str = new BufferedOutputStream(fstr);
//XmlSerializer serializer = XmlUtils.serializerInstance();
XmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(str, "utf-8");
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, "packages");//包標(biāo)簽
serializer.startTag(null, "last-platform-version");
serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform));
serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
serializer.attribute(null, "fingerprint", mFingerprint);
serializer.endTag(null, "last-platform-version");
serializer.startTag(null, "database-version");
serializer.attribute(null, "internal", Integer.toString(mInternalDatabaseVersion));
serializer.attribute(null, "external", Integer.toString(mExternalDatabaseVersion));
serializer.endTag(null, "database-version");
if (mVerifierDeviceIdentity != null) {
serializer.startTag(null, "verifier");
serializer.attribute(null, "device", mVerifierDeviceIdentity.toString());
serializer.endTag(null, "verifier");
}
if (mReadExternalStorageEnforced != null) {
serializer.startTag(null, TAG_READ_EXTERNAL_STORAGE);
serializer.attribute(
null, ATTR_ENFORCEMENT, mReadExternalStorageEnforced ? "1" : "0");
serializer.endTag(null, TAG_READ_EXTERNAL_STORAGE);
}
serializer.startTag(null, "permission-trees");
for (BasePermission bp : mPermissionTrees.values()) {
writePermissionLPr(serializer, bp);
}
serializer.endTag(null, "permission-trees");
serializer.startTag(null, "permissions");
for (BasePermission bp : mPermissions.values()) {
writePermissionLPr(serializer, bp);
}
serializer.endTag(null, "permissions");
for (final PackageSetting pkg : mPackages.values()) {
writePackageLPr(serializer, pkg);
}
for (final PackageSetting pkg : mDisabledSysPackages.values()) {
writeDisabledSysPackageLPr(serializer, pkg);
}
for (final SharedUserSetting usr : mSharedUsers.values()) {
serializer.startTag(null, "shared-user");//共享用戶標(biāo)簽
serializer.attribute(null, ATTR_NAME, usr.name);
serializer.attribute(null, "userId",Integer.toString(usr.userId));//獨(dú)立用戶id
usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
serializer.startTag(null, "perms");
for (String name : usr.grantedPermissions) {
serializer.startTag(null, TAG_ITEM);
serializer.attribute(null, ATTR_NAME, name);
serializer.endTag(null, TAG_ITEM);
}
serializer.endTag(null, "perms");
serializer.endTag(null, "shared-user");
}
if (mPackagesToBeCleaned.size() > 0) {
for (PackageCleanItem item : mPackagesToBeCleaned) {
final String userStr = Integer.toString(item.userId);
serializer.startTag(null, "cleaning-package");
serializer.attribute(null, ATTR_NAME, item.packageName);
serializer.attribute(null, ATTR_CODE, item.andCode ? "true" : "false");
serializer.attribute(null, ATTR_USER, userStr);
serializer.endTag(null, "cleaning-package");
}
}
if (mRenamedPackages.size() > 0) {
for (Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
serializer.startTag(null, "renamed-package");
serializer.attribute(null, "new", e.getKey());
serializer.attribute(null, "old", e.getValue());
serializer.endTag(null, "renamed-package");
}
}
mKeySetManagerService.writeKeySetManagerServiceLPr(serializer);
//包標(biāo)簽結(jié)束packages
serializer.endTag(null, "packages");
//文檔標(biāo)簽結(jié)束
serializer.endDocument();
str.flush();
FileUtils.sync(fstr);
str.close();
......
}
可以看到此迅,每個(gè)程序都是以package標(biāo)簽為單位來(lái)存儲(chǔ)的,name表示了包名旧巾,userId和sharedUserId描述分配給程序的獨(dú)立Linux用戶id和共享Linux用戶id耸序,這兩個(gè)id是互斥的,即要么為獨(dú)立用戶要么為共享用戶鲁猩。
這一步完成坎怪,PMS就將程序所使用的Linux用戶id保存起來(lái)了,當(dāng)重裝一個(gè)應(yīng)用程序時(shí)廓握,它所對(duì)應(yīng)的Linux用戶id是不變的搅窿。
Android系統(tǒng)是類(lèi)Linux系統(tǒng),根據(jù)Linux用戶id來(lái)防止程序的篡改和破壞疾棵,程序的進(jìn)程是AMS向Zygote進(jìn)程請(qǐng)求創(chuàng)建的戈钢,而Zygote正是根據(jù)這個(gè)id來(lái)創(chuàng)建進(jìn)程痹仙。我們可以看下AMS的startProcessLocked方法是尔。
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
long startTime = SystemClock.elapsedRealtime();
//
if (app.pid > 0 && app.pid != MY_PID) {
checkTime(startTime, "startProcess: removing from pids map");
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(app.pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
checkTime(startTime, "startProcess: done removing from pids map");
app.setPid(0);
}
mProcessesOnHold.remove(app);
checkTime(startTime, "startProcess: starting to update cpu stats");
updateCpuStats();
checkTime(startTime, "startProcess: done updating cpu stats");
try {
//獲取Linux用戶id
int uid = app.uid;
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
if (!app.isolated) {
int[] permGids = null;
try {
checkTime(startTime, "startProcess: getting gids from package manager");
final PackageManager pm = mContext.getPackageManager();
permGids = pm.getPackageGids(app.info.packageName);
if (Environment.isExternalStorageEmulated()) {
checkTime(startTime, "startProcess: checking external storage perm");
if (pm.checkPermission(
android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE,
app.info.packageName) == PERMISSION_GRANTED) {
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
} else {
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
}
}
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Unable to retrieve gids", e);
}
if (permGids == null) {
gids = new int[2];
} else {
gids = new int[permGids.length + 2];
System.arraycopy(permGids, 0, gids, 2, permGids.length);
}
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
}
......
//告訴Zygote子進(jìn)程孵化ActivityThread進(jìn)程后,調(diào)用main方法
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
checkTime(startTime, "startProcess: asking zygote to start proc");
//開(kāi)啟進(jìn)程
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
checkTime(startTime, "startProcess: returned from zygote!");
......
}
Process.start用于通知Zygote開(kāi)啟新進(jìn)程开仰,在調(diào)用的過(guò)程會(huì)根據(jù)第3拟枚、4、5個(gè)參數(shù)來(lái)創(chuàng)建進(jìn)程众弓。
到此恩溅,應(yīng)用程序的安裝過(guò)程便分析完畢,這個(gè)分析過(guò)程是從系統(tǒng)啟動(dòng)時(shí)開(kāi)始的谓娃,如果一個(gè)程序在系統(tǒng)啟動(dòng)后在安裝脚乡,它的入口會(huì)是PMS的installPackage,最終也會(huì)執(zhí)行scanPackageLI滨达,其流程是相似的奶稠。
程序安裝完成后,我們看到桌面會(huì)生成一個(gè)圖標(biāo)捡遍,這一流程將在下一篇<<App桌面圖標(biāo)顯示過(guò)程>>中講解锌订。