Android 设计模式 笔记 - PackageManagerService信息树

Posted 鲨鱼丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 设计模式 笔记 - PackageManagerService信息树相关的知识,希望对你有一定的参考价值。

Intent

关于Intent我们都知道他是各个组件,进程之间的通信纽带,android系统也是通过Intent来查找软件中的对应的组件,并且进行通信。

我们知道在系统启动之后,系统会自动注册各种服务,WindowManagerService和ActivityManagerService就在其中,另外,一个和Intent息息相关的服务也被注册了,这个服务就是PackageManagerService,这个服务主要功能就是解析AndroidMainnifest.xml文件中的APP相关的信息,获取信息完成之后构建项目的信息树。

我们看下PackageManagerService的构造函数:

    public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) 
        //代码省略
        synchronized (mInstallLock) 
        // writer
        synchronized (mPackages) 
            //获取/data目录
            File dataDir = Environment.getDataDirectory();
            mAppDataDir = new File(dataDir, "data");
            //获取第三方应用安装目录 /data/app
            mAppInstallDir = new File(dataDir, "app");
            //代码省略

            File frameworkDir = new File(Environment.getRootDirectory(), "framework");

            //加载FrameWork资源
            alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");

            //加载核心库
            alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");

            //省略代码

            // 获取系统APP安装路径
            File systemAppDir = new File(Environment.getRootDirectory(), "app");
            mSystemInstallObserver = new AppDirObserver(
                systemAppDir.getPath(), OBSERVER_EVENTS, true, false);
            mSystemInstallObserver.startWatching();
            //扫描系统APP安装路径
            scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

            //省略代码
            //非核心应用

            if (!mOnlyCore) 
                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                        SystemClock.uptimeMillis());
                mAppInstallObserver = new AppDirObserver(
                    mAppInstallDir.getPath(), OBSERVER_EVENTS, false, false);
                mAppInstallObserver.startWatching();
                //扫描第三方APP安装路径
                scanDirLI(mAppInstallDir, 0, scanMode, 0);
    
                //代码省略
             else 
                mAppInstallObserver = null;
                mDrmAppInstallObserver = null;
            

           //代码省略
         // synchronized (mPackages)
         // synchronized (mInstallLock)
    

代码又臭又长,省略了部分,我们只要明白在构造函数里面PMS做了几件事:

  • 加载了系统已经安装的APK
  • 加载了FrameWork与核心库
  • 扫描了指定目录下的apk文件并进行解析

上面代码中有个很重要的函数就是扫描第三方的APP安装路径即:scanDirLI函数,我们去看下具体实现:

    private void scanDirLI(File dir, int flags, int scanMode, long currentTime) 
        //获取目录下的所有文件
        String[] files = dir.list();
        if (files == null) 
            Log.d(TAG, "No files in app dir " + dir);
            return;
        

        if (DEBUG_PACKAGE_SCANNING) 
            Log.d(TAG, "Scanning app dir " + dir + " scanMode=" + scanMode
                    + " flags=0x" + Integer.toHexString(flags));
        

        int i;
        //解析目录下的所有apk文件
        for (i=0; i<files.length; i++) 
            File file = new File(dir, files[i]);
            if (!isPackageFilename(files[i])) 
                // Ignore entries which are not apk's
                //不是apk文件,忽略
                continue;
            
            //解析apk文件
            PackageParser.Package pkg = scanPackageLI(file,
                    flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null);
            // Don't mess around with apps in system partition.
            if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                    mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) 
                // Delete the apk
                Slog.w(TAG, "Cleaning up failed install of " + file);
                file.delete();
            
        
    

