当前位置: 首页 > news >正文

ActivityManagerService bindService(7)

ActivityManagerService bindService

简述

Android中Service是一个非常常用的组件,尤其是系统应用开发时,Service使用甚至会比Activity的频率更高。
先说一下为什么需要Service吧,在刚刚接触Android开发的时候我非常不理解Service是什么,会把他和线程搞混,认为Service的作用和一个线程差不多,当时还在想为什么需要Service,直接启动一个线程来做需要做的工作不就行了吗?其实组件和线程是完全没有关系的,其实按照Android的规范来说,一个app进程必须要有四大组件,如果一个app进程没有任何组件还在active的生命周期中,仅仅有一些线程还在工作,这个app的odj值很大,即很容易被杀掉,这种行为也是不规范的,例如我们通过接收一个广播拉起进程,然后在广播接收处理里启动一个线程让进程一直在后台干活,这个是一个不规范的行为,也是不可靠的行为,进程被杀的概率非常高。
Service的作用就是这个,当我们使用Service组件,它相当于告诉框架,我这个进程就是要在后台干活的,你别随便杀我。就好比Activity组件是告诉系统,我这个app需要在前台显示页面,但是不代表有Service进程就肯定不会被杀,lowmemkiller该杀还是要杀你,只是你的被杀的优先级会降低,当然如果你是一个前台Service(即有前台通知的Service),那么被杀的优先级会更低。
可能站在应用开发的角度很难接收这种应用会被杀的情况,因为这个会导致应用开发需要处理很多极端场景,但是这个对于系统来说是很科学的,因为当如果没有杀进程的机制,当一个应用问题,导致内存满了,很可能会导致系统直接瘫了。
所以Android在这块的约束也是越来越多,包括后台广播拉起进程的约束等。

言归正传,我们现在明白Service组件等作用,我们就从bindService开始学习。

bindService开始创建Service

在这里插入图片描述

1.1 ContextImpl.bindService
这里几个参数是应用传入的,Intent代表需要bind的Service信息,ServiceConnection则是bind成功后的回调,flags我们这里需要关注BIND_AUTO_CREATE,表示如果没有bind的Service没有启动这里需要启动。

public boolean bindService(Intent service, ServiceConnection conn, int flags) {warnIfCallingFromSystemProcess();// 详见1.2return bindServiceCommon(service, conn, Integer.toUnsignedLong(flags), null,mMainThread.getHandler(), null, getUser());
}

1.2 ContextImpl.bindServiceCommon
参数检查,通过调用bindServiceInstance,binder调用到AMS侧。

private boolean bindServiceCommon(Intent service, ServiceConnection conn, long flags,String instanceName, Handler handler, Executor executor, UserHandle user) {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();// ...service.prepareToLeaveProcess(this);// 调用AMS bindServiceInstance来bind service,详见1.3int res = ActivityManager.getService().bindServiceInstance(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();}
}

1.3 bindServiceInstance
这里已经是SystemServer进程里,bindServiceInstance有几个重载函数,最终都会调用到这里。

private int bindServiceInstance(IApplicationThread caller, IBinder token, Intent service,String resolvedType, IServiceConnection connection, long flags, String instanceName,boolean isSdkSandboxService, int sdkSandboxClientAppUid,String sdkSandboxClientAppPackage,IApplicationThread sdkSandboxClientApplicationThread,String callingPackage, int userId)throws TransactionTooLargeException {enforceNotIsolatedCaller("bindService");enforceAllowedToStartOrBindServiceIfSdkSandbox(service);// ...参数检测try {// ...synchronized (this) {// 调用bindServiceLocked,详见1.4return mServices.bindServiceLocked(caller, token, service, resolvedType, connection,flags, instanceName, isSdkSandboxService, sdkSandboxClientAppUid,sdkSandboxClientAppPackage, sdkSandboxClientApplicationThread,callingPackage, userId);}} finally {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}
}

1.4 ActiveServices.bindServiceLocked
这里有几个数据结构:
ServiceRecord,和ActivityRecord类似,AMS用于记录Service的信息。
AppBindRecord,用于记录bind调用的进程信息和ServiceRecord对应关系。ServiceRecord里面有一个Intent.FilterComparison和IntentBindRecord的Map,而IntentBindRecord里有ProcessRecord和AppBindRecord的Map。
ConnectionRecord会记录bindService所有信息,如AppBindRecord,ServiceConnection,caller ActivityRecord等。

