Android系统源码阅读(17):Android 应用的安装

Android系统源码阅读(17):Android 应用的安装

学到的才是自己的,干活都是扯淡


1. 应用的安装

PackageManagerService负责管理应用的安装。在第14章中讲到,SystemService会启动PackageManagerService,那么我们就从SystemService启动PackageManagerService开始分析。

1.1 PackageManagerService.main

创建PackageManagerService对象。

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java :

public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
     //先创建一个PackageManagerService对象
     PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore);
     //将他注册到ServiceManager里面
     ServiceManager.addService("package", m);
     return m;
 }

1.2 PackageManagerService.PackageManagerService

PackageManagerService的构造函数。

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java :

  public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        //...

        mSettings = new Settings(mPackages);

    //...
        synchronized (mInstallLock) {
        // writer
        synchronized (mPackages) {
            //一个PackageManagerService自己的Looper
            mHandlerThread = new ServiceThread(TAG,
                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
       //线程启动,开启自己的消息循环队列
            mHandlerThread.start();
            //并且创建了一个Handler该线程
            mHandler = new PackageHandler(mHandlerThread.getLooper());

       //获取文件路径
            File dataDir = Environment.getDataDirectory();
            mAppDataDir = new File(dataDir, "data");
            mAppInstallDir = new File(dataDir, "app");
            mAppLib32InstallDir = new File(dataDir, "app-lib");
            mAsecInternalPath = new File(dataDir, "app-asec").getPath();
            mUserAppDataDir = new File(dataDir, "user");
            mDrmAppPrivateInstallDir = new File(dataDir, "app-private");

            sUserManager = new UserManagerService(context, this,
                    mInstallLock, mPackages);

       // 获取权限配置文件的中的权限
            // Propagate permission configuration in to package manager.
            ArrayMap permConfig
                    = systemConfig.getPermissions();
            for (int i=0; iif (bp == null) {
                    bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
                    mSettings.mPermissions.put(perm.name, bp);
                }
                if (perm.gids != null) {
                    bp.setGids(perm.gids, perm.perUser);
                }
            }

       //获取共享库
            ArrayMap libConfig = systemConfig.getSharedLibraries();
            for (int i=0; inew SharedLibraryEntry(libConfig.valueAt(i), null));
            }

            //恢复上一次应用安装信息,见1.3
            mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
                    mSdkVersion, mOnlyCore);

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



            File frameworkDir = new File(Environment.getRootDirectory(), "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");

            /**
             * 将一些应用dexopt转化
             * 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.
             */

            //...

            //设备厂商提供的应用
            // Collect vendor overlay packages.
            // (Do this before scanning any apps.)
            // For security and version matching reason, only consider
            // overlay packages if they reside in VENDOR_OVERLAY_DIR.
            File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
            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);

            if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
            mInstaller.moveFiles();

            // Prune any system packages that no longer exist.
            final List possiblyDeletedUpdatedSystemApps = new ArrayList();
            //...


            //look for any incomplete package installations
            ArrayList deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
            //clean up list
            for(int i = 0; i < deletePkgsList.size(); i++) {
                //clean up here
                cleanupInstallFailedPackage(deletePkgsList.get(i));
            }
            //delete tmp files
            deleteTempPackageFiles();

            // Remove any shared userIDs that have no associated packages
            mSettings.pruneSharedUsersLPw();
            //...

            // Now that we know all the packages we are keeping,
            // read and update their last usage times.
            mPackageUsage.readLP();

            // If the platform SDK has changed since the last time we booted,
            // we need to re-grant app permission to catch any new ones that
            // appear.  This is really a hack, and means that apps can in some
            // cases get permissions that the user didn't initially explicitly
            // allow...  it would be nice to have some better way to handle
            // this situation.
            int updateFlags = UPDATE_PERMISSIONS_ALL;
            if (ver.sdkVersion != mSdkVersion) {
                Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to "
                        + mSdkVersion + "; regranting permissions for internal storage");
                updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
            }
            //为申请了特定资源的访问权限的应用分配用户组id
            updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);
            ver.sdkVersion = mSdkVersion;

            //将应用安装信息保存到本地的配置文件
            // can downgrade to reader
            mSettings.writeLPr();


        } // synchronized (mPackages)
        } // synchronized (mInstallLock)

        // 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();

        // Expose private service for system components to use.
        LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
    }

