百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Android中的Service是如何启动的(android service用法)

lipiwang 2024-11-15 22:03 30 浏览 0 评论

1:前言

ServiceAndroid中的四大组件之一,日常开发中我们经常会使用startService之类的方法来启动Service,那这个方法调用的底层原理是什么呢?Android系统是如何启动起来Service的呢?本文我们从源码出发,介绍一下Android中的Service是如何启动Service的,本文的结构如下:

2:源码分析

2.1:ContextImpl.startService&startForegroundService:应用层调用的入口

我们调用startService/startForegroundService之后,会调用到android.app.ContextImpl#startService/startForegroundService

class ContextImpl extends Context {  
    @Override
    public ComponentName startService(Intent service) {
        return startServiceCommon(service, false, mUser);
    }
    @Override
    public ComponentName startForegroundService(Intent service) {
        return startServiceCommon(service, true, mUser);
    }

    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
         ...
    }
}

可以看到,startServicestartForegroundService最终调用的都是startServiceCommon这个方法,唯一不同的是第二个参数requireForeground的值不一样,用来标识当前Service是否是前台Serivice,我们来看startServiceCommon的具体实现:

class ContextImpl extends Context {  
   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(), getAttributionTag(), user.getIdentifier());
            if (cn != null) {
                if (cn.getPackageName().equals("!")) {
                    throw new SecurityException(
                            "Not allowed to start service " + service
                            + " without permission " + cn.getClassName());
                } else if (cn.getPackageName().equals("!!")) {
                    throw new SecurityException(
                            "Unable to start service " + service
                            + ": " + cn.getClassName());
                } else if (cn.getPackageName().equals("?")) {
                    throw new IllegalStateException(
                            "Not allowed to start service " + service + ": " + cn.getClassName());
                }
            }
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}

可以看到,核心是调用到了ActivityManager.getService().startService()方法进行Service的启动,即AMS中,我们来看一下AMS中是如何启动Service的.

2.2:ActivityManagerService.startService:执行前置判断,满足启动service的条件的话触发真正startService的逻辑

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub{
      final ActiveServices mServices;

     @Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage,
            String callingFeatureId, 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, callingFeatureId, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }
}

可以看到,最终调用到了ActiveServices.startServiceLocked()中:

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
public final class ActiveServices {
    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage,
            @Nullable String callingFeatureId, final int userId)
            throws TransactionTooLargeException {
        return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
                callingPackage, callingFeatureId, userId, false);
    }

      ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage,
            @Nullable String callingFeatureId, final int userId,
            boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
          /**
          *对当前Service的启动进行判断,看下Service启动的限制(比如权限、前后台等是否满足)
          **/
          ...
        //启动Service
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        if (!r.mAllowWhileInUsePermissionInFgs) {
            r.mAllowWhileInUsePermissionInFgs =
                    shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid,
                            callingUid, service, r, allowBackgroundActivityStarts);
        }
        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;
    }
}

核心是调用到了ActiveServices.bringUpServiceLocked.

2.3:ActiveServices.bringUpServiceLocked:根据进程&线程是否存在执行不同操作

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
public final class ActiveServices {
       private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
             //如果进程和线程已经不为空,说明该Service已经create了,直接调用sendServiceArgsLocked
        if (r.app != null && r.app.thread != null) {
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }
        ...
        final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        final String procName = r.processName;
        HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
        ProcessRecord app;
        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
           //如果进程已经在了,调用realStartServiceLocked进行start service
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
                }
                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
        } 
        // 如果进程还没启动,调用mAm.startProcessLocked启动进程
        if (app == null && !permissionsReviewRequired) {
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)) == null) {
              //埋下异常
              bringDownServiceLocked(r);
              ...
            }
        }
                //将当前ServiceRecord加到mPendingServices里,
        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }
        ...
    }
}

在《Android的进程》一文中我们介绍过,最终进程起来之后会执行ActivityManagerService.attachApplication-->ActivityManagerService.attachApplicationLocked:

public class ActivityManagerService extends IActivityManager.Stub{
        public ActivityTaskManagerInternal mAtmInternal;
        final ActiveServices mServices;
        private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
                    int pid, int callingUid, long startSeq) {
                     boolean badApp = false;
                boolean didSomething = false;
                // 先尝试启动Activity
                if (normalMode) {
                    try {
                        didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
                    } catch (Exception e) {
                        Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                        badApp = true;
                    }
                }
                //Activity启动没问题,尝试启动Service
                if (!badApp) {
                    try {
                        didSomething |= mServices.attachApplicationLocked(app, processName);

                    } catch (Exception e) {
                        Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
                        badApp = true;
                    }
                }
        }
}

可以看到,先启动了Activity,如果Activity的启动过程中没有出错,就启动Service即调用ActiveServices.attachApplicationLocked.

2.4:ActiveServices.attachApplicationLocked:进程启动完成,继续启动service

public final class ActiveServices {
            boolean attachApplicationLocked(ProcessRecord proc, String processName){
        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);
                    if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                            || !processName.equals(sr.processName))) {
                        continue;
                    }
                    mPendingServices.remove(i);
                    i--;
                    proc.addPackage(sr.appInfo.packageName, sr.appInfo.longVersionCode,
                            mAm.mProcessStats);
                    //核心操作是调用realStartServiceLocked
                    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) {
                Slog.w(TAG, "Exception in new application when starting service "
                        + sr.shortInstanceName, e);
                throw e;
            }
        }
        // Also, if there are any services that are waiting to restart and
        // would run in this process, now is a good time to start them.  It would
        // be weird to bring up the process but arbitrarily not let the services
        // run at this point just because their restart time hasn't come up.
        if (mRestartingServices.size() > 0) {
            ServiceRecord sr;
            for (int i=0; i<mRestartingServices.size(); i++) {
                sr = mRestartingServices.get(i);
                if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                        || !processName.equals(sr.processName))) {
                    continue;
                }
                mAm.mHandler.removeCallbacks(sr.restarter);
                mAm.mHandler.post(sr.restarter);
            }
        }
        return didSomething;
    }

}

可以看到最终调用到了realStartServiceLocked.

2.5:ActiveServices.realStartServiceLocked:先埋炸弹,然后触发service启动

public final class ActiveServices {
        /**
     * Note the name of this method should not be confused with the started services concept.
     * The "start" here means bring up the instance in the client, and this method is called
     * from bindService() as well.
     */
    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        if (app.thread == null) {
            throw new RemoteException();
        }
        if (DEBUG_MU)
            Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
                    + ", ProcessRecord.uid = " + app.uid);
        r.setProcess(app);
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
                //调用ProcessRecord.startService,实质是将此处的ServiceRecord add到ProcessRecord.mServices中
        final boolean newService = app.startService(r);
          //埋下ANR炸弹
        bumpServiceExecutingLocked(r, execInFg, "create");
        //调整进程的优先级
        mAm.updateLruProcessLocked(app, false, null);
        updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
        mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
        boolean created = false;
           ...
           //最终触发service.onCreate
          app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.getReportedProcState());
          ...
         //bind service
        requestServiceBindingsLocked(r, execInFg);
        updateServiceClientActivitiesLocked(app, null, true);
        if (newService && created) {
            app.addBoundClientUidsOfNewService(r);
        }
        // If the service is in the started state, and there are no
        // pending arguments, then fake up one so its onStartCommand() will
        // be called.
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null, 0));
        }
                //拉起timeout,最终调用Service.onStartCommand
        sendServiceArgsLocked(r, execInFg, true);
        if (r.delayed) {
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
            getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
            r.delayed = false;
        }
        if (r.delayedStop) {
            // Oh and hey we've already been asked to stop!
            r.delayedStop = false;
            if (r.startRequested) {
                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                        "Applying delayed stop (from start): " + r);
                stopServiceLocked(r);
            }
        }
    }

