《Android开发艺术探索》之理解四大组件的工作过程下(十一)

135 阅读6分钟

                                                               第九章   Service的工作过程(下)
(三)Service的工作过程
本节将介绍Service的启动过程和绑定过程,一种是启动状态,主要用于执行后台计算;一种是绑定状态,主要用于其他组件与Service的交互。使用Context的startService和bindService可以完成Service的启动和绑定。

 

    //启动Service 
    Intent intent = new Intent(this, MyService.class);
    startService(intent);

   //绑定Service
    Intent intent = new Intent(this, TestService.class);
    bindService(intent,mServiceConnection,BIND_AUTO_CREATE);

3.1.Service的启动过程
步骤一:从ContextWrapper的startService开始,mBase的类型是ContextImpl,Activity在启动时会通过attach方法讲一个ContextImpl对象关联起来。其大部分操作是通过mBase做的。

    @Override
    public ComponentName startService(Intent service) {
        return mBase.startService(service);
}

      步骤二:startService方法会调用startServiceCommon方法,而startServiceCommon方法又是通过ActivityManagerNative.getDefault().startService(ActivityManagerNative.getDefault().其实是AMS)的对象来启动一个服务的。

   @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, mUser);
    }

    private ComponentName startServiceCommon(Intent service, UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess();
            ComponentName cn = ActivityManagerNative.getDefault().startService(
                mMainThread.getApplicationThread(), service,
                service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
            if (cn != null) {
.               ...
            }
            return cn;
        } catch (RemoteException e) {
            return null;
        }
    }

        步骤三:通过AMS来启动服务的行为是一个远程过程调用,在AMS中,mServices对象类型是ActiveServices,其是一个辅助AMS进行Service的管理(启动、绑定、停止等),在ActiveServices的startServiceLocked中,它在结尾会调用startServiceInnerLocked,调用了bringUpServiceLocked方法,后续的工作在bringUpServiceLocked的realStartServiceLocked方法中处理。

  @Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, int userId) {
        ....
        synchronized(this) {
            ....
            ComponentName res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }

    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,
            ServiceRecord r, boolean callerFg, boolean addToStarting) {
        //ServiceRecord 是一个Service记录,一直贯穿Service的启动过程
        ProcessStats.ServiceState stracker = r.getTracker();
        if (stracker != null) {
            stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
        }
        r.callStart = false;
        synchronized (r.stats.getBatteryStats()) {
            r.stats.startRunningLocked();
        }
        //后续的工作在bringUpServiceLocked的realStartServiceLocked方法中处理
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);
        if (error != null) {
            return new ComponentName("!!", error);
        }
        ....
        return r.name;
}

      步骤四:在realStartServiceLocked方法中,app.thread.scheduleCreateService创建Service对象并调用其onCreate,app.thread其实是一个Binder,发送消息给Handler H来处理,通过ActivityThread的handleCreateService方法来完成Service的最终启动。sendServiceArgsLocked调用Service的其他方法,譬如StartCommand。

    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
            ...
          //1.创建Service对象并调用其onCreate,app.thread其实是一个Binder,发送消息给Handler H来处理,通过ActivityThread的handleCreateService方法来完成Service的最终启动。
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
             .....
        //2.通过该方法调用Service的其他方法,譬如StartCommand
        sendServiceArgsLocked(r,execInFg,true)
}

       步骤五:handleCreateService方法主要完成了:(1)通过类加载器创建了Service对象;(2)创建Application对象并调用onCreate,只会创建一次;(3)创建ContextImpl并且通过Service的attach方法建立两者的关系;(4)调用Service的onCreate并且将Service独享存储到ActivityThread中的一个列表中;(5)通过handleServiceArgs方法去调用onstartCommond方法。
3.2.Service的绑定过程
步骤一:类似于Service的启动过程,也是从ContextWrapper开始,并通过bindService方法最终调用binServiceCommon方法。

   @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        return mBase.bindService(service, conn, flags);
    }

        步骤二:binServiceCommon方法,完成两件事情:1.将ServiceCommon对象转换为ServiceDispatcher.InnerConnection对象(绑定服务可能是跨进程的,譬如IntentService),ServiceCommon内部类InnerConnection刚好充当了Binder这个角色。2.最后调用了onServiceConnected方法。