这个方法主要的功能就是扫描指定目录下的apk文件,然后通过scanPackageLIb函数进行解析。所以这个方法的主要功能在scanPackageLIb函数中,我们去查看这个代码:

    private PackageParser.Package scanPackageLI(File scanFile,
            int parseFlags, int scanMode, long currentTime, UserHandle user) 
        mLastScanError = PackageManager.INSTALL_SUCCEEDED;
        String scanPath = scanFile.getPath();
        if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanPath);
        parseFlags |= mDefParseFlags;
        PackageParser pp = new PackageParser(scanPath);
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setOnlyCoreApps(mOnlyCore);
        final PackageParser.Package pkg = pp.parsePackage(scanFile,
                scanPath, mMetrics, parseFlags);

        if (pkg == null) 
            mLastScanError = pp.getParseError();
            return null;
        

        PackageSetting ps = null;
        PackageSetting updatedPkg;
        // reader
        synchronized (mPackages) 
            // Look to see if we already know about this package.
            String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
            if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) 
                // This package has been renamed to its original name.  Let's
                // use that.
                ps = mSettings.peekPackageLPr(oldName);
            
            // If there was no original package, see one for the real package name.
            if (ps == null) 
                ps = mSettings.peekPackageLPr(pkg.packageName);
            
            // Check to see if this package could be hiding/updating a system
            // package.  Must look for it either under the original or real
            // package name depending on our state.
            updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
            if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);
        
        // First check if this is a system package that may involve an update
        if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) 
            if (ps != null && !ps.codePath.equals(scanFile)) 
                // The path has changed from what was last scanned...  check the
                // version of the new path against what we have stored to determine
                // what to do.
                if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath);
                if (pkg.mVersionCode < ps.versionCode) 
                    // The system package has been updated and the code path does not match
                    // Ignore entry. Skip it.
                    Log.i(TAG, "Package " + ps.name + " at " + scanFile
                            + " ignored: updated version " + ps.versionCode
                            + " better than this " + pkg.mVersionCode);
                    if (!updatedPkg.codePath.equals(scanFile)) 
                        Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg : "
                                + ps.name + " changing from " + updatedPkg.codePathString
                                + " to " + scanFile);
                        updatedPkg.codePath = scanFile;
                        updatedPkg.codePathString = scanFile.toString();
                        // This is the point at which we know that the system-disk APK
                        // for this package has moved during a reboot (e.g. due to an OTA),
                        // so we need to reevaluate it for privilege policy.
                        if (locationIsPrivileged(scanFile)) 
                            updatedPkg.pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
                        
                    
                    updatedPkg.pkg = pkg;
                    mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
                    return null;
                 else 
                    // The current app on the system partion is better than
                    // what we have updated to on the data partition; switch
                    // back to the system partition version.
                    // At this point, its safely assumed that package installation for
                    // apps in system partition will go through. If not there won't be a working
                    // version of the app
                    // writer
                    synchronized (mPackages) 
                        // Just remove the loaded entries from package lists.
                        mPackages.remove(ps.name);
                    
                    Slog.w(TAG, "Package " + ps.name + " at " + scanFile
                            + "reverting from " + ps.codePathString
                            + ": new version " + pkg.mVersionCode
                            + " better than installed " + ps.versionCode);

                    InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps),
                            ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString);
                    synchronized (mInstallLock) 
                        args.cleanUpResourcesLI();
                    
                    synchronized (mPackages) 
                        mSettings.enableSystemPackageLPw(ps.name);
                    
                
            
        

        if (updatedPkg != null) 
            // An updated system app will not have the PARSE_IS_SYSTEM flag set
            // initially
            parseFlags |= PackageParser.PARSE_IS_SYSTEM;

            // An updated privileged app will not have the PARSE_IS_PRIVILEGED
            // flag set initially
            if ((updatedPkg.pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0) 
                parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
            
        
        // Verify certificates against what was last scanned
        if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) 
            Slog.w(TAG, "Failed verifying certificates for package:" + pkg.packageName);
            return null;
        

        /*
         * A new system app appeared, but we already had a non-system one of the
         * same name installed earlier.
         */
        boolean shouldHideSystemApp = false;
        if (updatedPkg == null && ps != null
                && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) 
            /*
             * Check to make sure the signatures match first. If they don't,
             * wipe the installed application and its data.
             */
            if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
                    != PackageManager.SIGNATURE_MATCH) 
                if (DEBUG_INSTALL) Slog.d(TAG, "Signature mismatch!");
                deletePackageLI(pkg.packageName, null, true, null, null, 0, null, false);
                ps = null;
             else 
                /*
                 * If the newly-added system app is an older version than the
                 * already installed version, hide it. It will be scanned later
                 * and re-added like an update.
                 */
                if (pkg.mVersionCode < ps.versionCode) 
                    shouldHideSystemApp = true;
                 else 
                    /*
                     * The newly found system app is a newer version that the
                     * one previously installed. Simply remove the
                     * already-installed application and replace it with our own
                     * while keeping the application data.
                     */
                    Slog.w(TAG, "Package " + ps.name + " at " + scanFile + "reverting from "
                            + ps.codePathString + ": new version " + pkg.mVersionCode
                            + " better than installed " + ps.versionCode);
                    InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps),
                            ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString);
                    synchronized (mInstallLock) 
                        args.cleanUpResourcesLI();
                    
                
            
        

        // The apk is forward locked (not public) if its code and resources
        // are kept in different files. (except for app in either system or
        // vendor path).
        // TODO grab this value from PackageSettings
        if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) 
            if (ps != null && !ps.codePath.equals(ps.resourcePath)) 
                parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
            
        

        String codePath = null;
        String resPath = null;
        if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0) 
            if (ps != null && ps.resourcePathString != null) 
                resPath = ps.resourcePathString;
             else 
                // Should not happen at all. Just log an error.
                Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
            
         else 
            resPath = pkg.mScanPath;
        

        codePath = pkg.mScanPath;
        // Set application objects path explicitly.
        setApplicationInfoPaths(pkg, codePath, resPath);
        // Note that we invoke the following method only if we are about to unpack an application
        PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
                | SCAN_UPDATE_SIGNATURE, currentTime, user);

        /*
         * If the system app should be overridden by a previously installed
         * data, hide the system app now and let the /data/app scan pick it up
         * again.
         */
        if (shouldHideSystemApp) 
            synchronized (mPackages) 
                /*
                 * We have to grant systems permissions before we hide, because
                 * grantPermissions will assume the package update is trying to
                 * expand its permissions.
                 */
                grantPermissionsLPw(pkg, true);
                mSettings.disableSystemPackageLPw(pkg.packageName);
            
        

        return scannedPkg;
    

    private PackageParser.Package scanPackageLI(File scanFile,
            int parseFlags, int scanMode, long currentTime, UserHandle user) 
        mLastScanError = PackageManager.INSTALL_SUCCEEDED;
        String scanPath = scanFile.getPath();
        if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanPath);
        parseFlags |= mDefParseFlags;
        //创建一个包解析器
        PackageParser pp = new PackageParser(scanPath);
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setOnlyCoreApps(mOnlyCore);
        //解析apk包
        final PackageParser.Package pkg = pp.parsePackage(scanFile,
                scanPath, mMetrics, parseFlags);

        if (pkg == null) 
            mLastScanError = pp.getParseError();
            return null;
        

        //代码省略

        //解析apk包中的Activity,Service等组件
        PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
                | SCAN_UPDATE_SIGNATURE, currentTime, user);

        //代码省略

        return scannedPkg;
    

这个方法做了下面几件事情:

  • 创建一个包解析器PackageParser
  • 通过包解析器解析apk包
  • 解析了apk包中的Activity,Service等组件

从上面的代码可以看到,解析apk包的重要的功能是PackageParser下的parsePackage函数,我们追踪这个函数,看看具体实现:

  private Package parsePackage(
        Resources res, XmlResourceParser parser, int flags, String[] outError)
        throws XmlPullParserException, IOException 
        AttributeSet attrs = parser;

        mParseInstrumentationArgs = null;
        mParseActivityArgs = null;
        mParseServiceArgs = null;
        mParseProviderArgs = null;
        //解析到AndroidMainnifest.xml的包名
        
        //代码省略

        //构建Package对象
        final Package pkg = new Package(pkgName);
        boolean foundApp = false;
        

        //获取AndroidMainnifest.xml文件中的VersionCode,VersionName等参数
        TypedArray sa = res.obtainAttributes(attrs,
                com.android.internal.R.styleable.AndroidManifest);
        pkg.mVersionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
        pkg.mVersionName = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_versionName, 0);
        if (pkg.mVersionName != null) 
            pkg.mVersionName = pkg.mVersionName.intern();
        
        String str = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
        if (str != null && str.length() > 0) 
            String nameError = validateName(str, true);
            if (nameError != null && !"android".equals(pkgName)) 
                outError[0] = "<manifest> specifies bad sharedUserId name \\""
                    + str + "\\": " + nameError;
                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
                return null;
            
            pkg.mSharedUserId = str.intern();
            pkg.mSharedUserLabel = sa.getResourceId(
                    com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
        
        sa.recycle();

        pkg.installLocation = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_installLocation,
                PARSE_DEFAULT_INSTALL_LOCATION);
        pkg.applicationInfo.installLocation = pkg.installLocation;

        /* Set the global "forward lock" flag */
        if ((flags & PARSE_FORWARD_LOCK) != 0) 
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK;
        

        /* Set the global "on SD card" flag */
        if ((flags & PARSE_ON_SDCARD) != 0) 
            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
        

        // Resource boolean are -1, so 1 means we don't know the value.
        int supportsSmallScreens = 1;
        int supportsNormalScreens = 1;
        int supportsLargeScreens = 1;
        int supportsXLargeScreens = 1;
        int resizeable = 1;
        int anyDensity = 1;
        
        //解析AndroidMainnifest.xml中的元素
        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("application")) 
                //代码省略

                //解析Application标签,Activity和Service的所在
                if (!parseApplication(pkg, res, parser, attrs, flags, outError)) 
                    return null;
                
             else if (tagName.equals("uses-permission")) 
                //解析用户权限标签
                if (!parseUsesPermission(pkg, res, parser, attrs, outError)) 
                    return null;
                

            
            //其他标签省略~很多,常见的两个在上面了
        

        //省略代码

        return pkg;
    



