Android开发艺术探索——第九章:四大组件的工作过程(下)

我們继续来看四大组件的工作过程

一.BroadcastReceiver的工作过程

广播的工作过程,我们主要看两个方面,一个是注册过程,另一个就是接收的过程,我们想使用广播是非常简单的,只需要继承BroadcastReceiver即可

   class TestReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.i(TAG,"action:" + action);
        }
    }

广播注册也分两种,一种静态一种动态,静态的就是在XML中了,我们来看下动态的即可

    mTestReceiver = new TestReceiver();
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(Intent.ACTION_ANSWER);
    registerReceiver(mTestReceiver,intentFilter);

1.广播的注册过程

由于静态广播是系统自己PMS完成的处理,这里我们只解析动态注册过程,他的一切开始是ContextWrapper的registerReceiver开始的,和Activity和Service一样,ContextWrapper并没有做什么实际的工作,而是交给了ContextImpl来完成,最终也是调用自身的registerReceiverInternal来实现

    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context) {
        IIntentReceiver rd = null;
        if (receiver != null) {
            if (mPackageInfo != null && context != null) {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            return ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);
        } catch (RemoteException e) {
            return null;
        }
    } 

而在这段代码中,系统首先是获取到了IIntentReceiver对象,然后再采用跨进程的方式向AMS发送广播注册的请求,之所以采用IIntentReceiver而不是直接采用BroadCastReceiver是因为这个过程是一个进程间通信的过程,他BroadCastReceiver是一个Android的组件是不能跨进程的,所以需要IIntentReceiver来中转一下,毫无疑问,IIntentReceiver必然是一个Binder接口,他的具体实现是LoadedApk.ReceiverDispatcher.IIntentReceiver,ReceiverDispatcher内部同时保存了BoradcastReceiver和IIntentReceiver

关于ActivityManagerNative.getDefault(),这里就不做说明了,他就是AMS。在前面的章节我们也很多次提到他了,下面我们来看下ReceiverDispatcher的getIIntentReceiver的实现,先看代码

    public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
            Context context, Handler handler,
            Instrumentation instrumentation, boolean registered) {
        synchronized (mReceivers) {
            LoadedApk.ReceiverDispatcher rd = null;
            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
            if (registered) {
                map = mReceivers.get(context);
                if (map != null) {
                    rd = map.get(r);
                }
            }
            if (rd == null) {
                rd = new ReceiverDispatcher(r, context, handler,
                        instrumentation, registered);
                if (registered) {
                    if (map == null) {
                        map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                        mReceivers.put(context, map);
                    }
                    map.put(r, rd);
                }
            } else {
                rd.validate(context, handler);
            }
            rd.mForgotten = false;
            return rd.getIIntentReceiver();
        }
    } 

这个方法创建了一个ReceiverDispatcher对象并且将其保存的IIntentReceiver对象作为返回值返回

由于注册广播的真正实现过程是在AMS中,因此我们需要看下AMS的实现部分。AMS的registerReceiver方法看起来很长,其实关键的就是这一个部分,最终把远程的InnerReceiver对象以及IntentFilter对象存储起来,这样整个广播的注册过程就完成了

   public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
        enforceNotIsolatedCaller("registerReceiver");
        int callingUid;
        int callingPid;
        synchronized(this) {
            ProcessRecord callerApp = null;
            if (caller != null) {
                callerApp = getRecordForAppLocked(caller);
                if (callerApp == null) {
                    throw new SecurityException(
                            "Unable to find app for caller " + caller
                            + " (pid=" + Binder.getCallingPid()
                            + ") when registering receiver " + receiver);
                }
                if (callerApp.info.uid != Process.SYSTEM_UID &&
                        !callerApp.pkgList.containsKey(callerPackage) &&
                        !"android".equals(callerPackage)) {
                    throw new SecurityException("Given caller package " + callerPackage
                            + " is not running in process " + callerApp);
                }
                callingUid = callerApp.info.uid;
                callingPid = callerApp.pid;
            } else {
                callerPackage = null;
                callingUid = Binder.getCallingUid();
                callingPid = Binder.getCallingPid();
            }

            userId = this.handleIncomingUser(callingPid, callingUid, userId,
                    true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage);

            List allSticky = null;

            // Look for any matching sticky broadcasts...
            Iterator actions = filter.actionsIterator();
            if (actions != null) {
                while (actions.hasNext()) {
                    String action = (String)actions.next();
                    allSticky = getStickiesLocked(action, filter, allSticky,
                            UserHandle.USER_ALL);
                    allSticky = getStickiesLocked(action, filter, allSticky,
                            UserHandle.getUserId(callingUid));
                }
            } else {
                allSticky = getStickiesLocked(null, filter, allSticky,
                        UserHandle.USER_ALL);
                allSticky = getStickiesLocked(null, filter, allSticky,
                        UserHandle.getUserId(callingUid));
            }

            // The first sticky in the list is returned directly back to
            // the client.
            Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;

            if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter
                    + ": " + sticky);

            if (receiver == null) {
                return sticky;
            }

            ReceiverList rl
                = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                    rl.app.receivers.add(rl);
                } else {
                    try {
                        receiver.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            } else if (rl.uid != callingUid) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for uid " + callingUid
                        + " was previously registered for uid " + rl.uid);
            } else if (rl.pid != callingPid) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for pid " + callingPid
                        + " was previously registered for pid " + rl.pid);
            } else if (rl.userId != userId) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for user " + userId
                        + " was previously registered for user " + rl.userId);
            }
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId);
            rl.add(bf);
            if (!bf.debugCheck()) {
                Slog.w(TAG, "==> For Dynamic broadast");
            }
            mReceiverResolver.addFilter(bf);

            // Enqueue broadcasts for all existing stickies that match
            // this filter.
            if (allSticky != null) {
                ArrayList receivers = new ArrayList();
                receivers.add(bf);

                int N = allSticky.size();
                for (int i=0; i<N; i++) {
                    Intent intent = (Intent)allSticky.get(i);
                    BroadcastQueue queue = broadcastQueueForIntent(intent);
                    BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                            null, -1, -1, null, null, AppOpsManager.OP_NONE, receivers, null, 0,
                            null, null, false, true, true, -1);
                    queue.enqueueParallelBroadcastLocked(r);
                    queue.scheduleBroadcastsLocked();
                }
            }

            return sticky;
        }
    }

2.广播的发送和接收部分

上图分析了广播的注册过程,可以发现注册过程的逻辑还是比较简单的,下面来分析广播的发送和接收,当send发送之后,AMS会查找出匹配的广播接收器并且将广播交给他去处理,关闭的发送有几种:普通广播,有序广播 和 粘性广播,他们的实现方式有一些不一样,但是过程都是一样的

广播的发送和接收,可以说是两个阶段。这里从发射的广播说起,广播的发送仍然开始于ContextWrapper的sendBroadcast,之所以不是Context,那是因为Context的sendBroadcast是一个抽象的方法,和广播的注册过程一样,他也什么都没有做,也是ContextImpl去处理的,我们来看下代码


    @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess();
            ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,
                getUserId());
        } catch (RemoteException e) {
        }
    }

这段代码里,他也是直接异步向AMS发送一个broadcastIntent

    public final int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle map,
            String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) {
        enforceNotIsolatedCaller("broadcastIntent");
        synchronized(this) {
            intent = verifyBroadcastLocked(intent);

            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo,
                    resultCode, resultData, map, requiredPermission, appOp, serialized, sticky,
                    callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }

这里随即又调用了一个broadcastIntentLocked,这个方法就有点复杂了。在这个方法里最开始有这么一行

   // By default broadcasts do not go to stopped apps.
   intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

这表示在Android5.0中,默认情况下广播不会发送给已经停止的应用,其实在3.1就已经有这种特性,在broadcastIntentLocked内部,会根据intent-filter来匹配并且进行广播过滤,最终将满足的广播添加到BrocastQueue中,接着就发送给对应的广播接收者了。源码如下:

        int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
        if (!ordered && NR > 0) {
            // If we are not serializing this broadcast, then send the
            // registered receivers separately so they don't wait for the
            // components to be launched.
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
                    appOp, registeredReceivers, resultTo, resultCode, resultData, map,
                    ordered, sticky, false, userId);
            if (DEBUG_BROADCAST) Slog.v(
                    TAG, "Enqueueing parallel broadcast " + r);
            final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
            if (!replaced) {
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0;
        }

下面我们看一下BroadcastQueue中广播的发送过程

    public void scheduleBroadcastsLocked() {
        if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
                + mQueueName + "]: current="
                + mBroadcastsScheduled);

        if (mBroadcastsScheduled) {
            return;
        }
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }

他就是发了一个Handler

            // First, deliver any non-serialized broadcasts right away.
            while (mParallelBroadcasts.size() > 0) {
                r = mParallelBroadcasts.remove(0);
                r.dispatchTime = SystemClock.uptimeMillis();
                r.dispatchClockTime = System.currentTimeMillis();
                final int N = r.receivers.size();
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
                        + mQueueName + "] " + r);
                for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
                    if (DEBUG_BROADCAST)  Slog.v(TAG,
                            "Delivering non-ordered on [" + mQueueName + "] to registered "
                            + target + ": " + r);
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
                }
                addBroadcastToHistoryLocked(r);
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
                        + mQueueName + "] " + r);
            }

在这段代码中,会创建一个Args对象并且通过post方式执行Args的逻辑,而Args实现了Runnable的接口,在这里面有这么一段代码

    final BroadcastReceiver receiver = mReceiver;
    receiver.setPendingResult(this);
    receiver.onReceiver(mContext,intent);

很显然,这个时候onReceiver被执行了,应用也就收到了广播了,这就是整个广播的工作过程。

二.ContentProvider

ContentProvider的使用方式在之前就有讲过,这里做一个简单的说明,ContentProvider是一个内存共享型组件,他通过Binder向其他组件乃至其他应用提供数据,当ContentProvider所在的进程启动的时候,ContentProvider会同时启动并且发布到AMS中,需要注意的是,这个时候ContentProvider的onCreate要先于Application的onCreate执行,这是四大组件一个少有的现象

一个应用启动的时候,入口方法在ActivityThread中的main里,main是一个静态方法,在main中会创建ActivityThread的实例并创建主线程的消息队列,然后在ActivityThread的attach中远程调用AMS的attachApplication方法并将ActivityThread提供给AMS,ActivityThread是一个Binder对象,他的Binder接口是IApplicationThread,他主要用于ActivityThread和AMS之间的通信,会调用ApplicationThread的bindApplication方法,注意这个过程同样是跨进程完成的,bindApplication的逻辑是经过ActivityThread中的mH Hander切换到ActivityThread执行,具体是方法是handlerBindApplication,在handlerApplication方法中,ActivityThread会加载一个ContentProvider,然后再调用Application的onCreate,整个过程可以看图

这里写图片描述

这就是ContentProvider的启动过程,ContentProvider启动后,外界就可以通过他所提供的增删改查四个接口来操作ContentProvider的数据源,insert,delete,update,query,这四个方法都是通过Binder来调用的,外界无法直接访问ContentProvider,他只能通过AMS提供的Uri来获取对应的ContentProvider的Binder接口和IContentProvider,然后通过IContentProvider来访问ContentProvider的数据源。

一般来说,ContentProvider都应该是单实例的,ContentProvider到底是不是单实例的,这是由他的android:multiprocess来决定的,当他为false的时候为多实例,默认为true,在实际的开发当中,我们并没有发现多实例的案例,官方文档的解释是避免进程间通信的开销,但是在实际开发中仍然缺少使用价值,因此我们可以简单认为ContentProvider就是单实例,接下来我们来分析下ContentProvider的启动过程

党文ContentProvider需要通过ContentResolver,ContentResolver是一个抽象类,通过Context的getContentResolver方法获取的实际上是ApplicationContentResolver对象,当ContentProvider所在的进程未启动的时候,第一次访问他时就会触发ContentProvider的创建,这也就伴随着ContentProvider所在的进程启动,通过ContentProvider的第四个方法的任何一个都能启动,这里我们通过query来讲解

ContentProvider的query方法,首先获取的IContentProvider对象,不管是通过acquireUnstableProvider方法还是直接通过acquireProvider方法,他们的本质都是一样的,最终都是通过acquireProvider的方法来获取ContentProvider,下面是ApplicationContentProvider的acquireProvider具体的实现方式:

    protected IContentProvider acquireProvider(Context context,String auth){
        return mMainThread.acquireProvider(context,
                ContentResolver.getAuthorityWithoutUserId(auth),
                resolveUserIdFromAuthority(auth),true);
    }

ApplicationContentResolver的acquireProvider方法并没有处理任何逻辑,他直接调用了ActivityThread的acquireProvider方法,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;
        }

        // There is a possible race here.  Another thread may try to acquire
        // the same provider at the same time.  When this happens, we want to ensure
        // that the first one wins.
        // Note that we cannot hold the lock while acquiring and installing the
        // provider since it might take a long time to run and it could also potentially
        // be re-entrant in the case where the provider is in the same process.
        IActivityManager.ContentProviderHolder holder = null;
        try {
            holder = ActivityManagerNative.getDefault().getContentProvider(
                    getApplicationThread(), auth, userId, stable);
        } catch (RemoteException ex) {
        }
        if (holder == null) {
            Slog.e(TAG, "Failed to find provider info for " + auth);
            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;
    }

上面的代码首先会从ActivityThread中超找是否已经存在目标的ContentProvider,如果存在就直接返回,ActivityThread中通过mProviderMap来存储已经启动的ContentProvider

    // The lock of mProviderMap protects the following variables.
    final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
        = new ArrayMap<ProviderKey, ProviderClientRecord>();

如果目前ContentProvider并没有启动,那么久发送一个进程间请求给AMS让其启动目标ContentProvider,最后通过installProvider方法来修改引用计数,那么AMS是如何启动ContentProvider的呢?我们知道,ContentProvider被启动时伴随着进程也会被启动,那么AMS重,首先会启动ContentProvider所在的进程,然后再ContentProvider,启动进程是由AMS的startProcessLocked方法来完成的,其内部主要是通过Process的start方法来完成一系列的新进程启动,新进程启动后其入口方法为ActivityThread的main方法:

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

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        Security.addProvider(new AndroidKeyStoreProvider());

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

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

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

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

        Looper.loop();

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

可以看到,ActivityThread的main方法是一个静态方法,他在内部先创建了一个实例并且调用了attach方法来进行一系列的初始化,接着开始消息循环了,最终会将ApplicationThread对象通过AMS的attchApplication方法跨进程传递给AMS,最终AMS会将ContentProvider的创建过程

            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                // Ignore
            } 

AMS的attachApplication方法又调用attachApplicationLocked方法,attachApplicationLocked中又调用了bindApplication,注意这个过程也是进程间调用

ActivityThread的bindApplication会发送一个BIND_APPLICATION类型的消息给mH,他是一个Handler,他收到消息后会调用ActivityThread,,过程如下:

            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);

ActivityThread的bindBaseApplication则完成了Application的创建以及ContentProvider的创建,可以分为如下四个步骤:

1.创建ContextImpl和instrumentation

            ContextImpl instrContext = ContextImpl.createAppContext(this, pi);

            try {
                java.lang.ClassLoader cl = instrContext.getClassLoader();
                mInstrumentation = (Instrumentation)
                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();
            } catch (Exception e) {
                throw new RuntimeException(
                    "Unable to instantiate instrumentation "
                    + data.instrumentationName + ": " + e.toString(), e);
            }

            mInstrumentation.init(this, instrContext, appContext,
                   new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
                   data.instrumentationUiAutomationConnection);

2.创建Application对象

            Application app = data.info.makeApplication(data.restrictedBackupMode, null);
            mInitialApplication = app; 

3.启动当前进程的ContentProvider并调用onCreate方法

            if (!data.restrictedBackupMode) {
                List<ProviderInfo> 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);
                }
            } 

installContentProviders完成了ContentProvider的启动工作,他的实现,首先是遍历ProviderInfo的列表并一一调用installProvider方法来启动他们,接着将以及启动的ContentProvider发送到AMS中,AMS会把他们存储在ProviderMap中,这样一来外部调用者可以直接从AMS中获取ContentProvider了

    private void installContentProviders(
            Context context, List<ProviderInfo> providers) {
        final ArrayList<IActivityManager.ContentProviderHolder> results =
            new ArrayList<IActivityManager.ContentProviderHolder>();

        for (ProviderInfo cpi : providers) {
            if (DEBUG_PROVIDER) {
                StringBuilder buf = new StringBuilder(128);
                buf.append("Pub ");
                buf.append(cpi.authority);
                buf.append(": ");
                buf.append(cpi.name);
                Log.i(TAG, buf.toString());
            }
            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) {
        }
    }

下面看一下ContentProvider对象的创建过程,在installProvider方法中有下面一段代码,并通过类加载器完成了ContentProvider对象的创建:

           try {
                final java.lang.ClassLoader cl = c.getClassLoader();
                localProvider = (ContentProvider)cl.
                    loadClass(info.name).newInstance();
                provider = localProvider.getIContentProvider();
                if (provider == null) {
                    Slog.e(TAG, "Failed to instantiate class " +
                          info.name + " from sourceDir " +
                          info.applicationInfo.sourceDir);
                    return null;
                }
                if (DEBUG_PROVIDER) Slog.v(
                    TAG, "Instantiating local provider " + info.name);
                // XXX Need to create the correct context for this provider.
                localProvider.attachInfo(c, info); 

在上述代码中,除了完成ContentProvider对象的创建,还会通过ContentProvider的attachInfo方法来调用他的onCreate方法,如下所示:

    private void attachInfo(Context context, ProviderInfo info, boolean testing) {
        mNoPerms = testing;

        /*
         * Only allow it to be set once, so after the content service gives
         * this to us clients can't change it.
         */
        if (mContext == null) {
            mContext = context;
            if (context != null) {
                mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
                        Context.APP_OPS_SERVICE);
            }
            mMyUid = Process.myUid();
            if (info != null) {
                setReadPermission(info.readPermission);
                setWritePermission(info.writePermission);
                setPathPermissions(info.pathPermissions);
                mExported = info.exported;
                mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
                setAuthorities(info.authority);
            }
            ContentProvider.this.onCreate();
        }
    } 

到此为止,ContentProvider已经被创建并且其onCreate方法也被调用了,这意味着他已经启动完成了

4.调用Application的onCreate方法

            try {
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!mInstrumentation.onException(app, e)) {
                    throw new RuntimeException(
                        "Unable to create application " + app.getClass().getName()
                        + ": " + e.toString(), e);
                }
            }

经过上面的四个步骤,ContentProvider已经启动了,并且在其所在进程的Application也已经启动了,这意味着ContentProvider所在的进程已经完成了整个的启动过程,然后其他应用通过AMS来访问这个ContentProvider,我们来看下query的实现

        @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) {
                return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
                        CancellationSignal.fromTransport(cancellationSignal));
            }
            final String original = setCallingPackage(callingPkg);
            try {
                return ContentProvider.this.query(
                        uri, projection, selection, selectionArgs, sortOrder,
                        CancellationSignal.fromTransport(cancellationSignal));
            } finally {
                setCallingPackage(original);
            }
        }

很显然,ContentProvider.Transport的query方法调用了ContentProvider的query方法,query方法的执行结果再通过Binder返回给调用者,这样一来整个调用过程就完成了,除了query方法,其他方法也是类似的,这里就不去深究了

猜你喜欢

转载自blog.csdn.net/qq_26787115/article/details/80875432
今日推荐