美文网首页
ContentProvider启动流程分析

ContentProvider启动流程分析

作者: feifei_fly | 来源:发表于2020-12-23 12:36 被阅读0次

    一、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系统中的唯一标识。

            <provider
                android:name=".MyProvider"
                android:authorities="com.sogou.feifei"
                android:exported="true"
                >
            </provider>
    

    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<ProviderInfo> providers) {
        final ArrayList<ContentProviderHolder> 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<ContentProviderHolder> 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启动流程分析

          本文链接:https://www.haomeiwen.com/subject/hfvynktx.html