系列笔记9、解释器模式-PackageParser & PMS

UML类图

《系列笔记9、解释器模式-PackageParser & PMS》

解释器模式应用相当广泛,我们使用解释器模式对“m+n+p”这个表达式进行解释,那么代表数字的m、n和p就可以看成终结符号,而“+”这个运算符号可以当做非终结符号。 
TerminalExpression:终结符表达式,实现文法中与终结符有关的解释操作。文法中每个终结符都有一个具体的终结表达式与之对应。 
NonterminalExpression :非终结符表达式,实现文法中与非终结符有关的解释操作。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。

抽象的算数运算解释器

public abstract class ArithemticExpression {
    /** * 抽象的解析方法 * 具体的解析逻辑由具体的子类实现 * * @return 解析得到具体的值 */
    public abstract int interpreter();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

数字解释器

public class NumExpression extends ArithemticExpression{

    private int num;

    public NumExpression(int num){
        this.num = num;
    }

    @Override
    public int interpreter() {
        return num;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

运算符号解释器

public abstract class OperatorExpression extends ArithemticExpression{

    protected ArithemticExpression exp1, exp2;

    public OperatorExpression(ArithemticExpression exp1, ArithemticExpression exp2){
        this.exp1 = exp1;
        this.exp2 = exp2;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

具体的加法运算符解释器

public class AdditionExpression extends OperatorExpression{

    public AdditionExpression(ArithemticExpression exp1,
            ArithemticExpression exp2) {
        super(exp1, exp2);
    }

    @Override
    public int interpreter() {
        return exp1.interpreter() + exp2.interpreter();
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

处理解释器

public class Calculator {

    //声明一个Stack栈储存并操作所有相关的解释器
    private Stack<ArithemticExpression> mExpStack = new Stack<ArithemticExpression>();

    public Calculator(String expression){
        //声明两个ArithemticExpression类型的临时变量,储存运算符左右两边的数字解释器
        ArithemticExpression exp1,exp2;

        //根据空格分割表达式字符串(比如1 + 2 + 3 + 4)
        String[] elements = expression.split(" ");

        /* * 遍历表达式元素数组 */
        for(int i = 0; i < elements.length; i++){
            /* * 判断运算符号 */
            switch (elements[i].charAt(0)) {
            case '+':
                //如果是加号,则将栈中的解释器弹出作为运算符号左边的解释器
                exp1 = mExpStack.pop();
                //同时将运算符号数组下标的下一个元素构造为一个数字解释器
                exp2 = new NumExpression(Integer.parseInt(elements[++i]));
                //通过上面的两个数字解释器构造加法运算解释器 
                mExpStack.push(new AdditionExpression(exp1, exp2));
                break;

            default:
                /* * 如果为数字,直接构造数字解释器并压入栈 */
                mExpStack.push(new NumExpression(Integer.valueOf(elements[i])));
                break;
            }
        }
    }

    /** * 计算结果 * * @return 最终的计算结果 */
    public int calculate(){
        return mExpStack.pop().interpreter();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

调用

public class Client {
    public static void main(String[] args) {
        Calculator c = new Calculator("22 + 553 + 83 + 5");
        System.out.println("计算结果:"+c.calculate());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

结果:

计算结果:663
  • 1
  • 1

如果相加如减法的操作,在Calculator中加入相应判断即可:

public class SubtractionExpression extends OperatorExpression{

    public SubtractionExpression(ArithemticExpression exp1,
            ArithemticExpression exp2) {
        super(exp1, exp2);
    }

    @Override
    public int interpreter() {
        return exp1.interpreter() - exp2.interpreter();
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

Calculator中加入:

case '-':
    exp1 = mExpStack.pop();
    exp2 = new NumExpression(Integer.parseInt(elements[++i]));
    mExpStack.push(new SubtractionExpression(exp1, exp2));
    break;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

从上面可以看出解释器模式很灵活,他将复杂问题可以简单化、模块化、分离实现、解释执行。


一、PackageParser

解析AndroidManifest.xml文件用到的是PackageParser类。

PackageParser.java

public class PackageParser {

  public final static class Package {…}

  public final static class Permission extends Component<IntentInfo> {…}

  public final static class PermissionGroup extends Component<IntentInfo> {…}

  public final static class ActivityIntentInfo extends IntentInfo {…}

  public final static class Activity extends Component<ActivityIntentInfo> {…}

  public final static class Service extends Component<ServiceIntentInfo> {…}

  }

Android中,某个apk文件的解析会用到PackageManagerService的scanPackageLI()方法,这是一个重载方法,在解析某个文件先调用第一种实现解析apk文件,再调用第二种实现将解析后的信息保存至PMS

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 {

            //解析apk文件

            pkg = pp.parsePackage(scanFile, parseFlags);

        } catch (PackageParserException e) {

            throw PackageManagerException.from(e);

        }

        …

        //调用第二种scanPackageLI的实现将解析后的信息保存至PMS

        PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags

                | SCAN_UPDATE_SIGNATURE, currentTime, user);

        …

       return scannedPkg;

    }

    private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,

            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {

  我们来看PackageParser调用parsePackage(scanFile, parseFlags)解析apk文件是怎样一个过程。

 PackageParser.java

 public Package parsePackage(File packageFile, int flags) throws PackageParserException {

        if (packageFile.isDirectory()) {

            return parseClusterPackage(packageFile, flags);

        } else {

            return parseMonolithicPackage(packageFile, flags);

        }

    }

 public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {

        if (mOnlyCoreApps) {

            final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);

            if (!lite.coreApp) {

                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,

                        “Not a coreApp: ” + apkFile);

            }

        }

        final AssetManager assets = new AssetManager();

        try {

            final Package pkg = parseBaseApk(apkFile, assets, flags);

            pkg.codePath = apkFile.getAbsolutePath();

            return pkg;

        } finally {

            IoUtils.closeQuietly(assets);

        }

    }

    private Package parseBaseApk(File apkFile, AssetManager assets, int flags)

            throws PackageParserException {

        final String apkPath = apkFile.getAbsolutePath();

        String volumeUuid = null;

        if (apkPath.startsWith(MNT_EXPAND)) {

            final int end = apkPath.indexOf(‘/’, MNT_EXPAND.length());

            volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);

        }

        mParseError = PackageManager.INSTALL_SUCCEEDED;

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

            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

            final String[] outError = new String[1];

            //解析

            final Package pkg = parseBaseApk(res, parser, flags, outError);

          

            pkg.volumeUuid = volumeUuid;

            pkg.baseCodePath = apkPath;

            pkg.mSignatures = null;

            …

            return pkg;   

    }

     //具体针对各个标签的解析过程

     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;

        mParseInstrumentationArgs = null;

        mParseActivityArgs = null;

        mParseServiceArgs = null;

       

        final Package pkg = new Package(pkgName);

       

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

        pkg.baseRevisionCode = sa.getInteger(

                com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);

        pkg.mVersionName = sa.getNonConfigurationString(

                com.android.internal.R.styleable.AndroidManifest_versionName, 0);

        …

        sa.recycle();

        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标签

                if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {

                    return null;

                }

            } else if (tagName.equals(“overlay”)) {

                pkg.mTrustedOverlay = trustedOverlay;

                sa = res.obtainAttributes(attrs,

                        com.android.internal.R.styleable.AndroidManifestResourceOverlay);

                pkg.mOverlayTarget = sa.getString(

                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);

                pkg.mOverlayPriority = sa.getInt(

                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,

                        -1);

                sa.recycle();

                if (pkg.mOverlayTarget == null) {

                    outError[0] = “<overlay> does not specify a target package”;

                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;

                    return null;

                }

                if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {

                    outError[0] = “<overlay> priority must be between 0 and 9999”;

                    mParseError =

                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;

                    return null;

                }

                XmlUtils.skipCurrentTag(parser);

            } else if (tagName.equals(“key-sets”)) {

                if (!parseKeySets(pkg, res, parser, attrs, outError)) {

                    return null;

                }

            } else if (tagName.equals(“permission-group”)) {

                if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) {

                    return null;

                }

            } else if (tagName.equals(“permission”)) {

                if (parsePermission(pkg, res, parser, attrs, outError) == null) {

                    return null;

                }

            } else if (tagName.equals(“permission-tree”)) {

                if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {

                    return null;

                }

            } else if (tagName.equals(“uses-permission”)) {

                if (!parseUsesPermission(pkg, res, parser, attrs)) {

                    return null;

           

        

             

            } else if (tagName.equals(“instrumentation”)) {

                if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) {

                    return null;

                }

        //省略对多行标签的解析

        …

        return pkg;

    }

下面来看看解析”application”标签。

 PackageParser.java

private boolean (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();

            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”)) {

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

    }

可以看到是对application的子节点标签解析,下面来看看解析”activity”标签的过程。

 PackageParser.java

   private Activity parseActivity(Package owner, Resources res,

            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,

            boolean receiver, boolean hardwareAccelerated)

            throws XmlPullParserException, IOException {

    TypedArray sa = res.obtainAttributes(attrs, R.styleable.AndroidManifestActivity);

    Activity a = new Activity(mParseActivityArgs, new ActivityInfo());

        a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);

        a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,

                a.info.applicationInfo.uiOptions);

        str = sa.getNonConfigurationString(

                R.styleable.AndroidManifestActivity_taskAffinity,

                Configuration.NATIVE_CONFIG_VERSION);

        a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,

                owner.applicationInfo.taskAffinity, str, outError);

        …

        //只针对”activity”的解析

        if (!receiver) {

         a.info.launchMode = sa.getInt(

                    R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);

        …

        }

        //只针对”receiver”的解析

        if (receiver && (owner.applicationInfo.privateFlags

                &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {

            // A heavy-weight application can not have receives in its main process

            // We can do direct compare because we intern all strings.

            if (a.info.processName == owner.packageName) {

                outError[0] = “Heavy-weight applications can not have receivers in main process”;

            }

        }

        

 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT

               && (type != XmlPullParser.END_TAG

                       || parser.getDepth() > outerDepth)) {

            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {

                continue;

            }

            if (parser.getName().equals(“intent-filter”)) {

                ActivityIntentInfo intent = new ActivityIntentInfo(a);

                if (!parseIntent(res, parser, attrs, true, true, intent, outError)) {

                    return null;

                }

                if (intent.countActions() == 0) {

                    Slog.w(TAG, “No actions in intent filter at “

                            + mArchiveSourcePath + ” “

                            + parser.getPositionDescription());

                } else {

                    a.intents.add(intent);

                }

            } else if (!receiver && parser.getName().equals(“preferred”)) {

                ActivityIntentInfo intent = new ActivityIntentInfo(a);

                if (!parseIntent(res, parser, attrs, false, false, intent, outError)) {

                    return null;

                }

                if (intent.countActions() == 0) {

                    Slog.w(TAG, “No actions in preferred at “

                            + mArchiveSourcePath + ” “

                            + parser.getPositionDescription());

                } else {

                    if (owner.preferredActivityFilters == null) {

                        owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();

                    }

                    owner.preferredActivityFilters.add(intent);

                }

            } else if (parser.getName().equals(“meta-data”)) {

                if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,

                        outError)) == null) {

                    return null;

                }

            } else {

        …

        return a;

    }

 要说明的是parseActiviy解析Activity,也解析Broadcast广播标签。通过这样的遍历,整个AndroidManifast.xml文件就完成了解析,并把最终的结果存在了Package中。

二、PMS

作为Android在java层的服务之一,PMS与所有其他的服务一样都是由SystemServer启动

SystemServer.java
package com.android.server;
public final class SystemServer {
 private PackageManagerService mPackageManagerService;
   
    private void startBootstrapServices() {
        …
        mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        …
    }
}

PackageManagerService通过静态main方法,返回一个实例化对象。
PackageManagerService.java
package com.android.server.pm;
public class PackageManagerService extends IPackageManager.Stub {

 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                SystemClock.uptimeMillis());

public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
    
   public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        ServiceManager.addService(“package”, m);
        return m;
    }

}

android.os.ServiceManager是Binder进程间通信机制的守护进程,目的是管理Android系统里的Binder对象。
看看初始化PackageManagerService时在构造函数里做了什么工作
PackageManagerService.java
    public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        //向事件日志写入事件,标识PackageManagerService启动
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                SystemClock.uptimeMillis());
        //检查sdk版本
        if (mSdkVersion <= 0) {
            Slog.w(TAG, “**** ro.build.version.sdk not set!”);
        }

        mContext = context;
        //开机模式是否为工厂模式
        mFactoryTest = factoryTest;
        //是否仅启动内核
        mOnlyCore = onlyCore;
        //如果编译版本为eng则不需要dex优化
        mLazyDexOpt = “eng”.equals(SystemProperties.get(“ro.build.type”));
        //构造DisplayMetrics对象以便获取尺寸数据
        mMetrics = new DisplayMetrics();
        //构造Settings对象存储系统运行时的设置信息
        mSettings = new Settings(mPackages);
        //添加一些用户uid(做什么用的?)
        mSettings.addSharedUserLPw(“android.uid.system”, Process.SYSTEM_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw(“android.uid.phone”, RADIO_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw(“android.uid.log”, LOG_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw(“android.uid.nfc”, NFC_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw(“android.uid.bluetooth”, BLUETOOTH_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw(“android.uid.shell”, SHELL_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

        // TODO: add a property to control this?
        long dexOptLRUThresholdInMinutes;
        if (mLazyDexOpt) {
            dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds.
        } else {
            dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users.
        }
        mDexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000;
        //判断是否在不同的进程
        String separateProcesses = SystemProperties.get(“debug.separate_processes”);
        if (separateProcesses != null && separateProcesses.length() > 0) {
            if (“*”.equals(separateProcesses)) {
                mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
                mSeparateProcesses = null;
                Slog.w(TAG, “Running with debug.separate_processes: * (ALL)”);
            } else {
                mDefParseFlags = 0;
                mSeparateProcesses = separateProcesses.split(“,”);
                Slog.w(TAG, “Running with debug.separate_processes: “
                        + separateProcesses);
            }
        } else {
            mDefParseFlags = 0;
            mSeparateProcesses = null;
        }
        //Installer由SystemServer构造,这里通过该对象负责与底层通信,进行具体的安装卸载等操作
        mInstaller = installer;
        mPackageDexOptimizer = new PackageDexOptimizer(this);
        mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());

        mOnPermissionChangeListeners = new OnPermissionChangeListeners(
                FgThread.get().getLooper());
        //测量显示对象
        getDefaultDisplayMetrics(context, mMetrics);

        SystemConfig systemConfig = SystemConfig.getInstance();
        mGlobalGids = systemConfig.getGlobalGids();
        mSystemPermissions = systemConfig.getSystemPermissions();
        mAvailableFeatures = systemConfig.getAvailableFeatures();

        synchronized (mInstallLock) {
        // writer
        synchronized (mPackages) {
            //启动消息处理线程
            mHandlerThread = new ServiceThread(TAG,
                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
            mHandlerThread.start();
            //通过消息处理线程的Looper对象构造一个处理消息的Handler对象
            mHandler = new PackageHandler(mHandlerThread.getLooper());
            //使用看门狗监测当前消息处理线程
            Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
            //获取/data目录下的几个子目录
            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”);
            //构造UserManagerService对象
            sUserManager = new UserManagerService(context, this,
                    mInstallLock, mPackages);

            // Propagate permission configuration in to package manager.
            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.setGids(perm.gids, perm.perUser);
                }
            }

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

            mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();

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

            String customResolverActivity = Resources.getSystem().getString(
                    R.string.config_customResolverActivity);
            if (TextUtils.isEmpty(customResolverActivity)) {
                customResolverActivity = null;
            } else {
                mCustomResolverComponentName = ComponentName.unflattenFromString(
                        customResolverActivity);
            }

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

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

            final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();
            final String[] dexCodeInstructionSets =
                    getDexCodeInstructionSets(
                            allInstructionSets.toArray(new String[allInstructionSets.size()]));

            /**
             * Ensure all external libraries have had dexopt run on them.
             */
            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 {
                            int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
                            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
                                alreadyDexOpted.add(lib);
                                mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded);
                            }
                        } 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”);

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

            /**
             * 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 {
                            int dexoptNeeded = DexFile.getDexOptNeeded(path, null, dexCodeInstructionSet, false);
                            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
                                mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded);
                            }
                        } catch (FileNotFoundException e) {
                            Slog.w(TAG, “Jar not found: ” + path);
                        } catch (IOException e) {
                            Slog.w(TAG, “Exception reading jar: ” + path, e);
                        }
                    }
                }
            }

            final VersionInfo ver = mSettings.getInternalVersion();
            mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
            // when upgrading from pre-M, promote system app permissions from install to runtime
            mPromoteSystemApps =
                    mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;

            // save off the names of pre-existing system packages prior to scanning; we don’t
            // want to automatically grant runtime permissions for new system apps
            if (mPromoteSystemApps) {
                Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
                while (pkgSettingIter.hasNext()) {
                    PackageSetting ps = pkgSettingIter.next();
                    if (isSystemApp(ps)) {
                        mExistingSystemPackages.add(ps.name);
                    }
                }
            }

            // 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<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
            if (!mOnlyCore) {
                Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
                while (psit.hasNext()) {
                    PackageSetting ps = psit.next();

                    /*
                     * If this is not a system app, it can’t be a
                     * disable system app.
                     */
                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                        continue;
                    }

                    /*
                     * If the package is scanned, it’s not erased.
                     */
                    final PackageParser.Package scannedPkg = mPackages.get(ps.name);
                    if (scannedPkg != null) {
                        /*
                         * If the system app is both scanned and in the
                         * disabled packages list, then it must have been
                         * added via OTA. Remove it from the currently
                         * scanned package so the previously user-installed
                         * application can be scanned.
                         */
                        if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
                            logCriticalInfo(Log.WARN, “Expecting better updated system app for “
                                    + ps.name + “; removing system app.  Last known codePath=”
                                    + ps.codePathString + “, installStatus=” + ps.installStatus
                                    + “, versionCode=” + ps.versionCode + “; scanned versionCode=”
                                    + scannedPkg.mVersionCode);
                            removePackageLI(ps, true);
                            mExpectingBetter.put(ps.name, ps.codePath);
                        }

                        continue;
                    }

                    if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
                        psit.remove();
                        logCriticalInfo(Log.WARN, “System package ” + ps.name
                                + ” no longer exists; wiping its data”);
                        removeDataDirsLI(null, ps.name);
                    } else {
                        final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
                        if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
                            possiblyDeletedUpdatedSystemApps.add(ps.name);
                        }
                    }
                }
            }

            //look for any incomplete package installations
            ArrayList<PackageSetting> 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();

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

                /**
                 * Remove disable package settings for any updated system
                 * apps that were removed via an OTA. If they’re not a
                 * previously-updated app, remove them completely.
                 * Otherwise, just revoke their system-level permissions.
                 */
                for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
                    PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
                    mSettings.removeDisabledSystemPackageLPw(deletedAppName);

                    String msg;
                    if (deletedPkg == null) {
                        msg = “Updated system package ” + deletedAppName
                                + ” no longer exists; wiping its data”;
                        removeDataDirsLI(null, deletedAppName);
                    } else {
                        msg = “Updated system app + ” + deletedAppName
                                + ” no longer present; removing system privileges for “
                                + deletedAppName;

                        deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;

                        PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
                        deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
                    }
                    logCriticalInfo(Log.WARN, msg);
                }

                /**
                 * Make sure all system apps that we expected to appear on
                 * the userdata partition actually showed up. If they never
                 * appeared, crawl back and revive the system version.
                 */
                for (int i = 0; i < mExpectingBetter.size(); i++) {
                    final String packageName = mExpectingBetter.keyAt(i);
                    if (!mPackages.containsKey(packageName)) {
                        final File scanFile = mExpectingBetter.valueAt(i);

                        logCriticalInfo(Log.WARN, “Expected better ” + packageName
                                + ” but never showed up; reverting to system”);

                        final int reparseFlags;
                        if (FileUtils.contains(privilegedAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR
                                    | PackageParser.PARSE_IS_PRIVILEGED;
                        } else if (FileUtils.contains(systemAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else if (FileUtils.contains(vendorAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else if (FileUtils.contains(oemAppDir, scanFile)) {
                            reparseFlags = PackageParser.PARSE_IS_SYSTEM
                                    | PackageParser.PARSE_IS_SYSTEM_DIR;
                        } else {
                            Slog.e(TAG, “Ignoring unexpected fallback path ” + scanFile);
                            continue;
                        }

                        mSettings.enableSystemPackageLPw(packageName);

                        try {
                            scanPackageLI(scanFile, reparseFlags, scanFlags, 0, null);
                        } catch (PackageManagerException e) {
                            Slog.e(TAG, “Failed to parse original system package: “
                                    + e.getMessage());
                        }
                    }
                }
            }
            mExpectingBetter.clear();

            // Now that we know all of the shared libraries, update all clients to have
            // the correct library paths.
            updateAllSharedLibrariesLPw();

            for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
                // NOTE: We ignore potential failures here during a system scan (like
                // the rest of the commands above) because there’s precious little we
                // can do about it. A settings error is reported, though.
                adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */,
                        false /* force dexopt */, false /* defer dexopt */);
            }

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

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                    SystemClock.uptimeMillis());
            Slog.i(TAG, “Time to scan packages: “
                    + ((SystemClock.uptimeMillis()-startTime)/1000f)
                    + ” seconds”);

            // 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;
            }
            updatePermissionsLPw(null, null, updateFlags);
            ver.sdkVersion = mSdkVersion;
            // clear only after permissions have been updated
            mExistingSystemPackages.clear();
            mPromoteSystemApps = false;

            // 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.applyDefaultPreferredAppsLPw(this, UserHandle.USER_OWNER);
                applyFactoryDefaultBrowserLPw(UserHandle.USER_OWNER);
                primeDomainVerificationsLPw(UserHandle.USER_OWNER);
            }

            // If this is first boot after an OTA, and a normal boot, then
            // we need to clear code cache directories.
            if (mIsUpgrade && !onlyCore) {
                Slog.i(TAG, “Build fingerprint changed; clearing code caches”);
                for (int i = 0; i < mSettings.mPackages.size(); i++) {
                    final PackageSetting ps = mSettings.mPackages.valueAt(i);
                    if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
                        deleteCodeCacheDirsLI(ps.volumeUuid, ps.name);
                    }
                }
                ver.fingerprint = Build.FINGERPRINT;
            }

            checkDefaultBrowser();

            // All the changes are done during package scanning.
            ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;

            // can downgrade to reader
            mSettings.writeLPr();

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                    SystemClock.uptimeMillis());

            mRequiredVerifierPackage = getRequiredVerifierLPr();
            mRequiredInstallerPackage = getRequiredInstallerLPr();

            mInstallerService = new PackageInstallerService(context, this);

            mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
            mIntentFilterVerifier = new IntentVerifierProxy(mContext,
                    mIntentFilterVerifierComponent);

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

  
PMS的作用主要是管理应用程序包。

 

    原文作者:caidai1989
    原文地址: https://blog.csdn.net/caidai1989/article/details/68066572
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