Android 11源码分析:Service工作流程

1,354 阅读6分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

之前的学习记录都是在自己的本地,借着掘金的这次8月活动的机会,也挑战一下自己。各位看官点点赞,小弟先谢过。

前言

我们知道Service分为两种工作状态,一种是启动状态,一种是绑定状态。前者适用于后台计算,后者适用于Service与其他组件的交互。 Service的两种生命周期

  • startService方式:onCreate()--->onStartCommand() --->onDestroy();

  • bindService方式:onCreate()--->onBind() --->onUnbind()--->onDestroy();

Service的启动过程

从Activity的startServic开始旅程。点击会进入ContextWrapper类的startService方法

android.content.ContextWrapper

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

mBase是ContextImpl类型,在Activity启动过程中,执行attach方法时进行关联。具体代码在文字末尾附加 ContextWrapper的大部分操作都是通过mBase实现。这就是桥接模式 下面去看看具体实现

android.appContextImpl
class ContextImpl extends Context {
   @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }
    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
            ......
            ComponentName cn = ActivityManager.getService().startService(
                    mMainThread.getApplicationThread(), service,
                    service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
                    getOpPackageName(), getAttributionTag(), user.getIdentifier());
    }
}

ActivityManager.getService()获取的就是ActivityManageService,一般简称AMS,源码中出现很频繁,还不清楚的可以去看看我之前的文章。

继续去看AMS下的startService

com.android.server.am.ActivityManagerService

final ActiveServices mServices;
......
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, boolean requireForeground, String callingPackage,
        String callingFeatureId, int userId)
        throws TransactionTooLargeException {
        ......
        ComponentName res;
        try {
            关键代码
            res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid,
                    requireForeground, callingPackage, callingFeatureId, userId);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
        return res;
    }
}

如果是打开AS跟着看代码的小伙伴,可以滚动鼠标看看上下的方法,其实都是和Service相关的,所以记住AMS这个类吧。

mServices是ActiveServices类型的,后续的Service操作由它完成。

com.android.server.am.ActiveServices

   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 {
            ......
              关键代码
            ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
            if (!r.mAllowWhileInUsePermissionInFgs) {
                r.mAllowWhileInUsePermissionInFgs =
                        shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid,
                                callingUid, service, r, allowBackgroundActivityStarts);
            }
                return cmp;
            }
            

在startServiceLocked中调用startServiceInnerLocked

com.android.server.am.ActiveServices

    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;
        ......
         关键代码
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
        ......
        return r.name;
    }

bringUpServiceLocked方法内部挺长的,看的迷迷糊糊,忽然看的一个realStartServiceLocked方法。看这名字,应该就是真正启动Service的地方了吧。

com.android.server.am.ActiveServices
    private final void realStartServiceLocked(ServiceRecord r,ProcessRecord app, boolean execInFg) throws RemoteException {
            ......
            //内部将会执行onStartCreate
            app.thread.scheduleCreateService(r, r.serviceInfo,
            mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.getReportedProcState());
            ......
            //内部将会执行onStartCommond
            sendServiceArgsLocked(r, execInFg, true);
            ......
   }

app.thread 和ActivityManager.getService()一样,也是很常见的引用,就是ApplicationThread对象

Service的onCreate

接下来去ApplicationThread看看scheduleCreateService做了些什么,看过文章的小伙伴,就该知道,多半又是去发消息了。

android.app.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;

            sendMessage(H.CREATE_SERVICE, s);
        }
        
在内部类H中,对这个消息的处理是
        case CREATE_SERVICE:
                    if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                                ("serviceCreate: " + String.valueOf(msg.obj)));
                    }
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;

熟悉的套路,去ApplicationThread发消息,H去处理具体实现。

android.app.ActivityThread
    @UnsupportedAppUsage
    private void handleCreateService(CreateServiceData data) {
          unscheduleGcIdler();
    
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            创建ContextImpl对象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            获取application
            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);
            将ContextImpl于Service建立链接,与Activity类似
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            执行Service的onCreate
            service.onCreate();
            将当前Service添加到mServices中
            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. 创建ContextImpl对象
  2. 创建Application,当然这个东西全局只有一个,在Appliction初始化中介绍过
  3. 通过反射获取service
  4. 将ContextImpl于Service建立链接
  5. 执行Service的onCreate
  6. 将当前Service添加到mServices中,定义如下 至此,Service的onCreat 执行了,也就意味着Service启动了。
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();

Service的onStartCommond

在前面的代码realStartServiceLocked方法内部,下面还有一个关键方法sendServiceArgsLocked