1.3 Settings.readLPw

读取保存的应用信息。
frameworks/base/services/core/java/com/android/server/pm/Settings.java :

boolean readLPw(PackageManagerService service, List users, int sdkVersion,
            boolean onlyCore) {
        FileInputStream str = null;
        if (mBackupSettingsFilename.exists()) {
            try {
                //获取/data/system/packages-backup.xml文件
                str = new FileInputStream(mBackupSettingsFilename);
                //如果backup不存在,则获取/data/system/packages.xml文件
                //...
            } catch (java.io.IOException e) {
                // We'll try for the normal settings file.
            }
        }
    //...
        try {
            if (str == null) {
                //...
                str = new FileInputStream(mSettingsFilename);
            }
            //用parser解析xml文件
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(str, StandardCharsets.UTF_8.name());
            //...
            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")) {
                    //获取上次分配给他的应用用户ID,见1.4
                    readPackageLPw(parser);
                } else if (tagName.equals("permissions")) {
                    readPermissionsLPw(mPermissions, parser);
                } else if (tagName.equals("permission-trees")) {
                    readPermissionsLPw(mPermissionTrees, parser);
                } else if (tagName.equals("shared-user")) {
                    //获取上次分配的共享用户ID,见1.6
                    readSharedUserLPw(parser);
                } else if {
                  //...
                } else {
                    Slog.w(PackageManagerService.TAG, "Unknown element under : "
                            + parser.getName());
                    XmlUtils.skipCurrentTag(parser);
                }
            }

            str.close();

        } catch (XmlPullParserException e) {
           //...
        } catch (java.io.IOException e) {
           //....
        }
        //...
        return true;
    }

1.4 Settings.readPackageLPw

读取package信息。

frameworks/base/services/core/java/com/android/server/pm/Settings.java :

 private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
        String name = null;
        //...
        String idStr = null;
        String sharedIdStr = null;
    //...

        try {
            name = parser.getAttributeValue(null, ATTR_NAME);
            realName = parser.getAttributeValue(null, "realName");
            idStr = parser.getAttributeValue(null, "userId");
            //...
            //名字不能为null
            if (name == null) {
                PackageManagerService.reportSettingsProblem(Log.WARN,
                        "Error in package manager settings:  has no name at "
                                + parser.getPositionDescription());
            } else if (codePathStr == null) {
                PackageManagerService.reportSettingsProblem(Log.WARN,
                        "Error in package manager settings:  has no codePath at "
                                + parser.getPositionDescription());
            } else if (userId > 0) {
                //该应用上次已经分配过ID,所以这次还使用该id,见1.5
                packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
                        new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
                        secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,
                        pkgPrivateFlags);
                //...
            } else if (sharedIdStr != null) {
                userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
                if (userId > 0) {
                    //如果上次使用的是共享id,则说明上次该app没有独立的id
                    //所以这次不能直接将该id分配给他,要先将其保存起来以后处理
                    packageSetting = new PendingPackage(name.intern(), realName, new File(
                            codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
                            primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
                            userId, versionCode, pkgFlags, pkgPrivateFlags);
                    //...
                    mPendingPackages.add((PendingPackage) packageSetting);
                   //...
                } else {
                   //...
                }
            } else {
                //...
            }
        } catch (NumberFormatException e) {
            //...
        }
      //...
    }

1.5 Setttings.addPackageLPw

为该package分配UID,创建保存package信息的PackageSetting对象。

frameworks/base/services/core/java/com/android/server/pm/Settings.java :

    PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
            String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
            String cpuAbiOverrideString, int uid, int vc, int pkgFlags, int pkgPrivateFlags) {
        //每一个app的信息都保存于一个PackageSetting对象中
        PackageSetting p = mPackages.get(name);
        if (p != null) {
            //该应用已经有对应的PackageSetting对象了,无需再次添加
            if (p.appId == uid) {
                return p;
            }
            PackageManagerService.reportSettingsProblem(Log.ERROR,
                    "Adding duplicate package, keeping first: " + name);
            return null;
        }
        //为该app创建一个PackageSetting
        p = new PackageSetting(name, realName, codePath, resourcePath,
                legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
                cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags);
        p.appId = uid;
        //在系统中保留值为uid的Linux用户ID,会在下面详解
        if (addUserIdLPw(uid, p, name)) {
            //mPackages保存创建的app PackageSetting对象
            mPackages.put(name, p);
            return p;
        }
        return null;
    }

