Android应用程序组件Content Provider的启动过程源代码分析(3)

 Step 7. ActivityManagerService.getContentProviderImpl
        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

  1. public final class ActivityManagerService extends ActivityManagerNative   
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {   
  3.     ......   
  4.    
  5.     private final ContentProviderHolder getContentProviderImpl(   
  6.             IApplicationThread caller, String name) {   
  7.         ContentProviderRecord cpr;   
  8.         ProviderInfo cpi = null;   
  9.    
  10.         synchronized(this) {   
  11.             ProcessRecord r = null;   
  12.             if (caller != null) {   
  13.                 r = getRecordForAppLocked(caller);   
  14.                 ......   
  15.             }   
  16.    
  17.             // First check if this content provider has been published...   
  18.             cpr = mProvidersByName.get(name);   
  19.             if (cpr != null) {   
  20.                 ......   
  21.             } else {   
  22.                 try {   
  23.                     cpi = AppGlobals.getPackageManager().   
  24.                         resolveContentProvider(name,   
  25.                         STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);   
  26.                 } catch (RemoteException ex) {   
  27.                 }   
  28.                 ......   
  29.             }   
  30.    
  31.             cpr = mProvidersByClass.get(cpi.name);   
  32.             final boolean firstClass = cpr == null;   
  33.             if (firstClass) {   
  34.                 try {   
  35.                     ApplicationInfo ai =   
  36.                         AppGlobals.getPackageManager().   
  37.                         getApplicationInfo(   
  38.                         cpi.applicationInfo.packageName,   
  39.                         STOCK_PM_FLAGS);   
  40.                     ......   
  41.                     cpr = new ContentProviderRecord(cpi, ai);   
  42.                 } catch (RemoteException ex) {   
  43.                     // pm is in same process, this will never happen.   
  44.                 }   
  45.             }   
  46.    
  47.             if (r != null && cpr.canRunHere(r)) {   
  48.                 // If this is a multiprocess provider, then just return its   
  49.                 // info and allow the caller to instantiate it.  Only do   
  50.                 // this if the provider is the same user as the caller's   
  51.                 // process, or can run as root (so can be in any process).   
  52.                 return cpr;   
  53.             }   
  54.    
  55.             ......   
  56.    
  57.             // This is single process, and our app is now connecting to it.   
  58.             // See if we are already in the process of launching this   
  59.             // provider.   
  60.             final int N = mLaunchingProviders.size();   
  61.             int i;   
  62.             for (i=0; i<N; i++) {   
  63.                 if (mLaunchingProviders.get(i) == cpr) {   
  64.                     break;   
  65.                 }   
  66.             }   
  67.    
  68.             // If the provider is not already being launched, then get it   
  69.             // started.   
  70.             if (i >= N) {   
  71.                 final long origId = Binder.clearCallingIdentity();   
  72.                 ProcessRecord proc = startProcessLocked(cpi.processName,   
  73.                     cpr.appInfo, false0"content provider",   
  74.                     new ComponentName(cpi.applicationInfo.packageName,   
  75.                     cpi.name), false);   
  76.                 ......   
  77.                 mLaunchingProviders.add(cpr);   
  78.                 ......   
  79.             }   
  80.    
  81.             // Make sure the provider is published (the same provider class   
  82.             // may be published under multiple names).   
  83.             if (firstClass) {   
  84.                 mProvidersByClass.put(cpi.name, cpr);   
  85.             }   
  86.             cpr.launchingApp = proc;   
  87.             mProvidersByName.put(name, cpr);   
  88.    
  89.             ......   
  90.         }   
  91.    
  92.         // Wait for the provider to be published...   
  93.         synchronized (cpr) {   
  94.             while (cpr.provider == null) {   
  95.                 ......   
  96.                 try {   
  97.                     cpr.wait();   
  98.                 } catch (InterruptedException ex) {   
  99.                 }   
  100.             }   
  101.         }   
  102.    
  103.         return cpr;   
  104.     }   
  105.        
  106.     ......   
  107. }   
    这个函数比较长,我们一步一步地分析。
        函数首先是获取调用者的进程记录块信息:
  1. ProcessRecord r = null;  
  2. if (caller != null) {  
  3.     r = getRecordForAppLocked(caller);  
  4.     ......  
  5. }  
        在我们这个情景中,要获取的就是应用程序Article的进程记录块信息了,后面会用到。
 
        在ActivityManagerService中,有两个成员变量是用来保存系统中的Content Provider信息的,一个是mProvidersByName,一个是mProvidersByClass,前者是以Content Provider的authoriry值为键值来保存的,后者是以Content Provider的类名为键值来保存的。一个Content Provider可以有多个authority,而只有一个类来和它对应,因此,这里要用两个Map来保存,这里为了方便根据不同条件来快速查找而设计的。下面的代码就是用来检查要获取的Content Provider是否已经加存在的了:

  1. // First check if this content provider has been published...   
  2. cpr = mProvidersByName.get(name);   
  3. if (cpr != null) {   
  4.     ......   
  5. else {   
  6.     try {   
  7.         cpi = AppGlobals.getPackageManager().   
  8.             resolveContentProvider(name,   
  9.             STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);   
  10.     } catch (RemoteException ex) {   
  11.     }   
  12.     ......   
  13. }   
  14.    
  15. cpr = mProvidersByClass.get(cpi.name);   
  16. final boolean firstClass = cpr == null;   
  17. if (firstClass) {   
  18.     try {   
  19.         ApplicationInfo ai =   
  20.             AppGlobals.getPackageManager().   
  21.             getApplicationInfo(   
  22.             cpi.applicationInfo.packageName,   
  23.             STOCK_PM_FLAGS);   
  24.         ......   
  25.         cpr = new ContentProviderRecord(cpi, ai);   
  26.     } catch (RemoteException ex) {   
  27.         // pm is in same process, this will never happen.   
  28.     }   
  29. }   
      在我们这个情景中,由于是第一次调用ArticlesProvider接口,因此,在mProvidersByName和mProvidersByClass两个Map中都不存在ArticlesProvider的相关信息,因此,这里会通过AppGlobals.getPackageManager函数来获得PackageManagerService服务接口,然后分别通过它的resolveContentProvider和getApplicationInfo函数来分别获取ArticlesProvider应用程序的相关信息,分别保存在cpi和cpr这两个本地变量中。这些信息都是在安装应用程序的过程中保存下来的,具体可以参考Android应用程序安装过程源代码分析一文。




本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966983,如需转载请自行联系原作者
上一篇:在ServerCore中卸载软件


下一篇:云服务器不能远程登录-CredSSP,解决方案:卸载KB4103727补丁