com.android.server.am.ActiveServices
    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
            ......
            try {
                r.app.thread.scheduleServiceArgs(r, slice);
            } catch (TransactionTooLargeException e) {
               ......
            }
            ......
    }

执行了ApplicationThread的scheduleServiceArgs方法

android.app.ActivityThread
       内部类ApplicationThread中:
       public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
            List<ServiceStartArgs> list = args.getList();

            for (int i = 0; i < list.size(); i++) {
                ......
                sendMessage(H.SERVICE_ARGS, s);
            }
        }
       内部类H中: 
        case SERVICE_ARGS:
                 if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                                ("serviceStart: " + String.valueOf(msg.obj)));
                 }
                 handleServiceArgs((ServiceArgsData)msg.obj);
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                 break;
                 
                 
        private void handleServiceArgs(ServiceArgsData data) {
            // 从mServices取出Service实例
            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) {
                    执行onStartCommand
                        res = s.onStartCommand(data.args, data.flags, data.startId);
                    } else {
                        s.onTaskRemoved(data.args);
                        res = Service.START_TASK_REMOVED_COMPLETE;
                    }
                    ......
                } catch (Exception e) {
                    if (!mInstrumentation.onException(s, e)) {
                        throw new RuntimeException(
                                "Unable to start service " + s
                                + " with " + data.args + ": " + e.toString(), e);
                    }
                }
            }
    }

在handleServiceArgs中, 先是从mServices中取出之前创建好的Service,然后执行Service的onStartCommand方法。这也就说明了,onStartCommand确实是在onCreate之后执行的。

Service的绑定过程

与Service的启动过程一样,bindService在ContextImpl中实现,内部会调用bindServiceCommon

android.content.ContextWrapper

    @Override
    public boolean bindService(Intent service, ServiceConnection conn, int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
                getUser());
    }
   

内部调用的是bindServiceCommon方法,需要我们重点关注一下

android.content.ContextImpl

  private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            String instanceName, Handler handler, Executor executor, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;
        ......
        ①将conn参数传入getServiceDispatcher,获取IServiceConnection类型的对象 sd
        if (mPackageInfo != null) {
            if (executor != null) {
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
            } else {
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
            }
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
            service.prepareToLeaveProcess(this);
            ②通过AMS完成绑定操作
            int res = ActivityManager.getService().bindIsolatedService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

bindServiceCommon方法比较长,主要做了两件事:

  1. 将ServiceConnection对象conn转换成ServiceDispatcher.InnerConnection类型对象sd
  2. 通过AMS完成绑定操作 我知道只看上面代码得出做了上述的两件事的结论是比较懵逼的,无妨,我们进到具体代码来说明。

将ServiceConnection类型转换成ServiceDispatcher.InnerConnection

首先,来确定为什么说IServiceConnection的实例sd实际上是ServiceDispatcher.InnerConnection类型。

sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags); 点击getServiceDispatcher可以发现在类LoadedApk中,这个类我们也不陌生,因为Application的创建就在这个类里。

android.app.LoadedApk

  public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
        return getServiceDispatcherCommon(c, context, handler, null, flags);
    }
        private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
            Context context, Handler handler, Executor executor, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            ......
            return sd.getIServiceConnection();
        }
    }

这边最后进入的是ServiceDispatcher类里的getIServiceConnection方法

android.app.LoadedApk

 static final class ServiceDispatcher{
     private final ServiceDispatcher.InnerConnection mIServiceConnection;
      IServiceConnection getIServiceConnection() {
            return mIServiceConnection;
        }
 }

问题得到解释,getIServiceConnection方法最后返回的mIServiceConnection是ServiceDispatcher.InnerConnection类型。 新的问题又来了,为什么要这么大费周章的去将ServiceConnection转换成ServiceDispatcher.InnerConnection呢? 《Android开发艺术探索》是这么解释的:

之所以不能直接使用ServiceConnection对象,这是因为服务的绑定可能是跨进程的,因此ServiceConnection对象必须借助于Binder才能让远程服务端回调自己的方法,而ServiceDispatcher的内部类InnerConnection刚好充当Binder这个角色,那么ServiceDispatcher的作用起着链接ServiceConnection和InnerConnection的作用。

ActivityManagerSerice完成绑定

我们已经熟悉的指导ActivityManager.getService()其实获取的就是ActivityManagerSerice(AMS)对象,所以去里面找bindIsolatedService即可

com.android.server.am.ActivityManagerSerice

final ActiveServices mServices;
......
public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String instanceName,
            String callingPackage, int userId) throws TransactionTooLargeException {
        ......
        synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, instanceName, callingPackage, userId);
        }
    }

流程来到ActiveServices中

