[Android Pro] Basic use of ContentProvider
www.cnblogs.com/0616 – ataoz…


Understand the Principle of ContentProvider (1)
www.sohu.com/a/115624727…






Androidxref.com/5.0.0_r2/xr…
Androidxref.com/5.0.0_r2/xr…
Androidxref.com/5.0.0_r2/xr…
Androidxref.com/5.0.0_r2/xr…
Androidxref.com/5.0.0_r2/xr…
Androidxref.com/5.0.0_r2/xr…




1. How to use ContentResolver

public void testQuery() {
    Uri uri = Uri.parse("content://cn.xyCompany.providers.personProvider/person/19");
    ContentResolver resolver = this.getContext().getContentResolver();
    Cursor cursor = resolver.query(uri, new String[]{"id"."name"."phone"}, null, null, "id asc");
    if(cursor.moveToFirst()) {
        Log.i("query", cursor.getString(cursor.getColumnIndex("name")));
    }
    cursor.close();
}Copy the code

2. ContentResolver is what



Both the Activity and get ContextResolver application Context, finally calls the ContextImpl. GetContentResolver,

806    @Override
807    public ContentResolver getContentResolver() {808returnmContentResolver; 809}Copy the code



When was it constructed

2224 private ContextImpl(ContextImpl container, ActivityThread mainThread, 2225 LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted, 2226 Display display, Configuration overrideConfiguration) { 2227 mOuterContext = this; 2228 2229 mMainThread = mainThread; 2230 mActivityToken = activityToken; 2231 mRestricted = restricted; 2232, 2233,if(user == null) { 2234 user = Process.myUserHandle(); 2235 } 2236 mUser = user; 2237 2238 mPackageInfo = packageInfo; 2239 mResourcesManager = ResourcesManager.getInstance(); 2250 } 2251 mDisplayAdjustments.setCompatibilityInfo(compatInfo); 2252 mDisplayAdjustments.setActivityToken(activityToken); 2253 2254 Resources resources = packageInfo.getResources(mainThread); 2267 mResources = resources; 2286 mContentResolver = new ApplicationContentResolver(this, mainThread, user); 2287}Copy the code

The last line of code above, create a ApplicationContentResolver

2407    private static final class ApplicationContentResolver extends ContentResolver {
2408        private final ActivityThread mMainThread;
2409        private final UserHandle mUser;
2410
2411        public ApplicationContentResolver(
2412                Context context, ActivityThread mainThread, UserHandle user) {
2413            super(context);
2414            mMainThread = Preconditions.checkNotNull(mainThread);
2415            mUser = Preconditions.checkNotNull(user);
2416        }
2417
2418        @Override
2419        protected IContentProvider acquireProvider(Context context, String auth) {
2420            return mMainThread.acquireProvider(context,
2421                    ContentProvider.getAuthorityWithoutUserId(auth),
2422                    resolveUserIdFromAuthority(auth), true);
2423        }
2424
2425        @Override
2426        protected IContentProvider acquireExistingProvider(Context context, String auth) {
2427            return mMainThread.acquireExistingProvider(context,
2428                    ContentProvider.getAuthorityWithoutUserId(auth),
2429                    resolveUserIdFromAuthority(auth), true);
2430        }
2431
2432        @Override
2433        public boolean releaseProvider(IContentProvider provider) {
2434            return mMainThread.releaseProvider(provider, true);
2435        }
2436
2437        @Override
2438        protected IContentProvider acquireUnstableProvider(Context c, String auth) {
2439            return mMainThread.acquireProvider(c,
2440                    ContentProvider.getAuthorityWithoutUserId(auth),
2441                    resolveUserIdFromAuthority(auth), false);
2442        }
2443
2444        @Override
2445        public boolean releaseUnstableProvider(IContentProvider icp) {
2446            return mMainThread.releaseProvider(icp, false);
2447        }
2448
2449        @Override
2450        public void unstableProviderDied(IContentProvider icp) {
2451            mMainThread.handleUnstableProviderDied(icp.asBinder(), true);
2452        }
2453
2454        @Override
2455        public void appNotRespondingViaProvider(IContentProvider icp) {
2456            mMainThread.appNotRespondingViaProvider(icp.asBinder());
2457        }
2458
2459        /** @hide */
2460        protected int resolveUserIdFromAuthority(String auth) {
2461            returnContentProvider.getUserIdFromAuthority(auth, mUser.getIdentifier()); 2462} 2463} 2464}Copy the code