2.6:ActiveServices.bumpServiceExecutingLocked:埋下ANR炸弹(SERVICE_TIMEOUT_MSG)

public final class ActiveServices {
      // How long we wait for a service to finish executing.
    static final int SERVICE_TIMEOUT = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
    // How long we wait for a service to finish executing.
    static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;

    // How long the startForegroundService() grace period is to get around to
    // calling startForeground() before we ANR + stop it.
    static final int SERVICE_START_FOREGROUND_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;

        private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
        long now = SystemClock.uptimeMillis();
        if (r.executeNesting == 0) {
            r.executeFg = fg;
            ServiceState stracker = r.getTracker();
            if (stracker != null) {
                stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
            }
            if (r.app != null) {
                r.app.executingServices.add(r);
                r.app.execServicesFg |= fg;
                if (timeoutNeeded && r.app.executingServices.size() == 1) {
                      //启动延迟炸弹(触发ANR)
                    scheduleServiceTimeoutLocked(r.app);
                }
            }
        } else if (r.app != null && fg && !r.app.execServicesFg) {
            r.app.execServicesFg = true;
            if (timeoutNeeded) {
                scheduleServiceTimeoutLocked(r.app);
            }
        }
        r.executeFg |= fg;
        r.executeNesting++;
        r.executingStart = now;
    }
   void scheduleServiceTimeoutLocked(ProcessRecord proc) {
        if (proc.executingServices.size() == 0 || proc.thread == null) {
            return;
        }
        Message msg = mAm.mHandler.obtainMessage(
                ActivityManagerService.SERVICE_TIMEOUT_MSG);
        msg.obj = proc;
             //前台Service延迟SERVICE_TIMEOUT(20s),后台Service延迟SERVICE_BACKGROUND_TIMEOUT(200s)
        mAm.mHandler.sendMessageDelayed(msg,
                proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
    }
}

2.7:ActivityThread.scheduleCreateService:触发Service.onCreate

可以看到这里主要是发送了一个CREATE_SERVICEMessage消息:

//frameworks/base/core/java/android/app/ActivityThread.java
public final class ActivityThread extends ClientTransactionHandler 
    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;
      sendMessage(H.CREATE_SERVICE, s);
    }

     public void handleMessage(Message msg) {
         ...
        case CREATE_SERVICE:
             handleCreateService((CreateServiceData)msg.obj);
             break;
     ...
   }
   public static final int SERVICE_DONE_EXECUTING_ANON = 0;
   @UnsupportedAppUsage
    private void handleCreateService(CreateServiceData data) {
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
              //实例化Service的对象
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
            // Service resources must be initialized with the same loaders as the application
            // context.
            context.getResources().addLoaders(
                    app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
            context.setOuterContext(service);
              //调用Service.attach
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
              //调用Service.onCreate
            service.onCreate();
            mServices.put(data.token, service);
          //通知ActivityManagerService,Service启动完成,拆除预埋的炸弹,调整进程优先级
                       ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (Exception e) {
        }
    }
}
//frameworks/base/core/java/android/app/AppComponentFactory.java
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();
    }
}

2.8:ActivityManagerService.serviceDoneExecuting:拆除预埋的炸弹

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub{
      final ActiveServices mServices;
      public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
                throw new IllegalArgumentException("Invalid service token");
            }
            mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
        }
    }
}

最终调用到了ActiveServices.serviceDoneExecutingLocked

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
public final class ActiveServices {
        void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
          if (r != null) {
          ...
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
        }
    }

      private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
            boolean finishing) {
          //拆除预埋的SERVICE_TIMEOUT_MSG炸弹
            mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
          //调整进程优先级
           mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
      }
}

2.9:ActiveServices.sendServiceArgsLocked:启动延迟任务,埋下ANR和崩溃炸弹、触发onstartCommand

