Android Framework学习笔记(十)Content Provider启动过程

query方法到AMS的调用

在上述文章中我用到了Content Provider查询数据库的例子如下:

private void query() {
        Cursor cursor = this.getContentResolver().query(mCurrentURI, null, null, null, null);  //1
        showlog("count=" + cursor.getCount());
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            String table = cursor.getString(cursor.getColumnIndex("table_name"));
            String name = cursor.getString(cursor.getColumnIndex("name"));
            String detail = cursor.getString(cursor.getColumnIndex("detail"));
            showlog("table_name:" + table);
            showlog("name: " + name);
            showlog("detail: " + detail);
            cursor.moveToNext();
        }
        cursor.close();
    }

要想调用Content Provider,首先需要使用注释1处的getContentResolver方法,如下所示。

frameworks/base/core/Java/android/content/ContextWrapper.java

ContextWrapper#getContentResolver()

    @Override
    public ContentResolver getContentResolver() {
        return mBase.getContentResolver();
    }

Framework学习(八)Service的启动/绑定过程
这篇文章中我们已经分析了,mBase具体指向就是ContextImpl。

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

ContextImpl#getContentResolver()

    private final ApplicationContentResolver mContentResolver;
    ...
    @Override
    public ContentResolver getContentResolver() {
        return mContentResolver;
    }

上面代码返回了ApplicationContentResolver类型的mContentResolver对象,ApplicationContentResolver是ContextImpl中的静态内部类,继承自ContentResolver,它在ContextImpl的构造方法中被创建。

当我们调用ContentResolver的insert、query、update、delete等方法时就会启动Content Provider,这里拿query方法来进行举例。query方法的实现在ApplicationContentResolver的父类ContentResolver中。

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

ContentResolver#query()

public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
            @Nullable String[] projection, @Nullable String selection,
            @Nullable String[] selectionArgs, @Nullable String sortOrder,
            @Nullable CancellationSignal cancellationSignal) {
        Preconditions.checkNotNull(uri, "uri");
        IContentProvider unstableProvider = acquireUnstableProvider(uri);  //1
        ...
        try {
           ...
            try {
                qCursor = unstableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);  //2
            } catch (DeadObjectException e) {
               ...
            }
    ...
   }

注释1处通过acquireUnstableProvider方法返回IContentProvider类型的unstableProvider对象。
注释2处调用unstableProvider的query方法。
先看看注释1的方法吧。

ContentResolver#acquireUnstableProvider()

    public final IContentProvider acquireUnstableProvider(Uri uri) {
        if (!SCHEME_CONTENT.equals(uri.getScheme())) { //1
            return null;
        }
        String auth = uri.getAuthority();
        if (auth != null) {
            return acquireUnstableProvider(mContext, uri.getAuthority());  //2
        }
        return null;
    }

注释1处用来检查Uri的scheme是否等于”content”,如果不是则返回null。
注释2处调用了acquireUnstableProvider方法,这是个抽象方法,它的实现在ContentResolver的子类ApplicationContentResolver中。

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

ApplicationContentResolver#acquireUnstableProvider()

@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
    return mMainThread.acquireProvider(c,
            ContentProvider.getAuthorityWithoutUserId(auth),
            resolveUserIdFromAuthority(auth), false);
}

返回了ActivityThread类型的mMainThread对象的acquireProvider方法。

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

ActivityThread#acquireProvider()

public final IContentProvider acquireProvider(
         Context c, String auth, int userId, boolean stable) {
     final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);  //1
     if (provider != null) {
         return provider;
     }
     IActivityManager.ContentProviderHolder holder = null;
     try {
         holder = ActivityManagerNative.getDefault().getContentProvider(
                 getApplicationThread(), auth, userId, stable);  //2
     } catch (RemoteException ex) {
         throw ex.rethrowFromSystemServer();
     }
     if (holder == null) {
         Slog.e(TAG, "Failed to find provider info for " + auth);
         return null;
     }
     holder = installProvider(c, holder, holder.info,
             true /*noisy*/, holder.noReleaseNeeded, stable);  //3
     return holder.provider;
 }

注释1处检查ActivityThread中的ArrayMap类型的mProviderMap中是否有目标ContentProvider存在,有则返回,没有就会在注释2处调用AMP的getContentProvider方法,最终会调用AMS的getContentProvider方法。
注释3处的installProvider方法用来将注释2处返回的ContentProvider相关的数据存储在mProviderMap中,起到缓存的作用,这样使用相同的Content Provider时,就不需要每次都要调用AMS的getContentProvider方法。

AMS到ActivityThread的调用

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

ActivityManagerService#getContentProvider()

@Override
public final ContentProviderHolder getContentProvider(
        IApplicationThread caller, String name, int userId, boolean stable) {
 ...
    return getContentProviderImpl(caller, name, null, stable, userId);
}

ActivityManagerService#getContentProviderImpl()