There doesn’t seem to be anything either, passing in ContextImpl itself and ActivityThread. Note that it inherits from ContentResolver. If you look at the code there are 2000 lines, so let’s look at the key functions. A constructor didn’t do what, a few abstract function for ApplicationContentResolver implementation. It seems that providers are broken down into Stable and unStable

282 public ContentResolver(Context context) { 283 mContext = context ! = null ? context : ActivityThread.currentApplication(); 284 mPackageName = mContext.getOpPackageName(); 285 } 286 287 /** @hide */ 288 protected abstract IContentProvider acquireProvider(Context c, String name); 289 290 /** 291 * Providing a default implementation of this, to avoid having to change a 292 * lot of other things, but implementations of ContentResolver should 293 * implement it. 294 * 295 * @hide 296 */ 297 protected IContentProvider acquireExistingProvider(Context c, String name) { 298return acquireProvider(c, name);
299    }
300
301    /** @hide */
302    public abstract boolean releaseProvider(IContentProvider icp);
303    /** @hide */
304    protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
305    /** @hide */
306    public abstract boolean releaseUnstableProvider(IContentProvider icp);
307    /** @hide */
308    public abstract void unstableProviderDied(IContentProvider icp);Copy the code



Ignore the other functions and focus for the moment on the Query and call methods. Let’s look at query. The five parameters are very clear, but the second parameter name is a little confusing.

420    public final Cursor query(Uri uri, String[] projection,
421            String selection, String[] selectionArgs, String sortOrder) {
422        returnquery(uri, projection, selection, selectionArgs, sortOrder, null); 423}Copy the code

The query method first calls the abstract method acquireUnStableProvider to obtain the IContentProvider unstableProvider and call its query method. If an exception occurs, then use acquireProvider to obtain the stable IContentProvider stableProvider and call its query method. Either way, the Release method will eventually be called to release the IContentProvider.

459    public final Cursor query(final Uri uri, String[] projection,
460            String selection, String[] selectionArgs, String sortOrder,
461            CancellationSignal cancellationSignal) {
462        IContentProvider unstableProvider = acquireUnstableProvider(uri);
463        if (unstableProvider == null) {
464            return null;
465        }
466        IContentProvider stableProvider = null;
467        Cursor qCursor = null;
468        try {
469            long startTime = SystemClock.uptimeMillis();
470
477            try {
478                qCursor = unstableProvider.query(mPackageName, uri, projection,
479                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
480            } catch (DeadObjectException e) {
484                unstableProviderDied(unstableProvider);
485                stableProvider = acquireProvider(uri);
486                if (stableProvider == null) {
487                    returnnull; 488 } 489 qCursor = stableProvider.query(mPackageName, uri, projection, 490 selection, selectionArgs, sortOrder, remoteCancellationSignal); 491} 492if (qCursor == null) {
493                returnnull; 494 } 495 497 qCursor.getCount(); 498 long durationMillis = SystemClock.uptimeMillis() - startTime; 500 501 // Wrap the cursor object into CursorWrapperInner object. 502 CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, 503 stableProvider ! = null ? stableProvider : acquireProvider(uri)); 504 stableProvider = null; 505 qCursor = null; 506return wrapper;
507        } catch (RemoteException e) {
510            return null;
511        } finally {
512            if (qCursor != null) {
513                qCursor.close();
514            }
515            if (cancellationSignal != null) {
516                cancellationSignal.setRemote(null);
517            }
518            if (unstableProvider != null) {
519                releaseUnstableProvider(unstableProvider);
520            }
521            if(stableProvider ! = null) { 522 releaseProvider(stableProvider); 523} 524} 525}Copy the code



The call method extends Binder implements IContentProvider, which implements IContentProvider. This method implements IContentProvider, which implements IContentProvider. Providers use a Transport object, ContentProviderBinder.
Androidxref.com/5.0.0_r2/xr…


Okay, call method, very pure! After obtaining the stable IContentProvider, call call directly.

1360    public final Bundle call(Uri uri, String method, String arg, Bundle extras) {
1361        if (uri == null) {
1362            throw new NullPointerException("uri == null"); 1363} 1364if (method == null) {
1365            throw new NullPointerException("method == null");
1366        }
1367        IContentProvider provider = acquireProvider(uri);
1368        if (provider == null) {
1369            throw new IllegalArgumentException("Unknown URI " + uri);
1370        }
1371        try {
1372            return provider.call(mPackageName, method, arg, extras);
1373        } catch (RemoteException e) {
1374            // Arbitrary and not worth documenting, as Activity
1375            // Manager will kill this process shortly anyway.
1376            returnnull; 1377 } finally { 1378 releaseProvider(provider); 1380 1379}}Copy the code



Let’s draw a line. I’d love to see what a ContentProvider class looks like! Finish see then ApplicationContentResolver analysis
————————————————————————————————


The main interface is IContentProvider, but the implemented Native class is ContentProviderNative and the Proxy class is ContentProviderProxy. ContentProvider and ContentProviderNative are not an inheritance relationship, but a combination relationship, which contains a member variable mTranspot of type ContentProviderNative. Then later, this mTranspot will definitely be sent to AMS, remaining as the ContentProviderProxy, and AMS will send it to the Client when it needs it.


————————————————————————————————


Back to ApplicationContentResolver below, this call ActivityThread acquireProvider obtain IContentProvider, then call the query method and the method call.


Call ();

1360    public final Bundle call(Uri uri, String method, String arg, Bundle extras) {
1367        IContentProvider provider = acquireProvider(uri);
1371        try {
1372            return provider.call(mPackageName, method, arg, extras);
1373        } catch (RemoteException e) {
1376            returnnull; 1377 } finally { 1378 releaseProvider(provider); 1380 1379}}Copy the code

1. First of all use ActivityThread invokes the ActivityManagerNative. GetDefault () getContentProvider, finally can get a IContentProvider

2. The icontentProvider.call is supported
3. The last call ActivityManagerNative. GetDefault () refContentProvider to release IContentProvider references


As you can see from here is ApplicationContentResolver IContentProvider a class appearance, using steps: acquisition, use, release. Let’s focus on the acquisition process.
————————————————————————————————

The IContentProvider is first retrieved from the cache mProviderMap. If the cache hits, the IContentProvider is returned. If the cache does not hit, the Holder is retrieved through ActivityManagerNative and stored in the mProviderMap

4574    public final IContentProvider acquireProvider(
4575            Context c, String auth, int userId, boolean stable) {
4576        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
4577        if(provider ! = null) { 4578return provider;
4579        }
4580
4587        IActivityManager.ContentProviderHolder holder = null;
4588        try {
4589            holder = ActivityManagerNative.getDefault().getContentProvider(
4590                    getApplicationThread(), auth, userId, stable);
4591        } catch (RemoteException ex) {
4592        }
4593        if (holder == null) {
4594            Slog.e(TAG, "Failed to find provider info for " + auth);
4595            return null;
4596        }
4600        holder = installProvider(c, holder, holder.info,
4601                true /*noisy*/, holder.noReleaseNeeded, stable);
4602        return holder.provider;
4603    }

9204    private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller, 9205 String name, IBinder token, boolean stable, int userId) { 9206 ContentProviderRecord cpr; 9207 ContentProviderConnection conn = null; 9208 ProviderInfo cpi = null; 9209 9210 synchronized(this) { 9247 9248 boolean providerRunning = cpr ! = null; 9249if (providerRunning) {
9250                cpi = cpr.info;
9251                String msg;
9259                if(r ! = null && cpr.canRunHere(r)) { 9267 holder.provider = null; 9268return holder;
9269                }
9332            boolean singleton;
9430                // This is single process, and our app is now connecting to it.
9431                // See if we are already in the process of launching this
9432                // provider.
9433                final int N = mLaunchingProviders.size();
9434                int i;
9435                for (i=0; i<N; i++) {
9436                    if (mLaunchingProviders.get(i) == cpr) {
9437                        break;
9438                    }
9439                }
9440
9441                // If the provider is not already being launched, then get it
9442                // started.
9443                if (i >= N) {
9444                    final long origId = Binder.clearCallingIdentity();
9445
9446                    try {
9461                        ProcessRecord proc = getProcessRecordLocked(
9462                                cpi.processName, cpr.appInfo.uid, false);
9463                        if(proc ! = null && proc.thread ! = null) { 9468 proc.pubProviders.put(cpi.name, cpr); 9469 try { 9470 proc.thread.scheduleInstallProvider(cpi); 9471 } catch (RemoteException e) { 9472 } 9473 }else {
9474                            checkTime(startTime, "getContentProviderImpl: before start process");
9475                            proc = startProcessLocked(cpi.processName,
9476                                    cpr.appInfo, false, 0, "content provider",
9477                                    new ComponentName(cpi.applicationInfo.packageName,
9478                                            cpi.name), false.false.false);
9480                            if (proc == null) {
9485                                return null;
9486                            }
9487                        }
9488                        cpr.launchingApp = proc;
9489                        mLaunchingProviders.add(cpr);
9490                    } finally {
9491                        Binder.restoreCallingIdentity(origId);
9492                    }
9493                }
9508            }
9510        }
9511
9513        synchronized (cpr) {
9514            while (cpr.provider == null) {
9515                if (cpr.launchingApp == null) {
9524                    return null;
9525                }
9526                try {
9531                    if(conn ! = null) { 9532 conn.waiting =true;
9533                    }
9534                    cpr.wait();
9535                } catch (InterruptedException ex) {
9536                } finally {
9537                    if(conn ! = null) { 9538 conn.waiting =false; 9539} 9540} 9541} 9542} 9543return cpr != null ? cpr.newHolder(conn) : null;
9544    }
2515    public void handleInstallProvider(ProviderInfo info) {
2516        installContentProviders(mInitialApplication, Lists.newArrayList(info));
2517    }Copy the code