public final class ActiveServices {
      final ActivityManagerService mAm;

    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
                boolean oomAdjusted) throws TransactionTooLargeException {
            final int N = r.pendingStarts.size();
            if (N == 0) {
                return;
            }
            ArrayList<ServiceStartArgs> args = new ArrayList<>();
            while (r.pendingStarts.size() > 0) {
                ServiceRecord.StartItem si = r.pendingStarts.remove(0);
                //核心操作,埋下ANR炸弹,上面介绍过了
                bumpServiceExecutingLocked(r, execInFg, "start");
                if (!oomAdjusted) {
                    oomAdjusted = true;
                    //更新进程优先级
                    mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
                }
                if (r.fgRequired && !r.fgWaiting) {
                    if (!r.isForeground) {
                      //对于前台Service,启动延迟任务,检测Service调用了startForeground,否则会崩溃
                        scheduleServiceForegroundTransitionTimeoutLocked(r);
                    } else {
                        r.fgRequired = false;
                    }
                }
                int flags = 0;
                if (si.deliveryCount > 1) {
                    flags |= Service.START_FLAG_RETRY;
                }
                if (si.doneExecutingCount > 0) {
                    flags |= Service.START_FLAG_REDELIVERY;
                }
                args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
            }
            ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
            slice.setInlineCountLimit(4);
            Exception caughtException = null;
            try {
              //调用ActivityThread.scheduleServiceArgs,最终执行Service.onstartCommand
                r.app.thread.scheduleServiceArgs(r, slice);
            }
        }
        // How long the startForegroundService() grace period is to get around to
        // calling startForeground() before we ANR + stop it.
        static final int SERVICE_START_FOREGROUND_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
        void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {
            if (r.app.executingServices.size() == 0 || r.app.thread == null) {
                return;
            }
            Message msg = mAm.mHandler.obtainMessage(
                    ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG);
            msg.obj = r;
            r.fgWaiting = true;
          //延迟10s发送,埋下崩溃炸弹
            mAm.mHandler.sendMessageDelayed(msg, SERVICE_START_FOREGROUND_TIMEOUT);
        }
}

2.10:ActivityThread.scheduleServiceArgs:触发onStartcommand

 //frameworks/base/core/java/android/app/ActivityThread.java
public final class ActivityThread extends ClientTransactionHandler 
         public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
            List<ServiceStartArgs> list = args.getList();
            for (int i = 0; i < list.size(); i++) {
                ServiceStartArgs ssa = list.get(i);
                ServiceArgsData s = new ServiceArgsData();
                s.token = token;
                s.taskRemoved = ssa.taskRemoved;
                s.startId = ssa.startId;
                s.flags = ssa.flags;
                s.args = ssa.args;
                sendMessage(H.SERVICE_ARGS, s);
            }
        }
      public void handleMessage(Message msg) {
         ...
        case SERVICE_ARGS:
             handleServiceArgs((ServiceArgsData)msg.obj);
             break;
     ...
   }
    private void handleServiceArgs(ServiceArgsData data) {
        Service s = mServices.get(data.token);
        ...
          //调用onStartcommand
          res = s.onStartCommand(data.args, data.flags, data.startId);
            //拆除预埋的炸弹
                 ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
            ...
    }
}

核心是发送了一个SERVICE_ARGS的message。

2.11:ActivityManagerService.handleMessage:处理不同的message(炸弹)

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub{
     final MainHandler mHandler;
   final ActiveServices mServices;
   final class MainHandler extends Handler {
        public MainHandler(Looper looper) {
            super(looper, null, true);
        }
        @Override
        public void handleMessage(Message msg) {
          switch (msg.what) {
                            case SERVICE_TIMEOUT_MSG: {
                        //抛出anr
                        mServices.serviceTimeout((ProcessRecord)msg.obj);
                    } 
                  break;
              case SERVICE_FOREGROUND_TIMEOUT_MSG: {
                        //抛出anr
                        mServices.serviceForegroundTimeout((ServiceRecord)msg.obj);
                    } 
                  break;
              case SERVICE_FOREGROUND_CRASH_MSG: {
                  //引发crash,报错Context.startForegroundService() did not then call Service.startForeground() xxx
                    mServices.serviceForegroundCrash(
                        (ProcessRecord) msg.obj, msg.getData().getCharSequence(SERVICE_RECORD_KEY));
                } 
                break;
          }
        }
   }
}

