ContentProvider的基本使用

weixin_34148340發表於2018-09-07

理解 ContentProvider 原理(一)





1.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();
}複製程式碼

2.ContentResolver是個啥


無論Activity還是應用Context獲取ContextResolver,最終都呼叫了ContextImpl.getContentResolver,

806    @Override
807    public ContentResolver getContentResolver() {
808        return mContentResolver;
809    }複製程式碼

是在什麼時候構造的呢

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    }複製程式碼
上面最後一行程式碼,建立了一個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            return ContentProvider.getUserIdFromAuthority(auth, mUser.getIdentifier());
2462        }
2463    }
2464}複製程式碼

似乎也沒有啥東西,傳入了ContextImpl本身以及ActivityThread,單得注意它繼承自ContentResolver. 看一下程式碼也有2000行,看看關鍵函式吧。一個建構函式沒做啥,幾個abstract函式留給ApplicationContentResolver實現。看樣子似乎把Provider分成了Stable的和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) {
298        return 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);複製程式碼

其他函式可以不看,暫時關注一下query方法和call方法吧。先看看query,五個引數看看註釋很明瞭,就第二個引數名字有點費解。

420    public final Cursor query(Uri uri, String[] projection,
421            String selection, String[] selectionArgs, String sortOrder) {
422        return query(uri, projection, selection, selectionArgs, sortOrder, null);
423    }複製程式碼
這裡的query方法首先呼叫abstract方法acquireUnStableProvider獲取IContentProvider unstableProvider,呼叫其query方法。如果出現異常,那麼再利用acquireProvider獲得穩定的IContentProvider stableProvider,呼叫其query方法。不管哪種選擇,最終都會呼叫release方法釋放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                    return null;
488                }
489                qCursor = stableProvider.query(mPackageName, uri, projection,
490                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
491            }
492            if (qCursor == null) {
493                return null;
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;
506            return 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    }複製程式碼

我們接下來要看看call方法,但是這裡已經很好奇了,Provider基本會是extends Binder implements IContentProvider吧,先查原始碼發現並不是呀,就看看誰實現了IContentProvider唄,後面再分析Provider吧,Provider使用了一個Transport物件,就是ContentProviderBinder。

好了繼續看call方法,非常純淨!獲取了穩定的IContentProvider,直接呼叫call。

1360    public final Bundle call(Uri uri, String method, String arg, Bundle extras) {
1361        if (uri == null) {
1362            throw new NullPointerException("uri == null");
1363        }
1364        if (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            return null;
1377        } finally {
1378            releaseProvider(provider);
1379        }
1380    }複製程式碼

先畫一條分割線吧,很想看看ContentProvider類是啥樣!看完接著分析ApplicationContentResolver
------------------------------------------------------------------------------------------------

主要的介面是IContentProvider,只不過實現的Native類為ContentProviderNative,而Proxy類為ContentProviderProxy。ContentProvider與ContentProviderNative不是繼承關係,而是組合關係,它其中包含了一個型別為ContentProviderNative的成員變數mTranspot。那麼後續,這個mTranspot肯定會傳送到AMS中,保持為ContentProviderProxy,當Client需要時AMS會傳送給Client。

------------------------------------------------------------------------------------------------


下面回到ApplicationContentResolver中,該呼叫ActivityThread的acquireProvider獲取IContentProvider,然後呼叫query方法和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            return null;
1377        } finally {
1378            releaseProvider(provider);
1379        }
1380    }複製程式碼

1.首先利用在ActivityThread中呼叫ActivityManagerNative.getDefault().getContentProvider,最終可以得到一個IContentProvider

2.其次支援使用這個IContentProvider.call
3.最後呼叫ActivityManagerNative.getDefault().refContentProvider來釋放IContentProvider引用

從這裡可以看出ApplicationContentResolver只是IContentProvider的一個外觀類,使用步驟:獲取、使用、釋放。下面關注一下獲取的過程。
------------------------------------------------------------------------------------------------

首先從快取mProviderMap中獲取IContentProvider,如果快取命中則返回,如果沒有命中則通過ActivityManagerNative來獲取holder並保持到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) {
4578            return 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;
9249            if (providerRunning) {
9250                cpi = cpr.info;
9251                String msg;
9259                if (r != null && cpr.canRunHere(r)) {
9267                    holder.provider = null;
9268                    return 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        }
9543        return cpr != null ? cpr.newHolder(conn) : null;
9544    }
2515    public void handleInstallProvider(ProviderInfo info) {
2516        installContentProviders(mInitialApplication, Lists.newArrayList(info));
2517    }複製程式碼
1.上面的程式碼首先看AMS的快取中有沒有IContentProvider,有則返回,否則進入2

2.如果程式沒有啟動則啟動程式,否則進入3

3.呼叫thread.scheuleInstallProvider

這裡很奇怪,為什麼會有步驟三呢?應用程式啟動的時候在handleBindApplication中,不是已經安裝了所有的Provider元件嗎?莫非是中途被幹掉了,比如禁用了元件!


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    }複製程式碼
上面的程式碼就是Provider初始化程式碼,首先初始化類呼叫onCreate函式,快取到mProviderMap中,通知AMS本應用的Providers都準備好了,其他應用可以使用了。

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                    return null;
4960                }
4964                localProvider.attachInfo(c, info);
4965            } catch (java.lang.Exception e) {
4971                return null;
4972            }
4973        } 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);
4988                if (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) {
5013                    if (!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
5038        return retHolder;
5039    }複製程式碼
具體的installProvider函式,上面已經說過了,只不過provider是放在holder中的,holder會存到mProviderMap中。mProviderMap在下面的函式中,接著看。


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        }
4901        return pcr;
4902    }複製程式碼
mProviderMap是用auth和userId作為Key來儲存的,ProviderKey的equals方法被改寫了。


------------------------------------------------------------------------------------------------

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;
4498                if (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);
4528        }
4529    }
複製程式碼

本應用的Provider是在應用啟動bindApplication的時候installProviders的,而應用外表的Provider是在acquireProvider的時候獲得holder的進行installProvider的。
1.本應用的,啟動時installProviders
2.應用外部的,在ProviderResolver遠端呼叫時ActivityThread.acquireProvider時獲取得

------------------------------------------------------------------------------------------------

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);
9699        }
9700    }複製程式碼
應用的釋出過程,即通知AMS已經準備好了Provider,其他應用可以取IContentProvider了

------------------------------------------------------------------------------------------------


上面的程式碼分析,後續再記錄一下。
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
------------------------------------------------------------------------------------------------
unStable和stable的區別在於,unStable的呼叫在傳送DeadObjectException的時候,會重新觸發一次啟動Provider的操作,會讓程式重啟,所以使用unStable方式是說要防止Provider程式不穩定被殺死。

------------------------------------------------------------------------------------------------

為什麼ContentProviderNative傳遞到另外一個程式中,最後變成了ContentProviderProxy呢?這其實很簡單,首先遵循基本的Binder機制,ContentProviderNative在natvie層表述為BBinder,透過Binder驅動傳遞到另外一個程式後,會變成BpBinder,如果是Java層接收在Parcel中會將其轉化為BindProxy的Java物件。最後上層使用了ContentProviderHolder序列化資料,在接收到BindProxy後會呼叫ContentProviderNative.asInterface(IBinder)靜態函式,看看程式碼就會明白了了,new ContentProviderProxy(new BindProxy(BpBinder(handle))).  這行程式碼挺帶感的,順便再寫一句吧new ContentProviderNative().mObject=new JavaBBinderHolder().mObject=new JavaBBinder(ContentProviderNative)。


相關文章