ContentProvider启动流程分析

一、ContentProvider 介绍

1.1、什么是ContentProvider

ContentProvider是跨进程对外提供信息的一种标准接口
信息提供者 可以自定义ContentProvider,在Manifest.xml向系统进行注册,并指定唯一标识authorities。

信息查询者 可以利用ContentResolver指定authorities 获取到IContentProvider,查询返回Cursor对象,获取查询结果。

1.2、ContentProvider的基本使用

1.2.1、内容提供者

定义ContentProvider

public class MyProvider extends ContentProvider{

    private Context mContext;
    DBHelper mDbHelper = null;
    SQLiteDatabase db = null;
    public static final String AUTOHORITY = "com.sogou.feifei";
    // UriMatcher类使用:在ContentProvider 中注册URI
    private static final UriMatcher mMatcher;

    public static final int User_Code = 1;
    public static final int Job_Code = 2;


    static{
        mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        // 初始化
        mMatcher.addURI(AUTOHORITY,"user", User_Code);
        mMatcher.addURI(AUTOHORITY, "job", Job_Code);
        // 若URI资源路径 = content://cn.scu.myprovider/user ,则返回注册码User_Code
        // 若URI资源路径 = content://cn.scu.myprovider/job ,则返回注册码Job_Code
    }


    @Override
    public boolean onCreate() {
        mContext = getContext();
        mDbHelper = new DBHelper(getContext());
        db = mDbHelper.getWritableDatabase();

        // 初始化两个表的数据(先清空两个表,再各加入一个记录)
        db.execSQL("delete from user");
        db.execSQL("insert into user values(1,'Carson');");
        db.execSQL("insert into user values(2,'Kobe');");

        db.execSQL("delete from job");
        db.execSQL("insert into job values(1,'Android');");
        db.execSQL("insert into job values(2,'iOS');");

        Log.d("MyProvider","MyProvider was onCreate()");
        return true;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        // 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
        // 该方法在最下面
        String table = getTableName(uri);
        // 查询数据
        return db.query(table,projection,selection,selectionArgs,null,null,sortOrder,null);
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        // 由于不展示,此处不作展开
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        // 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
        // 该方法在最下面
        String table = getTableName(uri);
        // 向该表添加数据
        db.insert(table, null, values);

        // 当该URI的ContentProvider数据发生变化时,通知外界(即访问该ContentProvider数据的访问者)
        mContext.getContentResolver().notifyChange(uri, null);

        return uri;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        //...
        return 0;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        //...
        return 0;
    }

    /**
     * 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
     */
    private String getTableName(Uri uri){
        String tableName = null;
        switch (mMatcher.match(uri)) {
            case User_Code:
                tableName = DBHelper.USER_TABLE_NAME;
                break;
            case Job_Code:
                tableName = DBHelper.JOB_TABLE_NAME;
                break;
        }
        return tableName;
    }
}



class DBHelper extends SQLiteOpenHelper {
    // 数据库名
    private static final String DATABASE_NAME = "finch.db";
    private static final int DATABASE_VERSION = 1;
    // 表名
    public static final String USER_TABLE_NAME = "user";
    public static final String JOB_TABLE_NAME = "job";

    public DBHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // 创建两个表格:用户表 和职业表
        db.execSQL("CREATE TABLE IF NOT EXISTS " + USER_TABLE_NAME + "(_id INTEGER PRIMARY KEY AUTOINCREMENT," + " name TEXT)");

        db.execSQL("CREATE TABLE IF NOT EXISTS " + JOB_TABLE_NAME + "(_id INTEGER PRIMARY KEY AUTOINCREMENT," + " job TEXT)");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

Manifest.xml中声明 Provider,指定其authorities。authorities是ContentProvider在Android系统中的唯一标识。

        
        

1.2.2、内容使用者