2.12:Service.startFroeground:前台Service必须调用,展示通知,解除崩溃炸弹

对于前台Service,必须在Service启动之后手动调用Service.startFroeground,否则会触发上文中的崩溃炸弹:

//frameworks/base/core/java/android/app/Service.java
public abstract class Service extends ContextWrapper {
      public final void startForeground(int id, Notification notification) {
        try {
            mActivityManager.setServiceForeground(
                    new ComponentName(this, mClassName), mToken, id,
                    notification, 0, FOREGROUND_SERVICE_TYPE_MANIFEST);
        } catch (RemoteException ex) {
        }
    }
}

最终调用到了AMS.setServiceForeground

 //frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public class ActivityManagerService extends IActivityManager.Stub{ 
   final ActiveServices mServices;
  @Override
    public void setServiceForeground(ComponentName className, IBinder token,
            int id, Notification notification, int flags, int foregroundServiceType) {
        synchronized(this) {
            mServices.setServiceForegroundLocked(className, token, id, notification, flags,
                    foregroundServiceType);
        }
    }
}

核心是调用ActiveServices.setServiceForegroundLocked.

2.13:ActiveServices.setServiceForegroundLocked:发送通知,取消崩溃

//frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
public final class ActiveServices {
    public void setServiceForegroundLocked(ComponentName className, IBinder token,
            int id, Notification notification, int flags, int foregroundServiceType) {
        final int userId = UserHandle.getCallingUserId();
        final long origId = Binder.clearCallingIdentity();
        try {
            ServiceRecord r = findServiceLocked(className, token, userId);
            if (r != null) {
                setServiceForegroundInnerLocked(r, id, notification, flags, foregroundServiceType);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }
   /**
     * @param id Notification ID.  Zero === exit foreground state for the given service.
     */
    private void setServiceForegroundInnerLocked(final ServiceRecord r, int id,
            Notification notification, int flags, int foregroundServiceType) {
      //id不可为0
      if (id != 0) {
         //notification不可为空
             if (notification == null) {
                throw new IllegalArgumentException("null notification");
            }
                ...
                if (r.fgRequired) {
                if (DEBUG_SERVICE || DEBUG_BACKGROUND_CHECK) {
                    Slog.i(TAG, "Service called startForeground() as required: " + r);
                }
                r.fgRequired = false;
                r.fgWaiting = false;
                alreadyStartedOp = stopProcStatsOp = true;
                  //移除SERVICE_FOREGROUND_TIMEOUT_MSG消息,取消崩溃
                mAm.mHandler.removeMessages(
                        ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
            }
      }
    }
}

3:整个Service启动过程中涉及到的跨进程调用

3.1:ContextImpl -→ AMS:调用方进程→system_server进程

  1. 被调用方法:AMS中的startService()
ActivityManager.getService().startService() 

3.2:ActivityThread -→ AMS:service所在进程→system_server进程

  1. 被调用方法:AMS中的attachApplication()
ActivityManager.getService().attachApplication()  
  1. 拆除炸弹
ActivityManager.getService().serviceDoneExecuting() 

3.3: AMS -→ ActivityThread:system_server进程→service所在进程

  1. 被调用方法:ApplicationThread中的scheduleCreateService()
app.thread.scheduleCreateService()  
  1. 被调用方法:ApplicationThread中的scheduleServiceArgs()
app.threadscheduleServiceArgs() 

4:总结

基于上述源码的分析,我们可以将Service的整体启动流程总结为下图:


以上就是Android中Service启动的大致原理,如果觉得有收获,欢迎关注点赞~

5:参考

  1. Android源码
  2. Android service 启动篇之 startService
  3. Android 从进程角度看Service启动流程

相关推荐

前端入门——css 网格轨道详细介绍

上篇前端入门——cssGrid网格基础知识整体大概介绍了cssgrid的基本概念及使用方法,本文将介绍创建网格容器时会发生什么?以及在网格容器上使用行、列属性如何定位元素。在本文中,将介绍:...

Islands Architecture(孤岛架构)在携程新版首页的实践

一、项目背景2022,携程PC版首页终于迎来了首次改版,完成了用户体验与技术栈的全面升级。作为与用户连接的重要入口,旧版PC首页已经陪伴携程走过了22年,承担着重要使命的同时,也遇到了很多问题:维护/...

HTML中script标签中的那些属性

HTML中的<script>标签详解在HTML中,<script>标签用于包含或引用JavaScript代码,是前端开发中不可或缺的一部分。通过合理使用<scrip...

CSS 中各种居中你真的玩明白了么

页面布局中最常见的需求就是元素或者文字居中了,但是根据场景的不同,居中也有简单到复杂各种不同的实现方式,本篇就带大家一起了解下,各种场景下,该如何使用CSS实现居中前言页面布局中最常见的需求就是元...

CSS样式更改——列表、表格和轮廓

上篇文章主要介绍了CSS样式更改篇中的字体设置Font&边框Border设置,这篇文章分享列表、表格和轮廓,一起来看看吧。1.列表List1).列表的类型<ulstyle='list-...

一文吃透 CSS Flex 布局

原文链接:一文吃透CSSFlex布局教学游戏这里有两个小游戏,可用来练习flex布局。塔防游戏送小青蛙回家Flexbox概述Flexbox布局也叫Flex布局,弹性盒子布局。它决定了...

css实现多行文本的展开收起

背景在我们写需求时可能会遇到类似于这样的多行文本展开与收起的场景:那么,如何通过纯css实现这样的效果呢?实现的难点(1)位于多行文本右下角的展开收起按钮。(2)展开和收起两种状态的切换。(3)文本...

css 垂直居中的几种实现方式

前言设计是带有主观色彩的,同样网页设计中的css一样让人摸不头脑。网上列举的实现方式一大把,或许在这里你都看到过,但既然来到这里我希望这篇能让你看有所收获,毕竟这也是前端面试的基础。实现方式备注:...

WordPress固定链接设置

WordPress设置里的最后一项就是固定链接设置,固定链接设置是决定WordPress文章及静态页面URL的重要步骤,从站点的SEO角度来讲也是。固定链接设置决定网站URL,当页面数少的时候,可以一...

面试发愁!吃透 20 道 CSS 核心题,大厂 Offer 轻松拿

前端小伙伴们,是不是一想到面试里的CSS布局题就发愁?写代码时布局总是对不齐,面试官追问兼容性就卡壳,想跳槽却总被“多列等高”“响应式布局”这些问题难住——别担心!从今天起,咱们每天拆解一...

3种CSS清除浮动的方法

今天这篇文章给大家介绍3种CSS清除浮动的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。首先,这里就不讲为什么我们要清楚浮动,反正不清除浮动事多多。下面我就讲3种常用清除浮动的...

2025 年 CSS 终于要支持强大的自定义函数了?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!1.什么是CSS自定义属性CSS自...

css3属性(transform)的一个css3动画小应用

闲言碎语不多讲,咱们说说css3的transform属性:先上效果:效果说明:当鼠标移到a标签的时候,从右上角滑出二维码。实现方法:HTML代码如下:需要说明的一点是,a链接的跳转需要用javasc...

CSS基础知识(七)CSS背景

一、CSS背景属性1.背景颜色(background-color)属性值:transparent(透明的)或color(颜色)2.背景图片(background-image)属性值:none(没有)...

CSS 水平居中方式二

<divid="parent"><!--定义子级元素--><divid="child">居中布局</div>...

取消回复欢迎 发表评论: