简单分析 mPM.getPackageInfo() 调用流程
来源:互联网 发布:淘宝手机端卖家中心 编辑:程序博客网 时间:2024/06/08 15:08
上文分析了 mContext.getPackageManager() 调用流程,本文再简单说下 mPM.getPacakgeInfo()调用流程。
这里就涉及到了 binder 知识。
mPM 是 ApplicationPackageManager.java 类型,此类封装了 IPackageManager 的实现。
@Override public PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException { return getPackageInfoAsUser(packageName, flags, mContext.getUserId()); } @Override public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId) throws NameNotFoundException { try { PackageInfo pi = mPM.getPackageInfo(packageName, flags, userId); if (pi != null) { return pi; } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } throw new NameNotFoundException(packageName); }
这里我们就要分析 IPacakgeManager.java,这个java文件是编译时转好 AIDL 文件生成的,这个AIDL文件位置:
base/core/java/android/content/pm/IPackageManager.aidl
/**
* See {@link PackageManager} for documentation on most of the APIs
* here.
*
* {@hide}
*/
interface IPackageManager {
void checkPackageStartable(String packageName, int userId);
boolean isPackageAvailable(String packageName, int userId);
PackageInfo getPackageInfo(String packageName, int flags, int userId);
.........................
说白了,aidl 文件顾名思义就是定义接口描述:接口名称,接口参数,返回值类型。跨进程通讯双方遵循这个格式传递数据。
Android在编译代码的时候转化未 IPackageManager.java文件:
@Override public android.content.pm.PackageInfo getPackageInfo(java.lang.String packageName, int flags, int userId) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();android.content.pm.PackageInfo _result;try {_data.writeInterfaceToken(DESCRIPTOR);_data.writeString(packageName);_data.writeInt(flags);_data.writeInt(userId);mRemote.transact(Stub.TRANSACTION_getPackageInfo, _data, _reply, 0);_reply.readException();if ((0!=_reply.readInt())) {_result = android.content.pm.PackageInfo.CREATOR.createFromParcel(_reply);}else {_result = null;}}finally {_reply.recycle();_data.recycle();}return _result;}从上面自动生成的代码可以看出,getPackageInfo 函数讲传入参数打包成 Parcel请求,作为一个业务调用 mRemote.transact 函数发送到系统进程。
这个 mRemote 是个代理类,在 IPacakgeManager.java 实例化时就被创建:
/** * Cast an IBinder object into an android.content.pm.IPackageManager interface, * generating a proxy if needed. */public static android.content.pm.IPackageManager asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof android.content.pm.IPackageManager))) {return ((android.content.pm.IPackageManager)iin);}return new android.content.pm.IPackageManager.Stub.Proxy(obj);}
..........
private static class Proxy implements android.content.pm.IPackageManager{private android.os.IBinder mRemote;Proxy(android.os.IBinder remote){mRemote = remote;}
.............这个 transact 函数是在 frameworks/base/core/java/android/os/Binder.java 中由 BinderProxy 类实现的:
final class BinderProxy implements IBinder { public native boolean pingBinder(); public native boolean isBinderAlive(); public IInterface queryLocalInterface(String descriptor) { return null; } public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { Binder.checkParcel(this, code, data, "Unreasonably large binder buffer"); if (Binder.isTracingEnabled()) { Binder.getTransactionTracker().addTrace(); } return transactNative(code, data, reply, flags); }从前面 IPackageManager 从 ActivityThread.java 中获取到的,这个从 ServiceManager 获取的 IBinder 接口来自于 PackageManagerService.java
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public class PackageManagerService extends IPackageManager.Stub {
....
public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { // Self-check for initial settings. PackageManagerServiceCompilerMapping.checkProperties(); PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore); m.enableSystemUserPackages(); ServiceManager.addService("package", m); return m; }
从IPackageManager.java我们可以看到 IPackageManager.Stub继承自 android.os.Binder。
所以那个 transact 函数最终掉一个到 Binder.java 里的实现,最终走到 c 语言 so 库里执行。