在系统中保留指定的UID。这里可以看出,一共可以分配10000个uid给应用程序,小于10000的uid是分配给特权用户的。这些特权用户的uid可以通过共享的形式给其它应用使用。例如,一个想修改系统时间的的应用可以共享”android.uid.system”的特权用户的uid,即在配置文件中将它的android:sharedUserId的属性设置为“android.uid.system”。uid不能重复,但是shareduid是可以共享的。

frameworks/base/services/core/java/com/android/server/pm/Settings.java :

    private boolean addUserIdLPw(int uid, Object obj, Object name) {
        //分配的uid不能超过LAST_APPLICATION_UID,19999
        if (uid > Process.LAST_APPLICATION_UID) {
            return false;
        }

        //分配的uid应该大于等于FIRST_APPLICATION_UID,10000
        if (uid >= Process.FIRST_APPLICATION_UID) {
            int N = mUserIds.size();
            final int index = uid - Process.FIRST_APPLICATION_UID;
            while (index >= N) {
                //将中间没分配的uid先置为空
                mUserIds.add(null);
                N++;
            }
            if (mUserIds.get(index) != null) {
                //该uid重复了,分配失败
                return false;
            }
            //正式分配uid,所有的uid被mUserIds管理
            mUserIds.set(index, obj);
        } else {
            //这里是特权用户的uid
            if (mOtherUserIds.get(uid) != null) {
                //uid已经分配过,返回失败
                return false;
            }
            mOtherUserIds.put(uid, obj);
        }
        return true;
    }

到这里,应用的uid已经分配完成。下面回到1.3,看如何读取shareduid。

1.6 Setttings.readSharedUserLPw

读取共享uid。

frameworks/base/services/core/java/com/android/server/pm/Settings.java :

    private void readSharedUserLPw(XmlPullParser parser) throws XmlPullParserException,IOException {
        String name = null;
        String idStr = null;
        int pkgFlags = 0;
        int pkgPrivateFlags = 0;
        SharedUserSetting su = null;
        try {
            name = parser.getAttributeValue(null, ATTR_NAME);
            idStr = parser.getAttributeValue(null, "userId");
            int userId = idStr != null ? Integer.parseInt(idStr) : 0;
            //该共享id是系统应用还是用户类型的应用
            if ("true".equals(parser.getAttributeValue(null, "system"))) {
                pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
            }
            if (name == null) {
                //...
            } else if (userId == 0) {
               //...
            } else {
                //在系统中为该应用申请该userId,见1.7
                if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags, pkgPrivateFlags))
                        == null) {
                   //...
                }
            }
        } catch (NumberFormatException e) {
        //...
        }
       //....
        } else {
            XmlUtils.skipCurrentTag(parser);
        }
    }

1.7 Settings.addSharedUserLPw

添加共享用户。

frameworks/base/services/core/java/com/android/server/pm/Settings.java :

SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
        SharedUserSetting s = mSharedUsers.get(name);
        if (s != null) {
            if (s.userId == uid) {
                return s;
            }
            //添加uid和已经添加的不同,则失败返回
            return null;
        }
        //mSharedUsers中没有该共享用户id,则创建一个SharedUserSetting
        s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
        s.userId = uid;
        //在系统中为它分配该uid,重复1.6
        if (addUserIdLPw(uid, s, name)) {
        //分配成功,记录下来
            mSharedUsers.put(name, s);
            return s;
        }
        return null;
    }

在1.4中,mPendingPackages保存了一些使用共享用户id的package。现在已经解析完毕共享用户的信息,在1.3 readLPw函数中将会处理这些package了。

frameworks/base/services/core/java/com/android/server/pm/Settings.java :

