PackageManagerService比较长,我们挑主要的内容讲:
先来看下其在SystemServer的创建:
mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore); ...... mPackageManagerService.performBootDexOpt(); ...... try { mPackageManagerService.systemReady(); } catch (Throwable e) { reportWtf("making Package Manager Service ready", e); }
我们来看下PackageManagerService的main函数:
public static final 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函数就是new了一个PackageManagerService然后把它加入ServiceManager中。
下面我们主要分析PackageManagerService的构造函数:
mSettings = new Settings(context);//新建Settings mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,//往Settings中添加SharedUserSetting 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);
我们还是挑主要的讲,在构造函数中新建了Setting类,然后又调用了addSharedUserLPw函数。
我们先看Settings类:
Settings(Context context) { 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); mSettingsFilename = new File(mSystemDir, "packages.xml"); mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml"); mPackageListFilename = new File(mSystemDir, "packages.list"); FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID); // Deprecated: Needed for migration mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml"); mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml"); }
Settings类在data目录下创建了system目录,然后分别保存了下面文件。
1.packages.xml:记录系统中所有安装的应用的信息
2.packages-backup.xml:上面文件的备份
3.packages-stopped.xml:被强制停止运行的应用信息
4.packages-stopped-backup.xml:上面文件的备份
5.packages.list:保存普通应用的数据目录和uid信息等
当Android对文件packages.xml和packages-stopped.xml写之前,会先把它们备份,如果写文件成功了,再把备份文件删除掉。如果写的时候,系统出问题重启了,重启后会读取这两个文件时,发现有备份文件,会使用备份文件的内容,因为这个时候原文件已经损坏了。
每个应用的信息会保存在PackageSetting中,而所有的PackageSetting对象会保存在Settings的成员变量mPackages中。
回到构造函数,在Settings添加了SharedUserSetting,6种系统的uid:system radio log nfc bluetooth shell。相同shareUserId的包可以运行在一个进程中。
继续分析构造函数:
SystemConfig systemConfig = SystemConfig.getInstance(); mGlobalGids = systemConfig.getGlobalGids(); mSystemPermissions = systemConfig.getSystemPermissions(); mAvailableFeatures = systemConfig.getAvailableFeatures();
SystemConfig构造函数中会去读取etc下面的各个文件分析
SystemConfig() { // Read configuration from system readPermissions(Environment.buildPath( Environment.getRootDirectory(), "etc", "sysconfig"), false); // Read configuration from the old permissions dir readPermissions(Environment.buildPath( Environment.getRootDirectory(), "etc", "permissions"), false); // Only read features from OEM config readPermissions(Environment.buildPath( Environment.getOemDirectory(), "etc", "sysconfig"), true); readPermissions(Environment.buildPath( Environment.getOemDirectory(), "etc", "permissions"), true); }
分析完了后,会保存在各个成员变量中。
继续分析,会创建一个消息线程,会创建一些目录
mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/); mHandlerThread.start(); mHandler = new PackageHandler(mHandlerThread.getLooper()); Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT); File dataDir = Environment.getDataDirectory();//存放应用数据目录 mAppDataDir = new File(dataDir, "data"); mAppInstallDir = new File(dataDir, "app");//放应用 mAppLib32InstallDir = new File(dataDir, "app-lib");//native库 mAsecInternalPath = new File(dataDir, "app-asec").getPath(); mUserAppDataDir = new File(dataDir, "user");//存放用户数据 mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
前面systemconfig解析etc下的文件,然后将Permissions放在mSettings的mPermission,以及共享库放在mSharedLibraries中
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)); }
继续分析,调用了Settings的readLPw函数。
mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false), mSdkVersion, mOnlyCore);
我们来详细分析,先会去看packages-backup.xml有没有,没有就去看packages.xml, 然后再去解析xml文件。
boolean readLPw(PackageManagerService service, List<UserInfo> users, int sdkVersion, boolean onlyCore) { FileInputStream str = null; 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"); if (mSettingsFilename.exists()) { // If both the backup and settings file exist, we // ignore the settings since it might have been // corrupted. Slog.w(PackageManagerService.TAG, "Cleaning up settings file " + mSettingsFilename); 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(); parser.setInput(str, null); int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { ; } 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; } 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(); if (tagName.equals("package")) { readPackageLPw(parser); } else if (tagName.equals("permissions")) {//解析各个xml节点 readPermissionsLPw(mPermissions, parser); } else if (tagName.equals("permission-trees")) { readPermissionsLPw(mPermissionTrees, parser); } else if (tagName.equals("shared-user")) { readSharedUserLPw(parser); } else if (tagName.equals("preferred-packages")) { // no longer used. } else if (tagName.equals("preferred-activities")) { // Upgrading from old single-user implementation; // these are the preferred activities for user 0. readPreferredActivitiesLPw(parser, 0); } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) { // TODO: check whether this is okay! as it is very // similar to how preferred-activities are treated readPersistentPreferredActivitiesLPw(parser, 0); } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) { // TODO: check whether this is okay! as it is very // similar to how preferred-activities are treated readCrossProfileIntentFiltersLPw(parser, 0); } else if (tagName.equals("updated-package")) { readDisabledSysPackageLPw(parser); } else if (tagName.equals("cleaning-package")) { String name = parser.getAttributeValue(null, ATTR_NAME); String userStr = parser.getAttributeValue(null, ATTR_USER); String codeStr = parser.getAttributeValue(null, ATTR_CODE); if (name != null) { int userId = 0; boolean andCode = true; try { if (userStr != null) { userId = Integer.parseInt(userStr); } } catch (NumberFormatException e) { } if (codeStr != null) { andCode = Boolean.parseBoolean(codeStr); } addPackageToCleanLPw(new PackageCleanItem(userId, name, andCode)); } } else if (tagName.equals("renamed-package")) { String nname = parser.getAttributeValue(null, "new"); String oname = parser.getAttributeValue(null, "old"); if (nname != null && oname != null) { mRenamedPackages.put(nname, oname); } } else if (tagName.equals("last-platform-version")) { mInternalSdkPlatform = mExternalSdkPlatform = 0; try { String internal = parser.getAttributeValue(null, "internal"); if (internal != null) { mInternalSdkPlatform = Integer.parseInt(internal); } String external = parser.getAttributeValue(null, "external"); if (external != null) { mExternalSdkPlatform = Integer.parseInt(external); } } catch (NumberFormatException e) { } mFingerprint = parser.getAttributeValue(null, "fingerprint"); } else if (tagName.equals("database-version")) { mInternalDatabaseVersion = mExternalDatabaseVersion = 0; try { String internalDbVersionString = parser.getAttributeValue(null, "internal"); if (internalDbVersionString != null) { mInternalDatabaseVersion = Integer.parseInt(internalDbVersionString); } String externalDbVersionString = parser.getAttributeValue(null, "external"); if (externalDbVersionString != null) { mExternalDatabaseVersion = Integer.parseInt(externalDbVersionString); } } catch (NumberFormatException ignored) { } } else if (tagName.equals("verifier")) { final String deviceIdentity = parser.getAttributeValue(null, "device"); try { mVerifierDeviceIdentity = VerifierDev ......
下面开始优化dex文件变成oat文件,记录开始扫描系统的时间。
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; 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. */ 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!"); } if (systemServerClassPath != null) { String[] systemServerClassPathElements = splitString(systemServerClassPath, ':'); for (String element : systemServerClassPathElements) { alreadyDexOpted.add(element); } } else { Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!"); }
下面扫描动态库和framework下的文件执行dex到odex的转换
*/ 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 { byte dexoptRequired = DexFile.isDexOptNeededInternal(lib, null, dexCodeInstructionSet, false); if (dexoptRequired != DexFile.UP_TO_DATE) { alreadyDexOpted.add(lib); // The list of "shared libraries" we have at this point is if (dexoptRequired == DexFile.DEXOPT_NEEDED) { mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);//到intalld执行 } else { mInstaller.patchoat(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);//art虚拟机执行oat } } } 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");//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. 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. alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar"); /** * And 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. */ 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. if (alreadyDexOpted.contains(path)) { continue; } // Skip the file if it is not a type we want to dexopt. 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); } else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) { mInstaller.patchoat(path, Process.SYSTEM_UID, true, dexCodeInstructionSet); } } catch (FileNotFoundException e) { Slog.w(TAG, "Jar not found: " + path); } catch (IOException e) { Slog.w(TAG, "Exception reading jar: " + path, e); } } }
扫描各个目录下的文件信息,保存在Settings中。
scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0); // Find base frameworks (resource packages without code). scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanFlags | SCAN_NO_DEX, 0); // Collected privileged system packages. 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. 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. 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. final File oemAppDir = new File(Environment.getOemDirectory(), "app"); scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
还有一些,扫描并删除未成功安装的apk包,删除临时文件,升级应用的一些处理,更新应用动态库路径。
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr(); //clean up list for(int i = 0; i < deletePkgsList.size(); i++) { //clean up here cleanupInstallFailedPackage(deletePkgsList.get(i));//删除未成功安装的apk包 } //delete tmp files deleteTempPackageFiles();//删除临时文件 // Remove any shared userIDs that have no associated packages mSettings.pruneSharedUsersLPw(); if (!mOnlyCore) {//开始处理非系统应用 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0); scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanFlags | SCAN_REQUIRE_KNOWN, 0); .....
最后有一个扫描时间结束的log。
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis()); Slog.i(TAG, "Time to scan packages: " + ((SystemClock.uptimeMillis()-startTime)/1000f) + " seconds");
继续分析
final boolean regrantPermissions = mSettings.mInternalSdkPlatform != mSdkVersion;//因为sdk版本变化,permission的定义也改变了,需要重新赋予应用权限 if (regrantPermissions) Slog.i(TAG, "Platform changed from " + mSettings.mInternalSdkPlatform + " to " + mSdkVersion + "; regranting permissions for internal storage"); mSettings.mInternalSdkPlatform = mSdkVersion; updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL | (regrantPermissions//是否要重新赋权限 ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL) : 0)); // If this is the first boot, and it is a normal boot, then // we need to initialize the default preferred apps. if (!mRestoredSettings && !onlyCore) { mSettings.readDefaultPreferredAppsLPw(this, 0); } // If this is first boot after an OTA, and a normal boot, then // we need to clear code cache directories. mIsUpgrade = !Build.FINGERPRINT.equals(mSettings.mFingerprint); if (mIsUpgrade && !onlyCore) { Slog.i(TAG, "Build fingerprint changed; clearing code caches"); for (String pkgName : mSettings.mPackages.keySet()) { deleteCodeCacheDirsLI(pkgName);//如果是执行OTA后第一次启动,清除cache } mSettings.mFingerprint = Build.FINGERPRINT; } // All the changes are done during package scanning. mSettings.updateInternalDatabaseVersion();//更新数据库 // can downgrade to reader mSettings.writeLPr();//把mSettings写入packages.xml EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); mRequiredVerifierPackage = getRequiredVerifierLPr(); } // synchronized (mPackages) } // synchronized (mInstallLock) mInstallerService = new PackageInstallerService(context, this, mAppInstallDir); // 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();//启动垃圾回收updatePermissionsLPw函数
private void updatePermissionsLPw(String changingPkg, PackageParser.Package pkgInfo, int flags) { // Make sure there are no dangling permission trees. Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator(); while (it.hasNext()) { final BasePermission bp = it.next(); if (bp.packageSetting == null) { // We may not yet have parsed the package, so just see if // we still know about its settings. bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage); } if (bp.packageSetting == null) { Slog.w(TAG, "Removing dangling permission tree: " + bp.name + " from package " + bp.sourcePackage); it.remove(); } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) { if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) { Slog.i(TAG, "Removing old permission tree: " + bp.name + " from package " + bp.sourcePackage); flags |= UPDATE_PERMISSIONS_ALL; it.remove(); } } } // Make sure all dynamic permissions have been assigned to a package, // and make sure there are no dangling permissions. it = mSettings.mPermissions.values().iterator(); while (it.hasNext()) { final BasePermission bp = it.next(); if (bp.type == BasePermission.TYPE_DYNAMIC) { if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name=" + bp.name + " pkg=" + bp.sourcePackage + " info=" + bp.pendingInfo); if (bp.packageSetting == null && bp.pendingInfo != null) { final BasePermission tree = findPermissionTreeLP(bp.name); if (tree != null && tree.perm != null) { bp.packageSetting = tree.packageSetting; bp.perm = new PackageParser.Permission(tree.perm.owner, new PermissionInfo(bp.pendingInfo)); bp.perm.info.packageName = tree.perm.info.packageName; bp.perm.info.name = bp.name; bp.uid = tree.uid; } } } if (bp.packageSetting == null) { // We may not yet have parsed the package, so just see if // we still know about its settings. bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage); } if (bp.packageSetting == null) { Slog.w(TAG, "Removing dangling permission: " + bp.name + " from package " + bp.sourcePackage); it.remove(); } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) { if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) { Slog.i(TAG, "Removing old permission: " + bp.name + " from package " + bp.sourcePackage); flags |= UPDATE_PERMISSIONS_ALL; it.remove(); } } } // Now update the permissions for all packages, in particular // replace the granted permissions of the system packages. if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {//flags为UPDATE_PERMISSIONS_ALL for (PackageParser.Package pkg : mPackages.values()) { if (pkg != pkgInfo) { grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0, changingPkg); } } } if (pkgInfo != null) {//传进来的pkgInfo为null grantPermissionsLPw(pkgInfo, (flags&UPDATE_PERMISSIONS_REPLACE_PKG) != 0, changingPkg); } }
我们再来看看grantPermissionsLPw函数
private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace, String packageOfInterest) { final PackageSetting ps = (PackageSetting) pkg.mExtras; if (ps == null) { return; } final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; ArraySet<String> origPermissions = gp.grantedPermissions; boolean changedPermission = false; if (replace) { ps.permissionsFixed = false; if (gp == ps) { origPermissions = new ArraySet<String>(gp.grantedPermissions); gp.grantedPermissions.clear(); gp.gids = mGlobalGids; } } if (gp.gids == null) { gp.gids = mGlobalGids;//把gid的群组赋值 } final int N = pkg.requestedPermissions.size(); for (int i=0; i<N; i++) { final String name = pkg.requestedPermissions.get(i); final boolean required = pkg.requestedPermissionsRequired.get(i); final BasePermission bp = mSettings.mPermissions.get(name); if (DEBUG_INSTALL) { if (gp != ps) { Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp); } } if (bp == null || bp.packageSetting == null) { if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) { Slog.w(TAG, "Unknown permission " + name + " in package " + pkg.packageName); } continue; } final String perm = bp.name; boolean allowed; boolean allowedSig = false; if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) { // Keep track of app op permissions. ArraySet<String> pkgs = mAppOpPermissionPackages.get(bp.name); if (pkgs == null) { pkgs = new ArraySet<>(); mAppOpPermissionPackages.put(bp.name, pkgs); } pkgs.add(pkg.packageName); } final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE; if (level == PermissionInfo.PROTECTION_NORMAL || level == PermissionInfo.PROTECTION_DANGEROUS) { // We grant a normal or dangerous permission if any of the following // are true: // 1) The permission is required // 2) The permission is optional, but was granted in the past // 3) The permission is optional, but was requested by an // app in /system (not /data) // // Otherwise, reject the permission. allowed = (required || origPermissions.contains(perm) || (isSystemApp(ps) && !isUpdatedSystemApp(ps))); } else if (bp.packageSetting == null) { // This permission is invalid; skip it. allowed = false; } else if (level == PermissionInfo.PROTECTION_SIGNATURE) { allowed = grantSignaturePermission(perm, pkg, bp, origPermissions); if (allowed) { allowedSig = true; } } else { allowed = false; } if (DEBUG_INSTALL) { if (gp != ps) { Log.i(TAG, "Package " + pkg.packageName + " granting " + perm); } } if (allowed) { if (!isSystemApp(ps) && ps.permissionsFixed) { // If this is an existing, non-system package, then // we can't add any new permissions to it. if (!allowedSig && !gp.grantedPermissions.contains(perm)) { // Except... if this is a permission that was added // to the platform (note: need to only do this when // updating the platform). allowed = isNewPlatformPermissionForPackage(perm, pkg); } } if (allowed) { if (!gp.grantedPermissions.contains(perm)) { changedPermission = true; gp.grantedPermissions.add(perm); gp.gids = appendInts(gp.gids, bp.gids); } else if (!ps.haveGids) { gp.gids = appendInts(gp.gids, bp.gids); } } else { if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) { Slog.w(TAG, "Not granting permission " + perm + " to package " + pkg.packageName + " because it was previously installed without"); } } } else { if (gp.grantedPermissions.remove(perm)) { changedPermission = true; gp.gids = removeInts(gp.gids, bp.gids); Slog.i(TAG, "Un-granting permission " + perm + " from package " + pkg.packageName + " (protectionLevel=" + bp.protectionLevel + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) + ")"); } else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) { // Don't print warning for app op permissions, since it is fine for them // not to be granted, there is a UI for the user to decide. if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) { Slog.w(TAG, "Not granting permission " + perm + " to package " + pkg.packageName + " (protectionLevel=" + bp.protectionLevel + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) + ")"); } } } } if ((changedPermission || replace) && !ps.permissionsFixed && !isSystemApp(ps) || isUpdatedSystemApp(ps)){ // This is the first that we have heard about this package, so the // permissions we have now selected are fixed until explicitly // changed. ps.permissionsFixed = true; } ps.haveGids = true; }
这样我们这节就讲完了,后面我们会详细讲解下每个函数,读取权限,扫描文件等。这里只是讲个大概。