Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

Android中bindService的细节之四:bindService时,你所忽略的代码流程细节

$
0
0

Android中bindService的细节之四:bindService时,你所忽略的代码流程细节

0. 说明

事先声明:本文所讲的内容,即使被你忽略了,也不影响对bindService()代码流程的理解。

场景: App A绑定App B的MyService时,App B进程之前没有启动,即需要创建App B进程。

本文要讲的内容是,从App B的ActivityThread的main()执行开始到Looper.loop()执行这段时间内的代码流程,这部分流程是 《Android中bindService的细节之一:从进程的角度分析绑定Service的流程【Service所在进程首次启动】》 的一部分,看完整的流程,可以参考这个链接

本文从创建App B进程后,在App B进程中执行ActivityThread的main()讲起。

注:AMS所在进程为system_server,为突出AMS,将AMS所在进程称为AMS进程。

1. bindService()的代码流程

1.1 ActivityThread的main()

    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();// 创建Looper

        ActivityThread thread = new ActivityThread();
        thread.attach(false);// 执行这里
        ...
    }

创建ActivityThread,执行attach()。

1.2 thread.attach(false)

attach() @ ActivityThread

参数system为false

    private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ...
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                // 执行这里
                mgr.attachApplication(mAppThread);
            } catch ...
            ...
        } else {
            ...
        }
        ...
    }

1.3 mgr.attachApplication(mAppThread)

attachApplication() @ ActivityManagerService

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

1.4 attachApplicationLocked(thread, callingPid)

attachApplicationLocked() @ ActivityManagerService

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

        ProcessRecord app;
        if (pid != MY_PID && pid >= 0) {
            synchronized (mPidsSelfLocked) {
                // 执行这里,因为App B进程刚刚创建,ProcessRecord是在Zygote fork进程前创建的
                app = mPidsSelfLocked.get(pid);
            }
        } else ...
        ...
        // makeActive()把App B进程传过来的IApplicationThread binder对象保存到ProcessRecord的成员变量thread中
        app.makeActive(thread, mProcessStats);
        ...
        // 在创建进程时,设置了超时处理的消息,在这里取消掉
        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

        // 获取App B中的provider信息
        boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
        List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;

        try {
            ...
            // 执行这里,将向App B的消息队列中放入BIND_APPLICATION消息
            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                    profilerInfo, ...);
            ...
        } catch (Exception e) {
            ...
        }

        boolean badApp = false;
        boolean didSomething = false;

        // See if the top visible activity is waiting to run in this process...
        if (normalMode) {
            try {
                // 执行这里,但是在此场景中不创建新的Activity,所以if语句条件不为true
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true;// 不执行这里
                }
            } catch ...
        }

        // Find any services that should be running in this process...
        if (!badApp) {
            try {
                // 执行这里
                didSomething |= mServices.attachApplicationLocked(app, processName);
            } catch ...
        }
        ...
        return true;
    }

1.5 thread.bindApplication(processName, appInfo, providers…)

切换到App B进程。
bindApplication() @ ApplicationThread @ ActivityThread

        public final void bindApplication(String processName, ApplicationInfo appInfo,
                List<ProviderInfo> providers, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                ...
                ) {
            ...
            AppBindData data = new AppBindData();
            data.processName = processName;
            data.appInfo = appInfo;
            data.providers = providers;
            ...
            /* 向App B的消息队列中放入BIND_APPLICATION消息,
            因为Looper.loop()还没有执行,所以BIND_APPLICATION消息放入队列中,没有立即执行
            */
            sendMessage(H.BIND_APPLICATION, data);
        }

1.6 mServices.attachApplicationLocked(app, processName)

从App B进程回来,继续执行。