1. The above code first checks whether THE AMS cache has IContentProvider, if yes, return, otherwise enter 2

2. If the process is not started, start it. Otherwise, go to 3

3. The thread. ScheuleInstallProvider

This is weird. Why is there step three? Aren’t all Provider components already installed in the handleBindApplication when the application starts? Could it have been killed, like disabled components!


4545 private void installContentProviders( 4546 Context context, List<ProviderInfo> providers) { 4547 final ArrayList<IActivityManager.ContentProviderHolder> results = 4548 new ArrayList<IActivityManager.ContentProviderHolder>(); 4549, 4550,for (ProviderInfo cpi : providers) {
4551            if (DEBUG_PROVIDER) {
4552                StringBuilder buf = new StringBuilder(128);
4553                buf.append("Pub ");
4554                buf.append(cpi.authority);
4555                buf.append(":");
4556                buf.append(cpi.name);
4557                Log.i(TAG, buf.toString());
4558            }
4559            IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
4560                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
4561            if(cph ! = null) { 4562 cph.noReleaseNeeded =true;
4563                results.add(cph);
4564            }
4565        }
4566
4567        try {
4568            ActivityManagerNative.getDefault().publishContentProviders(
4569                getApplicationThread(), results);
4570        } catch (RemoteException ex) {
4571        }
4572    }Copy the code

The above code is Provider initialization code. First, the class initializes the onCreate function, which is cached in the mProviderMap to inform AMS that the Providers of this application are ready for use by other applications.


