Android 6.0 PKMS 构造 permission

来源:互联网 发布:杭州seo招聘 编辑:程序博客网 时间:2024/06/03 23:47

PackageManagerService比较长,我们挑主要的内容讲,这是这个系列的第一篇博客,我们主要介绍下构造函数以及一些对象。


一、SystemServer创建PackageManagerService

先来看下其在SystemServer的创建:

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1.       mPackageManagerService = PackageManagerService.main(mSystemContext, installer,  
  2.               mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);  
  3.   
  4. ......  
  5.   
  6. mPackageManagerService.performBootDexOpt();  
  7.   
  8.   
  9. ......  
  10. try {  
  11.           mPackageManagerService.systemReady();  
  12.       } catch (Throwable e) {  
  13.           reportWtf("making Package Manager Service ready", e);  
  14.       }  

我们来看下PackageManagerService的main函数:

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public static final PackageManagerService main(Context context, Installer installer,  
  2.         boolean factoryTest, boolean onlyCore) {  
  3.     PackageManagerService m = new PackageManagerService(context, installer,  
  4.             factoryTest, onlyCore);  
  5.     ServiceManager.addService("package", m);  
  6.     return m;  
  7. }  

main函数就是new了一个PackageManagerService然后把它加入ServiceManager中。


二、PackageManagerService构造函数

2.1 Settings

下面我们主要分析PackageManagerService的构造函数:

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. mSettings = new Settings(context);//新建Settings  
  2. mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,//往Settings中添加SharedUserSetting  
  3.         ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
  4. mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,  
  5.         ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
  6. mSettings.addSharedUserLPw("android.uid.log", LOG_UID,  
  7.         ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
  8. mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,  
  9.         ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
  10. mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,  
  11.         ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  
  12. mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,  
  13.         ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);  

我们还是挑主要的讲,在构造函数中新建了Setting类,然后又调用了addSharedUserLPw函数。

我们先看Settings类:

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. Settings(Context context) {  
  2.     this(context, Environment.getDataDirectory());  
  3. }  
  4.   
  5. Settings(Context context, File dataDir) {  
  6.     mSystemDir = new File(dataDir, "system");  
  7.     mSystemDir.mkdirs();  
  8.     FileUtils.setPermissions(mSystemDir.toString(),  
  9.             FileUtils.S_IRWXU|FileUtils.S_IRWXG  
  10.             |FileUtils.S_IROTH|FileUtils.S_IXOTH,  
  11.             -1, -1);  
  12.     mSettingsFilename = new File(mSystemDir, "packages.xml");  
  13.     mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");  
  14.     mPackageListFilename = new File(mSystemDir, "packages.list");  
  15.     FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);  
  16.   
  17.     // Deprecated: Needed for migration  
  18.     mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");  
  19.     mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");  
  20. }  

Settings类在data目录下创建了system目录,然后分别保存了下面文件。

1.packages.xml:记录系统中所有安装的应用的信息, 我们来看下这个文件关于一个package

[html] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <package name="com.android.providers.media" codePath="/system/priv-app/MediaProvider" nativeLibraryPath="/system/priv-app/MediaProvider/lib" publicFlags="944291397" privateFlags="8" ft="15659d595e8" it="15659d595e8" ut="15659d595e8" version="800" sharedUserId="10006">  
  2.     <sigs count="1">  
  3.         <cert index="2" key="308204a830820390a003020102020900f2b98e6123572c4e300d06092a864886f70d0101040500308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f6964311  
  4.     </sigs>  
  5.     <perms>  
  6.         <item name="android.permission.ACCESS_CACHE_FILESYSTEM" granted="true" flags="0" />  
  7.         <item name="android.permission.WRITE_SETTINGS" granted="true" flags="0" />  
  8.         <item name="android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS" granted="true" flags="0" />  
  9.         <item name="android.permission.RECEIVE_BOOT_COMPLETED" granted="true" flags="0" />  
  10.         <item name="android.permission.WRITE_MEDIA_STORAGE" granted="true" flags="0" />  
  11.         <item name="android.permission.INTERNET" granted="true" flags="0" />  
  12.         <item name="android.permission.UPDATE_DEVICE_STATS" granted="true" flags="0" />  
  13.         <item name="android.permission.ACCESS_ALL_DOWNLOADS" granted="true" flags="0" />  
  14.         <item name="android.permission.ACCESS_DOWNLOAD_MANAGER" granted="true" flags="0" />  
  15.         <item name="android.permission.MANAGE_USERS" granted="true" flags="0" />  
  16.         <item name="android.permission.ACCESS_NETWORK_STATE" granted="true" flags="0" />  
  17.         <item name="android.permission.ACCESS_MTP" granted="true" flags="0" />  
  18.         <item name="android.permission.INTERACT_ACROSS_USERS" granted="true" flags="0" />  
  19.         <item name="android.permission.CLEAR_APP_CACHE" granted="true" flags="0" />  
  20.         <item name="android.permission.CONNECTIVITY_INTERNAL" granted="true" flags="0" />  
  21.         <item name="android.permission.MODIFY_NETWORK_ACCOUNTING" granted="true" flags="0" />  
  22.         <item name="android.permission.WAKE_LOCK" granted="true" flags="0" />  
  23.         <item name="android.permission.UPDATE_APP_OPS_STATS" granted="true" flags="0" />  
  24.     </perms>  
  25.     <proper-signing-keyset identifier="4" />  
  26. </package>  

2.packages-backup.xml:上面文件的备份

3.packages-stopped.xml:被强制停止运行的应用信息

4.packages-stopped-backup.xml:上面文件的备份

5.packages.list:保存普通应用的数据目录和uid信息等

