源码探索系列9---四大金刚之ContentProvider

好了,终于到了最后一个啦,写到这里,真的觉得不容意啊,以前看这些组件也就那样了,现在还要记录下来,重点是这东西都被分析烂了,我们这些后人屌丝还在写,没点突破的。真没意思呢!就当写作业咯。啦啦啦啦,不管如何,让我们开始看下吧

起航 --- ContentResolver

API: 23

说真的,这个组件我还真的相对于Activity和Service用起来真的好少啊!
现在都不能记起来用他来干嘛了,虽然知道他能用来做跨进程通讯用,不过对于一般的app。
这玩意还真的用的次数少啊! 现在能想起来的一次使用这个就是要获取图片的时候。
以前开发的时候遇到的恶心的是,有些Rom把相册给阉割了,搞了个别的来代替,导致调不了图库!
所以搞到需要自己开发一个,真的很无语!

ContentResolver mContentResolver = this.getContentResolver();
Cursor mCursor = mContentResolver.query(mImageUri, null,
            MediaStore.Images.Media.MIME_TYPE + "=? or "
                    + MediaStore.Images.Media.MIME_TYPE + "=? or " + MediaStore.Images.Media.MIME_TYPE + "=?" + " or " + MediaStore.Images.Media.MIME_TYPE + "=?",
            new String[]{"image/jpeg", "image/png", "image/jpg", "image/jpe"},
            MediaStore.Images.Media.DATA);

从这里我们开始看起吧

public final Cursor query(Uri uri, String[] projection,
        String selection, String[] selectionArgs, String sortOrder) {
    return query(uri, projection, selection, selectionArgs, sortOrder, null);
}

public final Cursor query(final Uri uri, String[] projection,
        String selection, String[] selectionArgs, String sortOrder,
        CancellationSignal cancellationSignal) {
        
    IContentProvider unstableProvider = acquireUnstableProvider(uri);
    if (unstableProvider == null) {
        return null;
    }
    IContentProvider stableProvider = null;
    Cursor qCursor = null;
    try { 
        ...

        ICancellationSignal remoteCancellationSignal = null;
        if (cancellationSignal != null) {
            cancellationSignal.throwIfCanceled();
            remoteCancellationSignal = unstableProvider.createCancellationSignal();
            cancellationSignal.setRemote(remoteCancellationSignal);
        }
        try {
            qCursor = unstableProvider.query(mPackageName, uri, projection,
                    selection, selectionArgs, sortOrder, remoteCancellationSignal);
        } catch (DeadObjectException e) { 
            unstableProviderDied(unstableProvider);
            stableProvider = acquireProvider(uri);
            if (stableProvider == null) {
                return null;
            }
            qCursor = stableProvider.query(mPackageName, uri, projection,
                    selection, selectionArgs, sortOrder, remoteCancellationSignal);
        }
        if (qCursor == null) {
            return null;
        }

        // Force query execution.  Might fail and throw a runtime exception here.
        qCursor.getCount();
        long durationMillis = SystemClock.uptimeMillis() - startTime;
        maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);

        // Wrap the cursor object into CursorWrapperInner object.
        CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
                stableProvider != null ? stableProvider : acquireProvider(uri));
        stableProvider = null;
        qCursor = null;
        return wrapper;
    } catch (RemoteException e) { 
        return null;
    } finally {
       ...
    }
}
@Override
    protected IContentProvider acquireUnstableProvider(Context c, String auth) {
        return mMainThread.acquireProvider(c,
                ContentProvider.getAuthorityWithoutUserId(auth),
                resolveUserIdFromAuthority(auth), false);
    }

开头调用acquireUnstableProvider(uri),经过一轮跟踪,发现他跑到了ActivityThread里面的acquireProvider,内容如下

public final IContentProvider acquireProvider(
        Context c, String auth, int userId, boolean stable) {
        
    final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
    if (provider != null) {
        return provider;
    } 
    
    IActivityManager.ContentProviderHolder holder = null;
    try {
        holder = ActivityManagerNative.getDefault().getContentProvider(
                getApplicationThread(), auth, userId, stable);
    } catch (RemoteException ex) {
    }
    if (holder == null) {         
        return null;
    } 
    
    // Install provider will increment the reference count for us, and break
    // any ties in the race.
    holder = installProvider(c, holder, holder.info,
            true /*noisy*/, holder.noReleaseNeeded, stable);
    return holder.provider;
}

