Android四大组件系列9 ContentProvider原理
发布日期:2021-05-06 20:19:23 浏览次数:10 分类:技术文章

本文共 40214 字,大约阅读时间需要 134 分钟。

一 概述

ContentProvider 用于提供数据的统一访问格式,封装底层的具体实现。对于数据的使用者来说,无需知晓数据的来源是数据库、文件,或者网络,只需简单地使用 ContentProvider 提供的数据操作接口:增(insert)、删(delete)、改(update)、查(query) 即可,非常方便。在 Android 系统中通讯录或者短信的数据,都是以 ContentProvider 的形式提供的,ContentProvider 本质上就是是把数据存储在 SQLite 数据库中,另外 ContentProvider 读取数据时使用了匿名共享内存(ASM),ASM 实质上也是通过 Binder 通信的。

ContentProvider 的 onCreate 先于 Application 的 onCreate 启动,在应用启动的时候,会通过 ActivityThread 的 attach 方法,通过远程调用 AMS 的 attachApplication 来将 ApplicationThread 传递给 AMS,同时在该方法中会调用 ApplicationThread 的 bindApplication 方法,同样也是跨进程的。该方法最终跳转到 ActivityThread 中运行,具体为 handleBindApplication,进而调用 installContentProviders 完成 ContentProvider 的加载。

外界无法直接访问 ContentProvider,只能通过 AMS 根据 URI 来获取对应的 ContentProvider 的 Binder 接口 IContentProvider,然后再访问相应数据。

ContentProvider 可以做成多实例,通过属性控制,但是现实中很少采用因为浪费开销。外界访问其增删改查的任何一个方法都会导致 ContentProvider 的创建,并且拉起进程。

比如通过 query 方法启动 ContentProvider:

  1. 通过 acquireProvider 来获取 IContentProvider 对象
  2. 先检查本端 ActivityThread 中是否存在 ContentProvider,如果存在就直接返回(返回的是 IContentProvider 客户端接口对象)。如果没有,就通过远程 AMS.getContentProvider 方法
  3. ContentProvider 的启动伴随着进程的启动,启动进程靠的是 AMS 的 startProcessLocked,新进程启动后其入口方法为 ActivityThread.main() 方法,然后在 attach 方法中通过 attachApplication方法将ApplicationThread作为参数传递给AMS
  4. AMS 的方法中又调用了ApplicationThread.bindApplication
  5. ActivityThread 的 bindApplication 发送 BIND_APPLICATION 消息给 mH 使得 ActivityThread 完成一系列工作,包括(按步骤顺序):
  • 创建 ContextImpl 和 instrumrent
  • 创建 Application 对象
  • 启动当前进程的 ContentProvider 并调用其 onCreate 方法,将创建好的 Contentprovider 保存在 AMS 中的 providerMap 中,这样外部调用者就能直接从 AMS 中获取 ContentProvider 了,然后调用其onCreate 方法
  • 调用 Application 的 onCreate 方法

上述四个步骤之后,外部就能在 AMS 中拿到 ContentProvider 访问其接口了,但拿到的其实是 Binder 类型对象 IContentProvider。其具体实现是 ContentProvider.Transport,所以外界调用 query 方法时候,是通过调用 ContentProvider.Transport 中的 query 方法,其远程调用 ContentProvider.query 方法,结果通过 Binder 返回给调用者,其它方法调用类似。

涉及代码:

frameworks/base/core/java/android/app/ContextImpl.javaframeworks/base/core/java/android/app/ActivityThread.javaframeworks/base/core/java/android/content/ContentProvider.javaframeworks/base/core/java/android/content/ContentProviderNative.javaframeworks/base/core/java/android/app/ContentProviderHolder.javaframeworks/base/core/java/android/content/ContentResolver.javaframeworks/base/core/java/android/app/IActivityManager.aidlframeworks/base/core/java/android/os/ICancellationSignal.aidlframeworks/base/core/java/android/database/BulkCursorToCursorAdaptor.javaframeworks/base/core/java/android/database/AbstractWindowedCursor.javaframeworks/base/core/java/android/database/AbstractCursor.javaframeworks/base/core/java/android/database/CursorWindow.javaframeworks/base/core/jni/android_database_CursorWindow.cppframeworks/base/services/core/java/com/android/server/am/ActivityManagerService.javaframeworks/base/services/core/java/com/android/server/pm/PackageManagerService.javaframeworks/base/services/core/java/com/android/server/pm/ComponentResolver.javapackages/providers/ContactsProvider/src/com/android/providers/contacts/ContactsProvider2.java

二 分析流程

通过 ContentProvider 操作手机通信录的 demo 示例:

// 查询联系人信息public void getContactInfo() {       ContentResolver contentResolver = getContext().getContentResolver();    Uri uri = Uri.parse("content://com.android.contacts/contacts");    Cursor cursor = contentResolver.query(uri, null, null, null, null);    while(cursor.moveToNext()){           // 获取联系人姓名        String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));        String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));                 // 获取联系人手机号码        Cursor phones = contentResolver.query(		        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,		        null, 		        ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ contactId,                 null, null);         while (phones.moveToNext()) {               String phone = phones.getString(phones.getColumnIndex("data1"));        }             // 获取联系人Email        Cursor emails = contentResolver.query(		        ContactsContract.CommonDataKinds.Email.CONTENT_URI,                 null,                 ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = " + contactId,                 null, null);        while (emails.moveToNext()) {               String email = emails.getString(emails.getColumnIndex("data1"));        }    }}// 添加联系人信息public void addContactInfo() {       ContentValues values = new ContentValues();    // 首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获取系统返回的rawContactId    Uri rawContactUri = getContext().getContentResolver().insert(RawContacts.CONTENT_URI, values);    long rawContactId = ContentUris.parseId(rawContactUri);     // 往data表中插入联系人信息    values.clear();    values.put(Data.RAW_CONTACT_ID, rawContactId);    values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);    // 名字    values.put(StructuredName.GIVEN_NAME, "zhangsan");    // 手机号码    values.put(Phone.NUMBER, "5554");    values.put(Phone.TYPE, Phone.TYPE_MOBILE); 	    // Email 	    values.put(Email.DATA, "ljq218@126.com");    values.put(Email.TYPE, Email.TYPE_WORK);	getContext().getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);}

本文以获取联系人姓名(即 query 操作) 为例进行分析。

2.1 ContextImpl.getContentResolver

frameworks/base/core/java/android/app/ContextImpl.java

private final ApplicationContentResolver mContentResolver;private ContextImpl(@Nullable ContextImpl container,        @NonNull ActivityThread mainThread, @NonNull LoadedApk packageInfo,        @Nullable String splitName, @Nullable IBinder activityToken, ......) {       ...    mContentResolver = new ApplicationContentResolver(this, mainThread);} @Overridepublic ContentResolver getContentResolver() {       return mContentResolver;}

2.2 ApplicationContentResolver

frameworks/base/core/java/android/app/ContextImpl.java

private static final class ApplicationContentResolver extends ContentResolver {       private final ActivityThread mMainThread;     public ApplicationContentResolver(Context context,            ActivityThread mainThread) {           super(context);        mMainThread = Preconditions.checkNotNull(mainThread);    }     @Override    protected IContentProvider acquireProvider(Context context, String auth) {           return mMainThread.acquireProvider(context,                ContentProvider.getAuthorityWithoutUserId(auth),                resolveUserIdFromAuthority(auth), true);    }     @Override    protected IContentProvider acquireExistingProvider(Context context,            String auth) {           return mMainThread.acquireExistingProvider(context,                ContentProvider.getAuthorityWithoutUserId(auth),                resolveUserIdFromAuthority(auth), true);    }     @Override    protected IContentProvider acquireUnstableProvider(Context c, String auth) {           return mMainThread.acquireProvider(c,                ContentProvider.getAuthorityWithoutUserId(auth),                resolveUserIdFromAuthority(auth), false);    }     protected int resolveUserIdFromAuthority(String auth) {           return ContentProvider.getUserIdFromAuthority(auth, getUserId());    }	......}

而 ApplicationContentResolver 继承 ContentResolver,我们看下父类的实现:

frameworks/base/core/java/android/content/ContentResolver.java

public abstract class ContentResolver implements ContentInterface {   	......	public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,	        @Nullable String[] projection, @Nullable String selection,	        @Nullable String[] selectionArgs, @Nullable String sortOrder) {   	    return query(uri, projection, selection, selectionArgs, sortOrder, null);	}	public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,	        @Nullable String[] projection, @Nullable String selection,	        @Nullable String[] selectionArgs, @Nullable String sortOrder,	        @Nullable CancellationSignal cancellationSignal) {   	    // 将查询条件封装到Bundle. 参考【第4.1节】	    Bundle queryArgs = createSqlQueryBundle(selection, selectionArgs, sortOrder);	    // 查询操作. 参考【第4.2节】	    return query(uri, projection, queryArgs, cancellationSignal);	}	......}

其中 ContentResolver.query(…) 各参数含义如下:

  • uri:URI 类型, 以 content:// 开头, 如 content://com.android.contacts/contacts
  • projection:String[] 类型, 表示返回哪些列, null 表示返回所有列
  • selection:String 类型, SQL WHERE 后面语句(可以用?占位), 表示返回哪行, null 表示返回所有行
  • selectionArgs:String[] 类型, 表示 selection 中?占位符的值
  • sortOrder:返回行的排序方式, ORDER BY 后面语句, null 表示默认方式(即无序)
  • cancellationSignal:CancellationSignal 类型, 取消某操作(ContentResolver 增删改查操作)的信号, 当操作取消时会抛出OperationCanceledException 异常, null 表示不取消
  • 返回值:Cursor 类型, 指向第一项的前面, 可能返回 null (如果没有返回内容)

2.3 ContentResolver.createSqlQueryBundle

public static @Nullable Bundle createSqlQueryBundle(        @Nullable String selection,        @Nullable String[] selectionArgs,        @Nullable String sortOrder) {       if (selection == null && selectionArgs == null && sortOrder == null) {           return null;    }     Bundle queryArgs = new Bundle();    if (selection != null) {           queryArgs.putString(QUERY_ARG_SQL_SELECTION, selection);    }    if (selectionArgs != null) {           queryArgs.putStringArray(QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs);    }    if (sortOrder != null) {           queryArgs.putString(QUERY_ARG_SQL_SORT_ORDER, sortOrder);    }    return queryArgs;}

2.3 ContentResolver.query

@Overridepublic final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,        @Nullable String[] projection, @Nullable Bundle queryArgs,        @Nullable CancellationSignal cancellationSignal) {       // 此处mWrapped为空, 调不到    if (mWrapped != null) {           return mWrapped.query(uri, projection, queryArgs, cancellationSignal);    }     // 获取ContentProviderProxy对象(stable为false).     IContentProvider unstableProvider = acquireUnstableProvider(uri);    if (unstableProvider == null) {           return null;    }    IContentProvider stableProvider = null;    Cursor qCursor = null;    try {           long startTime = SystemClock.uptimeMillis();         ICancellationSignal remoteCancellationSignal = null;        if (cancellationSignal != null) {               cancellationSignal.throwIfCanceled();            // 拿到ICancellationSignal.Stub.Proxy            remoteCancellationSignal = unstableProvider.createCancellationSignal();            // 设置远程代理            cancellationSignal.setRemote(remoteCancellationSignal);        }        try {               // ContentProviderProxy#query.             qCursor = unstableProvider.query(mPackageName, uri, projection,                    queryArgs, remoteCancellationSignal);        } catch (DeadObjectException e) {               unstableProviderDied(unstableProvider);            // 获取ContentProviderProxy对象(stable为true)            stableProvider = acquireProvider(uri);            if (stableProvider == null) {                   return null;            }            // ContentProviderProxy#query            qCursor = stableProvider.query(mPackageName, uri, projection,                    queryArgs, remoteCancellationSignal);        }        if (qCursor == null) {               return null;        }         // 获取查到的行数, 当qCursor被关闭时会抛出异常        qCursor.getCount();         // CursorWrapperInner封装qCursor和provder并返回        final IContentProvider provider = (stableProvider != null) ?                 stableProvider : acquireProvider(uri);        final CursorWrapperInner wrapper =                 new CursorWrapperInner(qCursor, provider);        stableProvider = null;        qCursor = null;        return wrapper;    } catch (RemoteException e) {           return null;    } finally {   	    // 资源释放        if (qCursor != null) {               qCursor.close();        }        if (cancellationSignal != null) {               cancellationSignal.setRemote(null);        }        if (unstableProvider != null) {               releaseUnstableProvider(unstableProvider);        }        if (stableProvider != null) {               releaseProvider(stableProvider);        }    }}

ContentResolver#query 分为2个主要步骤:获取 Provider 和 query 查询。

2.4 ContentResolver.acquireUnstableProvider

// 根据Uri查询ContentProviderpublic final IContentProvider acquireUnstableProvider(Uri uri) {       // uri必须以content开头    if (!SCHEME_CONTENT.equals(uri.getScheme())) {           return null;    }     // 获取authority(全格式为host:port)    String auth = uri.getAuthority();    if (auth != null) {           // 走到实现类ApplicationContentResolver#acquireUnstableProvider        // 最终走到ActivityThread.acquireProvider        return acquireUnstableProvider(mContext, uri.getAuthority());    }    return null;}private static final class ApplicationContentResolver extends ContentResolver {           @UnsupportedAppUsage        private final ActivityThread mMainThread;        public ApplicationContentResolver(Context context,                ActivityThread mainThread) {               super(context);            mMainThread = Preconditions.checkNotNull(mainThread);        }        ......        @Override        protected IContentProvider acquireUnstableProvider(Context c,                String auth) {               return mMainThread.acquireProvider(c,                    ContentProvider.getAuthorityWithoutUserId(auth),                    resolveUserIdFromAuthority(auth), false);        }        ......    }

2.5 ActivityThread.acquireProvider

public final IContentProvider acquireProvider(Context c, String auth, ......) {       // 先从map缓存中查询本地ContentProvider.    final IContentProvider provider =            acquireExistingProvider(c, auth, userId, stable);    if (provider != null) {           return provider;    }    // IActivity.Stub.Proxy#getContentProvider获取ContentProviderHolder.    ContentProviderHolder holder = null;    synchronized (getGetProviderLock(auth, userId)) {           holder = ActivityManager.getService().getContentProvider(        getApplicationThread(), c.getOpPackageName(), auth, userId, stable);    }     if (holder == null) {           return null;    }    // 增加引用计数, 同时删除老的provider    holder = installProvider(c, holder, holder.info, true /*noisy*/,           holder.noReleaseNeeded, stable);     // ContentProviderProxy    return holder.provider;}

获取 ContentProvider 过程:

1.先根据 ProviderKey 从本地缓存中查询, 若查询到则直接返回
2.若本地缓存没有, 则通过 Binder 通信找 AMS 获取

其中 ProviderKey 由 authority 和 userId 组成,它们的获取逻辑为:

frameworks/base/core/java/android/content/ContentProvider.java

/ 例如userId@some.authority, 返回值为some.authority public static String getAuthorityWithoutUserId(String auth) {       if (auth == null) return null;    int end = auth.lastIndexOf('@');    return auth.substring(end+1);} // 例如userId@some.authority, 返回值为userIdpublic static int getUserIdFromAuthority(String auth, int defaultUserId) {       if (auth == null) return defaultUserId;    int end = auth.lastIndexOf('@');    if (end == -1) return defaultUserId;    String userIdString = auth.substring(0, end);    try {           return Integer.parseInt(userIdString);    } catch (NumberFormatException e) {           return UserHandle.USER_NULL;    }}

2.5.1 ActivityThread.acquireExistingProvider

// 从缓存查询ContentProviderpublic final IContentProvider acquireExistingProvider(Context c, String auth,        int userId, boolean stable) {       synchronized (mProviderMap) {   	    // 根据authority和userId封装ProviderKey对象        final ProviderKey key = new ProviderKey(auth, userId);        // 根据ProviderKey查询ProviderClientRecord        final ProviderClientRecord pr = mProviderMap.get(key);        if (pr == null) {               return null;        } 		// 拿到ContentProviderProxy        IContentProvider provider = pr.mProvider;        // 拿到mRemote-Transport(即ContentProviderNative实现类)        IBinder jBinder = provider.asBinder();        if (!jBinder.isBinderAlive()) {               // 若mRemote所在进程已经死掉, 则从mProviderMap和mProviderRefCountMap            // 中移除该provider及引用计数, 并告诉AMS该provider不可用            handleUnstableProviderDiedLocked(jBinder, true);            return null;        }         // 获取provider引用计数, 引用计数+1        ProviderRefCount prc = mProviderRefCountMap.get(jBinder);        if (prc != null) {               incProviderRefLocked(prc, stable);        }        return provider;    }}

2.5.2 ActivityThread.incProviderRefLocked

private final void incProviderRefLocked(ProviderRefCount prc, boolean stable) {       if (stable) {           prc.stableCount += 1;        if (prc.stableCount == 1) {               int unstableDelta;            if (prc.removePending) {                   unstableDelta = -1;                prc.removePending = false;                mH.removeMessages(H.REMOVE_PROVIDER, prc);            } else {                   unstableDelta = 0;            }        ActivityManager.getService().refContentProvider(prc.holder.connection,                    1, unstableDelta);        }    } else {           prc.unstableCount += 1;        if (prc.unstableCount == 1) {               if (prc.removePending) {                   prc.removePending = false;                mH.removeMessages(H.REMOVE_PROVIDER, prc);            } else {          ActivityManager.getService().refContentProvider(prc.holder.connection,                        0, 1);            }        }    }}

若本地缓存没有查找到, 则通过 Binder 通信找 AMS 获取。

下面主要分析 ActivityManager.getService().getContentProvider(…) 过程。是 AMP 向 AMS 发送获取 ContentProvider 对象的请求, AMS 会向 AMP 返回 ContentProvider。那么通过 AMP.getContentProvider(…) 获取到的 provider 究竟是什么呢? 我们通过下面的分析会知道是 ContentProviderProxy.

2.6 AMP.getContentProvider

2.6.1 IActivityManager.aidl

interface IActivityManager {       ......    ContentProviderHolder getContentProvider(in IApplicationThread caller,		    in String callingPackage, in String name, int userId, boolean stable);    ......}

IActivityManager.aidl 文件编译后的 Java 文件为:

public interface IActivityManager extends android.os.IInterface{       /** Local-side IPC implementation stub class. */    public static abstract class Stub extends android.os.Binder            implements android.app.IActivityManager    {           private static final java.lang.String DESCRIPTOR =                "android.app.IActivityManager";        /** Construct the stub at attach it to the interface. */        public Stub()        {               this.attachInterface(this, DESCRIPTOR);        }          // Cast an IBinder object into an android.app.IActivityManager interface,         // generating a proxy if needed.  public static android.app.IActivityManager asInterface(android.os.IBinder obj)        {               if ((obj==null)) {                   return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin!=null)&&(iin instanceof android.app.IActivityManager))) {                   return ((android.app.IActivityManager)iin);            }            return new android.app.IActivityManager.Stub.Proxy(obj);        }          @Override         public android.os.IBinder asBinder()        {               return this;        }          @Override         public boolean onTransact(int code, android.os.Parcel data,		     android.os.Parcel reply, int flags) throws android.os.RemoteException        {               java.lang.String descriptor = DESCRIPTOR;            switch (code)            {                   case INTERFACE_TRANSACTION:                {                       reply.writeString(descriptor);                    return true;                }                case TRANSACTION_getContentProvider:                {                       data.enforceInterface(descriptor);                    IApplicationThread _arg0 =                             (IApplicationThread) data.readStrongBinder();                    java.lang.String _arg1 = (java.lang.String) data.readString();                    java.lang.String _arg2 = data.readString();                    int _arg3 = data.readInt();                    boolean _arg4 = data.readBoolean();                    android.app.ContentProviderHolder _result =                         this.getContentProvider(_arg0, _arg1, _arg2, _arg3, _arg4);                    reply.writeNoException();                    if ((_result!=null)) {                           reply.writeInt(1);                        // 会走到ContentProviderHolder.writeToParcel                        // reply中写进的provider是Transport                        _result.writeToParcel(reply,                        android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);                    } else {                           reply.writeInt(0);                    }                    return true;                }                default:                {                       return super.onTransact(code, data, reply, flags);                }            }        }          private static class Proxy implements android.app.IActivityManager        {               private android.os.IBinder mRemote;            Proxy(android.os.IBinder remote)            {                   mRemote = remote;            }            @Override            public android.os.IBinder asBinder()            {                   return mRemote;            }            public java.lang.String getInterfaceDescriptor()            {                   return DESCRIPTOR;            }              @Override            public android.app.ContentProviderHolder getContentProvider(                 in IApplicationThread caller, java.lang.String callingPackage,                    java.lang.String name, int userId,                    boolean stable) throws android.os.RemoteException            {                   android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                android.app.ContentProviderHolder _result;                try {                       _data.writeInterfaceToken(DESCRIPTOR);                    _data.writeStrongBinder(caller);                    _data.writeString(callingPackage);                    _data.writeString(name);                    _data.writeInt(userId);                    _data.writeBoolean(stable);                    mRemote.transact(Stub.TRANSACTION_getContentProvider,                            _data, _reply, 0);                    _reply.readException();                    if ((0!=_reply.readInt())) {                           // 最终ContentProviderHolder中读取出来的                        // provider是ContentProviderProxy                        _result =                    android.app.ContentProviderHolder.CREATOR.createFromParcel(_reply);                    } else {                           _result = null;                    }                } finally {                       _reply.recycle();                    _data.recycle();                }                return _result;            }        }          static final int TRANSACTION_getContentProvider =              (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);    }      public android.app.ContentProviderHolder getContentProvider(            in IApplicationThread caller, java.lang.String callingPackage,            java.lang.String name, int userId,            boolean stable) throws android.os.RemoteException;}

IActivityManager.aidl 的调用逻辑

IActivityManager.Stub.Proxy#getContentProvider -> mRemote.transact ->IActivityManager.Stub#onTransact -> IActivityManager#getContentProvider(AMS端) ->ContentViewHolder.writeToParcel(AMS端) -> ContentProviderHolder.CREATOR.createFromParcel(AMP端)

我们再看 AMS.getContentProvider 过程, 那么它返回的 provider 是什么呢?

2.6.2 AMS.getContentProvider

@Overridepublic final ContentProviderHolder getContentProvider(        IApplicationThread caller, ......) {       // 不允许isolate进程调用    enforceNotIsolatedCaller("getContentProvider");    ...    final int callingUid = Binder.getCallingUid();    return getContentProviderImpl(caller, name, null, ......);}private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,        String name, IBinder token, int callingUid, String callingPackage,         String callingTag, boolean stable, int userId) {       ContentProviderRecord cpr;    ContentProviderConnection conn = null;    ProviderInfo cpi = null;    boolean providerRunning = false;     synchronized(this) {           long startTime = SystemClock.uptimeMillis();         ProcessRecord r = null;        if (caller != null) {               r = getRecordForAppLocked(caller);        }         boolean checkCrossUser = true;       //根据name获取ContentProviderRecord对象, 若普通用户未获取到, 则从系统用户获取        cpr = mProviderMap.getProviderByName(name, userId);        if (cpr == null && userId != UserHandle.USER_SYSTEM) {               cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);            if (cpr != null) {                   cpi = cpr.info;                if (isSingleton(cpi.processName,                       cpi.applicationInfo, cpi.name, cpi.flags)                       && isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {                       userId = UserHandle.USER_SYSTEM;                    checkCrossUser = false;                } else {                       cpr = null;                    cpi = null;                }            }        }         // 检查ContentProviderRecord所在进程是否被杀, 若进程被杀, 执行数据清理操作        if (cpr != null && cpr.proc != null) {   	        // 检查provider是否正在运行            providerRunning = !cpr.proc.killed;             if (cpr.proc.killed && cpr.proc.killedByAm) {                   appDiedLocked(cpr.proc);            }        } 		// 若provider正在运行        if (providerRunning) {               cpi = cpr.info;            String msg;             if (r != null && cpr.canRunHere(r)) {                   // 权限检查                ...                 ContentProviderHolder holder = cpr.newHolder(null);                holder.provider = null;                return holder;            }             // IPackageManager.Stub.Proxy#resolveContentProvider. 	 //Binder通信PMP请求PMS解析出ContentProvider, 即PMS.resolveContentProvider	        // 而PMS又通过ComponentResolver组件解析器解析出ProviderInfo. 	        // 对于联系人ProviderInfo中provider名称是ContactsProvider2            if (AppGlobals.getPackageManager().resolveContentProvider(name,                    0 /*flags*/, userId) == null) {                   return null;            }             final long origId = Binder.clearCallingIdentity();             // ContentProviderRecord计数+1            conn = incProviderCountLocked(r, cpr, token, ......);            if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {                   if (cpr.proc != null &&                        r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {                       // 更新lru进程信息               mProcessList.updateLruProcessLocked(cpr.proc, false, null);                }            }             final int verifiedAdj = cpr.proc.verifiedAdj;            boolean success = updateOomAdjLocked(cpr.proc,                    true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);            if (success && verifiedAdj != cpr.proc.setAdj &&                     !isProcessAliveLocked(cpr.proc)) {                   success = false;            }            if (!success) {                   boolean lastRef =                        decProviderCountLocked(conn, cpr, token, stable);                appDiedLocked(cpr.proc);                if (!lastRef) {                       return null;                }                providerRunning = false;                conn = null;            } else {                   cpr.proc.verifiedAdj = cpr.proc.setAdj;            }            Binder.restoreCallingIdentity(origId);        } 		// 若provider不在运行        if (!providerRunning) {           	// IPackageManager.Stub.Proxy#resolveContentProvider. 	  // Binder通信PMP请求PMS解析出ContentProvider, 即PMS.resolveContentProvider	        // 而PMS又通过ComponentResolver组件解析器解析出ProviderInfo. 	        // 对于联系人ProviderInfo中provider名称是ContactsProvider2            cpi = AppGlobals.getPackageManager().resolveContentProvider(name,            STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);            if (cpi == null) {                   return null;            }            boolean singleton = isSingleton(cpi.processName, ......)                && isValidSingletonCall(r.uid, cpi.applicationInfo.uid);            if (singleton) {                   userId = UserHandle.USER_SYSTEM;            }            cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);             // 各种有效性检查, 包括:系统是否ready            ...             // 根据ComponentName从mProviderMap中查找, 若没找到则新建            ComponentName comp = new ComponentName(cpi.packageName, cpi.name);            cpr = mProviderMap.getProviderByClass(comp, userId);            final boolean firstClass = cpr == null;            if (firstClass) {                   try {                       ApplicationInfo ai =                           AppGlobals.getPackageManager().getApplicationInfo(		                  cpi.applicationInfo.packageName, STOCK_PM_FLAGS, userId);                ai = getAppInfoForUser(ai, userId);                cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);                } catch (RemoteException ex) {                       // pm is in same process, this will never happen.                } finally {                       Binder.restoreCallingIdentity(ident);                }            }             // 如果是单进程, 或provider允许多进程多个实例            if (r != null && cpr.canRunHere(r)) {                   return cpr.newHolder(null);            }             // 检查当前ContentProviderRecord是否已启动            final int N = mLaunchingProviders.size();            int i;            for (i = 0; i < N; i++) {                   if (mLaunchingProviders.get(i) == cpr) {                       break;                }            }             // 若当前ContentProviderRecord未启动            if (i >= N) {                   final long origId = Binder.clearCallingIdentity();                try {              // Content provider is now in use, its package can't be stopped.                    AppGlobals.getPackageManager().setPackageStoppedState(                          cpr.appInfo.packageName, false, userId);                     // 获取当前ContentProvider所在进程                    ProcessRecord proc = getProcessRecordLocked(                          cpi.processName, cpr.appInfo.uid, false);                    if (proc != null && proc.thread != null && !proc.killed) {                           // 若进程正在运行中, 且cpi还未发布, 则将其加到map中并发布Provider                        if (!proc.pubProviders.containsKey(cpi.name)) {                               proc.pubProviders.put(cpi.name, cpr);                            // 安装和发布provider                            proc.thread.scheduleInstallProvider(cpi);                        }                    } else {                           // 否则启动新进程                        proc = startProcessLocked(cpi.processName,                                cpr.appInfo, false, 0,                          new HostingRecord("content provider",                    new ComponentName(cpi.applicationInfo.packageName, cpi.name)),                                 false, false, false);                    }                    // cpr添加到mLaunchingProviders列表                    cpr.launchingApp = proc;                    mLaunchingProviders.add(cpr);                } finally {                       Binder.restoreCallingIdentity(origId);                }            }             // ContentProviderRecord对象存到mProviderMap            if (firstClass) {                   mProviderMap.putProviderByClass(comp, cpr);            }            mProviderMap.putProviderByName(name, cpr);             // provider引用+1            conn = incProviderCountLocked(r, cpr, token, callingUid, ......);            if (conn != null) {                   conn.waiting = true;            }        }    }    // 等待provider被发布, 超时时间20秒    final long timeout =           SystemClock.uptimeMillis() + CONTENT_PROVIDER_WAIT_TIMEOUT;    boolean timedOut = false;    synchronized (cpr) {           while (cpr.provider == null) {               try {        final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());                if (conn != null) {                       conn.waiting = true;                }                cpr.wait(wait);                if (cpr.provider == null) {                       timedOut = true;                    break;                }            } catch (InterruptedException ex) {               } finally {                   if (conn != null) {                       conn.waiting = false;                }            }        }    }     // 超时返空    if (timedOut) {           return null;    }     // 返回ContentProviderHolder. 持有的provider是    // ContactsProvider2(可理解为Transport)    return cpr.newHolder(conn);}

AMS.getContentProvider(String name, int userId) 总结:

1.根据 name 从 mProviderMap 中查找 ContentProviderRecord 对象 cpr, 若普通用户未获取到, 则从系统用户获取
2.如果 cpr 非空, 则检查 cpr 所在进程是否被杀, 若进程被杀, 执行数据清理操作. 检查 provider 是否正在运行
3.若 provider 正在运行:通过 IPackageManger.Stub.Proxy#resolveContentProvider 解析出 ProviderInfo, 且 cpr 引用计数 +1, 并更新 lru 进程信息
4.若 provider 不在运行:

  • 通过 IPackageManger.Stub.Proxy#resolveContentProvider 解析出 ProviderInfo
  • 根据 ProviderInfo 封装 ComponentName, 并从 mProviderMap 中查找 cpr, 若没找到则新建一个
  • 如果当前是单进程, 或 provider 允许多进程多个实例, 则直接返回
  • 检查 cpr 是否在 mLaunchingProviders 列表, 若不在, 则检查 cpr 所在进程是否正在运行.
  • 若 cpr 所在进程正在运行, 但 ProviderInfo 对应的 provider 还未发布, 则将 ProviderInfo 加到 map 中, 执行 ApplicationThread#scheduleInstallProvider 发布 Provider
  • 若 cpr 所在进程不在运行, 则启动新进程. cpr 添加到 mLaunchingProviders 和 mProviderMap, cpr 引用计数+1, 等待 provider 被发布, 超时时间20秒, 若超时返空

5.返回 ContentProviderHolder. 此时持有的 provider 是 ContactsProvider2 (可理解为 Transport)

2.6.3 PMS.resolveContentProvider

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

@Overridepublic ProviderInfo resolveContentProvider(String name, int flags, int userId) {       return resolveContentProviderInternal(name, flags, userId);} private ProviderInfo resolveContentProviderInternal(String name, ......) {       if (!sUserManager.exists(userId)) return null;    flags = updateFlagsForComponent(flags, userId, name);    final int callingUid = Binder.getCallingUid();	// 组件解析器解析ComponentResolver.queryProvider.    final ProviderInfo providerInfo =             mComponentResolver.queryProvider(name, flags, userId);    if (providerInfo == null) {           return null;    }    if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {           return null;    }    synchronized (mPackages) {           final PackageSetting ps =                mSettings.mPackages.get(providerInfo.packageName);        final ComponentName component =                new ComponentName(providerInfo.packageName, providerInfo.name);     if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {               return null;        }        return providerInfo;    }}

我们知道 PMS.resolveContentProvider 最终会拿到 ContactsProvider2. 那么它是怎么拿到的呢? 我们继续往下看这个过程.

2.6.4 ComponentResolver.queryProvider

frameworks/base/services/core/java/com/android/server/pm/ComponentResolver.java

ProviderInfo queryProvider(String authority, int flags, int userId) {       synchronized (mLock) {           final PackageParser.Provider p = mProvidersByAuthority.get(authority);        if (p == null) {               return null;        }        final PackageSetting ps = (PackageSetting) p.owner.mExtras;        if (ps == null) {               return null;        }        return PackageParser.generateProviderInfo(p, flags, ......);    }}

现在分析下 mProvidersByAuthority 的取值.

根据赋值的地方反查可得出如下调用链:

PMS: PackageHandler.INIT_COPY -> startCopy -> handleReturnCode -> processPendingInstall ->	 processInstallRequestsAsync -> installPackagesLI -> commitPackagesLocked ->	 commitReconciledScanResultLocked -> commitPackageSettingsComponentResolver: addAllComponents -> addProvidersLocked

我们再看下 ComponentResolver#addProvidersLocked 实现。

private void addProvidersLocked(PackageParser.Package pkg, boolean chatty) {       final int providersSize = pkg.providers.size();    StringBuilder r = null;    for (int i = 0; i < providersSize; i++) {           PackageParser.Provider p = pkg.providers.get(i);        p.info.processName =         fixProcessName(pkg.applicationInfo.processName, p.info.processName);        mProviders.addProvider(p);        p.syncable = p.info.isSyncable;        if (p.info.authority != null) {               String[] names = p.info.authority.split(";");            p.info.authority = null;            for (int j = 0; j < names.length; j++) {                   if (j == 1 && p.syncable) {                       p = new PackageParser.Provider(p);                    p.syncable = false;                }                if (!mProvidersByAuthority.containsKey(names[j])) {                       mProvidersByAuthority.put(names[j], p);                    if (p.info.authority == null) {                           p.info.authority = names[j];                    } else {                           p.info.authority = p.info.authority + ";" + names[j];                    }                } else {                       final PackageParser.Provider other =                          mProvidersByAuthority.get(names[j]);                    final ComponentName component =                            (other != null && other.getComponentName() != null)                                    ? other.getComponentName() : null;                    final String packageName =                    component != null ? component.getPackageName() : "?";                }            }        }    }}

其中有个很重要的角色:包解析器 PackageParser, 它会在 App 安装过程中解析各种文件包括 AndroidManifest.xml

解析出来的信息会封装在 PackageParser.Package 对象中.

我们再看下 Contacts 应用程序的 providers 包下的 AndroidManifest.xml 文件.

packages/providers/ContactsProvider/AndroidManifest.xml

......
......
......

mProvidersByAuthority 最终会存储 key 为 contacts 和 com.android.contacts, value 为 ContactsProvider2 的信息. 因此我们得出结论, PMS.resolveContentProvider 拿到的是 ContactsProvider2 对应的 ProviderInfo.

那么经过 AIDL Binder 通信, AMP.getContentProvider 拿到的究竟是什么呢?

我们再看下 ContentProviderHolder 的实现:

2.6.5 ContentProviderHolder

frameworks/base/core/java/android/app/ContentProviderHolder.java

public class ContentProviderHolder implements Parcelable {       public final ProviderInfo info;    public IContentProvider provider;    public IBinder connection;    public boolean noReleaseNeeded;     public ContentProviderHolder(ProviderInfo _info) {           info = _info;    }     @Override    public int describeContents() {           return 0;    }     @Override    public void writeToParcel(Parcel dest, int flags) {           info.writeToParcel(dest, 0);        if (provider != null) {               // 写入的是Transport            dest.writeStrongBinder(provider.asBinder());        } else {               dest.writeStrongBinder(null);        }        dest.writeStrongBinder(connection);        dest.writeInt(noReleaseNeeded ? 1 : 0);    }     public static final Parcelable.Creator
CREATOR = new Parcelable.Creator
() { @Override public ContentProviderHolder createFromParcel(Parcel source) { return new ContentProviderHolder(source); } @Override public ContentProviderHolder[] newArray(int size) { return new ContentProviderHolder[size]; } }; private ContentProviderHolder(Parcel source) { info = ProviderInfo.CREATOR.createFromParcel(source); // 拿到的provider是ContentProviderProxy provider = ContentProviderNative.asInterface(source.readStrongBinder()); connection = source.readStrongBinder(); noReleaseNeeded = source.readInt() != 0; }}

结合上面的 IActivityManager.aidl 分析过程中的调用链:

IActivityManager.Stub.Proxy#getContentProvider -> mRemote.transact ->IActivityManager.Stub#onTransact -> IActivityManager#getContentProvider(AMS端) ->ContentViewHolder.writeToParcel(AMS端) -> ContentProviderHolder.CREATOR.createFromParcel(AMP端)

我们已经知道了AMS.getContentProvider 拿到的是 ContactsProvider2 (可理解为 Transport 和 ContentProviderNative)

结合 ContentProviderHolder 源码可知, ContentViewHolder.writeToParcel (AMS 端)写入的是 Transport, ContentProviderHolder.CREATOR.createFromParcel(AMP 端) 拿到的是 ContentProviderProxy.

最终 ActivityManager.getService().getContentProvider(…) 拿到的是 ContentProviderProxy

同时只有 provider 先发布, 才能获取到 provider. 发布逻辑主要在 ApplicationThread.scheduleInstallProvider

上一篇:Android四大组件系列10 深入理解Context
下一篇:Android四大组件系列8 sendBroadcast流程

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2025年03月26日 06时54分02秒