[html] view plain copy 在CODE上查看代码片派生到我的代码片
  1. ......  
  2. com.android.managedprovisioning 10009 0 /data/data/com.android.managedprovisioning platform 3003  
  3. com.android.gifviewer 10042 0 /data/data/com.android.gifviewer default none  
  4. com.android.dreams.phototable 10054 0 /data/data/com.android.dreams.phototable default none  
  5. com.leadcore.telassistant 1000 0 /data/data/com.leadcore.telassistant platform 3002,1023,1015,3003,3001  
  6. com.android.noisefield 10049 0 /data/data/com.android.noisefield default none  
  7. com.android.smspush 10064 0 /data/data/com.android.smspush default none  
  8. com.leadcore.codescan 10029 0 /data/data/com.leadcore.codescan platform 3003  
  9. com.android.wallpaper.livepicker 10046 0 /data/data/com.android.wallpaper.livepicker platform none  
  10. jp.co.omronsoft.openwnn 10051 0 /data/data/jp.co.omronsoft.openwnn default none  
  11. com.android.settings 1000 0 /data/data/com.android.settings platform 3002,1023,1015,3003,3001  
  12. com.leadcore.logservice 1000 0 /data/data/com.leadcore.logservice platform 3002,1023,1015,3003,3001  
  13. com.android.calculator2 10032 0 /data/data/com.android.calculator2 default none  
  14. com.leadcore.userfeedback 10062 0 /data/data/com.leadcore.userfeedback platform 3003  
  15. com.leadcore.filesearch 10035 0 /data/data/com.leadcore.filesearch default none  
  16. com.iflytek.inputmethod 10041 0 /data/data/com.iflytek.inputmethod default 3002,3003,3001  
  17. org.simalliance.openmobileapi.uiccterminal 10061 0 /data/data/org.simalliance.openmobileapi.uiccterminal platform none  
  18. com.android.wallpaper 10045 0 /data/data/com.android.wallpaper default none  
  19. com.android.vpndialogs 10018 0 /data/data/com.android.vpndialogs platform none  
  20. com.android.email 10031 0 /data/data/com.android.email default 3003  
  21. com.android.music 10048 0 /data/data/com.android.music platform 3002,1023,1015,3003  
  22. com.android.phone 1001 0 /data/data/com.android.phone platform 3002,3003,3001  
  23. com.android.shell 2000 0 /data/data/com.android.shell platform 3002,1023,1015,3008  
  24. com.android.video 10063 0 /data/data/com.android.video platform 1023,1015,3003  
  25. com.android.providers.userdictionary 10000 0 /data/data/com.android.providers.userdictionary default 3003  
  26. com.android.location.fused 1000 0 /data/data/com.android.location.fused platform 3002,1023,1015,3003,3001  
  27. com.android.deskclock 1000 0 /data/data/com.android.deskclock platform 3002,1023,1015,3003,3001  
  28. com.android.systemui 10017 0 /data/data/com.android.systemui platform 3002,1023,1015,3001,3006  
  29. ......  

当Android对文件packages.xml和packages-stopped.xml写之前,会先把它们备份,如果写文件成功了,再把备份文件删除掉。如果写的时候,系统出问题重启了,重启后会读取这两个文件时,发现有备份文件,会使用备份文件的内容,因为这个时候原文件已经损坏了。

每个应用的信息会保存在PackageSetting中,而所有的PackageSetting对象会保存在Settings的成员变量mPackages中。


回到构造函数,在Settings添加了SharedUserSetting,6种系统的uid:system radio log nfc bluetooth shell。相同shareUserId的包可以运行在一个进程中。


2.2 SystemConfig

继续分析构造函数:

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. SystemConfig systemConfig = SystemConfig.getInstance();  
  2. mGlobalGids = systemConfig.getGlobalGids();  
  3. mSystemPermissions = systemConfig.getSystemPermissions();  
  4. mAvailableFeatures = systemConfig.getAvailableFeatures();  

SystemConfig构造函数中会去读取etc下面的各个文件分析

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. SystemConfig() {  
  2.     // Read configuration from system  
  3.     readPermissions(Environment.buildPath(  
  4.             Environment.getRootDirectory(), "etc""sysconfig"), false);  
  5.     // Read configuration from the old permissions dir  
  6.     readPermissions(Environment.buildPath(  
  7.             Environment.getRootDirectory(), "etc""permissions"), false);  
  8.     // Only read features from OEM config  
  9.     readPermissions(Environment.buildPath(  
  10.             Environment.getOemDirectory(), "etc""sysconfig"), true);  
  11.     readPermissions(Environment.buildPath(  
  12.             Environment.getOemDirectory(), "etc""permissions"), true);  
  13. }  

分析完了后,会保存在各个成员变量中。

我们看下system/etc/permissions/platform.xml的一部分内容

[html] view plain copy 在CODE上查看代码片派生到我的代码片
  1. ......  
  2.     <permission name="android.permission.MANAGE_VOICE_KEYPHRASES">  
  3.         <group gid="audio" />  
  4.     </permission>  
  5.   
  6.     <permission name="android.permission.ACCESS_FM_RADIO" >  
  7.         <group gid="media" />  
  8.     </permission>  
  9.   
  10.     <!-- ================================================================== -->  
  11.     <!-- ================================================================== -->  
  12.     <!-- ================================================================== -->  
  13.   
  14.     <!-- The following tags are assigning high-level permissions to specific  
  15.          user IDs.  These are used to allow specific core system users to  
  16.          perform the given operations with the higher-level framework.  For  
  17.          example, we give a wide variety of permissions to the shell user  
  18.          since that is the user the adb shell runs under and developers and  
  19.          others should have a fairly open environment in which to  
  20.          interact with the system. -->  
  21.   
  22.     <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />  
  23.     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />  
  24.     <assign-permission name="android.permission.WAKE_LOCK" uid="media" />  
  25.     <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />  
  26.     <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />  
  27.   
  28.     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />  
  29. ......  


继续分析,会创建一个消息线程,会创建一些目录

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. mHandlerThread = new ServiceThread(TAG,  
  2.         Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);  
  3. mHandlerThread.start();  
  4. mHandler = new PackageHandler(mHandlerThread.getLooper());  
  5. Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);  
  6.   
  7. File dataDir = Environment.getDataDirectory();//存放应用数据目录  
  8. mAppDataDir = new File(dataDir, "data");  
  9. mAppInstallDir = new File(dataDir, "app");//放应用  
  10. mAppLib32InstallDir = new File(dataDir, "app-lib");//native库  
  11. mAsecInternalPath = new File(dataDir, "app-asec").getPath();  
  12. mUserAppDataDir = new File(dataDir, "user");//存放用户数据  
  13. mDrmAppPrivateInstallDir = new File(dataDir, "app-private");  

前面systemconfig解析etc下的文件,然后将Permissions放在mSettings的mPermission,以及共享库放在mSharedLibraries中

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. ArrayMap<String, SystemConfig.PermissionEntry> permConfig  
  2.         = systemConfig.getPermissions();  
  3. for (int i=0; i<permConfig.size(); i++) {  
  4.     SystemConfig.PermissionEntry perm = permConfig.valueAt(i);  
  5.     BasePermission bp = mSettings.mPermissions.get(perm.name);  
  6.     if (bp == null) {  
  7.         bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);  
  8.         mSettings.mPermissions.put(perm.name, bp);  
  9.     }  
  10.     if (perm.gids != null) {  
  11.         bp.gids = appendInts(bp.gids, perm.gids);  
  12.     }  
  13. }  
  14.   
  15. ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();  
  16. for (int i=0; i<libConfig.size(); i++) {  
  17.     mSharedLibraries.put(libConfig.keyAt(i),  
  18.             new SharedLibraryEntry(libConfig.valueAt(i), null));  
  19. }  


2.3 readLPw函数

继续分析,调用了Settings的readLPw函数。

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),  
  2.                     mSdkVersion, mOnlyCore);  

