Android進(jìn)階(五):Service啟動過程(最詳細(xì)&最簡單)

1.前言

  • 最近一直在看 《Android進(jìn)階解密》 的一本書,這本書編寫邏輯、流程都非常好,而且很容易看懂,非常推薦大家去看看(沒有收廣告費,單純覺得作者寫的很好)。
  • 上一篇簡單的介紹了Android進(jìn)階(四):Activity啟動過程(最詳細(xì)&最簡單)。
  • 今天就介紹Service 2種啟動方式中:startService啟動 (基于Android 8.0 系統(tǒng))。
  • 本文提供一種看源碼的思路,因此bindService啟動流程就沒有再本文展開(與startService流程類似)。
  • 文章中實例 linhaojian的Github

2.Context繼承關(guān)系

  • 在講解Service啟動過程前,先了解一下它的繼承關(guān)系,便于后續(xù)的源碼理解:


    Context繼承關(guān)系.png
  • 從圖中,可以發(fā)現(xiàn):
    • Activity,Service,Application都是ContextWrapper的子類;
    • ContextWrapper里面引用著一個ContextImpl實例;
    • ContextWrapper里所有的方法都是通過調(diào)用ContextImpl進(jìn)行實現(xiàn);
  • 通過上述3點可以發(fā)現(xiàn),其他就是[裝飾者模式](http://www.itdecent.cn/p/16e946f42ce1)

2.Service啟動過程的時序圖

Service啟動時序圖.png

3.源碼分析

3.1 startService()啟動分析

3.1.1 ContextImpl

class ContextImpl extends Context {
    @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);// 1
    }
    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            getOpPackageName(), user.getIdentifier());// 2
            // ....
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}
  • 注釋1:startService最終也是調(diào)用startServiceCommon函數(shù);
  • 注釋2:ActivityManager.getService()其實就是ActivityManagerService,調(diào)用ActivityManagerService類里面的startService方法;

3.1.2 ActivityManagerService

    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
        //.....
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, userId);// 1
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }
  • 注釋1:調(diào)用ActiveServices的startServiceLocked()

3.1.3 ActiveServices

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        //.....
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false, false);// 1
        if (res == null) {
            return null;
        }
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }
        ServiceRecord r = res.record;
        if (!mAm.mUserController.exists(r.userId)) {
            Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
            return null;
        }
        //.....
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);// 2
        return cmp;
    }
  • 注釋1:創(chuàng)建 & 封裝啟動Service的相關(guān)數(shù)據(jù);
  • 注釋2:調(diào)用自身的startServiceInnerLocked();
    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        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();
        }
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false); // 3
        if (error != null) {
            return new ComponentName("!!", error);
        }
        //.....
        return r.name;
    }
  • 注釋3:調(diào)用自身的bringUpServiceLocked();
    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
            // ....
        final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        final String procName = r.processName;
        String hostingType = "service";
        ProcessRecord app;
        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                        + " app=" + app);
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);// 4
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                }
            }
        } else {
            app = r.isolatedProc;
            if (WebViewZygote.isMultiprocessEnabled()
                    && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
                hostingType = "webview_service";
            }
        }
        //.....
    }
  • 注釋4:調(diào)用自身的realStartServiceLocked()
    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        //.....
        boolean created = false;
        try {
            if (LOG_SERVICE_START_STOP) {
                String nameTerm;
                int lastPeriod = r.shortName.lastIndexOf('.');
                nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
                EventLogTags.writeAmCreateService(
                        r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
            }
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startLaunchedLocked();
            }
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);// 5
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app);
            throw e;
        } finally {
            //...
        }
        // 通知ActivityThread調(diào)用Service的onStartCommand方法
        sendServiceArgsLocked(r, execInFg, true);// 6
        //.....
    }
  • 注釋5:通知ActivityThread,真正的創(chuàng)建Service
  • 注釋6:調(diào)用自身的sendServiceArgsLocked()啟動Service的其他生命周期方法,下面會介紹

3.1.4 ActivityThread

  • scheduleCreateService()其實就是通過Handler機(jī)制進(jìn)行線程切換,最后會調(diào)用handleCreateService();
    private void handleCreateService(CreateServiceData data) {
        unscheduleGcIdler();
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);// 1
        Service service = null;
        try {
            // 通過類加載器,創(chuàng)建Service實例
            java.lang.ClassLoader cl = packageInfo.getClassLoader();// 2
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);// 3
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to instantiate service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            //向Service對象中初始化基本設(shè)置
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());// 4
            //調(diào)用service的onCreate生命周期函數(shù)
            service.onCreate();// 5
            mServices.put(data.token, service);
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
    }
  • 注釋1:獲取LoadedApk對象,負(fù)責(zé)解析manifest文件;
  • 注釋2:獲取ClassLoader類加載器,負(fù)責(zé)創(chuàng)建Service實例;
  • 注釋3:通過AppComponentFactory,創(chuàng)建Service對象
  • 注釋4:設(shè)置Service基礎(chǔ)參數(shù)
  • 注釋5:調(diào)用Service的onCreate方法;

3.1.5 AppComponentFactory

public class AppComponentFactory {
    public @NonNull Service instantiateService(@NonNull ClassLoader cl,
            @NonNull String className, @Nullable Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Service) cl.loadClass(className).newInstance();// 1
    }
}
  • 注釋1:通過類加載器,創(chuàng)建Service實例

3.1.6 ActiveServices的sendServiceArgsLocked()函數(shù)

    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
        //...        
       Exception caughtException = null;
        try {
            r.app.thread.scheduleServiceArgs(r, slice);// 1
        } catch (TransactionTooLargeException e) {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Transaction too large for " + args.size()
                    + " args, first: " + args.get(0).args);
            Slog.w(TAG, "Failed delivering service starts", e);
            caughtException = e;
        }
        //....
    }
  • 注釋1:調(diào)用ActivityThread的scheduleServiceArgs函數(shù)(在Service創(chuàng)建之后,會調(diào)用sendServiceArgsLocked(),實現(xiàn)其他的生命周期方法的調(diào)用);

3.1.7 ActivityThread的handleServiceArgs函數(shù)

  • scheduleServiceArgs()最終通過Handler機(jī)制切換線程 & 調(diào)用handleServiceArgs();
    private void handleServiceArgs(ServiceArgsData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                if (data.args != null) {
                    data.args.setExtrasClassLoader(s.getClassLoader());
                    data.args.prepareToEnterProcess();
                }
                int res;
                if (!data.taskRemoved) {
                    res = s.onStartCommand(data.args, data.flags, data.startId);// 1
                } else {
                    s.onTaskRemoved(data.args);
                    res = Service.START_TASK_REMOVED_COMPLETE;
                }
               //...
            } catch (Exception e) {
                // ...
            }
        }
    }
  • 注釋1:調(diào)用Service的onStartCommand();

4.類關(guān)系

Service啟動類結(jié)構(gòu).png
  • 通過上圖發(fā)現(xiàn),Service啟動過程就是AMS與ActivityThread不同的進(jìn)程交互實現(xiàn)的。

5.總結(jié)

  • 到此,Service啟動過程介紹完畢。
  • 如果喜歡我的分享,可以點擊 關(guān)注 或者 ,你們支持是我分享的最大動力 。
  • linhaojian的Github

歡迎關(guān)注linhaojian_CSDN博客或者linhaojian_簡書

不定期分享關(guān)于安卓開發(fā)的干貨。


寫技術(shù)文章初心

  • 技術(shù)知識積累
  • 技術(shù)知識鞏固
  • 技術(shù)知識分享
  • 技術(shù)知識交流
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容