简单分析 mPM.getPackageInfo() 调用流程

编程入门 行业动态 更新时间:2024-10-20 05:28:17

上文分析了 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 库里执行。











更多推荐

简单分析 mPM.getPackageInfo() 调用流程

本文发布于:2023-06-14 09:45:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1462329.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:流程   简单   mPM   getPackageInfo

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!