我们看到他先查找本地有没有,有就返回,没有就去找了AMS要ContentProvider,拿回来后就存本地,然后返回。
好了,让我们去看下AMS里面的实现吧

 @Override
public final ContentProviderHolder getContentProvider(
        IApplicationThread caller, String name, int userId, boolean stable) {
        
    enforceNotIsolatedCaller("getContentProvider");
    if (caller == null) {
        String msg = "null IApplicationThread when getting content provider "
                + name;
        Slog.w(TAG, msg);
        throw new SecurityException(msg);
    } 
    
    return getContentProviderImpl(caller, name, null, stable, userId);
}

他跑去了他的实现函数getContentProviderImpl()....真无语,同个类里面还搞抽象和实现啊,
像前面那样写成realGetContentProviderImpl()不就好了嘛,哈哈,真 · 干活函数
不过这个实现还不小,三百多行,这在AMS里面都是这样的,看着头疼,一堆的判断,截取关键的部分:

private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
        String name, IBinder token, boolean stable, int userId) {
    ContentProviderRecord cpr;
    ContentProviderConnection conn = null;
    ProviderInfo cpi = null;

    ...
    
    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); 
     
    return cpr != null ? cpr.newHolder(conn) : null;
}

这里需要补充的说明是,我们都知道那个ContentProvider的启动是伴随进程的启动,启动进程是有上面的startProcessLocked()来完成的。我们来看下他里面写了什么。。。

  private final void startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
         ...
        
        checkTime(startTime, "startProcess: asking zygote to start proc");
        Process.ProcessStartResult startResult = Process.start(entryPoint,
                app.processName, uid, uid, gids, debugFlags, mountExternal,
                app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                app.info.dataDir, entryPointArgs);
        checkTime(startTime, "startProcess: returned from zygote!");
         ...
}

这个函数也是一个巨无霸,我想那个AMS一定是靠几个人写完的,因为他的函数风格不在一样,呵呵,虽然我也经常写得不一样。只截取重要的几句..
这个函数最终通过调用Process的start方法来启动。我们继续深入看下

 public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] zygoteArgs) {
    try {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                debugFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {
        Log.e(LOG_TAG,
                "Starting VM process through Zygote failed");
        throw new RuntimeException(
                "Starting VM process through Zygote failed", ex);
    }
}

好,遇到了一个传说级别的名字了Zygote,不要问我这个名词代表的故事,百度下吧。
感觉写完这些组件后,可以开始写更底层的部分了...哎。说真的,挺无聊的,看完又没怎么样,但出来混,他们老觉得高级开发就得看底层代码,精通整个Android系统啊!这学习量真的不小,不过也就那点工资...
还不如学校门口一个摆摊的,好了,罗嗦了,继续吧。

结论就是通过Zygote,最后我们到了ActivityThread的main方法,还记得这个玩意嘛?
我们在很久前解析那个Handler的时候有提到,程序的入口方法是ActivityThread的mian方法!
是不是觉得很像以前学java时候!居然在安卓里面遇到人家!

public static void main(String[] args) {
    SamplingProfilerIntegration.start();

    ...
    
    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    AsyncTask.init();

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

整个的main方法就初始主线程的地方,同时开动主Looper, 然后attach这个方法会最终把消息传递AMS,然后AMS就完成了ContentProvider的创建!

private void attach(boolean system) {
      ...
      
       try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            // Ignore
        } 
      ...
}

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

    // Find the application record that is being attached...  either via
    // the pid if we are running in multiple processes, or just pull the
    // next app record if we are emulating process with anonymous threads.
    ProcessRecord app;
    ...
    
        if (DEBUG_CONFIGURATION) Slog.v(TAG, "Binding proc "
                + processName + " with config " + mConfiguration);
        ApplicationInfo appInfo = app.instrumentationInfo != null
                ? app.instrumentationInfo : app.info;
        app.compat = compatibilityInfoForPackageLocked(appInfo);
        if (profileFd != null) {
            profileFd = profileFd.dup();
        }
        ProfilerInfo profilerInfo = profileFile == null ? null
                : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
        thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                isRestrictedBackupMode || !normalMode, app.persistent,
                new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
                mCoreSettingsObserver.getCoreSettingsLocked());
        updateLruProcessLocked(app, false, null);
        app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
        
     ...
}

