Service啟動過程

afxstarx發表於2018-09-08
        前面最先分析得Activity和Provider,其中Activity是在ActivityThread中直接啟動的,呼叫了handleLaunchActivity;而Provider如果是跨程式,則呼叫了AMS獲取IContentProvider會阻塞在“等待Provider安裝完成”,ActivityThread在安裝完成後通知AMS已經安裝Provider成功,AMS阻塞被喚醒返回給呼叫者。
        這裡感覺一下,startService應該跟Activity類似,而bindeService跟Provider類似。前者在ActivityThread中作出相應即可,而後者則需要在AMS中等待onBinder的安裝(bindService是非同步的,而Provider呼叫時同步的)。

1684    @Override
1685    public ComponentName startService(Intent service) {
1686        warnIfCallingFromSystemProcess();
1687        return startServiceCommon(service, mUser);
1688    }
1701    private ComponentName startServiceCommon(Intent service, UserHandle user) {
1702        try {
1703            validateServiceIntent(service);
1704            service.prepareToLeaveProcess();
1705            ComponentName cn = ActivityManagerNative.getDefault().startService(
1706                mMainThread.getApplicationThread(), service,
1707                service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
1719            return cn;
1720        } catch (RemoteException e) {
1721            return null;
1722        }
1723    }複製程式碼
穿越進入ActivityManagerService中,第一個引數ApplicationThread,第二個引數是Intent,第三個引數是型別,第四個引數是userid。

14680    @Override
14681    public ComponentName startService(IApplicationThread caller, Intent service,
14682            String resolvedType, int userId) {
14691        synchronized(this) {
14692            final int callingPid = Binder.getCallingPid();
14693            final int callingUid = Binder.getCallingUid();
14694            final long origId = Binder.clearCallingIdentity();
14695            ComponentName res = mServices.startServiceLocked(caller, service,
14696                    resolvedType, callingPid, callingUid, userId);
14698            return res;
14699        }
14700    }複製程式碼

282    ComponentName startServiceLocked(IApplicationThread caller,
283            Intent service, String resolvedType,
284            int callingPid, int callingUid, int userId) {
287
288        final boolean callerFg;
289        if (caller != null) {
290            final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
291            if (callerApp == null) {
296            }
298        } else {
299            callerFg = true;
300        }
301
303        ServiceLookupResult res =
304            retrieveServiceLocked(service, resolvedType,
305                    callingPid, callingUid, userId, true, callerFg);
314        ServiceRecord r = res.record;
332        final ServiceMap smap = getServiceMap(r.userId);
333        boolean addToStarting = false;
334        if (!callerFg && r.app == null && mAm.mStartedUsers.get(r.userId) != null) {
335            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
383        }
394        return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
395    }複製程式碼
Service的處理邏輯單獨放到了ActiveService中,如果ServiceRecord沒有則會在retrieveServiceLocked中新建一個smap中,new ServiceLoopupResult(serviceRecord)返回。

397    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,
398            ServiceRecord r, boolean callerFg, boolean addToStarting) {
399        ProcessStats.ServiceState stracker = r.getTracker();

407        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);
429
430        return r.name;
431    }複製程式碼

1305    private final String bringUpServiceLocked(ServiceRecord r,
1306            int intentFlags, boolean execInFg, boolean whileRestarting) {
1310        if (r.app != null && r.app.thread != null) {
1311            sendServiceArgsLocked(r, execInFg, false);
1312            return null;
1313        }
1358        final String procName = r.processName;
1359        ProcessRecord app;
1360
1361        if (!isolated) {
1362            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
1365            if (app != null && app.thread != null) {
1366                try {
1367                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
1368                    realStartServiceLocked(r, app, execInFg);
1369                    return null;
1370                } catch (RemoteException e) {
1372                }
1376            }
1377        } 
1389        if (app == null) {
1390            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
1391                    "service", r.name, false, isolated, false)) == null) {
1397                bringDownServiceLocked(r);
1398                return msg;
1399            }
1403        }
14041405        if (!mPendingServices.contains(r)) {
1406            mPendingServices.add(r);
1407        }
1418        return null;
1419    }
複製程式碼
三步走


第一步:如果服務,對ServiceRecord中掛起的任務處理一次。第一次建立ServiceRecord這裡不會執行的。騷年們要注意呀,這裡的判斷是ServiceRecord.app && ServiceRecord.app.thread

1507    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
1508            boolean oomAdjusted) {
1509        final int N = r.pendingStarts.size();
1510        if (N == 0) {
1511            return;
1512        }
1513
1514        while (r.pendingStarts.size() > 0) {
1515            try {
1516                ServiceRecord.StartItem si = r.pendingStarts.remove(0);
1519                if (si.intent == null && N > 1) {
1524                    continue;
1525                }
1545                r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
1546            } catch (RemoteException e) {
1550                break;
1551            } catch (Exception e) {
1553                break;
1554            }
1555        }
1556    }複製程式碼
呼叫IApplicationThread.handleServiceArgs,進入到ActivityThread中

第二步:如果是程式內,且程式已經啟動了,呼叫ActivityThread中的handleCreateService,後面再分析吧

1430    private final void realStartServiceLocked(ServiceRecord r,
1431            ProcessRecord app, boolean execInFg) throws RemoteException {
1440
1446        boolean created = false;
1447        try {
1448            String nameTerm;
1449            int lastPeriod = r.shortName.lastIndexOf('.');
1460            app.thread.scheduleCreateService(r, r.serviceInfo,
1461                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
1462                    app.repProcState);
1463            r.postNotification();
1464            created = true;
1465        } catch (DeadObjectException e) {
1467            mAm.appDiedLocked(app);
1468        } finally {
1469            if (!created) {
1470                app.services.remove(r);
1471                r.app = null;
1472                scheduleServiceRestartLocked(r, false);
1473                return;
1474            }
1475        }1477        requestServiceBindingsLocked(r, execInFg);
1478
1489        sendServiceArgsLocked(r, execInFg, true);
1505    }複製程式碼