com.android.server.am.ActiveServices

    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String instanceName, String callingPackage, final int userId)
            throws TransactionTooLargeException {
                ......
                内部执行onCreate
                bringUpServiceLocked(serviceRecord,serviceIntent.getFlags(),callerFg, false, false);
                ......
                内部执行onBind
                requestServiceBindingLocked(s, b.intent, callerFg, true);
                ......
            }

这里的流程和Serice启动的流程其实类似,第一步都是创建Service,然后执行启动或者绑定方法。bringUpServiceLocked内部就是执行Service的OnCreate,requestServiceBindingLocked内部则是执行绑定。

com.android.server.am.ActiveServices

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
            ......
            realStartServiceLocked(r, app, execInFg);
            ......
}

可以看到在bringUpServiceLocked内部,同样执行了realStartServiceLocked 方法,这个方法在分析Service启动流程中已经看到过,就是执行Service的onCreate。接着看

com.android.server.am.ActiveServices

 private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
            ......
              r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.getReportedProcState());
            ......
 }

同样的套路,去ApplicationThread发个消息,去H中执行。

android.app.ActivityThread

           public final void scheduleBindService(IBinder token, Intent intent,
                boolean rebind, int processState) {
            ......
            sendMessage(H.BIND_SERVICE, s);
        }
        
在内部类H中,对这个消息的处理是
       case BIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                    handleBindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;

看看handleBindService具体做了啥吧

android.app.ActivityThread
  private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (DEBUG_SERVICE)
            Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                //这里的代码就是说明,为什么我们常说Service只能绑定一次了
                try {
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        系统告知客户端已经成功链接Service了
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to bind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }

handleBindService做了两件事,

  1. 执行onBind
  2. 通知客户端已经完成了Service的绑定 当我自己分析到这的时候,我以为已经结束了。后面在《Android开发艺术》看到:onBind是Service的方法,客户端自己并不知道已经链接成功了,所以才有后面的通过AMS去通知客户端的操作。

所以继续分析呗:如何通知客服端,服务已经绑定成功。直接去AMS找

com.android.server.am.ActivityManagerService

   public void publishService(IBinder token, Intent intent, IBinder service) {
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                throw new IllegalArgumentException("Invalid service token");
            }
            之前分析中提到过mServices是ActiveServices类型
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
    }
com.android.server.am.ActiveServices

  void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        final long origId = Binder.clearCallingIdentity();
        try {
           ......
            c.conn.connected(r.name, service, false);	
        } catch (Exception e) {
          
        }
    }

这个conn是之前提过的ServiceDispatcher.InnerConnection类型

android.app.LoadedApk
static final class ServiceDispatcher {
        private final ServiceConnection mConnection;
        ......
        public void connected(ComponentName name, IBinder service, boolean dead) {
            if (mActivityExecutor != null) {
                mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
            } else if (mActivityThread != null) {
                mActivityThread.post(new RunConnection(name, service, 0, dead));
            } else {
                关键代码
                doConnected(name, service, dead);
            }
        }
        public void doConnected(ComponentName name, IBinder service, boolean dead) {
            ......
             mActivityThread.post(new RunConnection(name, service, 0, dead));
        }
}

mActivityThread内部有个Handler类型的H,所以这个方法直接post到主线程执行。RunConnection定义如下

        private final class RunConnection implements Runnable {
            RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
                mName = name;
                mService = service;
                mCommand = command;
                mDead = dead;
            }

            public void run() {
                if (mCommand == 0) {
                     //关键代码
                    doConnected(mName, mService, mDead);
                } else if (mCommand == 1) {
                    doDeath(mName, mService);
                }
            }

            final ComponentName mName;
            final IBinder mService;
            final int mCommand;
            final boolean mDead;
        }
public void doConnected(ComponentName name, IBinder service, boolean dead) {
    if (service != null) {
          mConnection.onServiceConnected(name, service);
    } 
}

mConnection就是我们一使用bindService传入的第二个参数,至此客户端的onServiceConnected执行,Service的绑定过程分析完成。

如果你对mConnection.onServiceConnected(name, service);这个行代码为何代表客户端已经执行onServiceConnected的结论还有疑问,文章末尾会加以解析

附加:mBase是个啥

android.content.ContextWrapper
    mBase的赋值
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
    
android.app.Activity
    @UnsupportedAppUsage
    final void attach(Context context, ...) {
        attachBaseContext(context);
        ......
    }
    而我们知道attach方法是在ActivityThread的performLaunchActivity内调用
android.app.ActivityThread
   private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
      ......
      ContextImpl appContext = createBaseContextForActivity(r);
      Activity activity = null;
      ......
       所以mBase就是ContextImpl类型
       activity.attach(appContext,...);
      ......
   }