  • 构建查询的Uri
image

//(1)自定义Uri 指定查询“com.sogou.feifei”ContentProvider的User表
Uri uri_user = Uri.parse("content://com.sogou.feifei/user");


//(2) 获取ContentResolver
ContentResolver resolver =  getContentResolver();

//(3)通过ContentResolver 根据URI 向ContentProvider中插入数据
resolver.insert(uri_user,values);

//(4)通过ContentResolver 向ContentProvider中查询数据
Cursor cursor = resolver.query(uri_user, new String[]{"_id","name"}, null, null, null);
while (cursor.moveToNext()){
    System.out.println("query book:" + cursor.getInt(0) +" "+ cursor.getString(1));
    // 将表中数据全部输出
}
cursor.close();

二、几个重要的类

2.1、ContentProvider

ContentProvider是一个抽象类:

  • 定义了insert、delete、updaete、query等抽象方法,具体的方法操作 由子类实现。
public abstract class ContentProvider implements ComponentCallbacks2 {
    
    private Context mContext = null;

     public abstract int delete(@NonNull Uri uri, @Nullable String selection,
            @Nullable String[] selectionArgs);

     public abstract int update(@NonNull Uri uri, @Nullable ContentValues values,
            @Nullable String selection, @Nullable String[] selectionArgs);
     
     public abstract @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues values);

     public abstract @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
        @Nullable String selection, @Nullable String[] selectionArgs,
        @Nullable String sortOrder);

     private Transport mTransport = new Transport();

  • ContentProvider内部持有一个Transport()对象,Transport是一个实现了IProvider接口的Binder类,用于对外提供IPC调用接口。
   class Transport extends ContentProviderNative {

     @Override
     public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection,
                @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {}

     @Override
     public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {}

     @Override
     public int update(String callingPkg, Uri uri, ContentValues values, String selection,
                String[] selectionArgs) {}

     public abstract int delete(@NonNull Uri uri, @Nullable String selection,
                @Nullable String[] selectionArgs);
    }

   abstract public class ContentProviderNative extends Binder implements IContentProvider {
  
   }

2.2、ContentResolver

ContentResolver 用于数据使用方,向ContentProvider查询数据

  • acquireProvider 方法 通过Uri中的authorities 在Android系统中查询对应的ContentProvider,返回ContentProvider的Bindder对象
  • 通过IContentProvider 代理实现 insert、delete、query、update等操作。
public abstract class ContentResolver {
    
       //向Android系统查询 uri对应的ContextProvider实例的Binder对象
       public final IContentProvider acquireProvider(Uri uri) {
            if (!SCHEME_CONTENT.equals(uri.getScheme())) {
                return null;
            }
            final String auth = uri.getAuthority();
            if (auth != null) {
                return acquireProvider(mContext, auth);
            }
            return null;
        }

        public final @Nullable Cursor query(uri) {
              return  acquireProvider().query(uri)
        }

        public final @Nullable Uri insert(Uri url) {

             return acquireProvider.insert(url)
        }

        public final int delete(Uri url){
            return acquireProvider.delete(url)
         }

         public final int update(Uri uri) {
                return acquireProvider(uri).update(uri)
         }
}
   

2.3、ProviderInfo

ProviderInfo 代表一个Provider信息,对应manifest.xml中声明的一条Provider记录

public final class ProviderInfo extends ComponentInfo
        implements Parcelable {
    

    public String authority = null;
    

    public String readPermission = null;
    

    public String writePermission = null;
    

    public boolean grantUriPermissions = false;
    
 
    public PatternMatcher[] uriPermissionPatterns = null;
    
   
    public PathPermission[] pathPermissions = null;
 
    public boolean multiprocess = false;

  }

2.4、ContentProviderHolder

ContentProviderHolder 数据持有者,持有ProviderInfo、IContentProvider对象,用于在IPC中传递参数

public class ContentProviderHolder implements Parcelable {
    public final ProviderInfo info;
    public IContentProvider provider;
    public IBinder connection;
    public boolean noReleaseNeeded;

    }

2.5、ProviderClientRecord

ProviderClientRecord 代表app端一条ContentProvider记录。
内部持有远端IContentProvider、本地ContentProvider实例和ContentProviderHolder实例

final class ProviderClientRecord {
        final String[] mNames;
        //mProvider 远端Provider实例
        final IContentProvider mProvider;
        //本地的Provider实例
        final ContentProvider mLocalProvider;
        final ContentProviderHolder mHolder;