每次到AMS里面的函数都是一大串!!!这里的thread就是那个ApplicationThread,我们很熟悉。
走了一圈,又跑回来了

 public final void bindApplication(String processName, ApplicationInfo appInfo,
            List providers, ComponentName instrumentationName,
            ProfilerInfo profilerInfo, Bundle instrumentationArgs,
            IInstrumentationWatcher instrumentationWatcher,
            IUiAutomationConnection instrumentationUiConnection, int debugMode,
            boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
            Configuration config, CompatibilityInfo compatInfo, Map services,
            Bundle coreSettings) {

        ...

        AppBindData data = new AppBindData();
        data.processName = processName;
        data.appInfo = appInfo;
        data.providers = providers;
        data.instrumentationName = instrumentationName;
        data.instrumentationArgs = instrumentationArgs;
        data.instrumentationWatcher = instrumentationWatcher;
        data.instrumentationUiAutomationConnection = instrumentationUiConnection;
        data.debugMode = debugMode;
        data.enableOpenGlTrace = enableOpenGlTrace;
        data.restrictedBackupMode = isRestrictedBackupMode;
        data.persistent = persistent;
        data.config = config;
        data.compatInfo = compatInfo;
        data.initProfilerInfo = profilerInfo;
        sendMessage(H.BIND_APPLICATION, data);
    }

最终这个变成了同我们的H先生发送BIND_APPLICATION消息!

private void handleBindApplication(AppBindData data) {
    ...
    // 1.创建Context        
   ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
          
   java.lang.ClassLoader cl = instrContext.getClassLoader();
   mInstrumentation = (Instrumentation)
         cl.loadClass(data.instrumentationName.getClassName()).newInstance();
     
  mInstrumentation.init(this, instrContext, appContext,
               new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
               data.instrumentationUiAutomationConnection);

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

   ...
   // 3. 启动ContentProvider,发送消息,调用onCreate函数
  // don't bring up providers in restricted mode; they may depend on the
  // app's custom Application class
  if (!data.restrictedBackupMode) {
      List providers = data.providers;
      if (providers != null) {
          installContentProviders(app, providers);
          // For process that contains content providers, we want to
          // ensure that the JIT is enabled "at some point".
          mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
      }
  }

  ...
  //4. 启动我们Application的onCreate方法。
  // Do this after providers, since instrumentation tests generally start their
     // test thread at this point, and we don't want that racing.         
   mInstrumentation.onCreate(data.instrumentationArgs); 
    mInstrumentation.callApplicationOnCreate(app);   
    StrictMode.setThreadPolicy(savedPolicy);
 
}

这个函数受AMS污染,也是贼长的一个函数。
在这个handleBindApplication函数里面,我截取保留了核心的信息,同时加了注释。
具体就是创建contextApplication,然后通过installContentProviders()来启动当前进程的ContentProvider,所以下次有人和你提问题,说你知道那个ContentProvider嘛?
你就反问,说你知道这个组件是在哪里初始化的嘛?
不知道你就说是在ActivityThread里面的H先生接受到了BindApplication消息,然后在处理消息对应的handleBindApplication()方法里面的installContentProviders()函数啦!
是不是很装逼的样子!!

为了彻底的装逼,我们来看下这个installContentProviders()到底做了什么!
免得人家也看过代码,惨遭装逼失败的下场。

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

    for (ProviderInfo cpi : providers) {
      
        IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
                false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
        if (cph != null) {
            cph.noReleaseNeeded = true;
            results.add(cph);
        }
    }

    try {
        ActivityManagerNative.getDefault().publishContentProviders(
            getApplicationThread(), results);
    } catch (RemoteException ex) {
    }
}

这里面遍历了providers,然后installProvider去启动他们。最后找AMS把他们给注册保存了。
而且是保存在一个叫mProviderMap的map里面中,便于别的进程通过AMS来调用!
有代码有真相,有木有,就在下面,没骗人的啊!

 public final void publishContentProviders(IApplicationThread caller,
        List providers) {
        
     ...
       
    enforceNotIsolatedCaller("publishContentProviders");
    synchronized (this) {
        final ProcessRecord r = getRecordForAppLocked(caller);
         final long origId = Binder.clearCallingIdentity();
         

        final int N = providers.size();
        for (int i=0; i

在彻底的装逼,我们需要来看下这个installProvider函数

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

    ...
    
        try { //用ClassLoader去加载!
            final java.lang.ClassLoader cl = c.getClassLoader();
            localProvider = (ContentProvider)cl.
                loadClass(info.name).newInstance();
            provider = localProvider.getIContentProvider();
             ...
            // XXX Need to create the correct context for this provider.
            localProvider.attachInfo(c, info);
        } catch (java.lang.Exception e) {
           ...   
         }
            return null;
        }
    }  

    ...
}

好了他的启动过程基本到这里结束,我们回溯到前面的步骤,回到我们处理Application消息的第四点

 //4. 启动我们Application的onCreate方法。
  // Do this after providers, since instrumentation tests generally start their
     // test thread at this point, and we don't want that racing.         
   mInstrumentation.onCreate(data.instrumentationArgs); 
    mInstrumentation.callApplicationOnCreate(app);   
    
    StrictMode.setThreadPolicy(savedPolicy);

好了,整个过程基本这样了。

我们从一开始的acquireUnstableProvider(uri);函数跑到这里,都快忘记原本是要干嘛了。

续航 ==== Query

让我们继续启程,回到一开始query函数,在获得了我们IContentProvider后,就调用了他的query方法。

    qCursor = unstableProvider.query(mPackageName, uri, projection,
                    selection, selectionArgs, sortOrder, remoteCancellationSignal);

这个IContentProvider 是一个Binder接口,具体的干活的人是谁呢?
IContentProvider的具体实现是ContentProviderNative,然后Transport 又继承了它。

abstract public class ContentProviderNative extends Binder implements IContentProvider 

class Transport extends ContentProviderNative 

这个类是躲在ContentProvider的里面的即ContentProvider.Transport 。好了,写了这么多,回主线

@Override
    public Cursor query(String callingPkg, Uri uri, String[] projection,
            String selection, String[] selectionArgs, String sortOrder,
            ICancellationSignal cancellationSignal) {
        validateIncomingUri(uri);
        uri = getUriWithoutUserId(uri);
        if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
               ...
             Cursor cursor = ContentProvider.this.query(uri, projection, selection,
                    selectionArgs, sortOrder, CancellationSignal.fromTransport(
                            cancellationSignal));
            if (cursor == null) {
                return null;
            }

            // Return an empty cursor for all columns.
            return new MatrixCursor(cursor.getColumnNames(), 0);
        }
        
        final String original = setCallingPackage(callingPkg);
        try {
            return ContentProvider.this.query(
                    uri, projection, selection, selectionArgs, sortOrder,
                    CancellationSignal.fromTransport(cancellationSignal));
        } finally {
            setCallingPackage(original);
        }
    }

到这里去调用了ContentProvider的query方法。这样整个过程就结束了。其余的方法也在这个类里面,套路类似的,就不再写了,这篇文章已经写了很长了,而且现在有事,得去做点别了!

后记

今天写得好晚,看到都有点累,不段的翻滚。。。写到后面都没精神和注意力了。。
先写到这里,洗个澡睡觉,明天抽时间在继续做补充。。

但无论如何把四大金刚的源码都写了一遍了。

====
更新:
重新补充了部分内容,把整个流程更细化了下。
不过还是有些具体的内容不是很清楚,
下一次在游览别的时候,能有空再把这个过程写得更清楚的话,就再来更新吧

对于Zygote这个下次得抽时间再写一篇他的专辑。
谷歌起这个名字给它,这么有深度东西,很有故事。

下一篇就这么定是他了 ^_ ^

你可能感兴趣的:(源码探索系列9---四大金刚之ContentProvider)