这个上面可以看到做的几件事情:

  • 解析包名
  • 构建Package对象
  • 解析AndroidMainnifest.xml中的各个标签

我们在上面的代码表现出来两个解析标签的函数,我们找到其中一个就是application的好了,我们发现具体解析application的函数是parseApplication函数,我们跟踪这个函数,看看具体实现:

   private boolean parseApplication(Package owner, Resources res,
            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
        throws XmlPullParserException, IOException 
        //应用信息
        final ApplicationInfo ai = owner.applicationInfo;
        //包名
        final String pkgName = owner.applicationInfo.packageName;
        //获取Application的标签
        TypedArray sa = res.obtainAttributes(attrs,
                com.android.internal.R.styleable.AndroidManifestApplication);
        //获取应用名
        String name = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifestApplication_name, 0);
        if (name != null) 
            ai.className = buildClassName(pkgName, name, outError);
            if (ai.className == null) 
                sa.recycle();
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                return false;
            
        

        //代码省略


        //获取程序的icon,logo等参数
        ai.icon = sa.getResourceId(
                com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
        ai.logo = sa.getResourceId(
                com.android.internal.R.styleable.AndroidManifestApplication_logo, 0);
        ai.banner = sa.getResourceId(
                com.android.internal.R.styleable.AndroidManifestApplication_banner, 0);
        ai.theme = sa.getResourceId(
                com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
        ai.descriptionRes = sa.getResourceId(
                com.android.internal.R.styleable.AndroidManifestApplication_description, 0);

       //代码省略
      

        final int innerDepth = parser.getDepth();

        int type;
        //获取Application下的所有子元素
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) 
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) 
                continue;
            
            //获取标签名
            String tagName = parser.getName();
            //解析Activity
            if (tagName.equals("activity")) 
                Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,
                        hardwareAccelerated);
                if (a == null) 
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                

                owner.activities.add(a);
            //解析receiver
             else if (tagName.equals("receiver")) 
                Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false);
                if (a == null) 
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                

                owner.receivers.add(a);
             //解析其他的例如Service等~代码省略
        return true;
    

这个代码做的一个非常普通的xml解析,并且会根据不同的标签使用不同的解析方法例如解析Activity的parseActivity和解析service的parseService他们都回返回一个向右的实例,并把这个实例添加到Package对象列表中去 。