        ProviderClientRecord(String[] names, IContentProvider provider,
                ContentProvider localProvider, ContentProviderHolder holder) {
            mNames = names;
            mProvider = provider;
            mLocalProvider = localProvider;
            mHolder = holder;
        }
    }

三、调用过程

  • ContextResolver.query()
  • ContextResolver.acquireUnstableProvider()
  • ApplicationContentResolver.acquireUnstableProvider()
  • ActivityThread.acquireProvider()

3.1、通过authority 在系统中查询 ContentProvider

 public final IContentProvider acquireProvider(
            Context c, String auth, int userId, boolean stable) {
        
        //(1)首先查询自身有没有缓存过该ContentProvider,命中缓存则直接返回。    
        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
        if (provider != null) {
            return provider;
        }

        //(2)调用IActivityManager.getContentProvider()
        ContentProviderHolder holder = null;
        try {
            synchronized (getGetProviderLock(auth, userId)) {
                holder = ActivityManager.getService().getContentProvider(
                        getApplicationThread(), auth, userId, stable);
            }
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        if (holder == null) {
            Slog.e(TAG, "Failed to find provider info for " + auth);
            return null;
        }

        //(3)将IActivityManager返回的ContentProviderHolder在本地进行安装
        holder = installProvider(c, holder, holder.info,
                true /*noisy*/, holder.noReleaseNeeded, stable);
        return holder.provider;
    }
  • 首先查询自身有没有缓存过该ContentProvider,命中缓存则直接返回

ActivityThread中的mProviderMap中保存这所有安装过的ContentProvider

  public final IContentProvider acquireExistingProvider(
            Context c, String auth, int userId, boolean stable) {
        synchronized (mProviderMap) {
            final ProviderKey key = new ProviderKey(auth, userId);
            final ProviderClientRecord pr = mProviderMap.get(key);
            if (pr == null) {
                return null;
            }

            IContentProvider provider = pr.mProvider;
            IBinder jBinder = provider.asBinder();
            if (!jBinder.isBinderAlive()) {
           
                handleUnstableProviderDiedLocked(jBinder, true);
                return null;
            }

         
            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
            if (prc != null) {
                incProviderRefLocked(prc, stable);
            }
            return provider;
        }
    }
  • 若ActivityThread本地没有命中缓存的ContentProvider,则IPC调用IActivityMangaer.query() 向Android系统查询ContentProvider,查询结果保存在返回值ContentProviderHolder中

将IActivityManager返回的ContentProviderHolder在ActivityThread中进行安装

安装的过程会区分本地ContentProvider和远端ContentProvider

 private ContentProviderHolder installProvider(Context context,
            ContentProviderHolder holder, ProviderInfo info,
            boolean noisy, boolean noReleaseNeeded, boolean stable) {
        
        ContentProvider localProvider = null;
        IContentProvider provider;


        //(1) 当Holder.provider == null 时,说明查询的ContentProvider属于当前进程,在ActivityThread中本地实例化一个ContentProvider实例,安装后进行查询操作
        //holder.provider != null,说明ContentProvider是运行在其他进程中,返回IProvider(Binder) IPC 跨进程查询。

        if (holder == null || holder.provider == null) {
           
            Context c = null;
            ApplicationInfo ai = info.applicationInfo;
        
            final java.lang.ClassLoader cl = c.getClassLoader();
            LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
            
            //在当前进程实例化一个ContentProvider
            localProvider = packageInfo.getAppFactory()
                    .instantiateProvider(cl, info.name);
            provider = localProvider.getIContentProvider();
         
        
            localProvider.attachInfo(c, info);
           
        } else { 
            provider = holder.provider;
        }

        ContentProviderHolder retHolder;

        //(2) 将LocalProvider和provider 封装成ProviderClientRecord 换成进入ActivityThread
        synchronized (mProviderMap) {
           
            IBinder jBinder = provider.asBinder();
            if (localProvider != null) { //对于本地ContentProvider 
 
                //本地创建一个ProviderClientRecord() 缓存在mLocalProviders和mLocalProvidersByName中。
                holder = new ContentProviderHolder(info);
                holder.provider = provider;
                holder.noReleaseNeeded = true;
                pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                mLocalProviders.put(jBinder, pr);
                mLocalProvidersByName.put(cname, pr);
                
                retHolder = pr.mHolder;
            } else {  //对于 远端ContentProvider 
            
                    ProviderClientRecord client = installProviderAuthoritiesLocked(
                            provider, localProvider, holder);
                    if (noReleaseNeeded) {
                        prc = new ProviderRefCount(holder, client, 1000, 1000);
                    } else {
                        prc = stable
                                ? new ProviderRefCount(holder, client, 1, 0)
                                : new ProviderRefCount(holder, client, 0, 1);
                    }
                    mProviderRefCountMap.put(jBinder, prc);
                }
                retHolder = prc.holder;
            }
        }
        return retHolder;
    }

