Android跨进程通信——ContentProvider

概念

作为四大组件之一(Activity , Service , BroadcastReciver , ContentProvider),为我们提供了不同进程甚至是不同应用之间共享数据的机制。

启动性能

ContentProvider的onCreate()在Application.onCreate()之前调用,而且都是在main线程创建的。因此,自定义ContentProvider的构造函数,静态代码块,onCreate()都尽量不要做耗时操作,否则会拖慢启动速度。
ContentProvider提供的query, insert, delete, update都是在Binder线程中执行的。可能存在多线程并发的问题,因此方法内部要做好线程同步。

稳定性

ContentProvider在进行跨进程数据传递时,利用了 Binder匿名共享内存 机制。概述:通过Binder传递CursorWindow对象内部的匿名共享内存的fd(文件描述符)。这样的话数据不需要跨进程,而是在不同的进程中通过fd来操作同一块匿名内存。
Android的Binder传输是有大小限制的,一般来说是 1~2M

安全性

如果在xml中注册ContentProvider时,android:exported="true",若支持执行SQL语句时就需要注意SQL注入的问题;
如果我们传入的参数是一个文件路径,然后返回文件的内容,这个时候要检验合法性,否则整个应用的私有数据都有可能泄露。

使用

  1. 自定义ContentProvider
public class CubeContentProvider extends ContentProvider {
    
    @Override
    public boolean onCreate() {
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        return null;
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return Uri.parse(Cube.AUTHORITY + getCloudValue(values));
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }
  1. 注册ContentProvider

android:authorities: ContentProvider的唯一标识
android:permission:外部应用访问时,必须声明该权限
android:multiprocess=“true”:会在每一个进程创建一个ContentProvider实例,会出现多实例问题。没有必要设置该属性

<provider
            android:authorities="xxx.CubeContentProvider"
            android:name="xxx.CubeContentProvider"
            android:permission = "xxx"
            android:process=":provider"/>
  1. 访问数据
mContext.getContentResolver().insert(uri,null)

问题

  1. AMS如何启动ContentProvider?

AMS通过startProcessLocked()启动ContentProvider所在的进程的时候,会启动ContentProvider;在进程没有启动的时候,由于执行ContentProvider中的任意CRUD方法,也会触发进程和ContentProvider的启动。

class ActivityThread
public final IContentProvider acquireProvider(...){
// 检测ContentProvider是否已经在mProviderMap中存在
    final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
    if (provider != null) {
            return provider;
        }
    // 通过AMS启动ContentProvider
    ContentProviderHolder holder = null;
        try {
            synchronized (getGetProviderLock(auth, userId)) {
                holder = ActivityManager.getService().getContentProvider(
                        getApplicationThread(), auth, userId, stable);
            }
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    // 修改引用计数
    holder = installProvider(c, holder, holder.info,
                true /*noisy*/, holder.noReleaseNeeded, stable);
    return holder.provider;
}

public static void main(String[] args){
    // 在main线程中,准备一个消息通知机制
     Looper.prepareMainLooper();
     ActivityThread thread = new ActivityThread();
     thread.attach(false, startSeq);
     if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
     Looper.loop();
}

private void attach(boolean system, long startSeq) {
    ****
    final IActivityManager mgr = ActivityManager.getService();
            try {
            // 最终会执行到bindApplication
                mgr.attachApplication(mAppThread, startSeq);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
    ****
}

 public final void bindApplication(***){
      AppBindData data = new AppBindData();
      ***
      省略代码
      ***
      sendMessage(H.BIND_APPLICATION, data);
      // 之后执行到handleBindApplication(data);
 }
 // 完成ContentProvider的创建启动以及调用Application,onCreate()
 private void handleBindApplication(AppBindData data) {
    // 创建ContextImpl和Instrumentation
    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);
            }

            final ComponentName component = new ComponentName(ii.packageName, ii.name);
            mInstrumentation.init(this, instrContext, appContext, component,
                    data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
    // 创建Application对象
    Application app = data.info.makeApplication(data.restrictedBackupMode, null);
    mInitialApplication = app;
    // 启动当前进程的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);
                }
            }
      }
    // 调用Application.onCreatr()
    mInstrumentation.callApplicationOnCreate(app);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值