1. 程式人生 > >Android原始碼之Service啟動流程

Android原始碼之Service啟動流程

 Service在開發中使用得或許沒有activity那麼頻繁,但它是Android四大元件之一,在Android中也是十分重要的,前面分析了activity的啟動流程,這裡也來分析一下Service是如何啟動的。
 Service分為兩種工作狀態,一種是啟動狀態,主要用於執行後臺計算;另外一種是繫結狀態,主要用於其他元件與Service的互動。需要注意的是,Service的兩種狀態是可以共存的,即Service既可以處於啟動狀態也可以同時處於繫結狀態。通過Context的startService即可啟動Service。

        Intent intent = new Intent
(this, MyService.class); startService(intent);

 通過Context的bindService方法即可以繫結的方式啟動一個Service。

        Intent intent = new Intent(this, MyService.class);
        bindService(intent,mServiceConnection,BIND_AUTO_CREATE);

1、Service的啟動過程

 startService方法存在於ContextWrapper中,具體實現如下

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

 這裡呼叫了mBase的startService方法,那mBase是什麼尼?其實mBase的型別是ContextImpl,在activity的attach方法中會將一個ContextImpl物件傳給mBase。那就來ContextImpl中看startService的實現。

    public ComponentName startService(Intent service) {
        .
.. return startServiceCommon(service, false, mUser); } private ComponentName startServiceCommon(Intent service, boolean requireForeground, UserHandle user) { try { ... ComponentName cn = ActivityManager.getService().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded( getContentResolver()), requireForeground, getOpPackageName(), user.getIdentifier()); ... } return cn; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }

 startService中呼叫了startServiceCommon這個方法,在startServiceCommon裡則通過Binder機制呼叫AMS中的startService方法。

    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
        ...
        //分段鎖
        synchronized(this) {
            ...
            try {
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, userId);
            } finally {
                ...
            }
            return res;
        }
    }

 startService這個方法很簡單,直接呼叫了ActiveServices的startServiceLocked方法。

   ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
           int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
           throws TransactionTooLargeException {
       ...
       ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
       return cmp;
   }
   ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
           boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
       ...
       String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
       ...
       return r.name;
   }

 startServiceLocked最後會呼叫startServiceInnerLocked這個方法,這個也比較簡單,直接呼叫了bringUpServiceLocked,這個方法就比較重要了,Service的建立就在這裡面實現的。

    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
        ...
        //如果該Service已經啟動則直接呼叫Service的onStartCommand方法
        if (r.app != null && r.app.thread != null) {
            //這個很重要,具體就是呼叫Service的onStartCommand方法
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }
        ...
        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            ...
            if (app != null && app.thread != null) {
                try {
                    ...
                    //建立Service
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    ...
                } catch (RemoteException e) {
                    ...
                }
            }
        } else {
            ...
        }

        //如果需要開啟程序,就先開啟程序
        if (app == null && !permissionsReviewRequired) {
            //開啟新的程序
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingType, r.name, false, isolated, false)) == null) {
                ....
                //程序建立失敗做的清除操作,如解綁Service、停止Service
                bringDownServiceLocked(r);
                return msg;
            }
            ...
        }
        ...
        return null;
    }

 bringUpServiceLocked中有四個方法非常重要,理解了這四個方法的實現就基本上理解了Service的啟動流程。

  • sendServiceArgsLocked:會呼叫Service的onStartCommand方法,當Service已經存在時則直接呼叫onStartCommand,不再重新建立Service
  • realStartServiceLocked:建立一個Service
  • startProcessLocked:開啟一個新的程序。
  • bringDownServiceLocked:主要是做解綁Service、停止Service的操作

 先來看sendServiceArgsLocked的實現。

    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
        //當bindService時,N==0,所以bindService就不會呼叫onStartCommand
        ////直接採用繫結方式建立服務時這個是沒有的,start流程中才有新增過程
        final int N = r.pendingStarts.size();
        if (N == 0) {
            return;
        }
        ...
        try {
            r.app.thread.scheduleServiceArgs(r, slice);
        } catch (TransactionTooLargeException e) {
            ...
        } catch (RemoteException e) {
            ...
        } catch (Exception e) {
            ...
        }
        ...
    }

 該方法還是比較簡單的,直接呼叫了ApplicationThread的scheduleServiceArgs方法,然後通過系統Handler來呼叫ActivityThread的handleServiceArgs方法。

    private void handleServiceArgs(ServiceArgsData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                ...
                int res;
                if (!data.taskRemoved) {
                    //呼叫了Service的onStartCommand的方法
                    res = s.onStartCommand(data.args, data.flags, data.startId);
                } else {
                    ...
                }
                ...
            } catch (Exception e) {
                ...
            }
        }
    }

 在handleServiceArgs方法中就會呼叫Service的onStartCommand方法,onStartCommand方法想必都很熟悉吧。再回到ActiveServices的bringUpServiceLocked方法中,現在再來看realStartServiceLocked這個方法。

    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        ...
        try {
            ...
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            ...
        } finally {
            //如果Service未建立成功,則清除
            if (!created) {
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);

                // Cleanup.
                if (newService) {
                    app.services.remove(r);
                    r.app = null;
                }

                // Retry.
                if (!inDestroying) {
                    scheduleServiceRestartLocked(r, false);
                }
            }
        }
        ...
        //呼叫Service的onBind方法,後面梳理繫結Service時在詳細講解
        requestServiceBindingsLocked(r, execInFg);
        ...
        //這個方法前面就講解了,主要是呼叫Service的onStartCommand方法
        sendServiceArgsLocked(r, execInFg, true);
        ...
    }

 realStartServiceLocked中首先呼叫了ApplicationThread的scheduleCreateService方法,scheduleCreateService中通過系統Handler來呼叫ActivityThread的handleCreateService方法。

    private void handleCreateService(CreateServiceData data) {
        ...
        try {
            //拿到ClassLoader
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            //通過反射建立Service
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            ...
        }

        try {
            ...
            //建立一個Service對應的ContextImpl 
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            //呼叫Service的attach方法,主要是初始化一些引數
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            //呼叫Service的onCreate方法,這個想必都很熟悉了
            service.onCreate();
            ...
        } catch (Exception e) {
            ...
        }
    }

 handleCreateService方法還是比較簡單的,該方法通過反射建立了Service並呼叫Service的onCreate方法。再回到ActiveServices的bringUpServiceLocked中,現在再來看startProcessLocked這個方法。這個方法在Android原始碼分析之Activity啟動流程這篇文章中有解介紹,這裡就不在詳細介紹了,只要知道它會建立一個新的程序,然後呼叫ActivityThread的main方法即可。接著呼叫attach方法,並最終呼叫AMS中的attachApplicationLocked方法。

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

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

 在該方法中呼叫了AMS的attachApplicationLocked方法,這個方法比較簡單。

    boolean attachApplicationLocked(ProcessRecord proc, String processName)
            throws RemoteException {
        boolean didSomething = false;
        // Collect any services that are waiting for this process to come up.
        if (mPendingServices.size() > 0) {
            ServiceRecord sr = null;
            try {
                for (int i=0; i<mPendingServices.size(); i++) {
                    sr = mPendingServices.get(i);
                    ...
                    //建立Service
                    realStartServiceLocked(sr, proc, sr.createdFromFg);
                    didSomething = true;
                    if (!isServiceNeededLocked(sr, false, false)) {
                        // We were waiting for this service to start, but it is actually no
                        // longer needed.  This could happen because bringDownServiceIfNeeded
                        // won't bring down a service that is pending...  so now the pending
                        // is done, so let's drop it.
                        bringDownServiceLocked(sr);
                    }
                }
            } catch (RemoteException e) {
                ...
            }
        }
        ...
        return didSomething;
    }

 上面的realStartServiceLocked方法是不是很熟悉啊,前面剛介紹完畢,這裡就不再繼續介紹。再回到ActiveServices的bringUpServiceLocked中,現在再來看bringDownServiceLocked這個方法。

    private final void bringDownServiceLocked(ServiceRecord r) {
        
        // Report to all of the connections that the service is no longer
        // available.
        for (int conni=r.connections.size()-1; conni>=0; conni--) {
            ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
            for (int i=0; i<c.size(); i++) {
                ConnectionRecord cr = c.get(i);
                //仍然存在與正在關閉的服務的連線。 把它標記為已死。
                cr.serviceDead = true;
                try {
                    cr.conn.connected(r.name, null, true);
                } catch (Exception e) {
                    ...
                }
            }
        }

        //與Service解除繫結
        if (r.app != null && r.app.thread != null) {
            for (int i=r.bindings.size()-1; i>=0; i--) {
                IntentBindRecord ibr = r.bindings.valueAt(i);
                if (ibr.hasBound) {
                    try {
                        ...
                        //呼叫Service的onUnbind方法
                        r.app.thread.scheduleUnbindService(r,
                                ibr.intent.getIntent());
                    } catch (Exception e) {
                        serviceProcessGoneLocked(r);
                    }
                }
            }
        }

        //檢查Service是否在前臺執行
        if (r.fgRequired) {
            ...
            r.fgRequired = false;
            r.fgWaiting = false;
            mAm.mHandler.removeMessages(
                    ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
            if (r.app != null) {
                Message msg = mAm.mHandler.obtainMessage(
                        ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
                msg.obj = r.app;
                mAm.mHandler.sendMessage(msg);
            }
        }
        ...
        //請注意,當通過bringUpServiceLocked()呼叫此方法時,則表示找不到該服務
        if (found != null && found != r) {
            // This is not actually the service we think is running...  this should not happen,
            // but if it does, fail hard.
            smap.mServicesByName.put(r.name, found);
            throw new IllegalStateException("Bringing down " + r + " but actually running "
                    + found);
        }
       
        ...
        //開始清除Service的相關資訊
        cancelForegroundNotificationLocked(r);
        if (r.isForeground) {
            decActiveForegroundAppLocked(smap, r);
        }
        r.isForeground = false;
        r.foregroundId = 0;
        r.foregroundNoti = null;
        r.clearDeliveredStartsLocked();
        r.pendingStarts.clear();

        if (r.app != null) {
            synchronized (r.stats.getBatteryStats()) {
                r.stats.stopLaunchedLocked();
            }
            r.app.services.remove(r);
            if (r.whitelistManager) {
                updateWhitelistManagerLocked(r.app);
            }
            if (r.app.thread