获取PackageManagerService

最近项目中有个需求需要在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")

然而在编译时报如下错误

《获取PackageManagerService》 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();
    原文作者:留给时光吧
    原文地址: https://www.jianshu.com/p/c915c7acd51b
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