for (int i = 0; i < N; i++) {
            final PendingPackage pp = mPendingPackages.get(i);
            Object idObj = getUserIdLPr(pp.sharedId);
            if (idObj != null && idObj instanceof SharedUserSetting) {
                //获得共享用户信息,说明该package使用的共享用户id是有效的,将在下面小节分析
                PackageSetting p = getPackageLPw(pp.name, null, pp.realName,
                        (SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
                        pp.legacyNativeLibraryPathString, pp.primaryCpuAbiString,
                        pp.secondaryCpuAbiString, pp.versionCode, pp.pkgFlags, pp.pkgPrivateFlags,
                        null, true /* add */, false /* allowInstall */);
                if (p == null) {
                    //...
                    continue;
                }
                p.copyFrom(pp);
            } else if (idObj != null) {
               //该package使用了一个非共享的id
            } else {
               //使用的共享id不存在
            }
        }
        mPendingPackages.clear();

1.8 PackageManagerService.scanDirLI

到此,PackageManagerService已经将上一次保存的应用信息恢复完毕,在1.2中接下来需要进一步安装各个目录下的应用。

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java :

    private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
        final File[] files = dir.listFiles();
        //依次访问文件夹中的每个apk文件
        for (File file : files) {
            final boolean isPackage = (isApkFile(file) || file.isDirectory())
                    && !PackageInstallerService.isStageName(file.getName());
            if (!isPackage) {
                // Ignore entries which are not packages
                continue;
            }
            try {
                scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
                        scanFlags, currentTime, null);
            } catch (PackageManagerException e) {
                //删除无效的文件
                // Delete invalid userdata apps
                if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                        e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                    if (file.isDirectory()) {
                        mInstaller.rmPackageDir(file.getAbsolutePath());
                    } else {
                        file.delete();
                    }
                }
            }
        }
    }

1.9 PackageManagerService.scanPackageLI

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java :

    private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
            long currentTime, UserHandle user) throws PackageManagerException {
        //...
        PackageParser pp = new PackageParser();
        //...
        final PackageParser.Package pkg;
        try {
            //解析目标文件
            pkg = pp.parsePackage(scanFile, parseFlags);
        } catch (PackageParserException e) {
            //...
        }
        //...
 }

1.10 PackageParser.parsePackage

frameworks/base/core/java/android/content/pm/PackageParser.java :

  public Package parsePackage(File packageFile, int flags) throws PackageParserException {
        if (packageFile.isDirectory()) {
            //一个目录下是一个应用
            return parseClusterPackage(packageFile, flags);
        } else {
            //一个整体的应用
            return parseMonolithicPackage(packageFile, flags);
        }
    }

1.11 PackageParser.parseMonolithicPackage

frameworks/base/core/java/android/content/pm/PackageParser.java :

   public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
        //...
        final AssetManager assets = new AssetManager();
        try {
            final Package pkg = parseBaseApk(apkFile, assets, flags);
            pkg.codePath = apkFile.getAbsolutePath();
            return pkg;
        } finally {
            IoUtils.closeQuietly(assets);
        }
  }

1.12 PackageParser.parseBaseApk

frameworks/base/core/java/android/content/pm/PackageParser.java :

    private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
            throws PackageParserException {
        //...
        final String apkPath = apkFile.getAbsolutePath();
        mArchiveSourcePath = apkFile.getAbsolutePath();
        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);

        Resources res = null;
        XmlResourceParser parser = null;
        try {
            res = new Resources(assets, mMetrics, null);
            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    Build.VERSION.RESOURCES_SDK_INT);
            //获取AndroidManifest.xml文件
            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

            //解析AndroidManifest.xml文件
            final Package pkg = parseBaseApk(res, parser, flags, outError);
           //...
            return pkg;
        } catch (PackageParserException e) {
           //...
        } finally {
            IoUtils.closeQuietly(parser);
        }
    }

