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

来源:互联网 发布:windows ce安装软件 编辑:程序博客网 时间:2024/06/06 10:45

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系统成为一个组件可复用的系统。


0 0