attachApplicationLocked() @ ActiveServices

    boolean attachApplicationLocked(ProcessRecord proc, String processName)
            throws RemoteException {
        boolean didSomething = false;
        /* 在启动App B进程的时候,将要绑定的服务ServiceRecord放入了mPendingServices,代码在bringUpServiceLocked()中,执行mAm.startProcessLocked()之后,执行了
        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }
        */
        if (mPendingServices.size() > 0) {
            ServiceRecord sr = null;
            try {
                for (int i=0; i<mPendingServices.size(); i++) {
                    sr = mPendingServices.get(i);
                    ...
                    mPendingServices.remove(i);
                    i--;
                    ...
                    // 执行这里
                    realStartServiceLocked(sr, proc, sr.createdFromFg);
                    didSomething = true;
                    ...
                }
            } catch ...
        }
        return didSomething;
    }

1.7 realStartServiceLocked(sr, proc, sr.createdFromFg)

realStartServiceLocked() @ ActiveServices

    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        ...
        r.app = app; // 此时将ServiceRecord中的app赋值
        ...

        boolean created = false;
        try {
            ...
            // 执行这里,将向App B的消息队列中放入CREATE_SERVICE消息
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            ...
        } finally {
            ...
        }
        ...
        // 执行这里
        requestServiceBindingsLocked(r, execInFg);
        ...
    }

1.8 app.thread.scheduleCreateService(r, r.serviceInfo,…)

进入App B进程。

scheduleCreateService() @ ApplicationThread @ ActivityThread

        public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;
            // 向App B的消息队列中放入CREATE_SERVICE消息
            // 因为Looper.loop()还没有执行,所以CREATE_SERVICE消息放入队列中,没有立即执行。此时队列中已经有2个消息,BIND_APPLICATION消息和CREATE_SERVICE消息
            sendMessage(H.CREATE_SERVICE, s);
        }

1.9 requestServiceBindingsLocked(r, execInFg)

回到AMS进程。

requestServiceBindingsLocked() @ ActiveServices

    private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
            throws TransactionTooLargeException {
        for (int i=r.bindings.size()-1; i>=0; i--) {
            IntentBindRecord ibr = r.bindings.valueAt(i);
            if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
                break;
            }
        }
    }

1.10 requestServiceBindingLocked(r, ibr, execInFg, false)

requestServiceBindingLocked() @ ActiveServices

    private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
        // 在realStartServiceLocked()中已经将r.app赋值
        if (r.app == null || r.app.thread == null) {
            // 不执行这里
            return false;
        }
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                ...
                // 执行这里,将向App B的消息队列中放入BIND_SERVICE消息
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
                if (!rebind) {
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            } catch (TransactionTooLargeException e) {
                ...
            } catch (RemoteException e) {
                ...
            }
        }
        return true;
    }

1.11 r.app.thread.scheduleBindService(r, …)

        public final void scheduleBindService(IBinder token, Intent intent,
                boolean rebind, int processState) {
            updateProcessState(processState, false);
            BindServiceData s = new BindServiceData();
            s.token = token;
            s.intent = intent;
            s.rebind = rebind;
            ...
            // 向App B的消息队列中放入BIND_SERVICE消息
            // 因为Looper.loop()还没有执行,所以BIND_SERVICE消息放入队列中,没有立即执行。此时队列中已经有3个消息,BIND_APPLICATION消息、CREATE_SERVICE消息和BIND_SERVICE消息
            sendMessage(H.BIND_SERVICE, s);
        }

以上这些代码都是由于执行ActivityThread的main()方法中的thread.attach(false)引起的,所以,执行完上面的代码将回到ActivityThread的attach(),继续执行thread.attach(false)之后的代码。

在本文讨论的场景中,最后ActivityThread将执行Looper.loop()。

1.12 回到ActivityThread的main()

当前在App B进程。

    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();// 创建Looper

        ActivityThread thread = new ActivityThread();
        // 之前的代码都是由thread.attach()引起的,AMS调用IApplicationThread接口向App B的消息队列中放入3个消息:BIND_APPLICATION消息、CREATE_SERVICE消息和BIND_SERVICE消息
        thread.attach(false);

        ...
        // 此时执行这里,监听消息队列中是否有新消息,如果没有消息,则阻塞在这里。
        // 但是,此时队列中已经有了3个待处理的消息,loop()之后将依次处理消息
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

