<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      安卓筆記俠

      專注安卓開發

      導航

      Android深入四大組件(九)Content Provider的啟動過程

      前言

      Content Provider做為四大組件之一,通常情況下并沒有其他的組件使用頻繁,但這不能作為我們不去深入學習它的理由。關于Content Provider一篇文章是寫不完的,這一篇文章先來介紹它的啟動過程。

      1.query方法到AMS的調用過程

      Android IPC機制(四)用ContentProvider進行進程間通信這篇文章我舉了一個Content Provider使用的例子,在Activity中我是使用如下代碼調用Content Provider的:

      public class ContentProviderActivity extends AppCompatActivity {
          private final static String TAG = "ContentProviderActivity";
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_content_provider);
              Uri uri = Uri.parse("content://com.example.liuwangshu.mooncontentprovide.GameProvider");
              ContentValues mContentValues = new ContentValues();
              mContentValues.put("_id", 2);
              mContentValues.put("name", "大航海時代ol");
              mContentValues.put("describe", "最好玩的航海網游");
              getContentResolver().insert(uri, mContentValues);//1
              Cursor gameCursor = getContentResolver().query(uri, new String[]{"name", "describe"}, null, null, null);
           ...
          }
      }
      View Code

      要想調用Content Provider,首先需要使用注釋1處的getContentResolver方法,如下所示。
      frameworks/base/core/Java/android/content/ContextWrapper.java

      @Override
      public ContentResolver getContentResolver() {
          return mBase.getContentResolver();
      }
      View Code

      這里mBase指的是ContextImpl,ContextImpl的getContentResolver方法如下所示。

      frameworks/base/core/java/android/app/ContextImpl.java

      @Override
      public ContentResolver getContentResolver() {
          return mContentResolver;
      }
      View Code

      上面的代碼return了ApplicationContentResolver類型的mContentResolver對象,ApplicationContentResolver是ContextImpl中的靜態內部類,繼承自ContentResolver,它在ContextImpl的構造方法中被創建。
      當我們調用ContentResolver的insert、query、update等方法時就會啟動Content Provider,這里拿query方法來進行舉例。
      query方法的實現在ApplicationContentResolver的父類ContentResolver中,代碼如下所示。
      frameworks/base/core/java/android/content/ContentResolver.java

      public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
                  @Nullable String[] projection, @Nullable String selection,
                  @Nullable String[] selectionArgs, @Nullable String sortOrder,
                  @Nullable CancellationSignal cancellationSignal) {
              Preconditions.checkNotNull(uri, "uri");
              IContentProvider unstableProvider = acquireUnstableProvider(uri);//1
              ...
              try {
                 ...
                  try {
                      qCursor = unstableProvider.query(mPackageName, uri, projection,
                              selection, selectionArgs, sortOrder, remoteCancellationSignal);//2
                  } catch (DeadObjectException e) {
                     ...
                  }
          ...
         }
      View Code

      在注釋1處通過acquireUnstableProvider方法返回IContentProvider類型的unstableProvider對象,在注釋2處調用unstableProvider的query方法。我們查看acquireUnstableProvider方法做了什么,如下所示。
      frameworks/base/core/java/android/content/ContentResolver.java

      public final IContentProvider acquireUnstableProvider(Uri uri) {
           if (!SCHEME_CONTENT.equals(uri.getScheme())) {//1
               return null;
           }
           String auth = uri.getAuthority();
           if (auth != null) {
               return acquireUnstableProvider(mContext, uri.getAuthority());//2
           }
           return null;
       }
      View Code

      注釋1處用來檢查Uri的scheme是否等于”content”,如果不是則返回null。注釋2處調用了acquireUnstableProvider方法,這是個抽象方法,它的實現在ContentResolver的子類ApplicationContentResolver中:
      frameworks/base/core/java/android/app/ContextImpl.java

      @Override
      protected IContentProvider acquireUnstableProvider(Context c, String auth) {
          return mMainThread.acquireProvider(c,
                  ContentProvider.getAuthorityWithoutUserId(auth),
                  resolveUserIdFromAuthority(auth), false);
      }
      View Code

      return了ActivityThread類型的mMainThread對象的acquireProvider方法:
      frameworks/base/core/java/android/app/ActivityThread.java

      public final IContentProvider acquireProvider(
               Context c, String auth, int userId, boolean stable) {
           final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);//1
           if (provider != null) {
               return provider;
           }
           IActivityManager.ContentProviderHolder holder = null;
           try {
               holder = ActivityManagerNative.getDefault().getContentProvider(
                       getApplicationThread(), auth, userId, stable);//2
           } catch (RemoteException ex) {
               throw ex.rethrowFromSystemServer();
           }
           if (holder == null) {
               Slog.e(TAG, "Failed to find provider info for " + auth);
               return null;
           }
           holder = installProvider(c, holder, holder.info,
                   true /*noisy*/, holder.noReleaseNeeded, stable);//3
           return holder.provider;
       }
      View Code

      注釋1處檢查ActivityThread中的ArrayMap類型的mProviderMap中是否有目標ContentProvider存在,有則返回,沒有就會在注釋2處調用AMP的getContentProvider方法,最終會調用AMS的getContentProvider方法。注釋3處的installProvider方法用來將注釋2處返回的ContentProvider相關的數據存儲在mProviderMap中,起到緩存的作用,這樣使用相同的Content Provider時,就不需要每次都要調用AMS的getContentProvider方法。使用我們接著查看AMS的getContentProvider方法,代碼如下所示。
      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

      @Override
      public final ContentProviderHolder getContentProvider(
              IApplicationThread caller, String name, int userId, boolean stable) {
       ...
          return getContentProviderImpl(caller, name, null, stable, userId);
      }
      View Code

      getContentProvider方法return了getContentProviderImpl方法:
      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

      private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
                  String name, IBinder token, boolean stable, int userId) {
      ...
             ProcessRecord proc = getProcessRecordLocked(
                                      cpi.processName, cpr.appInfo.uid, false);//1
                              if (proc != null && proc.thread != null && !proc.killed) {
                                  ...
                                  if (!proc.pubProviders.containsKey(cpi.name)) {
                                      checkTime(startTime, "getContentProviderImpl: scheduling install");
                                      proc.pubProviders.put(cpi.name, cpr);
                                      try {
                                          proc.thread.scheduleInstallProvider(cpi);//2
                                      } catch (RemoteException e) {
                                      }
                                  }
                              } else {
                                  checkTime(startTime, "getContentProviderImpl: before start process");
                                  proc = startProcessLocked(cpi.processName,
                                          cpr.appInfo, false, 0, "content provider",
                                          new ComponentName(cpi.applicationInfo.packageName,
                                                  cpi.name), false, false, false);//3
                                  checkTime(startTime, "getContentProviderImpl: after start process");
                                ...
                              }
                   ...           
                              
      }
      View Code

      getContentProviderImpl方法的代碼很多,這里截取了關鍵的部分。注釋1處通過getProcessRecordLocked方法來獲取目標ContentProvider的應用程序進程信息,這些信息用ProcessRecord類型的proc來表示,如果該應用進程已經啟動就會調用注釋2處的代碼,否則就會調用注釋3的startProcessLocked方法來啟動進程。這里我們假設ContentProvider的應用進程還沒有啟動,關于應用進程啟動過程,我在Android應用程序進程啟動過程(前篇)已經講過,最終會調用ActivityThread的main方法,代碼如下所示。
      frameworks/base/core/java/android/app/ActivityThread.java

      public static void main(String[] args) {
           ...
             Looper.prepareMainLooper();//1
             ActivityThread thread = new ActivityThread();//2
             thread.attach(false);
             if (sMainThreadHandler == null) {
                 sMainThreadHandler = thread.getHandler();
             }
             if (false) {
                 Looper.myLooper().setMessageLogging(new
                         LogPrinter(Log.DEBUG, "ActivityThread"));
             }
             // End of event ActivityThreadMain.
             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
             Looper.loop();//3
             throw new RuntimeException("Main thread loop unexpectedly exited");
         }
      View Code

      注釋1處通過prepareMainLooper方法在ThreadLocal中獲取Looper,并在注釋3處開啟消息循環。在注釋2處創建了ActivityThread并調用了它的attach方法:
      frameworks/base/core/java/android/app/ActivityThread.java

        private void attach(boolean system) {
        ...
          final IActivityManager mgr = ActivityManagerNative.getDefault();//1
                  try {
                      mgr.attachApplication(mAppThread);//2
                  } catch (RemoteException ex) {
                      throw ex.rethrowFromSystemServer();
                  }
        ...          
      }
      View Code

      注釋1處最終會得到AMS,在注釋2處調用AMS的attachApplication方法,并將ApplicationThread類型的mAppThread對象傳進去。
      query方法到AMS的調用過程,如下面時序圖所示(省略應用程序進程啟動過程)。

      2.AMS啟動Content Provider的過程

      我們接著來查看AMS的attachApplication方法,如下所示。
      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

      @Override
      public final void attachApplication(IApplicationThread thread) {
          synchronized (this) {
              int callingPid = Binder.getCallingPid();
              final long origId = Binder.clearCallingIdentity();
              attachApplicationLocked(thread, callingPid);
              Binder.restoreCallingIdentity(origId);
          }
      }
      View Code

      attachApplication方法中又調用了attachApplicationLocked方法:
      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

      private final boolean attachApplicationLocked(IApplicationThread thread,
                  int pid) {
         ...
         thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                          profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                          app.instrumentationUiAutomationConnection, testMode,
                          mBinderTransactionTrackingEnabled, enableTrackAllocation,
                          isRestrictedBackupMode || !normalMode, app.persistent,
                          new Configuration(mConfiguration), app.compat,
                          getCommonServicesLocked(app.isolated),
                          mCoreSettingsObserver.getCoreSettingsLocked());
      ...
      }
      View Code

      attachApplicationLocked方法中調用了thread的bindApplication方法,thread是IApplicationThread類型的,從類型名字就可以看出來是用于進程間通信,這里實現bindApplication方法的是ApplicationThreadProxy類,它實現了IApplicationThread接口。
      frameworks/base/core/java/android/app/ApplicationThreadNative.java

      class ApplicationThreadProxy implements IApplicationThread {
      ...
          @Override
          public final void bindApplication(String packageName, ApplicationInfo info,
                  List<ProviderInfo> providers, ComponentName testName, ProfilerInfo profilerInfo,
                  Bundle testArgs, IInstrumentationWatcher testWatcher,
                  IUiAutomationConnection uiAutomationConnection, int debugMode,
                  boolean enableBinderTracking, boolean trackAllocation, boolean restrictedBackupMode,
                  boolean persistent, Configuration config, CompatibilityInfo compatInfo,
                  Map<String, IBinder> services, Bundle coreSettings) throws RemoteException {
            ...
              mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
                      IBinder.FLAG_ONEWAY);
              data.recycle();
          }
      ...
      }
      View Code

      到目前為止,上面的調用過程還是在AMS進程中執行的,因此,需要通過IBinder類型的mRemote對象向新創建的應用程序進程(目標Content Provider所在的進程)發送BIND_APPLICATION_TRANSACTION類型的通信請求。處理這個通信請求的是在新創建的應用程序進程中執行的ApplicationThread的bindApplication方法,如下所示。
      frameworks/base/core/java/android/app/ActivityThread.java

      public final void bindApplication(String processName, ApplicationInfo appInfo,
                     List<ProviderInfo> providers, ComponentName instrumentationName,
                     ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                     IInstrumentationWatcher instrumentationWatcher,
                     IUiAutomationConnection instrumentationUiConnection, int debugMode,
                     boolean enableBinderTracking, boolean trackAllocation,
                     boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                     CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) {
                     ...
                     sendMessage(H.BIND_APPLICATION, data);
             }
      View Code

      調用sendMessage方法像H發送BIND_APPLICATION類型消息,H的handleMessage方法如下所示。
      frameworks/base/core/java/android/app/ActivityThread.java

      public void handleMessage(Message msg) {
          if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
                  switch (msg.what) {
                  ...
                  case BIND_APPLICATION:
                          Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                          AppBindData data = (AppBindData)msg.obj;
                          handleBindApplication(data);
                          Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                          break;
        ...
        }
        ... 
      }
      View Code

      我們接著查看handleBindApplication方法:
      frameworks/base/core/java/android/app/ActivityThread.java

      private void handleBindApplication(AppBindData data) {
       ...
            final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);//1
             try {
                    final ClassLoader cl = instrContext.getClassLoader();
                    mInstrumentation = (Instrumentation)
                        cl.loadClass(data.instrumentationName.getClassName()).newInstance();//2
                } catch (Exception e) {
                 ...
                }
                final ComponentName component = new ComponentName(ii.packageName, ii.name);
                mInstrumentation.init(this, instrContext, appContext, component,
                        data.instrumentationWatcher, data.instrumentationUiAutomationConnection);//3
               ...
                Application app = data.info.makeApplication(data.restrictedBackupMode, null);//4
                mInitialApplication = app;
                if (!data.restrictedBackupMode) {
                    if (!ArrayUtils.isEmpty(data.providers)) {
                        installContentProviders(app, data.providers);//5
                        mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
                    }
                }
              ...
               mInstrumentation.callApplicationOnCreate(app);//6
              ... 
      }
      View Code

      handleBindApplication方法的代碼很長,這里截取了主要的部分。注釋1處創建了ContextImpl 。注釋2處通過反射創建Instrumentation并在注釋3處初始化Instrumentation。注釋4處創建Application并且在注釋6處調用Application的onCreate方法,這意味著Content Provider所在的應用程序進程已經啟動完畢,在這之前,注釋5處調用installContentProviders方法來啟動Content Provider,代碼如下所示。
      frameworks/base/core/java/android/app/ActivityThread.java

      private void installContentProviders(
              Context context, List<ProviderInfo> providers) {
          final ArrayList<IActivityManager.ContentProviderHolder> results =
              new ArrayList<IActivityManager.ContentProviderHolder>();
      
          for (ProviderInfo cpi : providers) {//1
              ...
              IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
                      false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);//2
            ...
          }
      
          try {
              ActivityManagerNative.getDefault().publishContentProviders(
                  getApplicationThread(), results);//3
          } catch (RemoteException ex) {
              throw ex.rethrowFromSystemServer();
          }
      View Code

      注釋1處遍歷當前應用程序進程的ProviderInfo列表,得到每個Content Provider的ProviderInfo(存儲Content Provider的信息),并在注釋2處調用installProvider方法來啟動這些Content Provider。在注釋3處通過AMS的publishContentProviders方法將這些Content Provider存儲在AMS的mProviderMap中,這個mProviderMap在前面提到過,起到緩存的作用,防止每次使用相同的Content Provider時都會調用AMS的getContentProvider方法。來查看installProvider方法時如何啟動Content Provider的,installProvider方法如下所示。
      frameworks/base/core/java/android/app/ActivityThread.java

      private IActivityManager.ContentProviderHolder installProvider(Context context,
                 IActivityManager.ContentProviderHolder holder, ProviderInfo info,
                 boolean noisy, boolean noReleaseNeeded, boolean stable) {
             ContentProvider localProvider = null;
        ...
                     final java.lang.ClassLoader cl = c.getClassLoader();
                     localProvider = (ContentProvider)cl.
                         loadClass(info.name).newInstance();//1
                     provider = localProvider.getIContentProvider();
                     if (provider == null) {
                       ...
                         return null;
                     }
                     if (DEBUG_PROVIDER) Slog.v(
                         TAG, "Instantiating local provider " + info.name);
                     localProvider.attachInfo(c, info);//2
                 } catch (java.lang.Exception e) {
                    ...
                     }
                     return null;
                 }
             }
                ...
             return retHolder;
         }
      View Code

      在注釋1處通過反射來創建ContentProvider類型的localProvider對象,并在注釋2處調用了它的attachInfo方法:
      frameworks/base/core/java/android/content/ContentProvider.java

      private void attachInfo(Context context, ProviderInfo info, boolean testing) {
           ...
                ContentProvider.this.onCreate();
            }
        }
      View Code

      在attachInfo方法中調用了onCreate方法,它是一個抽象方法。這樣Content Provider就啟動完畢。
      最后給出AMS啟動Content Provider的時序圖。

      posted on 2018-06-27 16:34  安卓筆記俠  閱讀(1989)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 国产成人精品一区二区三| 国产性色的免费视频网站| 手机在线国产精品| 深夜在线观看免费av| 亚洲熟妇自偷自拍另亚洲| 人妻少妇精品中文字幕| 亚洲精品99久久久久久欧美版| 欧美亚洲国产精品久久| 色偷偷www.8888在线观看| 99久热在线精品视频| 影音先锋AV成人资源站在线播放| 国产欧美综合在线观看第十页| 国产精品九九久久精品女同| 在线观看国产成人av片| 亚洲人成网站77777在线观看| 一区二区乱子伦在线播放| 欧美亚洲一区二区三区在线| 国产一区二区三区四区激情| 亚洲av永久无码天堂影院| 激情综合色综合啪啪五月| 久草热大美女黄色片免费看| 蜜桃一区二区三区在线看| 日韩亚洲中文图片小说| 久久久精品94久久精品| 亚洲国产中文字幕精品| 明溪县| 日韩精品一区二区蜜臀av| 4399理论片午午伦夜理片| 色欲国产精品一区成人精品| 1精品啪国产在线观看免费牛牛| 性饥渴少妇AV无码毛片| 美女禁区a级全片免费观看| 日本在线 | 中文| 日产精品久久久久久久| 亚洲成在人线AⅤ中文字幕| 久久精品熟妇丰满人妻久久| 一本大道久久香蕉成人网| 久久国产成人精品国产成人亚洲| 无码激情亚洲一区| 激情自拍校园春色中文| 亚洲AV成人无码久久精品四虎|