我们来详细分析,先会去看packages-backup.xml有没有,有这个文件说明在写packages.xml的时候系统出问题了,所以在系统启动的时候就要读备份的想xml文件内容。如果没有这个备份文件再去看packages.xml, 然后再去解析xml文件,把解析出来的内容封装在各个对象中保存在mSettings中各个变量中。

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. boolean readLPw(PackageManagerService service, List<UserInfo> users, int sdkVersion,  
  2.             boolean onlyCore) {  
  3.         FileInputStream str = null;  
  4.         if (mBackupSettingsFilename.exists()) {//是否有备份文件  
  5.             try {  
  6.                 str = new FileInputStream(mBackupSettingsFilename);  
  7.                 mReadMessages.append("Reading from backup settings file\n");  
  8.                 PackageManagerService.reportSettingsProblem(Log.INFO,  
  9.                         "Need to read from backup settings file");  
  10.                 if (mSettingsFilename.exists()) {  
  11.                     // If both the backup and settings file exist, we  
  12.                     // ignore the settings since it might have been  
  13.                     // corrupted.  
  14.                     Slog.w(PackageManagerService.TAG, "Cleaning up settings file "  
  15.                             + mSettingsFilename);  
  16.                     mSettingsFilename.delete();  
  17.                 }  
  18.             } catch (java.io.IOException e) {  
  19.                 // We'll try for the normal settings file.  
  20.             }  
  21.         }  
  22.   
  23.         mPendingPackages.clear();  
  24.         mPastSignatures.clear();  
  25.   
  26.         try {  
  27.             if (str == null) {//这里为空,代表没有备份文件,就看packages.xml文件  
  28.                 if (!mSettingsFilename.exists()) {  
  29.                     mReadMessages.append("No settings file found\n");  
  30.                     PackageManagerService.reportSettingsProblem(Log.INFO,  
  31.                             "No settings file; creating initial state");  
  32.                     mInternalSdkPlatform = mExternalSdkPlatform = sdkVersion;  
  33.                     mFingerprint = Build.FINGERPRINT;  
  34.                     return false;  
  35.                 }  
  36.                 str = new FileInputStream(mSettingsFilename);  
  37.             }  
  38.             XmlPullParser parser = Xml.newPullParser();  
  39.             parser.setInput(str, null);  
  40.   
  41.             int type;  
  42.             while ((type = parser.next()) != XmlPullParser.START_TAG  
  43.                     && type != XmlPullParser.END_DOCUMENT) {  
  44.                 ;  
  45.             }  
  46.   
  47.             if (type != XmlPullParser.START_TAG) {  
  48.                 mReadMessages.append("No start tag found in settings file\n");  
  49.                 PackageManagerService.reportSettingsProblem(Log.WARN,  
  50.                         "No start tag found in package manager settings");  
  51.                 Slog.wtf(PackageManagerService.TAG,  
  52.                         "No start tag found in package manager settings");  
  53.                 return false;  
  54.             }  
  55.   
  56.             int outerDepth = parser.getDepth();  
  57.             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT  
  58.                     && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {  
  59.                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {  
  60.                     continue;  
  61.                 }  
  62.   
  63.                 String tagName = parser.getName();  
  64.                 if (tagName.equals("package")) {  
  65.                     readPackageLPw(parser);//解析packages.xml中的各内容  
  66.                 } else if (tagName.equals("permissions")) {  
  67.                     readPermissionsLPw(mPermissions, parser);  
  68.                 } else if (tagName.equals("permission-trees")) {  
  69.                     readPermissionsLPw(mPermissionTrees, parser);  
  70.                 } else if (tagName.equals("shared-user")) {  
  71.                     readSharedUserLPw(parser);  
  72.                 } else if (tagName.equals("preferred-packages")) {  
  73.                     // no longer used.  
  74.                 } else if (tagName.equals("preferred-activities")) {  
  75.                     // Upgrading from old single-user implementation;  
  76.                     // these are the preferred activities for user 0.  
  77.                     readPreferredActivitiesLPw(parser, 0);  
  78.                 } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {  
  79.                     // TODO: check whether this is okay! as it is very  
  80.                     // similar to how preferred-activities are treated  
  81.                     readPersistentPreferredActivitiesLPw(parser, 0);  
  82.                 } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {  
  83.                     // TODO: check whether this is okay! as it is very  
  84.                     // similar to how preferred-activities are treated  
  85.                     readCrossProfileIntentFiltersLPw(parser, 0);  
  86.                 } else if (tagName.equals("updated-package")) {  
  87.                     readDisabledSysPackageLPw(parser);  
  88.                 } else if (tagName.equals("cleaning-package")) {  
  89.                     String name = parser.getAttributeValue(null, ATTR_NAME);  
  90.                     String userStr = parser.getAttributeValue(null, ATTR_USER);  
  91.                     String codeStr = parser.getAttributeValue(null, ATTR_CODE);  
  92.                     if (name != null) {  
  93.                         int userId = 0;  
  94.                         boolean andCode = true;  
  95.                         try {  
  96.                             if (userStr != null) {  
  97.                                 userId = Integer.parseInt(userStr);  
  98.                             }  
  99.                         } catch (NumberFormatException e) {  
  100.                         }  
  101.                         if (codeStr != null) {  
  102.                             andCode = Boolean.parseBoolean(codeStr);  
  103.                         }  
  104.                         addPackageToCleanLPw(new PackageCleanItem(userId, name, andCode));  
  105.                     }  
  106.                 } else if (tagName.equals("renamed-package")) {  
  107.                     String nname = parser.getAttributeValue(null"new");  
  108.                     String oname = parser.getAttributeValue(null"old");  
  109.                     if (nname != null && oname != null) {  
  110.                         mRenamedPackages.put(nname, oname);  
  111.                     }  
  112.                 } else if (tagName.equals("last-platform-version")) {  
  113.                     mInternalSdkPlatform = mExternalSdkPlatform = 0;  
  114.                     try {  
  115.                         String internal = parser.getAttributeValue(null"internal");  
  116.                         if (internal != null) {  
  117.                             mInternalSdkPlatform = Integer.parseInt(internal);  
  118.                         }  
  119.                         String external = parser.getAttributeValue(null"external");  
  120.                         if (external != null) {  
  121.                             mExternalSdkPlatform = Integer.parseInt(external);  
  122.                         }  
  123.                     } catch (NumberFormatException e) {  
  124.                     }  
  125.                     mFingerprint = parser.getAttributeValue(null"fingerprint");  
  126.                 } else if (tagName.equals("database-version")) {  
  127.                     mInternalDatabaseVersion = mExternalDatabaseVersion = 0;  
  128.                     try {  
  129.                         String internalDbVersionString = parser.getAttributeValue(null"internal");  
  130.                         if (internalDbVersionString != null) {  
  131.                             mInternalDatabaseVersion = Integer.parseInt(internalDbVersionString);  
  132.                         }  
  133.                         String externalDbVersionString = parser.getAttributeValue(null"external");  
  134.                         if (externalDbVersionString != null) {  
  135.                             mExternalDatabaseVersion = Integer.parseInt(externalDbVersionString);  
  136.                         }  
  137.                     } catch (NumberFormatException ignored) {  
  138.                     }  
  139.                 } else if (tagName.equals("verifier")) {  
  140.                     final String deviceIdentity = parser.getAttributeValue(null"device");  
  141.                     try {  
  142.                         mVerifierDeviceIdentity = VerifierDev  
  143. ......  


2.4 扫描文件(转化格式,获取文件信息)

下面开始优化dex文件变成oat文件,记录开始扫描系统的时间。

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. long startTime = SystemClock.uptimeMillis();//记录开始扫描时间  
  2.   
  3. EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,  
  4.         startTime);  
  5.   
  6. // Set flag to monitor and not change apk file paths when  
  7. // scanning install directories.  
  8. final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;  
  9.   
  10. final ArraySet<String> alreadyDexOpted = new ArraySet<String>();//已经优化的文件集合  
  11.   
  12. /** 
  13.  * Add everything in the in the boot class path to the 
  14.  * list of process files because dexopt will have been run 
  15.  * if necessary during zygote startup. 
  16.  */  
  17. final String bootClassPath = System.getenv("BOOTCLASSPATH");  
  18. final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");  
  19.   
  20. if (bootClassPath != null) {  
  21.     String[] bootClassPathElements = splitString(bootClassPath, ':');  
  22.     for (String element : bootClassPathElements) {  
  23.         alreadyDexOpted.add(element);  
  24.     }  
  25. else {  
  26.     Slog.w(TAG, "No BOOTCLASSPATH found!");  
  27. }  
  28.   
  29. if (systemServerClassPath != null) {  
  30.     String[] systemServerClassPathElements = splitString(systemServerClassPath, ':');  
  31.     for (String element : systemServerClassPathElements) {  
  32.         alreadyDexOpted.add(element);  
  33.     }  
  34. else {  
  35.     Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");  
  36. }  

下面扫描动态库和framework下的文件执行dex到odex的转换

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1.  */  
  2. if (mSharedLibraries.size() > 0) {  
  3.     // NOTE: For now, we're compiling these system "shared libraries"  
  4.     // (and framework jars) into all available architectures. It's possible  
  5.     // to compile them only when we come across an app that uses them (there's  
  6.     // already logic for that in scanPackageLI) but that adds some complexity.  
  7.     for (String dexCodeInstructionSet : dexCodeInstructionSets) {  
  8.         for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {  
  9.             final String lib = libEntry.path;  
  10.             if (lib == null) {  
  11.                 continue;  
  12.             }  
  13.   
  14.             try {  
  15.                 byte dexoptRequired = DexFile.isDexOptNeededInternal(lib, null,  
  16.                                                                      dexCodeInstructionSet,  
  17.                                                                      false);  
  18.                 if (dexoptRequired != DexFile.UP_TO_DATE) {  
  19.                     alreadyDexOpted.add(lib);  
  20.   
  21.                     // The list of "shared libraries" we have at this point is  
  22.                     if (dexoptRequired == DexFile.DEXOPT_NEEDED) {  
  23.                         mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);//到intalld执行  
  24.                     } else {  
  25.                         mInstaller.patchoat(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);//art虚拟机执行oat  
  26.                     }  
  27.                 }  
  28.             } catch (FileNotFoundException e) {  
  29.                 Slog.w(TAG, "Library not found: " + lib);  
  30.             } catch (IOException e) {  
  31.                 Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "  
  32.                         + e.getMessage());  
  33.             }  
  34.         }  
  35.     }  
  36. }  
  37.   
  38. File frameworkDir = new File(Environment.getRootDirectory(), "framework");//framework目录  
  39.   
  40. // Gross hack for now: we know this file doesn't contain any  
  41. // code, so don't dexopt it to avoid the resulting log spew.  
  42. alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");  
  43.   
  44. // Gross hack for now: we know this file is only part of  
  45. // the boot class path for art, so don't dexopt it to  
  46. // avoid the resulting log spew.  
  47. alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");  
  48.   
  49. /** 
  50.  * And there are a number of commands implemented in Java, which 
  51.  * we currently need to do the dexopt on so that they can be 
  52.  * run from a non-root shell. 
  53.  */  
  54. String[] frameworkFiles = frameworkDir.list();  
  55. if (frameworkFiles != null) {  
  56.     // TODO: We could compile these only for the most preferred ABI. We should  
  57.     // first double check that the dex files for these commands are not referenced  
  58.     // by other system apps.  
  59.     for (String dexCodeInstructionSet : dexCodeInstructionSets) {  
  60.         for (int i=0; i<frameworkFiles.length; i++) {  
  61.             File libPath = new File(frameworkDir, frameworkFiles[i]);  
  62.             String path = libPath.getPath();  
  63.             // Skip the file if we already did it.  
  64.             if (alreadyDexOpted.contains(path)) {  
  65.                 continue;  
  66.             }  
  67.             // Skip the file if it is not a type we want to dexopt.  
  68.             if (!path.endsWith(".apk") && !path.endsWith(".jar")) {  
  69.                 continue;  
  70.             }  
  71.             try {  
  72.                 byte dexoptRequired = DexFile.isDexOptNeededInternal(path, null,  
  73.                                                                      dexCodeInstructionSet,  
  74.                                                                      false);  
  75.                 if (dexoptRequired == DexFile.DEXOPT_NEEDED) {  
  76.                     mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);  
  77.                 } else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {  
  78.                     mInstaller.patchoat(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);  
  79.                 }  
  80.             } catch (FileNotFoundException e) {  
  81.                 Slog.w(TAG, "Jar not found: " + path);  
  82.             } catch (IOException e) {  
  83.                 Slog.w(TAG, "Exception reading jar: " + path, e);  
  84.             }  
  85.         }  
  86.     }  

扫描各个目录下的文件信息,保存在PMS中。

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM  
  2.         | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);  
  3.   
  4. // Find base frameworks (resource packages without code).  
  5. scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM  
  6.         | PackageParser.PARSE_IS_SYSTEM_DIR  
  7.         | PackageParser.PARSE_IS_PRIVILEGED,  
  8.         scanFlags | SCAN_NO_DEX, 0);  
  9.   
  10. // Collected privileged system packages.  
  11. final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");  
  12. scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM  
  13.         | PackageParser.PARSE_IS_SYSTEM_DIR  
  14.         | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);  
  15.   
  16. // Collect ordinary system packages.  
  17. final File systemAppDir = new File(Environment.getRootDirectory(), "app");  
  18. scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM  
  19.         | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);  
  20.   
  21. // Collect all vendor packages.  
  22. File vendorAppDir = new File("/vendor/app");  
  23. try {  
  24.     vendorAppDir = vendorAppDir.getCanonicalFile();  
  25. catch (IOException e) {  
  26.     // failed to look up canonical path, continue with original one  
  27. }  
  28. scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM  
  29.         | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);  
  30.   
  31. // Collect all OEM packages.  
  32. final File oemAppDir = new File(Environment.getOemDirectory(), "app");  
  33. scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM  
  34.         | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);  