好了,解析apk的方法我们算是走了一遍了,回到调用这个方法的最初点:就是PackageManagerService类中的scanPackageLI方法,在这个方法里我们看到最后调用了一个和scanPackageLI同名的但是不同参数的函数scanPackageLI(PackageParser.Package pkg,int parseFlags, int scanMode, long currentTime, UserHandle user) 这个函数的我们看下主要实现过程:

 private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
            int parseFlags, int scanMode, long currentTime, UserHandle user) 
            //代码省略
            int N = pkg.providers.size();
            StringBuilder r = null;
            int i;
            for (i=0; i<N; i++) 
                PackageParser.Provider p = pkg.providers.get(i);
                p.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        p.info.processName, pkg.applicationInfo.uid);
                mProviders.addProvider(p);
                p.syncable = p.info.isSyncable;
                if (p.info.authority != null) 
                    String names[] = p.info.authority.split(";");
                    p.info.authority = null;
                    for (int j = 0; j < names.length; j++) 
                        if (j == 1 && p.syncable) 
                            // We only want the first authority for a provider to possibly be
                            // syncable, so if we already added this provider using a different
                            // authority clear the syncable flag. We copy the provider before
                            // changing it because the mProviders object contains a reference
                            // to a provider that we don't want to change.
                            // Only do this for the second authority since the resulting provider
                            // object can be the same for all future authorities for this provider.
                            p = new PackageParser.Provider(p);
                            p.syncable = false;
                        
                        if (!mProvidersByAuthority.containsKey(names[j])) 
                            mProvidersByAuthority.put(names[j], p);
                            if (p.info.authority == null) 
                                p.info.authority = names[j];
                             else 
                                p.info.authority = p.info.authority + ";" + names[j];
                            
                            if (DEBUG_PACKAGE_SCANNING) 
                                if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
                                    Log.d(TAG, "Registered content provider: " + names[j]
                                            + ", className = " + p.info.name + ", isSyncable = "
                                            + p.info.isSyncable);
                            
                         else 
                            PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
                            Slog.w(TAG, "Skipping provider name " + names[j] +
                                    " (in package " + pkg.applicationInfo.packageName +
                                    "): name already used by "
                                    + ((other != null && other.getComponentName() != null)
                                            ? other.getComponentName().getPackageName() : "?"));
                        
                    
                
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) 
                    if (r == null) 
                        r = new StringBuilder(256);
                     else 
                        r.append(' ');
                    
                    r.append(p.info.name);
                
            
            if (r != null) 
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Providers: " + r);
            

            N = pkg.services.size();
            r = null;
            for (i=0; i<N; i++) 
                PackageParser.Service s = pkg.services.get(i);
                s.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        s.info.processName, pkg.applicationInfo.uid);
                mServices.addService(s);
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) 
                    if (r == null) 
                        r = new StringBuilder(256);
                     else 
                        r.append(' ');
                    
                    r.append(s.info.name);
                
            
            if (r != null) 
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Services: " + r);
            

            N = pkg.receivers.size();
            r = null;
            for (i=0; i<N; i++) 
                PackageParser.Activity a = pkg.receivers.get(i);
                a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        a.info.processName, pkg.applicationInfo.uid);
                mReceivers.addActivity(a, "receiver");
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) 
                    if (r == null) 
                        r = new StringBuilder(256);
                     else 
                        r.append(' ');
                    
                    r.append(a.info.name);
                
            
            if (r != null) 
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Receivers: " + r);
            

            N = pkg.activities.size();
            r = null;
            for (i=0; i<N; i++) 
                PackageParser.Activity a = pkg.activities.get(i);
                a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        a.info.processName, pkg.applicationInfo.uid);
                mActivities.addActivity(a, "activity");
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) 
                    if (r == null) 
                        r = new StringBuilder(256);
                     else 
                        r.append(' ');
                    
                    r.append(a.info.name);
                
            
            if (r != null) 
                if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Activities: " + r);
            

            //代码省略
           if (pkg.protectedBroadcasts != null) 
                N = pkg.protectedBroadcasts.size();
                for (i=0; i<N; i++) 
                    mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
                
            

            pkgSetting.setTimeStamp(scanFileTime);
        

        return pkg;
    

这个函数主要做了一件事情,就是把在parsePackage中获取的apk配置列表读取出来,并加入到对应的mActivities,mServices等列表中去。到了这一步,整个已经安装apk的信息树已经建立了,每个apk的应用包名,应用名称,图标等等都已经在系统中有存储,当Intent跳转到某个Activity中的时候Intent就会在这个信息书中的列表中查找,符合条件的组件就会启动。

这样的话就可以通过Intent将各个组件连接到一起,使Android系统成为一个组件可复用的系统。


以上是关于Android 设计模式 笔记 - PackageManagerService信息树的主要内容,如果未能解决你的问题,请参考以下文章

Android笔记 - APK打包流程

Android学习笔记之AndroidManifest.xml文件解析

Android分享笔记 获取屏幕尺寸,包括状态栏

小白自我提高学习设计模式笔记—装饰者模式在Android开发的小试

读《Android电视机(机顶盒)初次开发的一些经验分享》后的笔记

java/android 设计模式学习笔记---抽象工厂模式