4918    private IActivityManager.ContentProviderHolder installProvider(Context context,
4919            IActivityManager.ContentProviderHolder holder, ProviderInfo info,
4920            boolean noisy, boolean noReleaseNeeded, boolean stable) {
4921        ContentProvider localProvider = null;
4922        IContentProvider provider;
4923        if (holder == null || holder.provider == null) {
4924            if (DEBUG_PROVIDER || noisy) {
4925                Slog.d(TAG, "Loading provider " + info.authority + ":"
4926                        + info.name);
4927            }
4928            Context c = null;
4929            ApplicationInfo ai = info.applicationInfo;
4950            try {
4951                final java.lang.ClassLoader cl = c.getClassLoader();
4952                localProvider = (ContentProvider)cl.
4953                    loadClass(info.name).newInstance();
4954                provider = localProvider.getIContentProvider();
4955                if (provider == null) {
4959                    returnnull; 4960} 4964localProvider.attachInfo(c, info);
4965            } catch (java.lang.Exception e) {
4971                returnnull; 4973 4972}}else {
4974            provider = holder.provider;
4977        }
4978
4979        IActivityManager.ContentProviderHolder retHolder;
4980
4981        synchronized (mProviderMap) {
4984            IBinder jBinder = provider.asBinder();
4985            if (localProvider ! = null) { 4986 ComponentName cname = new ComponentName(info.packageName, info.name); 4987 ProviderClientRecord pr = mLocalProvidersByName.get(cname); 4988if (pr != null) {
4993                    provider = pr.mProvider;
4994                } else {
4995                    holder = new IActivityManager.ContentProviderHolder(info);
4996                    holder.provider = provider;
4997                    holder.noReleaseNeeded = true;
4998                    pr = installProviderAuthoritiesLocked(provider, localProvider, holder); 4999 mLocalProviders.put(jBinder, pr); 5000 mLocalProvidersByName.put(cname, pr); 5001 } 5002 retHolder = pr.mHolder; 5003}else {
5004                ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
5005                if(prc ! = null) { 5013if(! noReleaseNeeded) { 5014 incProviderRefLocked(prc, stable); 5015 try { 5016 ActivityManagerNative.getDefault().removeContentProvider( 5017 holder.connection, stable); 5018 } catch (RemoteException e) { 5020 } 5021 } 5022 }else {
5023                    ProviderClientRecord client = installProviderAuthoritiesLocked(
5024                            provider, localProvider, holder);
5025                    if(noReleaseNeeded) { 5026 prc = new ProviderRefCount(holder, client, 1000, 1000); 5027}else{ 5028 prc = stable 5029 ? new ProviderRefCount(holder, client, 1, 0) 5030 : new ProviderRefCount(holder, client, 0, 1); 5031 } 5032 mProviderRefCountMap.put(jBinder, prc); 5033 } 5034 retHolder = prc.holder; 5035} 5036} 5037 5038returnretHolder; 5039}Copy the code

The specific installProvider function is described above, except that the provider is placed in the Holder, which is stored in the mProviderMap. The mProviderMap is in the function below, and then look.




4884    private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
4885            ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
4886        final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority);
4887        final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
4888
4889        final ProviderClientRecord pcr = new ProviderClientRecord(
4890                auths, provider, localProvider, holder);
4891        for (String auth : auths) {
4892            final ProviderKey key = new ProviderKey(auth, userId);
4893            final ProviderClientRecord existing = mProviderMap.get(key);
4894            if(existing ! = null) { 4897 }else{ 4898 mProviderMap.put(key, pcr); 4899} 4900} 4901returnpcr; 4902}Copy the code

MProviderMap is stored with auth and userId as keys. ProviderKey’s equals method has been overridden.


————————————————————————————————