frameworks/base/core/java/android/content/pm/PackageParser.java :

    private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
            String[] outError) throws XmlPullParserException, IOException {
        final boolean trustedOverlay = (flags & PARSE_TRUSTED_OVERLAY) != 0;

        AttributeSet attrs = parser;

        final String pkgName;
        final String splitName;
        try {
            Pair packageSplit = parsePackageSplitNames(parser, attrs, flags);
            //获取package名称
            pkgName = packageSplit.first;
            splitName = packageSplit.second;
        } catch (PackageParserException e) {
            //...
        }

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

        TypedArray sa = res.obtainAttributes(attrs,
                com.android.internal.R.styleable.AndroidManifest);
        //应用版本信息
        pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
        //...
        //用户共享id
        String str = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
        if (str != null && str.length() > 0) {
            String nameError = validateName(str, true, false);
            if (nameError != null && !"android".equals(pkgName)) {
                outError[0] = " specifies bad sharedUserId name \""
                    + str + "\": " + nameError;
                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
                return null;
            }
            //设置共享id后表示要和其它应用共享一个id
            pkg.mSharedUserId = str.intern();
            pkg.mSharedUserLabel = sa.getResourceId(
                    com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
        }

        //...

        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项的内容
                if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {
                    return null;
                }
        //...
            } else if (tagName.equals("uses-permission")) {
                //获取申请的权限
                if (!parseUsesPermission(pkg, res, parser, attrs)) {
                    return null;
                }

            }
       //...
    }
        return pkg;
    }

一个应用可以申请多个权限,应用权限是和用户组ID对应的。应用申请权限就是获得该用户组id的过程。

1.13

framework/base/core/java/android/content/pm/PackageParser.java

private boolean parseBaseApplication(Package owner, Resources res,
            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
        throws XmlPullParserException, IOException {

        final int innerDepth = parser.getDepth();
        int type;
        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,
                        owner.baseHardwareAccelerated);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.activities.add(a);

            } else if (tagName.equals("receiver")) {
                //解析出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);

            } else if (tagName.equals("service")) {
                //解析service
                Service s = parseService(owner, res, parser, attrs, flags, outError);
                if (s == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.services.add(s);

            } else if (tagName.equals("provider")) {
                //解析provider
                Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
                if (p == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.providers.add(p);

            } 
        }
            //...
        return true;
    }

1.14 下面步骤笼统讲一下

到这里,PackageManagerService已经解析完成一个apk文件。下面回到1.9 scanPackageLI中,继续下面的工作。1.9步中会调用重载函数scanPackageLI继续解析获得的package。重载函数会调用scanPackageDirtyLI来分析package。

这一步会为package分配id,当然该package可能使用的是一个共享id。首先,每个package信息会被保存在一个PackageSetting对象中,然后将其放到mPackages这个HashMap中。

因为在前面步骤中已经从上一次安装的应用信息中读取了一些package信息,所以需要先在HashMap中确定一下这个新解析的应用是否是已经在mPackages中。如果已经存在,说明这是一个老应用,就直接将PackageSetting 返回。如果不在,则新建一个PackageSetting,下面开始为它分配uid:
1. 使用共享id。将pkg的uid设置为想要共享的uid。
2. 使用原来的uid。禁用的系统程序使用它原来的uid。
3. 使用新的uid。创建一个新的uid给pkg。
4. 使用first application uid。所有应用使用同一个uid。

下面来看一下如何为新的应用分配新uid。mUserIds管理了所有的分配给用户的uid,这里会在规定的范围内找到一个uid分配。

到此为止,所有的安装了应用都存在PackageManagerService的mPackages中,下面需要依次为这些应用分配权限。在设备/system/etc/permissions/platform.xml文件中,表述了该设备的资源访问权限列表。如:

    <permission name="android.permission.BLUETOOTH" >
        <group gid="net_bt" />
    permission

gid指明了该资源权限所在的用户组,当然一个权限可以拥有多个用户组。应用获取权限就是加入相应的用户组。Package的申请的权限已经保存到它对应的PackageSetting对象中,如果当前package使用的是共享uid,则它获得权限与它共享的linux用户的资源权限相同。对于有自己独立uid的应用,它会首先获得一组默认的用户权限,这是所有应用都具有的基本权限。然后会一一验证应用申请的权限是否合法,如果合法,则会为其增加该项权限。

现在,应用已经被安装、分配uid和分配权限,接下来需要将这些应用的信息保存下来以备下次使用。保存的位置就是/data/system/packages.xml。注意,在保存uid时,userId和sharedUserId只能有一个。

Android系统就是通过用户id和用户组id来限制应用的资源访问权限,防止破坏其它应用的数据。分配的uid和gid会在创建应用进程时使用,是该进程在特定的用户组下运行。

你可能感兴趣的:(AOSP,源码,Android)