首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >ContentProvider 源码分析

ContentProvider 源码分析

作者头像
Yif
发布2019-12-26 15:24:07
发布2019-12-26 15:24:07
70800
代码可运行
举报
文章被收录于专栏:Android 进阶Android 进阶
运行总次数:0
代码可运行

ContentProvider 简介

  • ContentProvider 作为 Android 四大组件中的一种,为我们提供了不同进程甚至是不同应用程序之间共享数据的机制。
  • ContentProvider 的生命周期默认在 Application onCreate() 之前,而且都是在主线程创建的,这和其他四大组件是不同的
  • ContentProvider 多进程模式,它可以和 AndroidManifest 中的 multiprocess 属性结合使用
  • ContentProvider 进行跨进程数据传递时,利用Binder与内存共享机制,就是通过 Binder 传递 CursorWindow 对象内部的匿名共享内存的文件描述符。这样在跨进程传输中,结果数据并不需要跨进程传输,而是在不同进程中通过传输的匿名共享内存文件描述符来操作同一块匿名内存,这样来实现不同进程访问相同数据的目的。

ContentProvider 、 ContentResolver 、 ContentObserver 之间的关系

  • ContentProvider 内容提供者,用于对外提供数据
  • ContentResolver.notifyChange(uri)发出消息
  • ContentResolver 内容解析者,用于获取内容提供者提供的数据
  • ContentObserver 内容监听器,可以监听数据的改变状态
  • ContentResolver.registerContentObserver()监听消息。

ContentProvider 创建源码分析

ContentProvider 启动会伴随进程的启动,在ActivityManagerService中,启动进程是由startProcessLocked方法来完成的,内部通过Processstart方法来完成一个新的进程启动。 ActivityThreadmain方法

代码语言:javascript
代码运行次数:0
运行
复制
public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        CloseGuard.setEnabled(false);
 
        Environment.initForCurrentUser();
 
        EventLogger.setReporter(new EventLoggingReporter());
 
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);
 
        Process.setArgV0("<pre-initialized>");
 
        Looper.prepareMainLooper();
 
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
 
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
 
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
 
        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();
 
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

main方法是一个静态方法,首先创建ActivityThread,然后调用attach方法进行一系列的数据操作,再开启主线程Looper循环。 attach方法

代码语言:javascript
代码运行次数:0
运行
复制
private void attach(boolean system) {
......
 final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
......            
}

ActivityManager.getService()实质上就是ActivityManagerService,所以最终调用的是ActivityManagerServiceattachApplication方法 ,内部调用attachApplicationLocked,然后又调用ApplicationThread的bindApplication方法进行进程间调用。

代码语言:javascript
代码运行次数:0
运行
复制
 public final void bindApplication(String processName, ApplicationInfo appInfo,
                List<ProviderInfo> providers, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableBinderTracking, boolean trackAllocation,
                boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                String buildSerial) {
 
            if (services != null) {
                // Setup the service cache in the ServiceManager
                ServiceManager.initServiceCache(services);
            }
 
            setCoreSettings(coreSettings);
 
            AppBindData data = new AppBindData();
            data.processName = processName;
            data.appInfo = appInfo;
            data.providers = providers;
            data.instrumentationName = instrumentationName;
            data.instrumentationArgs = instrumentationArgs;
            data.instrumentationWatcher = instrumentationWatcher;
            data.instrumentationUiAutomationConnection = instrumentationUiConnection;
            data.debugMode = debugMode;
            data.enableBinderTracking = enableBinderTracking;
            data.trackAllocation = trackAllocation;
            data.restrictedBackupMode = isRestrictedBackupMode;
            data.persistent = persistent;
            data.config = config;
            data.compatInfo = compatInfo;
            data.initProfilerInfo = profilerInfo;
            data.buildSerial = buildSerial;
            sendMessage(H.BIND_APPLICATION, data);
        }

最后通过handler发送一个消息,调用ActivityTread的handleBindApplication方法。

代码语言:javascript
代码运行次数:0
运行
复制
首先创建ContextImpl与Instrumentation对象
final ApplicationInfo instrApp = new ApplicationInfo();
        ii.copyTo(instrApp);
        instrApp.initForUser(UserHandle.myUserId());
        final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
                appContext.getClassLoader(), false, true, false);
        final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);

        try {
            final ClassLoader cl = instrContext.getClassLoader();
            mInstrumentation = (Instrumentation)
                cl.loadClass(data.instrumentationName.getClassName()).newInstance();
        } catch (Exception e) {
            throw new RuntimeException(
                "Unable to instantiate instrumentation "
                + data.instrumentationName + ": " + e.toString(), e);
        }

  1. 然后再创建Application对象
代码语言:javascript
代码运行次数:0
运行
复制

 app = data.info.makeApplication(data.restrictedBackupMode, null);
启动当前进程ContentProvider并调用onCreate方法
if (!data.restrictedBackupMode) {
            if (!ArrayUtils.isEmpty(data.providers)) {
                installContentProviders(app, data.providers);
                // For process that contains content providers, we want to
                // ensure that the JIT is enabled "at some point".
                mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
            }
        }
private void installContentProviders(
        Context context, List<ProviderInfo> providers) {
    final ArrayList<ContentProviderHolder> results = new ArrayList<>();

    for (ProviderInfo cpi : providers) {
        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());
        }
        ContentProviderHolder cph = installProvider(context, null, cpi,
                false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
        if (cph != null) {
            cph.noReleaseNeeded = true;
            results.add(cph);
        }
    }

    try {
        ActivityManager.getService().publishContentProviders(
            getApplicationThread(), results);
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
}

  1. installContentProviders完成ContentProvider启动操作,遍历ProviderInfo列表通过installProvider进行启动操作,然后将已经启动的ContentProvider通过进程的方式发布到AMS中。 通过ClassLoader进行加载ContentProvider,完成ContentProvider对象创建
代码语言:javascript
代码运行次数:0
运行
复制

   final java.lang.ClassLoader cl = c.getClassLoader();
            localProvider = (ContentProvider)cl.
                loadClass(info.name).newInstance();
            provider = localProvider.getIContentProvider();

最后调用localProvider.attachInfo(c, info);完成ContentProvider的onCreate操作

代码语言:javascript
代码运行次数:0
运行
复制

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();
    }
}

最后调用Application的onCreate

代码语言:javascript
代码运行次数:0
运行
复制
try {
            mInstrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            if (!mInstrumentation.onException(app, e)) {
                throw new RuntimeException(
                  "Unable to create application " + app.getClass().getName()
                  + ": " + e.toString(), e);
            }
        }

ContentProvider已经完成所有的过程,这样ActivityManager就可以可以访问这个ContentProvider,并通过接口来访问它。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年9月6日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ContentProvider 简介
    • ContentProvider 、 ContentResolver 、 ContentObserver 之间的关系
  • ContentProvider 创建源码分析
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档