第三步:程式(程式內和程式外放到一起了)還沒有啟動,那麼呼叫startProcessLocked
-> ActivityThread.main -> ActivityThread.attach -> AMS.attachApplication -> IApplicationThread.scheduleBindAppliction + ActivityStackSupervisor.attachProceessLocked + ActiveServices.attachProcessLocked + mBroadcastQueues.sendPendingBraodcasts

http://androidxref.com/5.0.0_r2/xref/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java#attachApplicationLocked1917    boolean attachApplicationLocked(ProcessRecord proc, String processName)
1918            throws RemoteException {
1919        boolean didSomething = false;
1921        if (mPendingServices.size() > 0) {
1922            ServiceRecord sr = null;
1923            try {
1924                for (int i=0; i<mPendingServices.size(); i++) {
1925                    sr = mPendingServices.get(i);
1930
1931                    mPendingServices.remove(i);
1932                    i--;
1933                    proc.addPackage(sr.appInfo.packageName, sr.appInfo.versionCode,
1934                            mAm.mProcessStats);
1935                    realStartServiceLocked(sr, proc, sr.createdFromFg);
1936                    didSomething = true;
1937                }
1938            } catch (RemoteException e) {
1941                throw e;
1942            }
1943        }
1960        return didSomething;
1961    }複製程式碼
取出mPendingServices中的服務,啟動併傳送訊息。

1430    private final void realStartServiceLocked(ServiceRecord r,
1431            ProcessRecord app, boolean execInFg) throws RemoteException {
1440
1446        boolean created = false;
1447        try {
1448            String nameTerm;
1449            int lastPeriod = r.shortName.lastIndexOf('.');
1460            app.thread.scheduleCreateService(r, r.serviceInfo,
1461                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
1462                    app.repProcState);
1463            r.postNotification();
1464            created = true;
1465        } catch (DeadObjectException e) {
1467            mAm.appDiedLocked(app);
1468        } finally {
1469            if (!created) {
1470                app.services.remove(r);
1471                r.app = null;
1472                scheduleServiceRestartLocked(r, false);
1473                return;
1474            }
1475        }
1477        requestServiceBindingsLocked(r, execInFg);
1489        sendServiceArgsLocked(r, execInFg, true);
1505    }複製程式碼

總結一下三部曲:
如果服務啟動了,直接傳送訊息,並執行bind流程。如果服務沒有啟動,那麼:
如果程式啟動了,則啟動服務一下併傳送訊息;如果程式沒有啟動,那麼先把服務加入到mPendingServices中,再啟動程式,等程式啟動後執行ActiveServices.attachApplicationLocked解決呼叫mPendingServices。
------------------------------------------------------------------------------------------------
看看ActivityThread中的handleCreateService

2703    private void handleCreateService(CreateServiceData data) {
2706        unscheduleGcIdler();
2707
2708        LoadedApk packageInfo = getPackageInfoNoCheck(
2709                data.info.applicationInfo, data.compatInfo);
2710        Service service = null;
2711        try {
2712            java.lang.ClassLoader cl = packageInfo.getClassLoader();
2713            service = (Service) cl.loadClass(data.info.name).newInstance();
2714        } catch (Exception e) {
2715            if (!mInstrumentation.onException(service, e)) {
2719            }
2720        }
2721
2722        try {
2725            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
2726            context.setOuterContext(service);
2727
2728            Application app = packageInfo.makeApplication(false, mInstrumentation);
2729            service.attach(context, this, data.info.name, data.token, app,
2730                    ActivityManagerNative.getDefault());
2731            service.onCreate();
2732            mServices.put(data.token, service);
2733            try {
2734                ActivityManagerNative.getDefault().serviceDoneExecuting(
2735                        data.token, 0, 0, 0);
2736            } catch (RemoteException e) {
2738            }
2739        } catch (Exception e) {
2745        }
2746    }複製程式碼
首先反射構造Service例項,執行了onCreate函式,並儲存到mServices中。

再看看給Service傳送訊息handleServiceArgs

2854    private void handleServiceArgs(ServiceArgsData data) {
2855        Service s = mServices.get(data.token);
2856        if (s != null) {
2857            try {
2862                int res;
2863                if (!data.taskRemoved) {
2864                    res = s.onStartCommand(data.args, data.flags, data.startId);
2865                } else {
2866                    s.onTaskRemoved(data.args);
2867                    res = Service.START_TASK_REMOVED_COMPLETE;
2868                }
2870                QueuedWork.waitToFinish();
2879            } catch (Exception e) {
2885            }
2886        }
2887    }複製程式碼
因為建立的時候儲存到mService中,取出來然後執行onStartCommand操作。其中mService的key是ServiceRecord的代理。可以看看類資訊

應該是根據component儲存到了AMS.ActivieServices.smap中吧
------------------------------------------------------------------------------------------------
總結:AMS為每一個Service建立了一個ServiceRecord,儲存在smap中。首先需要建立Service,建立的時機是在mPendingServices或者直接建立,最終都呼叫scheduleCreateService。當建立完成後會傳送待處理的訊息,待處理的訊息放在了ServiceRecord.mPendingStars中,最終呼叫了scheduleServiceArgs。因此,startService的整個模型跟Activity差不多,AMS建立元件快取並轉發訊息給元件。


相關文章