当Holder.provider == null 时,说明查询的ContentProvider属于当前进程,在ActivityThread中本地实例化一个ContentProvider实例

holder.provider != null,说明ContentProvider运行在其他进程中,返回IProvider(Binder) IPC 跨进程查询

本地ContentProvider或者远端IContentProvider 封装成ProviderClientRecord 缓存在ActivityThread,方便下次复用。

3.2、ActivityManagerService 中查询ContentProvider

  • ActivityManagerService.getContentProvider()
  • ActivityManagerService.getContentProviderImpl()

ContentProvider的查询操作主要实现在getContentProviderImpl中,代码比较长,可以分几部分来看。

private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
            String name, IBinder token, boolean stable, int userId) {


        ContentProviderRecord cpr;
        ContentProviderConnection conn = null;
        ProviderInfo cpi = null;

        synchronized(this) {
          
            ProcessRecord r = null;
            if (caller != null) {
                r = getRecordForAppLocked(caller);
                if (r == null) {
                    throw new SecurityException(
                            "Unable to find app for caller " + caller
                          + " (pid=" + Binder.getCallingPid()
                          + ") when getting content provider " + name);
                }
            }

            //(1)查询ContentProvider 是否已经发布,发布后会缓存在mProviderMap中
            // First check if this content provider has been published...
            cpr = mProviderMap.getProviderByName(name, userId);

            boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
            if (providerRunning) {
                cpi = cpr.info;
             
                if (r != null && cpr.canRunHere(r)) {
                    //查询的ContentProvider允许 运行在调用者的进程,此时直接返回一个空的ContentProviderHolder给调用者进程,由调用者进程自己实例化ContentProvider实例。
                    ContentProviderHolder holder = cpr.newHolder(null);
                    holder.provider = null;
                    return holder;
                }
               

                conn = incProviderCountLocked(r, cpr, token, stable)
                cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);


            }


            if (!providerRunning) {  //查询ConntetProvider还没有发布,或者已发布但没有运行
              
             
                cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
     

                ComponentName comp = new ComponentName(cpi.packageName, cpi.name);


                //取出缓存的ContentProviderRecord,或者创建一个新的ContentProviderRecord,
                cpr = mProviderMap.getProviderByClass(comp, userId);
           
                final boolean firstClass = cpr == null;
                if (firstClass) {
                    ApplicationInfo ai =AppGlobals.getPackageManager().getApplicationInfo(cpi.applicationInfo.packageName,STOCK_PM_FLAGS, userId);
                    ai = getAppInfoForUser(ai, userId);

                    //创建一个ContentProviderRecord
                    cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
                    
                }

                if (r != null && cpr.canRunHere(r)) {
               
                    //查询的ContentProvider 可以运行在调用者进程,则直接返回空的ContentProviderHolder,由调用者进程自己实例化ContentProvider
                    return cpr.newHolder(null);
                }

              

                //尝试启动ContentProvider,
                //若ContetProvider所属的ProcessRecord进程存在,则直接调用proc.thread.scheduleInstallProvider(cpi);启动进程
                //若ContentProvider所属的进程(ProcessRecord不存在)尚未启动,则首先启动ProcessrRecord进程
                final int N = mLaunchingProviders.size();
                int i;
                for (i = 0; i < N; i++) {
                    if (mLaunchingProviders.get(i) == cpr) {
                        break;
                    }
                }

                // If the provider is not already being launched, then get it
                // started.
                if (i >= N) {
                    ProcessRecord proc = getProcessRecordLocked(
                            cpi.processName, cpr.appInfo.uid, false);
                    if (proc != null && proc.thread != null && !proc.killed) {
                      
                        if (!proc.pubProviders.containsKey(cpi.name)) {
                    
                            proc.pubProviders.put(cpi.name, cpr);
                            try {
                                //匹配上ContentProvider所属的进程,调用scheduleInstallProvider() 安装ContentProvider
                                proc.thread.scheduleInstallProvider(cpi);
                            } catch (RemoteException e) {
                            }
                        }
                    } else {
                       
                       //启动新的进程
                        proc = startProcessLocked(cpi.processName,
                                cpr.appInfo, false, 0, "content provider",
                                new ComponentName(cpi.applicationInfo.packageName,
                                        cpi.name), false, false, false);
            
                    }
                    cpr.launchingApp = proc;
                    mLaunchingProviders.add(cpr);
            
                }

            

                mProviderMap.putProviderByName(name, cpr);
                conn = incProviderCountLocked(r, cpr, token, stable);
                if (conn != null) {
                    conn.waiting = true;
                }
            }
           

        }

        //等待ContentProvider所属的进程启动,ContentProdier实例启动完成
        // Wait for the provider to be published...
        synchronized (cpr) {
            while (cpr.provider == null) {
                
                try {
                   
                    if (conn != null) {
                        conn.waiting = true;
                    }
                    cpr.wait();
                } catch (InterruptedException ex) {
                } finally {
                    if (conn != null) {
                        conn.waiting = false;
                    }
                }
            }
        }
        return cpr != null ? cpr.newHolder(conn) : null;
    }