private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
            String name, IBinder token, boolean stable, int userId) {
...
       ProcessRecord proc = getProcessRecordLocked(
                                cpi.processName, cpr.appInfo.uid, false); //1
                        if (proc != null && proc.thread != null && !proc.killed) {
                            ...
                            if (!proc.pubProviders.containsKey(cpi.name)) {
                                checkTime(startTime, "getContentProviderImpl: scheduling install");
                                proc.pubProviders.put(cpi.name, cpr);
                                try {
                                    proc.thread.scheduleInstallProvider(cpi); //2
                                } catch (RemoteException e) {
                                }
                            }
                        } else {
                            checkTime(startTime, "getContentProviderImpl: before start process");
                            proc = startProcessLocked(cpi.processName,
                                    cpr.appInfo, false, 0, "content provider",
                                    new ComponentName(cpi.applicationInfo.packageName,
                                            cpi.name), false, false, false); //3
                            checkTime(startTime, "getContentProviderImpl: after start process");
                          ...
                        }
             ...           

}

注释1处通过getProcessRecordLocked方法来获取目标ContentProvider的应用程序进程信息,这些信息用ProcessRecord类型的proc来表示,如果该应用进程已经启动就会调用注释2处的代码,否则就会调用注释3的startProcessLocked方法来启动进程。
应用程序进程启动过程请参考Framework学习(六)应用程序进程启动过程这篇文章。

ActivityThread启动Provider

frameworks/base/services/core/java/com/android/app/ActivityThread.java

ActivityThread#scheduleInstallProvider()

        @Override
        public void scheduleInstallProvider(ProviderInfo provider) {
            sendMessage(H.INSTALL_PROVIDER, provider);
        }

这里的H是ActivityThread的内部类并继承Handler。

ActivityThread.H

 private class H extends Handler {
        public static final int INSTALL_PROVIDER        = 145;
  ...

  public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case INSTALL_PROVIDER:
                    handleInstallProvider((ProviderInfo) msg.obj);
                    break;
                 ...
  } 

ActivityThread#handleInstallProvider()

    public void handleInstallProvider(ProviderInfo info) {
        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
        try {
            installContentProviders(mInitialApplication, Lists.newArrayList(info)); //1
        } finally {
            StrictMode.setThreadPolicy(oldPolicy);
        }
    }

注释1调用了installContentProviders方法。

ActivityThread#installContentProviders()

    private void installContentProviders(
            Context context, List<ProviderInfo> providers) {
        final ArrayList<IActivityManager.ContentProviderHolder> results =
            new ArrayList<IActivityManager.ContentProviderHolder>();

        for (ProviderInfo cpi : providers) {  //1
            if (DEBUG_PROVIDER) {
                StringBuilder buf = new StringBuilder(128);
                buf.append("Pub ");
                buf.append(cpi.authority);
                buf.append(": ");
                buf.append(cpi.name);
                Log.i(TAG, buf.toString());
            }
            IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);  //2
            if (cph != null) {
                cph.noReleaseNeeded = true;
                results.add(cph);
            }
        }

        try {
            ActivityManagerNative.getDefault().publishContentProviders(
                getApplicationThread(), results);  //3
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

注释1处遍历当前应用程序进程的ProviderInfo列表,得到每个Content Provider的ProviderInfo(存储Content Provider的信息)。
注释2处调用installProvider方法来启动这些Content Provider。
注释3处通过AMS的publishContentProviders方法将这些Content Provider存储在AMS的mProviderMap中,这个mProviderMap在前面提到过,起到缓存的作用,防止每次使用相同的Content Provider时都会调用AMS的getContentProvider方法。

ActivityThread#installProvider()

private IActivityManager.ContentProviderHolder installProvider(Context context,
           IActivityManager.ContentProviderHolder holder, ProviderInfo info,
           boolean noisy, boolean noReleaseNeeded, boolean stable) {
       ContentProvider localProvider = null;
  ...
               final java.lang.ClassLoader cl = c.getClassLoader();
               localProvider = (ContentProvider)cl.
                   loadClass(info.name).newInstance(); //1
               provider = localProvider.getIContentProvider();
               if (provider == null) {
                 ...
                   return null;
               }
               if (DEBUG_PROVIDER) Slog.v(
                   TAG, "Instantiating local provider " + info.name);
               localProvider.attachInfo(c, info); //2
           } catch (java.lang.Exception e) {
              ...
               }
               return null;
           }
       }
          ...
       return retHolder;
   }

注释1处通过反射来创建ContentProvider类型的localProvider对象。
注释2处调用了它的attachInfo方法。

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

ContentProvider#attachInfo()

public void attachInfo(Context context, ProviderInfo info) {
        attachInfo(context, info, false);
    }

    private void attachInfo(Context context, ProviderInfo info, boolean testing) {
        mNoPerms = testing;

        /*
         * Only allow it to be set once, so after the content service gives
         * this to us clients can't change it.
         */
        if (mContext == null) {
            mContext = context;
            if (context != null) {
                mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
                        Context.APP_OPS_SERVICE);
            }
            mMyUid = Process.myUid();
            if (info != null) {
                setReadPermission(info.readPermission);
                setWritePermission(info.writePermission);
                setPathPermissions(info.pathPermissions);
                mExported = info.exported;
                mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
                setAuthorities(info.authority);
            }
            ContentProvider.this.onCreate();  //1
        }
    }

注释1处调用了ContentProvider的onCreate方法,它是一个抽象方法,具体实现在具体Content Provider中。这样Content Provider就启动完毕了。



作者:码农小陈
链接:https://www.jianshu.com/p/86bb31f53a8a
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值