感觉看不到意义何在。
(四)BroadcastReceiver的工作过程
BroadcastReceiver先谈谈广播的注册过程,再一个是广播的发送和接收过程。
广播接受者的实现:

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

静态注册:

  <receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.hzk.receiver" />
            </intent-filter>
        </receiver>

动态注册:

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

send方法发送广播:

Intent intent = new Intent("com.hzk.receiver");
sendBroadcast(intent);

4.1.广播的注册过程
广播分为静态注册和动态注册两种,静态注册的广播在App安装时有系统完成注册,举例来说是由PackageManagerService来完成整个注册过程。这里分析其动态注册过程。
步骤一:registerReceiver调用了自己的registerReceiverInternal方法,首先从mPackageInfo获取IIntentReceiver对象;其次在AMS中完成广播的真正注册。

    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();
                }
    //1.从mPackageInfo获取IIntentReceiver对象
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
//2.AMS中完成代码的真正注册。
            return ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);
        } catch (RemoteException e) {
            return null;
        }
    } 

        步骤二:在AMS中,会把远程的InnerReceiver和IntentFilter对象存储起来,这样整个广播的注册过程就完成了。

  public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
            ....
            mRegisteredReceivers.put(receiver.asBinder(),r1);
            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);
            ...
            return sticky;
        }
    }

4.2.广播的发送和接收过程
当Send方法发送广播时,AMS会找出匹配的广播接收者并将广播发送给它们处理,广播发送的类型有:普通广播、有序广播和粘性广播。后两者与普通广播具有不同特性,但发送/接收流程类似,故而我们只分析普通广播的实现。
步骤一:发送广播始于ContextWrapper的senBroadCast方法,其并不做什么,将事情交给ContextImpl去处理。其直接向AMS发送一个异步请求用于发送广播。

  @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess();
           //直接向AMS发送一个异步请求用于发送广播
            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调用了broadcastIntentLocked方法,该方法用来筛选广播。

    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) {
              ....
//调用了broadcastIntentLocked方法,用来配置BroadCastReceiver的相关配置,怎么发送?怎么进行匹配?
            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方法中,Android5.0下默认情况下广播不会发送给已经停止的应用,可以使用FLAGS进行控制是否发送给已经停止的应用。使用Intent-filter查找出匹配的广播接收者并经过一些列的条件过滤,最终将满足条件的广播接收者添加到BroadcastQueue中,此时BroadcastQueue会将其发送给相应的广播接受者。如果是无序广播,则会遍历广播存储,最后onReceiver会被执行。

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

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

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

(五)ContentProvider的工作过程
ContentProvider是一个内存共享型组件,通过Binder向其他组件乃至其他应用提供数据,当ContentProvider所在的进程启动的时候,ContentProvider会同时启动并且发布到AMS中,需要注意的是,这个时候ContentProvider的onCreate要先于Application的onCreate执行。
启动过程:
(1)一个应用启动的时候,入口方法在ActivityThread中的main里,main是一个静态方法,在main中会创建ActivityThread的实例并创建主线程的消息队列;
(2)在ActivityThread的attach中远程调用AMS的attachApplication方法并将ActivityThread提供给AMS;
(3)ActivityThread是一个Binder对象,他的Binder接口是IApplicationThread,他主要用于ActivityThread和AMS之间的通信,会调用ApplicationThread的bindApplication方法,注意这个过程同样是跨进程完成的,
(4)bindApplication的逻辑是经过ActivityThread中的mHander切换到ActivityThread执行,具体是方法是handlerBindApplication,在handlerApplication方法中,ActivityThread会加载一个ContentProvider,然后再调用Application的onCreate方法。
需要说明的是,handlerBindApplication的功能是:(1)创建ContextImpl和Instrumentation;(2)创建Application对象;(3)启动当前进程的ContentProvider并调用其onCreate方法;(4)调用Application的onCreate方法。