4254 private void handleBindApplication(AppBindData data) { 4255 mBoundApplication = data; 4328 4329 final ContextImpl appContext = ContextImpl.createAppContext(this, data.info); 4343 4483 4487 final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites(); 4488 try { 4491 Application app = data.info.makeApplication(data.restrictedBackupMode, null); 4492 mInitialApplication = app; 4493, 4496,if(! data.restrictedBackupMode) { 4497 List<ProviderInfo> providers = data.providers; 4498if(providers ! = null) { 4499 installContentProviders(app, providers); 4502 mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000); 4503 } 4504 } 4505 4506 // Do this after providers, since instrumentation tests generally start their 4507 //test thread at this point, and we don't want that racing. 4508 try { 4509 mInstrumentation.onCreate(data.instrumentationArgs); 4510 } 4511 catch (Exception e) { 4515 } 4516 4517 try { 4518 mInstrumentation.callApplicationOnCreate(app); 4519 } catch (Exception e) { 4525 } 4526 } finally { 4527 StrictMode.setThreadPolicy(savedPolicy); 4529 4528}}Copy the code



AcquireProvider acquireProvider acquireProvider acquireProvider acquireProvider acquireProvider acquireProvider acquireProvider acquireProvider acquireProvider acquireProvider acquireProvider acquireProvider
1. InstallProviders of this application at startup
2. The application of external in ProviderResolver ActivityThread. When the remote call acquireProvider was obtained


————————————————————————————————

9643    public final void publishContentProviders(IApplicationThread caller. 9644 List<ContentProviderHolder> providers) { 9650 synchronized (this) { 9651 final ProcessRecord r = getRecordForAppLocked(caller);
9660
9661            final long origId = Binder.clearCallingIdentity();
9662
9663            final int N = providers.size();
9664            for (int i=0; i<N; i++) {
9665                ContentProviderHolder src = providers.get(i);
9666                if (src == null || src.info == null || src.provider == null) {
9667                    continue;
9668                }
9669                ContentProviderRecord dst = r.pubProviders.get(src.info.name);
9672                if(dst ! = null) { 9673 ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name); 9674 mProviderMap.putProviderByClass(comp, dst); 9675 String names[] = dst.info.authority.split(";");
9676                    for (int j = 0; j < names.length; j++) {
9677                        mProviderMap.putProviderByName(names[j], dst);
9678                    }
9679
9680                    int NL = mLaunchingProviders.size();
9681                    int j;
9682                    for (j=0; j<NL; j++) {
9683                        if(mLaunchingProviders.get(j) == dst) { 9684 mLaunchingProviders.remove(j); 9685 j--; 9686 NL--; 9687 } 9688 } 9689 synchronized (dst) { 9690 dst.provider = src.provider; 9691 dst.proc = r; 9692 dst.notifyAll(); 9693 } 9694 updateOomAdjLocked(r); 9695 } 9696 } 9697 9698 Binder.restoreCallingIdentity(origId); 9700 9699}}Copy the code

The application publishing process notifies AMS that the Provider is ready and other applications can use IContentProvider

————————————————————————————————



The above code analysis, later to record.
ContextImpl.ApplicationContentProvider.query
ActivityThread.acquireProvider
ActivityManagerService.getContentProvider
ContentProviderRecord.wait


1.thread.scheduleInstallProvider
ActivityThread.installContentProviders
provide = class.loadClass(provideInfo.name)
provide.attachInfo(providerInfo)
AMS.publishContentProviders


2.startProcessLocked
ActivityThread.main
AMS.attachApplication(ActivityThread)
thread.scheduleBindApplication
ActivityThread.handleBindApplication
ActivityThread.installContentProviders
provide = class.loadClass(provideInfo.name)
provide.attachInfo(providerInfo)
AMS.publishContentProviders
————————————————————————————————
The difference between unStable and stable is that when a DeadObjectException is sent, a Provider with unStable is restarted. To prevent unStable Provider processes from being killed, use unStable Provider.

————————————————————————————————

Why does ContentProviderNative get passed into another process and become ContentProviderProxy? It follows the basic Binder mechanism. ContentProviderNative is called BBinder at the Natvie layer. When it is passed through the Binder driver to another process, it becomes BpBinder. If the Java layer receives a Java object in a Parcel it will be converted to BindProxy. Finally use upper ContentProviderHolder serialized data, after receive the BindProxy invokes ContentProviderNative. AsInterface (IBinder) static function, look at the code will understand, new ContentProviderProxy(new BindProxy(BpBinder(handle))). This is a nice line of code, New ContentProviderNative().mobject =new JavaBBinderHolder().mobject = New JavaBBinder(ContentProviderNative).