还有一些,扫描并删除未成功安装的apk包,删除临时文件,升级应用的一些处理,更新应用动态库路径。

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1.         ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();  
  2.             //clean up list  
  3.             for(int i = 0; i < deletePkgsList.size(); i++) {  
  4.                 //clean up here  
  5.                 cleanupInstallFailedPackage(deletePkgsList.get(i));//删除未成功安装的apk包  
  6.             }  
  7.             //delete tmp files  
  8.             deleteTempPackageFiles();//删除临时文件  
  9.   
  10.             // Remove any shared userIDs that have no associated packages  
  11.             mSettings.pruneSharedUsersLPw();  
  12.   
  13.             if (!mOnlyCore) {//开始处理非系统应用  
  14.                 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,  
  15.                         SystemClock.uptimeMillis());  
  16.                 scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);  
  17.   
  18.                 scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,  
  19.                         scanFlags | SCAN_REQUIRE_KNOWN, 0);  
  20. .....  

最后有一个扫描时间结束的log。

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,  
  2.         SystemClock.uptimeMillis());  
  3. Slog.i(TAG, "Time to scan packages: "  
  4.         + ((SystemClock.uptimeMillis()-startTime)/1000f)  
  5.         + " seconds");  


2.5 赋予权限,写packages.xml