3.2.1、查询ContentProvider 在ActivityManagerService中是否已经发布(已发布的ContentProvider会缓存在mProviderMap中)

 
// First check if this content provider has been published...
cpr = mProviderMap.getProviderByName(name, userId);

3.2.2、若ContentProvider已经发布,并且ContentProvider所属的进程正在运行,如果ContentProvider可以在调用者进程中运行,则返回空的ContentProviderHolder,由调用者进程实例化一个本地的ContentProvider;否则在ActivityManagerService类中实例化一个ContentProviderConnection实例和ContentProviderRecord实例 备用。

boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
            if (providerRunning) {
                cpi = cpr.info;
             
                if (r != null && cpr.canRunHere(r)) {
                    //查询的ContentProvider允许 运行在调用者的进程,此时直接返回一个空的ContentProviderHolder给调用者进程,由调用者进程自己实例化ContentProvider实例。
                    ContentProviderHolder holder = cpr.newHolder(null);
                    holder.provider = null;
                    return holder;
                }
               

                conn = incProviderCountLocked(r, cpr, token, stable)
                cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);


            }

3.2.3、待查询的ConntetProvider在ActivityManagerService中还没有发布,则尝试安装该ContentProvider

ContentProvider可以在调用者进程中运行,则直接返回空的ContentProviderHolder

 if (!providerRunning) {  //查询ConntetProvider还没有发布,或者已发布但没有运行
              
             
                cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
     

                ComponentName comp = new ComponentName(cpi.packageName, cpi.name);


                //取出缓存的ContentProviderRecord,或者创建一个新的ContentProviderRecord,
                cpr = mProviderMap.getProviderByClass(comp, userId);
           
                final boolean firstClass = cpr == null;
                if (firstClass) {
                    ApplicationInfo ai =AppGlobals.getPackageManager().getApplicationInfo(cpi.applicationInfo.packageName,STOCK_PM_FLAGS, userId);
                    ai = getAppInfoForUser(ai, userId);

                    //创建一个ContentProviderRecord
                    cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
                    
                }

                if (r != null && cpr.canRunHere(r)) {
               
                    //查询的ContentProvider 可以运行在调用者进程,则直接返回空的ContentProviderHolder,由调用者进程自己实例化ContentProvider
                    return cpr.newHolder(null);
                }

     
 }

