最近项目中有个需求需要在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();
网友评论