美文网首页
获取PackageManagerService

获取PackageManagerService

作者: 留给时光吧 | 来源:发表于2017-04-17 16:45 被阅读0次

    最近项目中有个需求需要在PackageManagerService添加一个方法,然后进行调用。
    我们知道PackageManagerService作为系统的核心服务,由SystemServer在系统启动时创建,我们先看看SystemServer是如何创建的:

    mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
    

    原来是通过一个静态方法创建的,再看看这个静态方法:

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

    这个方法比较简单,就是new一个PackageManagerService的实例,然后向ServiceManager注册。既然注册到ServiceManager里面,我们在获取PackageManagerService时就不必new或者调用那个main方法,因为PackageManagerService在构造函数执行了大量逻辑。
    在ServiceManager中既然有addService方法,那么就应该有getService方法。(整个ServiceManager代码逻辑比较简单,就是维护了一个HashMap,用于保存各项系统服务)

    public static IBinder getService(String name) {
            try {
                IBinder service = sCache.get(name);
                if (service != null) {
                    return service;
                } else {
                    return getIServiceManager().getService(name);
                }
            } catch (RemoteException e) {
                Log.e(TAG, "error in getService", e);
            }
            return null;
        }
    

    看到这里我们是不是就可以这样获取

    (PackageManagerService)ServiceManager.getService("package")
    

    然而在编译时报如下错误

    pm.jpg

    看来是PackageManagerService所在的这个包无法访问。
    是不是在外部就无法获取了呢。这时想到,我们经常在Acticity中通过getPackageManager获取一个PackageManager,而PackageManager其实就是IPackageManager的一个客户端代理。于是,我们去看看getPackageManager是如何实现的。

    在ContextImpl中:

    @Override
        public PackageManager getPackageManager() {
            if (mPackageManager != null) {
                return mPackageManager;
            }
    
            IPackageManager pm = ActivityThread.getPackageManager();
            if (pm != null) {
                // Doesn't matter if we make more than one instance.
                return (mPackageManager = new ApplicationPackageManager(this, pm));
            }
    
            return null;
        }
    

    这里调用了ActivityThread的一个也叫getPackageManager的方法,继续看下去:
    在ActivityThread中

     public static IPackageManager getPackageManager() {
            if (sPackageManager != null) {
                //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
                return sPackageManager;
            }
            IBinder b = ServiceManager.getService("package");
            //Slog.v("PackageManager", "default service binder = " + b);
            sPackageManager = IPackageManager.Stub.asInterface(b);
            //Slog.v("PackageManager", "default service = " + sPackageManager);
            return sPackageManager;
        }
    

    这里就很清晰了,也是通过ServiceManager.getService获取,然后通过这样的方法IPackageManager.Stub.asInterface(b);来获取到PackageManagerService的。
    这样就比较简单了,我们就可以这样获取:

    IPackageManager.Stub.asInterface(ServiceManager.getService("package")).***
    

    类似的,我们也可以通过这种形式获取一些其他的系统服务,比如:

    ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)).endCall();
    

    相关文章

      网友评论

          本文标题:获取PackageManagerService

          本文链接:https://www.haomeiwen.com/subject/igvtzttx.html