bindServiceLocked首先进行一些参数检测,然后根据flag检测一些权限,有一些flag必须只有system才能使用。
根据intent的参数信息,检索ServiceRecord,如果没有则会创建。
然后构造AppBindRecord结构,构造ConnectionRecord,然后如果flag带BIND_AUTO_CREATE,则会调用bringUpServiceLocked,如果服务没启动,这里会启动服务。
后面会回调ServiceConnection.connected,这里会回调到app侧。

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,String resolvedType, final IServiceConnection connection, long flags,String instanceName, boolean isSdkSandboxService, int sdkSandboxClientAppUid,String sdkSandboxClientAppPackage, IApplicationThread sdkSandboxClientApplicationThread,String callingPackage, final int userId)throws TransactionTooLargeException {// ... 参数检测// ...检查ActivityRecord,bindService需要有ActivityRecordActivityServiceConnectionsHolder<ConnectionRecord> activity = null;if (token != null) {activity = mAm.mAtmInternal.getServiceConnectionsHolder(token);if (activity == null) {Slog.w(TAG, "Binding with unknown activity: " + token);return 0;}}int clientLabel = 0;PendingIntent clientIntent = null;final boolean isCallerSystem = callerApp.info.uid == Process.SYSTEM_UID;// ...// 检查flag以及权限,有一些flag必须要system才能使用。还有后台启动前台服务的权限检查等。// ...// 在AMS里检索ServiceRecord,如果没有则创建一个。ServiceLookupResult res = retrieveServiceLocked(service, instanceName,isSdkSandboxService, sdkSandboxClientAppUid, sdkSandboxClientAppPackage,resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg,isBindExternal, allowInstant, null /* fgsDelegateOptions */,inSharedIsolatedProcess);if (res == null) {return 0;}if (res.record == null) {return -1;}ServiceRecord s = res.record;// AppBindRecord用于记录bind调用的进程信息和ServiceRecord对应关系。ServiceRecord里面有一个Intent.FilterComparison和IntentBindRecord的Map// 而IntentBindRecord里有ProcessRecord和AppBindRecord的Mapfinal AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp, attributedApp);final ProcessServiceRecord clientPsr = b.client.mServices;// 进程达到最大的bindService数,直接返回if (clientPsr.numberOfConnections() >= mAm.mConstants.mMaxServiceConnectionsPerProcess) {// ...return 0;}final ProcessRecord callingApp;synchronized (mAm.mPidsSelfLocked) {callingApp = mAm.mPidsSelfLocked.get(callingPid);}final String callingProcessName = callingApp != null? callingApp.processName : callingPackage;final int callingProcessState =callingApp != null && callingApp.getThread() != null && !callingApp.isKilled()? callingApp.mState.getCurProcState() : ActivityManager.PROCESS_STATE_UNKNOWN;s.updateProcessStateOnRequest();// 冻结相关的逻辑,如果应用被冻结,则推迟。boolean packageFrozen = deferServiceBringupIfFrozenLocked(s, service, callingPackage, null,callingUid, callingPid, callingProcessName, callingProcessState,false, callerFg, userId, BackgroundStartPrivileges.NONE, true, connection);// ...try {// ...// 应用程序关联,会构造一个Association,里面记录了两进程的信息。mAm.startAssociationLocked(callerApp.uid, callerApp.processName,callerApp.mState.getCurProcState(), s.appInfo.uid, s.appInfo.longVersionCode,s.instanceName, s.processName);// ...// 每一个bind的具体信息都会由一个ConnectionRecord来记录,里面包含了ServiceConnection,activity,AppBindRecord等。ConnectionRecord c = new ConnectionRecord(b, activity,connection, flags, clientLabel, clientIntent,callerApp.uid, callerApp.processName, callingPackage, res.aliasComponent);IBinder binder = connection.asBinder();s.addConnection(binder, c);b.connections.add(c);if (activity != null) {activity.addConnection(c);}clientPsr.addConnection(c);c.startAssociationIfNeeded();// ...if (s.app != null) {updateServiceClientActivitiesLocked(s.app.mServices, c, true);}ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);if (clist == null) {clist = new ArrayList<>();mServiceConnections.put(binder, clist);}clist.add(c);boolean needOomAdj = false;// 如果flag带BIND_AUTO_CREATEif (c.hasFlag(Context.BIND_AUTO_CREATE)) {s.lastActivity = SystemClock.uptimeMillis();needOomAdj = true;// 详见1.5if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,permissionsReviewRequired, packageFrozen, true) != null) {mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_BIND_SERVICE);return 0;}}setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, s, userId,BackgroundStartPrivileges.NONE, true /* isBindService */,false /* isStartService */);// ... 更新adjfinal int packageState = wasStopped? SERVICE_REQUEST_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_STOPPED: SERVICE_REQUEST_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL;if (s.app != null && b.intent.received) {// 服务已经创建final ComponentName clientSideComponentName =res.aliasComponent != null ? res.aliasComponent : s.name;try {// 回调app侧,将binder传递给调用方,后续call使用binder和service通信。c.conn.connected(clientSideComponentName, b.intent.binder, false);}// ...return 1;
}