ContentProvider不是运行于调用者进程,则尝试安装该ContentProvider,分两种情况:

  • 当ContentProvider所属的进程已经存在,则直接调用scheduleInstallProvider()安装ContentProvider
  • 当前ContentProvider所属的进程不存在,则先启动进程
        //尝试启动ContentProvider,
        //若ContetProvider所属的ProcessRecord进程存在,则直接调用proc.thread.scheduleInstallProvider(cpi);启动进程
        //若ContentProvider所属的进程(ProcessRecord不存在)尚未启动,则首先启动ProcessrRecord进程
        final int N = mLaunchingProviders.size();
        int i;
        for (i = 0; i < N; i++) {
            if (mLaunchingProviders.get(i) == cpr) {
                break;
            }
        }

        // If the provider is not already being launched, then get it
        // started.
        if (i >= N) {
            ProcessRecord proc = getProcessRecordLocked(
                    cpi.processName, cpr.appInfo.uid, false);
            if (proc != null && proc.thread != null && !proc.killed) {
              
                if (!proc.pubProviders.containsKey(cpi.name)) {
            
                    proc.pubProviders.put(cpi.name, cpr);
                    try {
                        //匹配上ContentProvider所属的进程,调用scheduleInstallProvider() 安装ContentProvider
                        proc.thread.scheduleInstallProvider(cpi);
                    } catch (RemoteException e) {
                    }
                }
            } else {
               
               //启动新的进程
                proc = startProcessLocked(cpi.processName,
                        cpr.appInfo, false, 0, "content provider",
                        new ComponentName(cpi.applicationInfo.packageName,
                                cpi.name), false, false, false);
    
            }
            cpr.launchingApp = proc;
            mLaunchingProviders.add(cpr);
    
        }

    

        mProviderMap.putProviderByName(name, cpr);
        conn = incProviderCountLocked(r, cpr, token, stable);
        if (conn != null) {
            conn.waiting = true;
        }
    }
   

}

3.2.4、等待ContentProvider安装完成,然后返回ContentProviderHolder实例

若ContentProvider.provider==null,则调用cpr.wait(),lock主当前操作。


        //等待ContentProvider所属的进程启动,ContentProdier实例启动完成
        // Wait for the provider to be published...
        synchronized (cpr) {
            while (cpr.provider == null) {
                
                try {
                   
                    if (conn != null) {
                        conn.waiting = true;
                    }
                    cpr.wait();
                } catch (InterruptedException ex) {
                } finally {
                    if (conn != null) {
                        conn.waiting = false;
                    }
                }
            }
        }
        return cpr != null ? cpr.newHolder(conn) : null;

3.3、启动新进程,安装ContentProvider

承接上文 3.2.4 场景,新启动的ContentProvider需要,新启动进程,在新进程中安装ContentProvider


image

进程启动后,会调用ActivityThread.main()

  • ActivityThread().attach()
  • ActivityManagerService.attachApplication()
  • ActivityManagerService.attachApplicationLocked()

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {

    //providers 即为Manifest.xml中提取出来的所有的ContentProvider,告知ApplicationThread 有哪些ContentProvider需要安装
    thread.bindApplication(processName, appInfo, providers,
            app.instr.mClass,
            profilerInfo, app.instr.mArguments,
            app.instr.mWatcher,
            app.instr.mUiAutomationConnection, testMode,
            mBinderTransactionTrackingEnabled, enableTrackAllocation,
            isRestrictedBackupMode || !normalMode, app.persistent,
            new Configuration(getGlobalConfiguration()), app.compat,
            getCommonServicesLocked(app.isolated),
            mCoreSettingsObserver.getCoreSettingsLocked(),
            buildSerial, isAutofillCompatEnabled);

    return true;
}
  • ApplicationThread.bindApplication()
  • sendMessage(H.BIND_APPLICATION
  • ActivityThread.handleBindApplication()
private void handleBindApplication(AppBindData data) {

    //创建ContextImpl 
    final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);

    //创建Instrumentation
    final ClassLoader cl = instrContext.getClassLoader();
    mInstrumentation = (Instrumentation)
        cl.loadClass(data.instrumentationName.getClassName()).newInstance();

    final ComponentName component = new ComponentName(ii.packageName, ii.name);
    mInstrumentation.init(this, instrContext, appContext, component,
            data.instrumentationWatcher, data.instrumentationUiAutomationConnection);

    //创建Application    
    Application app;
    app = data.info.makeApplication(data.restrictedBackupMode, null);

    //注意,这里是install ContentProvider
    installContentProviders(app, data.providers);
    
    //调用Application的onCreate方法
    mInstrumentation.callApplicationOnCreate(app);
}

