PackageManagerService(Android5.1)深入分析(一)构造函数

来源:互联网 发布:光明骑士和游侠数据 编辑:程序博客网 时间:2024/06/05 16:34

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


一、SystemServer创建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构造函数

2.1 Settings

下面我们主要分析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:记录系统中所有安装的应用的信息, 我们来看下这个文件关于一个package

 <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">     <sigs count="1">         <cert index="2" key="308204a830820390a003020102020900f2b98e6123572c4e300d06092a864886f70d0101040500308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f6964311     </sigs>     <perms>         <item name="android.permission.ACCESS_CACHE_FILESYSTEM" granted="true" flags="0" />         <item name="android.permission.WRITE_SETTINGS" granted="true" flags="0" />         <item name="android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS" granted="true" flags="0" />         <item name="android.permission.RECEIVE_BOOT_COMPLETED" granted="true" flags="0" />         <item name="android.permission.WRITE_MEDIA_STORAGE" granted="true" flags="0" />         <item name="android.permission.INTERNET" granted="true" flags="0" />         <item name="android.permission.UPDATE_DEVICE_STATS" granted="true" flags="0" />         <item name="android.permission.ACCESS_ALL_DOWNLOADS" granted="true" flags="0" />         <item name="android.permission.ACCESS_DOWNLOAD_MANAGER" granted="true" flags="0" />         <item name="android.permission.MANAGE_USERS" granted="true" flags="0" />         <item name="android.permission.ACCESS_NETWORK_STATE" granted="true" flags="0" />         <item name="android.permission.ACCESS_MTP" granted="true" flags="0" />         <item name="android.permission.INTERACT_ACROSS_USERS" granted="true" flags="0" />         <item name="android.permission.CLEAR_APP_CACHE" granted="true" flags="0" />         <item name="android.permission.CONNECTIVITY_INTERNAL" granted="true" flags="0" />         <item name="android.permission.MODIFY_NETWORK_ACCOUNTING" granted="true" flags="0" />         <item name="android.permission.WAKE_LOCK" granted="true" flags="0" />         <item name="android.permission.UPDATE_APP_OPS_STATS" granted="true" flags="0" />     </perms>     <proper-signing-keyset identifier="4" /> </package>

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

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

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

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

......com.android.managedprovisioning 10009 0 /data/data/com.android.managedprovisioning platform 3003com.android.gifviewer 10042 0 /data/data/com.android.gifviewer default nonecom.android.dreams.phototable 10054 0 /data/data/com.android.dreams.phototable default nonecom.leadcore.telassistant 1000 0 /data/data/com.leadcore.telassistant platform 3002,1023,1015,3003,3001com.android.noisefield 10049 0 /data/data/com.android.noisefield default nonecom.android.smspush 10064 0 /data/data/com.android.smspush default nonecom.leadcore.codescan 10029 0 /data/data/com.leadcore.codescan platform 3003com.android.wallpaper.livepicker 10046 0 /data/data/com.android.wallpaper.livepicker platform nonejp.co.omronsoft.openwnn 10051 0 /data/data/jp.co.omronsoft.openwnn default nonecom.android.settings 1000 0 /data/data/com.android.settings platform 3002,1023,1015,3003,3001com.leadcore.logservice 1000 0 /data/data/com.leadcore.logservice platform 3002,1023,1015,3003,3001com.android.calculator2 10032 0 /data/data/com.android.calculator2 default nonecom.leadcore.userfeedback 10062 0 /data/data/com.leadcore.userfeedback platform 3003com.leadcore.filesearch 10035 0 /data/data/com.leadcore.filesearch default nonecom.iflytek.inputmethod 10041 0 /data/data/com.iflytek.inputmethod default 3002,3003,3001org.simalliance.openmobileapi.uiccterminal 10061 0 /data/data/org.simalliance.openmobileapi.uiccterminal platform nonecom.android.wallpaper 10045 0 /data/data/com.android.wallpaper default nonecom.android.vpndialogs 10018 0 /data/data/com.android.vpndialogs platform nonecom.android.email 10031 0 /data/data/com.android.email default 3003com.android.music 10048 0 /data/data/com.android.music platform 3002,1023,1015,3003com.android.phone 1001 0 /data/data/com.android.phone platform 3002,3003,3001com.android.shell 2000 0 /data/data/com.android.shell platform 3002,1023,1015,3008com.android.video 10063 0 /data/data/com.android.video platform 1023,1015,3003com.android.providers.userdictionary 10000 0 /data/data/com.android.providers.userdictionary default 3003com.android.location.fused 1000 0 /data/data/com.android.location.fused platform 3002,1023,1015,3003,3001com.android.deskclock 1000 0 /data/data/com.android.deskclock platform 3002,1023,1015,3003,3001com.android.systemui 10017 0 /data/data/com.android.systemui platform 3002,1023,1015,3001,3006......

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

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


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


2.2 SystemConfig

继续分析构造函数:

        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);    }

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

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

......    <permission name="android.permission.MANAGE_VOICE_KEYPHRASES">        <group gid="audio" />    </permission>    <permission name="android.permission.ACCESS_FM_RADIO" >        <group gid="media" />    </permission>    <!-- ================================================================== -->    <!-- ================================================================== -->    <!-- ================================================================== -->    <!-- The following tags are assigning high-level permissions to specific         user IDs.  These are used to allow specific core system users to         perform the given operations with the higher-level framework.  For         example, we give a wide variety of permissions to the shell user         since that is the user the adb shell runs under and developers and         others should have a fairly open environment in which to         interact with the system. -->    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />    <assign-permission name="android.permission.WAKE_LOCK" uid="media" />    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />......


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

            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));            }


2.3 readLPw函数

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

mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),                    mSdkVersion, mOnlyCore);

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

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) {//这里为空,代表没有备份文件,就看packages.xml文件                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);//解析packages.xml中的各内容                } else if (tagName.equals("permissions")) {                    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......


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

下面开始优化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);                        }                    }                }

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

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


2.5 赋予权限,写packages.xml

继续分析

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;    }

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


这样我们这节就讲完了,后面我们会详细讲解下每个函数,读取权限,扫描文件等。这里只是讲个大概框架。





3 0
原创粉丝点击