继续分析

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. final boolean regrantPermissions = mSettings.mInternalSdkPlatform  
  2.                     != mSdkVersion;//因为sdk版本变化,permission的定义也改变了,需要重新赋予应用权限  
  3.             if (regrantPermissions) Slog.i(TAG, "Platform changed from "  
  4.                     + mSettings.mInternalSdkPlatform + " to " + mSdkVersion  
  5.                     + "; regranting permissions for internal storage");  
  6.             mSettings.mInternalSdkPlatform = mSdkVersion;  
  7.               
  8.             updatePermissionsLPw(nullnull, UPDATE_PERMISSIONS_ALL  
  9.                     | (regrantPermissions//是否要重新赋权限  
  10.                             ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)  
  11.                             : 0));  
  12.   
  13.             // If this is the first boot, and it is a normal boot, then  
  14.             // we need to initialize the default preferred apps.  
  15.             if (!mRestoredSettings && !onlyCore) {  
  16.                 mSettings.readDefaultPreferredAppsLPw(this0);  
  17.             }  
  18.   
  19.             // If this is first boot after an OTA, and a normal boot, then  
  20.             // we need to clear code cache directories.  
  21.             mIsUpgrade = !Build.FINGERPRINT.equals(mSettings.mFingerprint);  
  22.             if (mIsUpgrade && !onlyCore) {  
  23.                 Slog.i(TAG, "Build fingerprint changed; clearing code caches");  
  24.                 for (String pkgName : mSettings.mPackages.keySet()) {  
  25.                     deleteCodeCacheDirsLI(pkgName);//如果是执行OTA后第一次启动,清除cache  
  26.                 }  
  27.                 mSettings.mFingerprint = Build.FINGERPRINT;  
  28.             }  
  29.   
  30.             // All the changes are done during package scanning.  
  31.             mSettings.updateInternalDatabaseVersion();//更新数据库  
  32.   
  33.             // can downgrade to reader  
  34.             mSettings.writeLPr();//把mSettings写入packages.xml  
  35.   
  36.             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,  
  37.                     SystemClock.uptimeMillis());  
  38.   
  39.   
  40.             mRequiredVerifierPackage = getRequiredVerifierLPr();  
  41.         } // synchronized (mPackages)  
  42.         } // synchronized (mInstallLock)  
  43.   
  44.         mInstallerService = new PackageInstallerService(context, this, mAppInstallDir);  
  45.   
  46.         // Now after opening every single application zip, make sure they  
  47.         // are all flushed.  Not really needed, but keeps things nice and  
  48.         // tidy.  
  49.         Runtime.getRuntime().gc();//启动垃圾回收  
updatePermissionsLPw函数
[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. private void updatePermissionsLPw(String changingPkg,  
  2.         PackageParser.Package pkgInfo, int flags) {  
  3.     // Make sure there are no dangling permission trees.  
  4.     Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();  
  5.     while (it.hasNext()) {  
  6.         final BasePermission bp = it.next();  
  7.         if (bp.packageSetting == null) {  
  8.             // We may not yet have parsed the package, so just see if  
  9.             // we still know about its settings.  
  10.             bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);  
  11.         }  
  12.         if (bp.packageSetting == null) {  
  13.             Slog.w(TAG, "Removing dangling permission tree: " + bp.name  
  14.                     + " from package " + bp.sourcePackage);  
  15.             it.remove();  
  16.         } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {  
  17.             if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {  
  18.                 Slog.i(TAG, "Removing old permission tree: " + bp.name  
  19.                         + " from package " + bp.sourcePackage);  
  20.                 flags |= UPDATE_PERMISSIONS_ALL;  
  21.                 it.remove();  
  22.             }  
  23.         }  
  24.     }  
  25.   
  26.     // Make sure all dynamic permissions have been assigned to a package,  
  27.     // and make sure there are no dangling permissions.  
  28.     it = mSettings.mPermissions.values().iterator();  
  29.     while (it.hasNext()) {  
  30.         final BasePermission bp = it.next();  
  31.         if (bp.type == BasePermission.TYPE_DYNAMIC) {  
  32.             if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="  
  33.                     + bp.name + " pkg=" + bp.sourcePackage  
  34.                     + " info=" + bp.pendingInfo);  
  35.             if (bp.packageSetting == null && bp.pendingInfo != null) {  
  36.                 final BasePermission tree = findPermissionTreeLP(bp.name);  
  37.                 if (tree != null && tree.perm != null) {  
  38.                     bp.packageSetting = tree.packageSetting;  
  39.                     bp.perm = new PackageParser.Permission(tree.perm.owner,  
  40.                             new PermissionInfo(bp.pendingInfo));  
  41.                     bp.perm.info.packageName = tree.perm.info.packageName;  
  42.                     bp.perm.info.name = bp.name;  
  43.                     bp.uid = tree.uid;  
  44.                 }  
  45.             }  
  46.         }  
  47.         if (bp.packageSetting == null) {  
  48.             // We may not yet have parsed the package, so just see if  
  49.             // we still know about its settings.  
  50.             bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);  
  51.         }  
  52.         if (bp.packageSetting == null) {  
  53.             Slog.w(TAG, "Removing dangling permission: " + bp.name  
  54.                     + " from package " + bp.sourcePackage);  
  55.             it.remove();  
  56.         } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {  
  57.             if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {  
  58.                 Slog.i(TAG, "Removing old permission: " + bp.name  
  59.                         + " from package " + bp.sourcePackage);  
  60.                 flags |= UPDATE_PERMISSIONS_ALL;  
  61.                 it.remove();  
  62.             }  
  63.         }  
  64.     }  
  65.   
  66.     // Now update the permissions for all packages, in particular  
  67.     // replace the granted permissions of the system packages.  
  68.     if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {//flags为UPDATE_PERMISSIONS_ALL  
  69.         for (PackageParser.Package pkg : mPackages.values()) {  
  70.             if (pkg != pkgInfo) {  
  71.                 grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0,  
  72.                         changingPkg);  
  73.             }  
  74.         }  
  75.     }  
  76.       
  77.     if (pkgInfo != null) {//传进来的pkgInfo为null  
  78.         grantPermissionsLPw(pkgInfo, (flags&UPDATE_PERMISSIONS_REPLACE_PKG) != 0, changingPkg);  
  79.     }  
  80. }  