1.13 Looper.loop()

    public static void loop() {
        final Looper me = myLooper();
        ...
        final MessageQueue queue = me.mQueue;
        ...
        for (;;) {
            // 阻塞在这里,监听消息队列是否有消息到来
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            ...
            try {
                // 处理之前放入的3个消息
                msg.target.dispatchMessage(msg);
            } finally {
                ...
            }
            ...
        }
    }

1.14 处理App B消息队列中的3个消息

【注:本文只关注3个消息,其实还有其他的消息】

之前放入App B的消息队列中的3个消息:

  • (1)BIND_APPLICATION消息:
    触发消息:AMS调用thread.bindApplication(processName, appInfo, providers,...)
    处理消息:handleBindApplication() @ ActivityThread

  • (2)CREATE_SERVICE消息:
    触发消息:AMS调用app.thread.scheduleCreateService(r, r.serviceInfo,...)
    处理消息:handleCreateService() @ ActivityThread

  • (3)BIND_SERVICE消息:
    触发消息:AMS调用r.app.thread.scheduleBindService(r, i.intent.getIntent(),...)
    处理消息:handleBindService() @ ActivityThread

1.15 小结

在App B进程创建后,从ActivityThread的main()开始,到Looper.loop()执行这段初始化的过程中,AMS调用App B的IApplicationThread接口,向App B的消息队列中放入了3个消息:BIND_APPLICATION消息、CREATE_SERVICE消息和BIND_SERVICE消息,但是没有立即被处理。

这3个消息都是在Looper.loop()执行的时候,才被处理的,而且按照队列先进先出的顺序,依次处理BIND_APPLICATION消息、CREATE_SERVICE消息和BIND_SERVICE消息。

可以通过在AMS和ActivityThread中加log来验证这个过程,也可以做一个模拟的测试过程。

2. 测试Handler、Looper的消息处理

2.1 模拟AMS

  • (1)用于与App B通信的IMyActivityManager.aidl
package com.galian.ams;

interface IMyActivityManager {
    void attachApplication(IBinder appThread);
}
  • (2)实现IMyActivityManager接口
package com.galian.ams;
...
import com.galian.app_a.IMyAppThread;

public class TestHandlerLooperActivity extends Activity {

    private static final String TAG = "AMS/Test";
    private EditText mDelaySecondsEditText = null;
    private IMyAppThread mAppThread = null;

    private class MyActivityManagerService extends IMyActivityManager.Stub {
        @Override
        public void attachApplication(IBinder appThread) throws RemoteException {
            Log.d(TAG, "attachApplication() start");

            mAppThread = IMyAppThread.Stub.asInterface(appThread);
            if (mAppThread != null) {
                mAppThread.bindApplication();
                mAppThread.scheduleCreateService();
                mAppThread.scheduleBindService();
                Log.d(TAG, "call bindApplication()/scheduleCreateService()/scheduleBindService()");
                Log.d(TAG, "attachApplication() end");
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_handler_looper);

        mDelaySecondsEditText = (EditText) findViewById(R.id.delay_seconds_edittext);

        Button test_handler_looper_Button = (Button) findViewById(R.id.test_handler_looper);
        test_handler_looper_Button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Editable edit = mDelaySecondsEditText.getText();
                int delaySeconds = 3;
                if (!edit.toString().trim().equals("")) {
                    delaySeconds = Integer.parseInt(edit.toString());
                }
                Intent intent =new Intent();
                intent.setClassName("com.galian.app_a",
                        "com.galian.app_a.MyHandlerService");
                // 通过Intent将binder对象传递给模拟的App B
                IMyActivityManager binder = new MyActivityManagerService();
                Bundle extras = new Bundle();
                extras.putBinder("binder", (IBinder)binder);
                extras.putInt("delay", delaySeconds);
                intent.putExtras(extras);
                Log.d(TAG, "star MyHandlerService");
                // App B的ActivityThread的模拟是通过Service来实现的
                startService(intent);
            }
        });

        Button finish_test_handler_looper_Button = (Button) findViewById(R.id.finish_test_handler_looper);
        finish_test_handler_looper_Button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent =new Intent();
                intent.setClassName("com.galian.app_a",
                        "com.galian.app_a.MyHandlerService");
                stopService(intent);
            }
        });
    }
}