1.5 ActiveServices.bringUpServiceLocked
调用bringUpServiceInnerLocked

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,boolean enqueueOomAdj)throws TransactionTooLargeException {try {// ...// 调用bringUpServiceInnerLocked,详见1.6return bringUpServiceInnerLocked(r, intentFlags, execInFg, whileRestarting,permissionsReviewRequired, packageFrozen, enqueueOomAdj);} finally {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}
}

1.6 ActiveServices.bringUpServiceInnerLocked
如果进程已经存在且服务已经启动,通过sendServiceArgsLocked直接通知app。
如果进程已经启动,则通过realStartServiceLocked来启动服务。
如果进程未启动则先启动进程。

private String bringUpServiceInnerLocked(ServiceRecord r, int intentFlags, boolean execInFg,boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,boolean enqueueOomAdj)throws TransactionTooLargeException {// 如果r.app不为空,且r.app.getThread()不为空,则说明app的service已经存在了,则通过sendServiceArgsLocked通知app service变更生命周期if (r.app != null && r.app.getThread() != null) {sendServiceArgsLocked(r, execInFg, false);return null;}if (!whileRestarting && mRestartingServices.contains(r)) { return null;}// ...// ... 确保该服务等user用于已经启动// ...final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;final String procName = r.processName;HostingRecord hostingRecord = new HostingRecord(HostingRecord.HOSTING_TYPE_SERVICE, r.instanceName,r.definingPackageName, r.definingUid, r.serviceInfo.processName,getHostingRecordTriggerType(r));ProcessRecord app;if (!isolated) {app = mAm.getProcessRecordLocked(procName, r.appInfo.uid);// ...if (app != null) {final IApplicationThread thread = app.getThread();final int pid = app.getPid();final UidRecord uidRecord = app.getUidRecord();if (thread != null) {try {//  ...// 启动service,详见1.7realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg,enqueueOomAdj);return null;} catch (TransactionTooLargeException e) {throw e;} catch (RemoteException e) {Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);} finally {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}}}} else {// ...}if (app == null && !permissionsReviewRequired && !packageFrozen) {// 如果service所在的进程没有启动,这里去启动进程,启动进程的逻辑和ActivityRecord启动进程一样,就不说了if (r.isSdkSandbox) {final int uid = Process.toSdkSandboxUid(r.sdkSandboxClientAppUid);app = mAm.startSdkSandboxProcessLocked(procName, r.appInfo, true, intentFlags,hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, uid, r.sdkSandboxClientAppPackage);r.isolationHostProc = app;} else {app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated);}if (app == null) {// ...bringDownServiceLocked(r, enqueueOomAdj);return msg;}if (isolated) {r.isolationHostProc = app;}}  // ...return null;
}

1.7 ActiveServices.realStartServiceLocked
调用scheduleCreateService通知app侧创建Service,app侧的逻辑我们就不看了,和创建Activity的逻辑类似,初始化一些数据,通过反射构造对应的Service,然后回调Service的onCreate。
调用sendServiceArgsLocked。

private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,boolean enqueueOomAdj) throws RemoteException {// ...参数检查,更新odj等boolean created = false;try {// ...// 回调app创建Servicethread.scheduleCreateService(r, r.serviceInfo,null /* compatInfo (unused but need to keep method signature) */,app.mState.getReportedProcState());r.postNotification(false);created = true;} catch (DeadObjectException e) {Slog.w(TAG, "Application dead when creating service " + r);mAm.appDiedLocked(app, "Died when creating service");throw e;} finally {// ...如果创建失败重试}// ...// 调用sendServiceArgsLocked,详见1.8sendServiceArgsLocked(r, execInFg, true);// ...
}

1.8 ActiveServices.sendServiceArgsLocked
回调Service的onStartCommand

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,boolean oomAdjusted) throws TransactionTooLargeException {// ...// 回调app侧,调用Service的onStartCommandr.app.getThread().scheduleServiceArgs(r, slice);// ...
}

小结

本节介绍了一下bindService的流程,这个也是我们AMS章节的最后一篇文章,如果大家看过Activity启动流程,然后再看Service的bind流程,大家会发现其实AMS这些组件流程都差不多,app bind call到SystemServer,SystemServer构造一些数据结构,ActivityRecord,ServiceRecord…然后再通过AppThread到binder回调回app,app通过反射构造对应的组件,回调对应的生命周期。
通过这几节的学习,大家应该AMS的结构有一些感觉,会对app开发会有更好的理解,对app的生命周期,四大组建,进程这些概念有更深的理解。


http://www.mrgr.cn/news/33497.html

相关文章:

  • 第十四章:html和css做一个心在跳动,为你而动的表白动画
  • ARM(Day 1)思维导图
  • EECS498 Deep Learning for Computer Vision (一)软件使用指南
  • 【Webpack--015】打包速度优化--loader配置oneOf
  • 江上场景目标检测系统源码分享
  • [mongodb][备份]MongoDBBak.bat
  • 【C++前缀和 排序】2171. 拿出最少数目的魔法豆|1748
  • .netCore运行的环境WindowsHosting和dotnet-sdk区别
  • 返回倒数第k个节点
  • 三阶魔方还原法 勾上回下 上右左左右
  • 字节数据转16进制对应十进制数
  • 【基础算法总结】模拟篇
  • C++之模版的进阶
  • arm-硬件
  • 240922-Conda的在线下载与离线安装
  • LeetcodeTop100 刷题总结(二)
  • 如何用Shell命令结合 正则表达式 统计文本中的ip地址数量
  • 【LeetCode热题100】位运算
  • MELON的难题- 华为OD统一考试(E卷)
  • Cpp类和对象(中)(4)