我们再来看看grantPermissionsLPw函数

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace,  
  2.         String packageOfInterest) {  
  3.     final PackageSetting ps = (PackageSetting) pkg.mExtras;  
  4.     if (ps == null) {  
  5.         return;  
  6.     }  
  7.     final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;  
  8.     ArraySet<String> origPermissions = gp.grantedPermissions;  
  9.     boolean changedPermission = false;  
  10.   
  11.     if (replace) {  
  12.         ps.permissionsFixed = false;  
  13.         if (gp == ps) {  
  14.             origPermissions = new ArraySet<String>(gp.grantedPermissions);  
  15.             gp.grantedPermissions.clear();  
  16.             gp.gids = mGlobalGids;  
  17.         }  
  18.     }  
  19.   
  20.     if (gp.gids == null) {  
  21.         gp.gids = mGlobalGids;//把gid的群组赋值  
  22.     }  
  23.   
  24.     final int N = pkg.requestedPermissions.size();  
  25.     for (int i=0; i<N; i++) {  
  26.         final String name = pkg.requestedPermissions.get(i);  
  27.         final boolean required = pkg.requestedPermissionsRequired.get(i);  
  28.         final BasePermission bp = mSettings.mPermissions.get(name);  
  29.         if (DEBUG_INSTALL) {  
  30.             if (gp != ps) {  
  31.                 Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);  
  32.             }  
  33.         }  
  34.   
  35.         if (bp == null || bp.packageSetting == null) {  
  36.             if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {  
  37.                 Slog.w(TAG, "Unknown permission " + name  
  38.                         + " in package " + pkg.packageName);  
  39.             }  
  40.             continue;  
  41.         }  
  42.   
  43.         final String perm = bp.name;  
  44.         boolean allowed;  
  45.         boolean allowedSig = false;  
  46.         if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {  
  47.             // Keep track of app op permissions.  
  48.             ArraySet<String> pkgs = mAppOpPermissionPackages.get(bp.name);  
  49.             if (pkgs == null) {  
  50.                 pkgs = new ArraySet<>();  
  51.                 mAppOpPermissionPackages.put(bp.name, pkgs);  
  52.             }  
  53.             pkgs.add(pkg.packageName);  
  54.         }  
  55.         final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;  
  56.         if (level == PermissionInfo.PROTECTION_NORMAL  
  57.                 || level == PermissionInfo.PROTECTION_DANGEROUS) {  
  58.             // We grant a normal or dangerous permission if any of the following  
  59.             // are true:  
  60.             // 1) The permission is required  
  61.             // 2) The permission is optional, but was granted in the past  
  62.             // 3) The permission is optional, but was requested by an  
  63.             //    app in /system (not /data)  
  64.             //  
  65.             // Otherwise, reject the permission.  
  66.             allowed = (required || origPermissions.contains(perm)  
  67.                     || (isSystemApp(ps) && !isUpdatedSystemApp(ps)));  
  68.         } else if (bp.packageSetting == null) {  
  69.             // This permission is invalid; skip it.  
  70.             allowed = false;  
  71.         } else if (level == PermissionInfo.PROTECTION_SIGNATURE) {  
  72.             allowed = grantSignaturePermission(perm, pkg, bp, origPermissions);  
  73.             if (allowed) {  
  74.                 allowedSig = true;  
  75.             }  
  76.         } else {  
  77.             allowed = false;  
  78.         }  
  79.         if (DEBUG_INSTALL) {  
  80.             if (gp != ps) {  
  81.                 Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);  
  82.             }  
  83.         }  
  84.         if (allowed) {  
  85.             if (!isSystemApp(ps) && ps.permissionsFixed) {  
  86.                 // If this is an existing, non-system package, then  
  87.                 // we can't add any new permissions to it.  
  88.                 if (!allowedSig && !gp.grantedPermissions.contains(perm)) {  
  89.                     // Except...  if this is a permission that was added  
  90.                     // to the platform (note: need to only do this when  
  91.                     // updating the platform).  
  92.                     allowed = isNewPlatformPermissionForPackage(perm, pkg);  
  93.                 }  
  94.             }  
  95.             if (allowed) {  
  96.                 if (!gp.grantedPermissions.contains(perm)) {  
  97.                     changedPermission = true;  
  98.                     gp.grantedPermissions.add(perm);  
  99.                     gp.gids = appendInts(gp.gids, bp.gids);  
  100.                 } else if (!ps.haveGids) {  
  101.                     gp.gids = appendInts(gp.gids, bp.gids);  
  102.                 }  
  103.             } else {  
  104.                 if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {  
  105.                     Slog.w(TAG, "Not granting permission " + perm  
  106.                             + " to package " + pkg.packageName  
  107.                             + " because it was previously installed without");  
  108.                 }  
  109.             }  
  110.         } else {  
  111.             if (gp.grantedPermissions.remove(perm)) {  
  112.                 changedPermission = true;  
  113.                 gp.gids = removeInts(gp.gids, bp.gids);  
  114.                 Slog.i(TAG, "Un-granting permission " + perm  
  115.                         + " from package " + pkg.packageName  
  116.                         + " (protectionLevel=" + bp.protectionLevel  
  117.                         + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)  
  118.                         + ")");  
  119.             } else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) {  
  120.                 // Don't print warning for app op permissions, since it is fine for them  
  121.                 // not to be granted, there is a UI for the user to decide.  
  122.                 if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {  
  123.                     Slog.w(TAG, "Not granting permission " + perm  
  124.                             + " to package " + pkg.packageName  
  125.                             + " (protectionLevel=" + bp.protectionLevel  
  126.                             + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)  
  127.                             + ")");  
  128.                 }  
  129.             }  
  130.         }  
  131.     }  
  132.   
  133.     if ((changedPermission || replace) && !ps.permissionsFixed &&  
  134.             !isSystemApp(ps) || isUpdatedSystemApp(ps)){  
  135.         // This is the first that we have heard about this package, so the  
  136.         // permissions we have now selected are fixed until explicitly  
  137.         // changed.  
  138.         ps.permissionsFixed = true;  
  139.     }  
  140.     ps.haveGids = true;  
  141. }  

PMS的构造函数先读取保存在packages.xml中的内容保存在mSettings中,然后扫描设备中几个应用目录下的应用文件,并把扫描结果保存在PMS的mPackages成员变量中,通过对比上一次扫描的结果就是mSettings内容是否有被升级包覆盖的系统应用,如果有从mPackages去除。这样mPackages和mSettings的记录一致了,最后将本次扫描内容写到packages.xml文件中。



PackageManagerService的构造函数中,调用了SystemConfig的getSystemPermissions方法来获取系统的permission列表。

下面我们就分析下如何从系统文件中获取permission。


一、分析构造SystemConfig构造函数

我们先来分析下SystemConfig类的构造函数

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. SystemConfig() {  
  2.     // Read configuration from system  
  3.     readPermissions(Environment.buildPath(  
  4.             Environment.getRootDirectory(), "etc""sysconfig"), false);  
  5.     // Read configuration from the old permissions dir  
  6.     readPermissions(Environment.buildPath(  
  7.             Environment.getRootDirectory(), "etc""permissions"), false);  
  8.     // Only read features from OEM config  
  9.     readPermissions(Environment.buildPath(  
  10.             Environment.getOemDirectory(), "etc""sysconfig"), true);  
  11.     readPermissions(Environment.buildPath(  
  12.             Environment.getOemDirectory(), "etc""permissions"), true);  
  13. }  