2.2 模拟App B的ActivityThread

  • (1)用于与AMS通信的IMyAppThread.aidl
package com.galian.app_a;

interface IMyAppThread {
    void bindApplication();
    void scheduleCreateService();
    void scheduleBindService();
}
  • (2)通过Service + Thread来模拟App B的ActivityThread
package com.galian.app_a;
...
import com.galian.ams.IMyActivityManager;

public class MyHandlerService extends Service {

    private static final String TAG = "AppA/MyHandlerService";

    IMyAppThread myAppThread = new MyAppThread();
    private int delaySeconds = 0;
    private MyHandler mHandler = null;
    private Looper mLooper = null;
    private boolean isLooperOK = false;

    @Override
    public void onCreate() {
        super.onCreate();

        // 模拟ActivityThread启动
        Thread thread = new MyThread();
        thread.start();
        Log.d(TAG, "onCreate()");
    }

    @Override
    public void onDestroy() {
        mLooper.quitSafely();
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
            Bundle extras = intent.getExtras();
            IMyActivityManager activityManager = IMyActivityManager.Stub.asInterface(extras.getBinder("binder"));
            try {
                // 服务启动
                if (activityManager != null) {
                    Log.d(TAG, "attachApplication()");
                    activityManager.attachApplication(myAppThread.asBinder());
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }

            delaySeconds = extras.getInt("delay");
            isLooperOK = true;// Looper在延迟几秒后可以正常运行了
        }
        return Service.START_NOT_STICKY;

    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private class MyAppThread extends IMyAppThread.Stub {

        @Override
        public void bindApplication() throws RemoteException {
            Message msg = Message.obtain();
            msg.what = MyHandler.BIND_APP;
            Log.d(TAG, "send BIND_APP msg");
            mHandler.sendMessage(msg);
        }

        @Override
        public void scheduleCreateService() throws RemoteException {
            Message msg = Message.obtain();
            msg.what = MyHandler.CREATE_SVC;
            Log.d(TAG, "send CREATE_SVC msg");
            mHandler.sendMessage(msg);
        }

        @Override
        public void scheduleBindService() throws RemoteException {
            Message msg = Message.obtain();
            msg.what = MyHandler.BIND_SVC;
            Log.d(TAG, "send BIND_SVC msg");
            mHandler.sendMessage(msg);
        }
    }

    public class MyHandler extends Handler {

        public static final int BIND_APP = 1;
        public static final int CREATE_SVC = 2;
        public static final int BIND_SVC = 3;

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BIND_APP:
                    Log.d(TAG, "handleBindApplication()");
                break;
                case CREATE_SVC:
                    Log.d(TAG, "handleCreateService()");
                    break;
                case BIND_SVC:
                    Log.d(TAG, "handleBindService()");
                    break;
                default:
                    break;
            }
        }
    }

    private  class MyThread extends Thread {
        @Override
        public void run() {
            Log.d(TAG, "thread is running.");
            // 创建Handler、Looper
            Looper.prepare();
            mHandler = new MyHandler();
            mLooper = Looper.myLooper();
            // 在服务没有执行onStartCommand()的时候,线程处于等待状态
            while (!isLooperOK) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            // 延迟的目的是,确保处理消息的代码一定在规定的延迟时间之后执行
            // 这样可以看出只有Looper.loop()执行之后,放入队列的消息才会被处理
            Log.d(TAG, "sleep " + delaySeconds + " seconds");
            try {
                Thread.sleep(delaySeconds*1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            Log.d(TAG, "Looper.loop()");
            Looper.loop();
        }
    }
}

2.3 模拟测试的结果

  • (1)模拟App B进程初次创建:MyHandlerService初次创建
01-30 00:40:06.767 15782 15782 D AMS/Test: star MyHandlerService
01-30 00:40:06.947  4537  4537 D AppA/MyHandlerService: onCreate()
01-30 00:40:06.947  4537  4567 D AppA/MyHandlerService: thread is running.
01-30 00:40:06.947  4537  4537 D AppA/MyHandlerService: attachApplication()
01-30 00:40:06.947 15782 15795 D AMS/Test: attachApplication() start
01-30 00:40:06.947  4537  4537 D AppA/MyHandlerService: send BIND_APP msg
01-30 00:40:06.947  4537  4537 D AppA/MyHandlerService: send CREATE_SVC msg
01-30 00:40:06.947  4537  4537 D AppA/MyHandlerService: send BIND_SVC msg
01-30 00:40:06.957 15782 15795 D AMS/Test: call bindApplication()/scheduleCreateService()/scheduleBindService()
01-30 00:40:06.957 15782 15795 D AMS/Test: attachApplication() end
01-30 00:40:07.447  4537  4567 D AppA/MyHandlerService: sleep 6 seconds
01-30 00:40:13.447  4537  4567 D AppA/MyHandlerService: Looper.loop()
01-30 00:40:13.447  4537  4567 D AppA/MyHandlerService: handleBindApplication()
01-30 00:40:13.447  4537  4567 D AppA/MyHandlerService: handleCreateService()
01-30 00:40:13.447  4537  4567 D AppA/MyHandlerService: handleBindService()

其中pid 4537为模拟App B的进程,pid 15782为AMS进程。
为了描述方便,下面提到的AMS和App B都是上面的代码模拟的出来的,不再说模拟的AMS和模拟的App B进程。
App B进程启动后,调用AMS的attachApplication();
AMS在attachApplication()中调用App B的接口,向App B的消息队列放入了3个消息:BIND_APP、CREATE_SVC和BIND_SVC。可以看到此时3个消息都放入了队列,但是没有被处理;
几秒后,Looper.loop()执行了,立即处理消息队列中的3个消息,而且是依次处理。

  • (2)模拟App B进程已经启动:MyHandlerService已经运行,此时往消息队列放入消息
01-30 00:40:52.797 15782 15782 D AMS/Test: star MyHandlerService
01-30 00:40:52.797  4537  4537 D AppA/MyHandlerService: attachApplication()
01-30 00:40:52.807 15782 15795 D AMS/Test: attachApplication() start
01-30 00:40:52.807  4537  4537 D AppA/MyHandlerService: send BIND_APP msg
01-30 00:40:52.807  4537  4567 D AppA/MyHandlerService: handleBindApplication()
01-30 00:40:52.807  4537  4537 D AppA/MyHandlerService: send CREATE_SVC msg
01-30 00:40:52.807  4537  4537 D AppA/MyHandlerService: send BIND_SVC msg
01-30 00:40:52.807 15782 15795 D AMS/Test: call bindApplication()/scheduleCreateService()/scheduleBindService()
01-30 00:40:52.807 15782 15795 D AMS/Test: attachApplication() end
01-30 00:40:52.807  4537  4567 D AppA/MyHandlerService: handleCreateService()
01-30 00:40:52.817  4537  4567 D AppA/MyHandlerService: handleBindService()

可以看到,将消息放入消息队列,消息是被立即处理的。
注:这里说的“立即处理”不是同步处理,AMS进程和App B进程是并行的。

3. 总结

  • (1)本文所讲的内容,即使被你忽略了,也不影响对bindService()代码流程的理解

  • (2)在App进程首次创建的时候,在Looper.loop()运行之前,AMS调用IApplicationThread接口放入App 消息队列的消息不会立即被处理。在Looper.loop()运行的时候,将依次处理消息队列中的所有消息。

继续阅读:

《Android中bindService的细节之一:从进程的角度分析绑定Service的流程【Service所在进程首次启动】》

《Android中bindService的细节之二:从进程的角度分析绑定Service的流程【Service所在进程已存在】》

作者:u013553529 发表于2017/1/30 1:10:41 原文链接
阅读:64 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>