handleBindApplication方法干了很多事情

创建ContextImpl
创建Instrumentation
创建Application
创建ContentProvider,并调用其onCreate方法
调用Application的onCreate方法

我们继续深入installContentProviders方法,实例化ContentProvider之后会调用IActivityManager.publishContentProviders()

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

    for (ProviderInfo cpi : providers) {
        //构建ContentProvider
        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();
    }
}

private ContentProviderHolder installProvider(Context context,
        ContentProviderHolder holder, ProviderInfo info,
        boolean noisy, boolean noReleaseNeeded, boolean stable) {
    ContentProvider localProvider = null;

    //通过ClassLoader 反射构建ContentProvider
    final java.lang.ClassLoader cl = c.getClassLoader();
    localProvider = packageInfo.getAppFactory()
            .instantiateProvider(cl, info.name);
    
    //attachInfo方法里面就会调用ContentProvider的onCreate方法
    localProvider.attachInfo(c, info);

    return retHolder;
}

我们再看publishContentProviders()方法。

    public final void publishContentProviders(IApplicationThread caller,
            List providers) {
      
        synchronized (this) {
            final ProcessRecord r = getRecordForAppLocked(caller);
            final int N = providers.size();
            for (int i = 0; i < N; i++) {
                ContentProviderHolder src = providers.get(i);
           
                ContentProviderRecord dst = r.pubProviders.get(src.info.name);
               
                if (dst != null) {
                  
                    int launchingCount = mLaunchingProviders.size();
                    int j;
                    boolean wasInLaunchingProviders = false;
                    for (j = 0; j < launchingCount; j++) {
                        if (mLaunchingProviders.get(j) == dst) {
                            mLaunchingProviders.remove(j);
                            wasInLaunchingProviders = true;
                            j--;
                            launchingCount--;
                        }
                    }
                  
                    synchronized (dst) {
                        dst.provider = src.provider;
                        dst.proc = r;
                        dst.notifyAll();
                    }
                 
                }
            }

        }
    }

publishContentProviders 内部 匹配对应的ContentProviderRecord,调用了ContentProviderRecord.notify()

此时因等待该ContentProvider启动而block主的代码就会恢复运行。见 3.2.4

四、小结

4.1、几点结论

  • app启动的时候 会将Manifest.xml中声明的ContentProvider进行实例化并安装
  • app本进程内安装之后,contentProvider实例 会在app本地进程进行缓存(mProviderMap),这样 app内自己调用contentResolver请求ContentProvider时,直接从缓存提取,不需向ActivityManagerService 进行IPC查询
  • app进程内安装ContentProvider后,会调用IActivityManager.publishContentProviders()向ActivityManagerService进行注册发布 ,这些ContentProvider会缓存在ActivityManagerService(mProviderMap)中,标记为已发布,当其他进程ICP查询该ContentProvider时,可以直接将缓存结果直接通过IPC返回。
  • app启动过程中,ContentProvider 先于Application 调用onCreate()方法

4.2、完整的调用时序图

下面是一张完整的ContentProvider的启动流程图

场景如下:

  • App B 提供ContentProvider,但从未启动
  • App A 通过authorities,首次向系统查询该ContentProvider
ContentProvider启动流程图

五、参考文章

ContentProvider基本使用

ContentProvider启动过程分析

https://blog.csdn.net/xfhy_/article/details/93138933

https://my.oschina.net/u/4580391/blog/4360153

你可能感兴趣的:(ContentProvider启动流程分析)