Environment.getRootDirectory方法代表的是system目录,我们再来看看Environment.buildPath方法

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public static File buildPath(File base, String... segments) {  
  2.     File cur = base;  
  3.     for (String segment : segments) {  
  4.         if (cur == null) {  
  5.             cur = new File(segment);  
  6.         } else {  
  7.             cur = new File(cur, segment);  
  8.         }  
  9.     }  
  10.     return cur;  
  11. }  

这个方法其实就是一层一层建文件,因此第一个文件就是system/etc/sysconfig 而第二个就是system/etc/permissions下面两个oem的就一样了。而我们手机中system/etc/sysconfig 这个目录是不存在的,因此只需分析permissions目录了。


二、xml文件

我们先来看Android.hardware.wifi.xml,就是一个feature,而且大部分的文件都是这样的,除了platform.xml

[html] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <permissions>  
  2.     <feature name="android.hardware.wifi" />  
  3. </permissions>  

下面就手机我们看下system/etc/permissions下的platform.xml文件

[html] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <permissions>  
  2.   
  3.     <!-- ================================================================== -->  
  4.     <!-- ================================================================== -->  
  5.     <!-- ================================================================== -->  
  6.   
  7.     <!-- The following tags are associating low-level group IDs with  
  8.          permission names.  By specifying such a mapping, you are saying  
  9.          that any application process granted the given permission will  
  10.          also be running with the given group ID attached to its process,  
  11.          so it can perform any filesystem (read, write, execute) operations  
  12.          allowed for that group. -->  
  13.   
  14.     <permission name="android.permission.BLUETOOTH_ADMIN" >  
  15.         <group gid="net_bt_admin" />  
  16.     </permission>  
  17.   
  18.     <permission name="android.permission.BLUETOOTH" >  
  19.         <group gid="net_bt" />  
  20.     </permission>  
  21.   
  22.     <permission name="android.permission.BLUETOOTH_STACK" >  
  23.         <group gid="net_bt_stack" />  
  24.     </permission>  
  25.   
  26.     <permission name="android.permission.NET_TUNNELING" >  
  27.         <group gid="vpn" />  
  28.     </permission>  
  29.   
  30.     <permission name="android.permission.INTERNET" >  
  31.         <group gid="inet" />  
  32.     </permission>  
  33.   
  34.     <permission name="android.permission.READ_LOGS" >  
  35.         <group gid="log" />  
  36.     </permission>  
  37.   
  38.     <permission name="android.permission.WRITE_MEDIA_STORAGE" >  
  39.         <group gid="media_rw" />  
  40.         <group gid="sdcard_rw" />  
  41.     </permission>  
  42.   
  43.     <permission name="android.permission.ACCESS_MTP" >  
  44.         <group gid="mtp" />  
  45.     </permission>  
  46.   
  47.     <permission name="android.permission.NET_ADMIN" >  
  48.         <group gid="net_admin" />  
  49.     </permission>  
  50.   
  51.     <!-- The group that /cache belongs to, linked to the permission  
  52.          set on the applications that can access /cache -->  
  53.     <permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >  
  54.         <group gid="cache" />  
  55.     </permission>  
  56.   
  57.     <!-- RW permissions to any system resources owned by group 'diag'.  
  58.          This is for carrier and manufacture diagnostics tools that must be  
  59.          installable from the framework. Be careful. -->  
  60.     <permission name="android.permission.DIAGNOSTIC" >  
  61.         <group gid="input" />  
  62.         <group gid="diag" />  
  63.     </permission>  
  64.   
  65.     <!-- Group that can read detailed network usage statistics -->  
  66.     <permission name="android.permission.READ_NETWORK_USAGE_HISTORY">  
  67.         <group gid="net_bw_stats" />  
  68.     </permission>  
  69.   
  70.     <!-- Group that can modify how network statistics are accounted -->  
  71.     <permission name="android.permission.MODIFY_NETWORK_ACCOUNTING">  
  72.         <group gid="net_bw_acct" />  
  73.     </permission>  
  74.   
  75.     <permission name="android.permission.LOOP_RADIO" >  
  76.         <group gid="loop_radio" />  
  77.     </permission>  
  78.   
  79.     <!-- Hotword training apps sometimes need a GID to talk with low-level  
  80.          hardware; give them audio for now until full HAL support is added. -->  
  81.     <permission name="android.permission.MANAGE_VOICE_KEYPHRASES">  
  82.         <group gid="audio" />  
  83.     </permission>  
  84.   
  85.     <permission name="android.permission.ACCESS_FM_RADIO" >  
  86.         <group gid="media" />  
  87.     </permission>  
  88.   
  89.     <!-- ================================================================== -->  
  90.     <!-- ================================================================== -->  
  91.     <!-- ================================================================== -->  
  92.   
  93.     <!-- The following tags are assigning high-level permissions to specific  
  94.          user IDs.  These are used to allow specific core system users to  
  95.          perform the given operations with the higher-level framework.  For  
  96.          example, we give a wide variety of permissions to the shell user  
  97.          since that is the user the adb shell runs under and developers and  
  98.          others should have a fairly open environment in which to  
  99.          interact with the system. -->  
  100.   
  101.     <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />  
  102.     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />  
  103.     <assign-permission name="android.permission.WAKE_LOCK" uid="media" />  
  104.     <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />  
  105.     <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />  
  106.   
  107.     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />  
  108.   
  109.     <!-- This is a list of all the libraries available for application  
  110.          code to link against. -->  
  111.   
  112.     <library name="android.test.runner"  
  113.             file="/system/framework/android.test.runner.jar" />  
  114.     <library name="javax.obex"  
  115.             file="/system/framework/javax.obex.jar" />  
  116.     <library name="org.apache.http.legacy"  
  117.             file="/system/framework/org.apache.http.legacy.jar" />  
  118.   
  119.     <!-- These are the standard packages that are white-listed to always have internet  
  120.          access while in power save mode, even if they aren't in the foreground. -->  
  121.     <allow-in-power-save-except-idle package="com.android.providers.downloads" />  
  122.   
  123. </permissions>  


platform.xml主要由3块组成:

1. <permission>把属性name中的字符串表示的权限(permission)赋予<group>标签中的属性gid中的用户组

2.<assign-permission>把属性name中的字符串表示的权限(permission)赋予<group>标签中的属性uid中的用户

3.<library>表示除了framework中的动态库以外,系统将为应用自动加载的动态库。


而解析出来这些标签又放在哪呢?

1.标签<permission>中的属性name字符串和<group>标签中的gid都放到了变量mSettings的mPermissions中

2.所有的gid放在mGlobalGids中

3.标签<assign-permission>的内容放到PackageManagerService的成员变量mSystemPermission中。

