现在的位置: 首页 > 综合 > 正文

ContentProvider的起源和获取

2014年01月10日 ⁄ 综合 ⁄ 共 7879字 ⁄ 字号 评论关闭

 ContentProvider的起源和获取

 

大名鼎鼎的ContentProvider相信大家都很熟悉了,但是或许你对于ContentProvider的起源和获取并不是很了解,下面我们就来看看吧!

ContentProvider的起源

先看看ContentProvider是如何安装于android系统中的吧!

1,在用户安装android app时,会用到PMPackage
Manager
),这一点相信大家都很熟悉了。在安装过程中,有以下代码需要关注:

PackageManagerService. scanPackageLI  (@PackageManagerService.java)

{

……

           int N = pkg.providers.size();

           StringBuilder r = null;

           int i;

           for (i=0; i<N; i++) {

               PackageParser.Provider p = pkg.providers.get(i);

               p.info.processName = fixProcessName(pkg.applicationInfo.processName,

                       p.info.processName, pkg.applicationInfo.uid);

               mProvidersByComponent.put(new ComponentName(p.info.packageName,

                       p.info.name), p);

               p.syncable = p.info.isSyncable;

               if (p.info.authority != null) {

                   String names[] = p.info.authority.split(";");

                   p.info.authority = null;

                   for (int j = 0; j < names.length; j++) {

                       if (j == 1 && p.syncable) {

                           // We only want the first authority for a provider to possibly be

                           // syncable, so if we already added this provider using a different

                           // authority clear the syncable flag. We copy the provider before

                           // changing it because the mProviders object contains a reference

                           // to a provider that we don't want to change.

                           // Only do this for the second authority since the resulting provider

                           // object can be the same for all future authorities for this provider.

                           p = new PackageParser.Provider(p);

                           p.syncable = false;

                       }

                       if (!mProviders.containsKey(names[j])) {

                           mProviders.put(names[j], p);

                           if (p.info.authority == null) {

                               p.info.authority = names[j];

                           } else {

                               p.info.authority = p.info.authority + ";" + names[j];

                           }

                           if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD)

                               Log.d(TAG, "Registered content provider: " + names[j] +

                                       ", className = " + p.info.name +

                                       ", isSyncable = " + p.info.isSyncable);

                       } else {

                           PackageParser.Provider other = mProviders.get(names[j]);

                           Slog.w(TAG, "Skipping provider name " + names[j] +

                                   " (in package " + pkg.applicationInfo.packageName +

                                   "): name already used by "

                                   + ((other != null && other.getComponentName() != null)

                                           ? other.getComponentName().getPackageName() : "?"));

                       }

                   }

               }

               if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {

                   if (r == null) {

                       r = new StringBuilder(256);

                   } else {

                       r.append(' ');

                   }

                   r.append(p.info.name);

               }

           }

……

}

这里PMappandroidManifest.xml中获取ContentProvider的信息且将其存储于mProvidersByComponent中。

2,Android系统对于app的启动处理中会调用到ActivityManagerService.attachApplicationLocked
(@ActivityManagerService.java)
,其中有以下处理

   private final boolean attachApplicationLocked(IApplicationThread thread,

           int pid) {

……

       boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);

       List providers = normalMode ? generateApplicationProvidersLocked(app) : null;

……

}

 

   private final List generateApplicationProvidersLocked(ProcessRecord app) {

       List providers = null;

       try {

           providers =
ActivityThread.getPackageManager().

               queryContentProviders(app.processName, app.info.uid,

                       STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);

       } catch (RemoteException ex) {

       }

       if (providers != null) {

           final int N = providers.size();

           for (int i=0; i<N; i++) {

               ProviderInfo cpi =

                   (ProviderInfo)providers.get(i);

               ContentProviderRecord cpr =

                   (ContentProviderRecord)mProvidersByClass.get(cpi.name);

               if (cpr == null) {

                   cpr = new ContentProviderRecord(cpi, app.info);

                   mProvidersByClass.put(cpi.name, cpr);

               }

               app.pubProviders.put(cpi.name, cpr);

               app.addPackage(cpi.applicationInfo.packageName);

               ensurePackageDexOpt(cpi.applicationInfo.packageName);

           }

       }

       return providers;

}

然后到PackageManagerService.java,看下面这个函数

   public List<ProviderInfo> queryContentProviders(String processName,

           int uid, int flags) {

       ArrayList<ProviderInfo> finalList = null;

 

       synchronized (mPackages) {

           Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();

           while (i.hasNext()) {

               PackageParser.Provider p = i.next();

               if (p.info.authority != null

                   && (processName == null ||

                           (p.info.processName.equals(processName)

                                   && p.info.applicationInfo.uid == uid))

                   && mSettings.isEnabledLP(p.info, flags)

                   && (!mSafeMode || (p.info.applicationInfo.flags

                           &ApplicationInfo.FLAG_SYSTEM) != 0)) {

                   if (finalList == null) {

                       finalList = new ArrayList<ProviderInfo>(3);

                   }

                   finalList.add(PackageParser.generateProviderInfo(p,

                           flags));

               }

           }

       }

 

       if (finalList != null) {

           Collections.sort(finalList, mProviderInitOrderSorter);

       }

 

       return finalList;

   }

上面的处理将会找到和app相关的ContentProvider(也即是在appandroidManifest.xml中定义的ContentProvider)。

3,找到appContentProvider后,下面就是安装和启动了,代码比较多,下面就简单说一下调用流程吧!

ActivityThrad:handleBindApplication

 

  ActivityThrad:installContentProviders

     ActivityThread:installProvider

         ContentProvider:attachInfo

            ContentProvider.this.onCreate()  ContentProvider在此启动了

 

ContentProvider的获取

ContentProvider的获取流程比较简单,且涉及的代码比较多,在这里就简单说调用流程吧!有兴趣的话,请看详细代码。

        ContentResolver:acquireProvider(Uri uri)

            ContentResolver:acquireProvider(mContext, uri.getAuthority()); 

               ActivityThread.acquireProvider(context, name)

                  ActivityThread:getProvider(c, name)

                     ActivityManagerService:getContentProvider 
          

                        ActivityManagerService:getContentProviderImpl

                           ActivityThread:getPackageManager():resolveContentProvider

 

ContentProvider的一个注意点:ContentProvider运行在定义它的app内。举例说明如下:app
A
定义了一个ContentProviderapp B访问这个ContentProvider。如果在app
B
访问app AContentProvider时,app
A
没有启动,那么此时app A会被启动。处理代码位置如下:

ActivityManagerService:getContentProviderImpl

{

……

               // If the provider is not already being launched, then get it

               // started.

               if (i >= N) {

                   final long origId = Binder.clearCallingIdentity();

                   ProcessRecord proc =
startProcessLocked(cpi.processName,

                           cpr.appInfo, false, 0, "content provider",

                           new ComponentName(cpi.applicationInfo.packageName,

                                   cpi.name), false);

                   if (proc == null) {

                       Slog.w(TAG, "Unable to launch app "

                               + cpi.applicationInfo.packageName + "/"

                               + cpi.applicationInfo.uid + " for provider "

                               + name + ": process is bad");

                       return null;

                   }

                   cpr.launchingApp = proc;

                   mLaunchingProviders.add(cpr);

                   Binder.restoreCallingIdentity(origId);

               }

……

}

 

 

抱歉!评论已关闭.