mSystemPermission是放在下面这样一个数据结构中

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();  
我们再看看它是如何操作的
[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. ArraySet<String> perms = mSystemPermissions.get(uid);  
  2. if (perms == null) {  
  3.     perms = new ArraySet<String>();  
  4.     mSystemPermissions.put(uid, perms);  
  5. }  
  6. perms.add(perm);  

4.<library>动态库放在mSharedLibraries

5.<feature>放在mAvailableFeatures中。

Android的很多功能是通过所谓的permission字符串来保护的,应用如果要使用某项权限,就要在AndroidManifest.xml显示的加上permission字符串。但是有些功能只能由特定用户组的应用使用,在platform.xml定义的就是这种限制规则。



下面我们再来看看核心函数readPermissions():

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. void readPermissions(File libraryDir, boolean onlyFeatures) {  
  2.         // Read permissions from given directory.  
  3.         if (!libraryDir.exists() || !libraryDir.isDirectory()) {// 不是一个目录或者不存在  
  4.             if (!onlyFeatures) {  
  5.                 Slog.w(TAG, "No directory " + libraryDir + ", skipping");  
  6.             }  
  7.             return;  
  8.         }  
  9.         if (!libraryDir.canRead()) {  
  10.             Slog.w(TAG, "Directory " + libraryDir + " cannot be read");  
  11.             return;  
  12.         }  
  13.   
  14.         // Iterate over the files in the directory and scan .xml files  
  15.         File platformFile = null;  
  16.         for (File f : libraryDir.listFiles()) {  
  17.             // We'll read platform.xml last  
  18.             if (f.getPath().endsWith("etc/permissions/platform.xml")) {  
  19.                 platformFile = f;//先不处理platform.xml  
  20.                 continue;  
  21.             }  
  22.   
  23.             if (!f.getPath().endsWith(".xml")) {  
  24.                 Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");  
  25.                 continue;  
  26.             }  
  27.             if (!f.canRead()) {  
  28.                 Slog.w(TAG, "Permissions library file " + f + " cannot be read");  
  29.                 continue;  
  30.             }  
  31.   
  32.             readPermissionsFromXml(f, onlyFeatures);  
  33.         }  
  34.   
  35.         // Read platform permissions last so it will take precedence  
  36.         if (platformFile != null) {//这边再来处理platform.xml  
  37.             readPermissionsFromXml(platformFile, onlyFeatures);  
  38.         }  
  39.     }  


然后就readPermissionsFromXml读取各个标签放在各个成员变量中。


我们最后再来看下Permission标签的解析:

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. void readPermission(XmlPullParser parser, String name)  
  2.         throws IOException, XmlPullParserException {  
  3.   
  4.     name = name.intern();  
  5.   
  6.     PermissionEntry perm = mPermissions.get(name);  
  7.     if (perm == null) {  
  8.         perm = new PermissionEntry(name);  
  9.         mPermissions.put(name, perm);  
  10.     }  
  11.     int outerDepth = parser.getDepth();  
  12.     int type;  
  13.     while ((type=parser.next()) != XmlPullParser.END_DOCUMENT  
  14.            && (type != XmlPullParser.END_TAG  
  15.                    || parser.getDepth() > outerDepth)) {  
  16.         if (type == XmlPullParser.END_TAG  
  17.                 || type == XmlPullParser.TEXT) {  
  18.             continue;  
  19.         }  
  20.   
  21.         String tagName = parser.getName();  
  22.         if ("group".equals(tagName)) {  
  23.             String gidStr = parser.getAttributeValue(null"gid");  
  24.             if (gidStr != null) {  
  25.                 int gid = Process.getGidForName(gidStr);  
  26.                 perm.gids = appendInt(perm.gids, gid);//放gid  
  27.             } else {  
  28.                 Slog.w(TAG, "<group> without gid at "  
  29.                         + parser.getPositionDescription());  
  30.             }  
  31.         }  
  32.         XmlUtils.skipCurrentTag(parser);  
  33.     }  
  34. }  

上面其中    final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();  mPermissions是个map,权限的name对应是map的key,然后每个PermissionEntry 放入各个gid。


question:

Q:博主,这里讲的是开机时PackageManager如何扫描和注册已安装的应用程序信息吧, 所以并不是“应用程序安装过程”?
A:对于注册和安装,你是怎么定义的呢?
Q:下载了apk之后(比如把它存在了SD卡的某个folder里),都得经过一个installer“安装”后才会出现在应用程序列表里吧。所以我理解博主所讲的部分并不是“安装”,而是扫描和提取已安装应用的元数据。当然,我所谓的“安装”可能只是把apk们存放在PackageManager能扫描到的几个指定folder下?
A:通过网络来安装的确是可以划分为三步:1. 下载;2. 拷贝到指定目录;3. 解析AndroidManifest.xml文件得到应用程序的信息,并且保存在PackageManagerService里面。怎么给这3个步骤起名字不是重点,但是第3步确实是重点,例如,会涉及到Linux用户ID和Linux用户组ID的分配。另外,如果PackageManagerService没有一个应用程序的信息的话,那么这个应用程序是跑不起来的,你在Launcher里面也不会看得到它。但是如果你去看第3步里面涉及到的函数调用,就会很多函数都是以install开头的,所以从字面来看,我认为把第3步称为“安装”是合理的。


Q:为什么android每次启动都要做一次解析上述文件夹下的apk文件。不是第一次解析完会在/data/system生成packages.xml的文件吗?而且每次解析完都要重写这个
packages.xml文件。
A:应用程序的信息并不是完全保存在packages.xml这个文件里面,而且关机之后,是可以对系统的应用程序进行修改的。
Q:android把每个包解析出的信息会保存到package类中,在内存中, 不知是否可以把这些package类全部保存到一个文件中,下次开机就不用逐个解析了。包扫描确实很花时间,特别是apk装多了之后。
A:这样做也不现实,因为关机之后,可以把system.img解压出来,增、删或者修改apk,再放system.img打包放回去,再开机的时候,安装的信息又会改变了。
对于智能机来说,一般都不会频繁的关机和开机,有些关机只是进入休眠状态而已,所以这个不是问题。
Q:机子关了都没电了,还怎么修改system.img???难道是进入fastboot模式去修改?
A:你搜一下bootimg,看看是怎么玩的


Q:楼主,如果apk在安装的时候,通过解析,把这些信息保存到内存中,那么在重新开机后,岂不是所有的已经安装的apk都要重新解析一遍,然后同样保存到内存中,感觉非常不效率啊?
A:是的,如果彻底关机之后再开机,那么系统就会重新安装一遍所有的应用程序的,因为关机之后,我们是可以改变系统中的应用程序的,例如,增加、删除或者修改系统中的应用程序。如果不重新检查一遍的话,那么就会有问题了。在实际使用中,我们很少会彻底地关机,一般意义上的关机只是让系统深度睡眠,这种情况不会导致系统重新安装一遍系统中的应用程序。
系统除了会把应用程序的安装信息保存在内存中之外,还会保存在一个本地文件中,因为有些应用程序的安装信息无论安装多少次,都是必须保持一致的,例如,应用程序的Linux用户ID。如果不保存下来的话,那么每次应用程序重新安装之后,表现可能都会不一致。

0 0