Android Framework—Service
介绍
Service是一种可以在后台执行长时间运行操作而不提供界面的应用组件。服务可以由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可以通过绑定到服务与之进行交互,甚至是执行进程之间的通信。
正文
1.Service的介绍
<service android:name=".MyService"android:isolatedProcess="true"android:directBootAware="true"android:process=":subService"/>
import android.app.Service
import android.content.Intent
import android.os.IBinderclass PreloadService : Service() {override fun onBind(p0: Intent?): IBinder? {return null}
}
service的标签属性比较简单,具体可以参考官网。我在这里就举几个属性的例子:
isolatedProcess
:服务与系统其余部分隔离的特殊进程下运行。
process
:指定服务运行的进程名称。以:
开头,系统会根据需要时创建新进程,并且服务会在该进程运行。
directBootAware
:服务是否支持直接启动,也就是可以在用户解锁设备之前运行。
Service的生命周期
它的生命周期会和我们使用Service
的不同 也有所不同。左边是startService
右边是bindService
。我们汇编可以根据源码 再来看看执行的时机。
Service的运行模式
1.前台Service:执行一些用户能注意到的操作,前台服务必须显示通知。
2.后台Service:后台服务不会影响用户,在26以后,系统会对后台服务施加限制。
更多Android Framework 学习资料 请点击免费领取
2.Service的启动
1.startService
在源码中我们可以直接在Activity中调用startService
,那就跟一下 看看它是如何开启Service的。 文件目录:/android/frameworks/base/core/java/android/content/ContextWrapper.java
public ComponentName startServiceAsUser(Intent service, UserHandle user) {return mBase.startServiceAsUser(service, user);
}
//mBase就是ContextImpl 参考Activity创建流程
Context mBase;public ComponentName startService(Intent service) {warnIfCallingFromSystemProcess();return startServiceCommon(service, false, mUser);
}//开启Service
private ComponentName startServiceCommon(Intent service, boolean requireForeground,UserHandle user) {try {//校验intentvalidateServiceIntent(service);//设置intent的属性,准备离开现有进程service.prepareToLeaveProcess(this);//调用AMS的startService 传入了 当前进程,service(目标servcie),true ComponentName cn = ActivityManager.getService().startService(mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(getContentResolver()), requireForeground,getOpPackageName(), user.getIdentifier());return cn;} catch (RemoteException e) {throw e.rethrowFromSystemServer();}
}
看看AMS
是如何开启Service
public ComponentName startService(IApplicationThread caller, Intent service,String resolvedType, boolean requireForeground, String callingPackage, int userId)throws TransactionTooLargeException {//判断是否是隔离进程调用enforceNotIsolatedCaller("startService");synchronized(this) {//获取pidfinal int callingPid = Binder.getCallingPid();//获取uidfinal int callingUid = Binder.getCallingUid();//获取origidfinal long origId = Binder.clearCallingIdentity();ComponentName res;try {//调用mService的startServiceLocked 这里的mService就是之前讲AMS启动流程时创建的ActiveServices 用来管理Service的res = mServices.startServiceLocked(caller, service,resolvedType, callingPid, callingUid,requireForeground, callingPackage, userId);} finally {Binder.restoreCallingIdentity(origId);}return res;}
}
文件目录:/android/frameworks/base/services/core/java/com/android/server/am/ActiveServices.javaComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)throws TransactionTooLargeException {return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,callingPackage, userId, false);
}ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,int callingPid, int callingUid, boolean fgRequired, String callingPackage,final int userId, boolean allowBackgroundActivityStarts)throws TransactionTooLargeException {final boolean callerFg;if (caller != null) {//不为null 获取到当前进程的ProcessRecordfinal ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;} else {callerFg = true;}//得到ServiceRecord对象:先从mServiceMap中查找 如果有就返回 没有的话就创建(通过pkms.resolveService 查找service创建ServiceRecord包装成ServiceLookupResult返回)ServiceLookupResult res =retrieveServiceLocked(service, null, resolvedType, callingPackage,callingPid, callingUid, userId, true, callerFg, false, false);//拿到ServiceRecord ServiceRecord继承自BinderServiceRecord r = res.record;final boolean bgLaunch = !mAm.isUidActiveLocked(r.appInfo.uid);boolean forcedStandby = false;if (bgLaunch && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {forcedStandby = true;}boolean forceSilentAbort = false;if (fgRequired) {//这里是false不走 前台走这里}if (forcedStandby || (!r.startRequested && !fgRequired)) {//判断是否运行启动服务:常驻内存、蓝牙、电源白名单允许直接启动服务 否则执行默认策略:如果大于AndroidO不允许启动后台服务final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);if (allowed != ActivityManager.APP_START_MODE_NORMAL) {//不允许启动服务的逻辑if (allowed == ActivityManager.APP_START_MODE_DELAYED || forceSilentAbort) {return null;}if (forcedStandby) {if (fgRequired) {//falsereturn null;}}UidRecord uidRec = mAm.mProcessList.getUidRecordLocked(r.appInfo.uid);return new ComponentName("?", "app is in background uid " + uidRec);}}if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) {//不走这里fgRequired = false;}//记录时间戳r.lastActivity = SystemClock.uptimeMillis();//设置已经开启了r.startRequested = true;r.delayedStop = false;r.fgRequired = fgRequired;//添加了一个ServiceRecord.StartItem taskRemoved = false 如果是BindService 不会添加 因为他直接调用的是realStartServicer.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),service, neededGrants, callingUid));if (fgRequired) {//这里不走}final ServiceMap smap = getServiceMapLocked(r.userId);boolean addToStarting = false;if (allowBackgroundActivityStarts) {r.whitelistBgActivityStartsOnServiceStart();}//调用startServiceInnerLockedComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);return cmp;
}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();}//调用bringUpServiceLocked 开启进程String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);if (error != null) {return new ComponentName("!!", error);}if (r.startRequested && addToStarting) {boolean first = smap.mStartingBackground.size() == 0;smap.mStartingBackground.add(r);r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;if (DEBUG_DELAYED_SERVICE) {RuntimeException here = new RuntimeException("here");here.fillInStackTrace();} else if (DEBUG_DELAYED_STARTS) {}if (first) {smap.rescheduleDelayedStartsLocked();}} else if (callerFg || r.fgRequired) {smap.ensureNotStartingBackgroundLocked(r);}return r.name;
}private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,boolean whileRestarting, boolean permissionsReviewRequired)throws TransactionTooLargeException {if (r.app != null && r.app.thread != null) {//已经运行sendServiceArgsLocked(r, execInFg, false);return null;}if (!whileRestarting && mRestartingServices.contains(r)) {return null;}if (mRestartingServices.remove(r)) {clearRestartingIfNeededLocked(r);}if (r.delayed) {getServiceMapLocked(r.userId).mDelayedStartList.remove(r);r.delayed = false;}//是否需要进程隔离下 运行final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;//获取进程名final String procName = r.processName;//创建HostingRecordHostingRecord hostingRecord = new HostingRecord("service", r.instanceName);ProcessRecord app;if (!isolated) {//非隔离进程//获取到service的ProcessRecordapp = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);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) {}}} else {//隔离进程//第一次开启isolatedProc是nullapp = r.isolatedProc;if (WebViewZygote.isMultiprocessEnabled()&& r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {hostingRecord = HostingRecord.byWebviewZygote(r.instanceName);}if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName,r.definingUid);}}//服务还没启动调用startProcessLocked 创建进程if (app == null && !permissionsReviewRequired) {if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,hostingRecord, false, isolated, false)) == null) {String msg = "Unable to launch app "+ r.appInfo.packageName + "/"+ r.appInfo.uid + " for service "+ r.intent.getIntent() + ": process is bad"; bringDownServiceLocked(r);return msg;}if (isolated) {r.isolatedProc = app;}}if (r.fgRequired) {//不走这里 是falsemAm.tempWhitelistUidLocked(r.appInfo.uid,SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");}if (!mPendingServices.contains(r)) {//假如mPendingServices中mPendingServices.add(r);}if (r.delayedStop) {r.delayedStop = false;if (r.startRequested) {stopServiceLocked(r);}}return null;
}
在AMS
这里会先检查Service是否可以执行(常驻内存、蓝牙、电源白名单允许直接启动服务),接着调用bringUpServiceLocked
判断是否需要隔离进程如果非隔离 就看是否已经启动进程 执行realStartServiceLocked
,否则是隔离进程 直接开启新进程。我们没有设置隔离进程 所以我们会直接开启新进程,开启进程的过程在之前已经接触很多次了,我们直接跳过,开启成功之后会将ServiceRecord添加到mPendingServices
中去。所以我们看看进程创建成功之后会如何开启Service。
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,int pid, int callingUid, long startSeq) {//到这里来thread.bindApplication(processName, appInfo, providers,instr2.mClass,profilerInfo, instr2.mArguments,instr2.mWatcher,instr2.mUiAutomationConnection, testMode,mBinderTransactionTrackingEnabled, enableTrackAllocation,isRestrictedBackupMode || !normalMode, app.isPersistent(),new Configuration(app.getWindowProcessController().getConfiguration()),app.compat, getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked(),buildSerial, autofillOptions, contentCaptureOptions);boolean badApp = false;boolean didSomething = false;//在这里开启activityif (normalMode) {try {didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());} catch (Exception e) {badApp = true;}}if (!badApp) {try {//开启ServicedidSomething |= mServices.attachApplicationLocked(app, processName);} catch (Exception e) {badApp = true;}}return true;
}
//还是在ActiveService中boolean attachApplicationLocked(ProcessRecord proc, String processName)throws RemoteException {boolean didSomething = false;//此时Services的size是大于0的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开启servicerealStartServiceLocked(sr, proc, sr.createdFromFg);didSomething = true;if (!isServiceNeededLocked(sr, false, false)) {bringDownServiceLocked(sr);}}} catch (RemoteException e) {throw e;}}return didSomething;
}//开启service
private final void realStartServiceLocked(ServiceRecord r,ProcessRecord app, boolean execInFg) throws RemoteException {//服务和当前进程绑定r.setProcess(app);r.restartTime = r.lastActivity = SystemClock.uptimeMillis();//添加到ProcessRecord中final boolean newService = app.services.add(r);//埋炸弹scheduleServiceTimeoutLockedbumpServiceExecutingLocked(r, execInFg, "create");//更新进程LRUmAm.updateLruProcessLocked(app, false, null);updateServiceForegroundLocked(r.app, /* oomAdj= */ false);//更新OOMAdjmAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);boolean created = false;try {synchronized (r.stats.getBatteryStats()) {r.stats.startLaunchedLocked();}mAm.notifyPackageUse(r.serviceInfo.packageName,PackageManager.NOTIFY_PACKAGE_USE_SERVICE);app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);//调用到应用进程 也就是服务进程 ActivityThreadapp.thread.scheduleCreateService(r, r.serviceInfo,mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),app.getReportedProcState());r.postNotification();created = true;} catch (DeadObjectException e) {} finally {}if (r.whitelistManager) {app.whitelistManager = true;}//处理Bind我们不处理 没有Bind 此时直说startServicerequestServiceBindingsLocked(r, execInFg);updateServiceClientActivitiesLocked(app, null, true);if (newService && created) {app.addBoundClientUidsOfNewService(r);}if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),null, null, 0));}//发送Service的argssendServiceArgsLocked(r, execInFg, true);if (r.delayed) {getServiceMapLocked(r.userId).mDelayedStartList.remove(r);r.delayed = false;}
}回到ActivityThread看看它的scheduleCreateServicepublic 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;//给mH发送了H.CREATE_SERVICEsendMessage(H.CREATE_SERVICE, s);
}case CREATE_SERVICE:handleCreateService((CreateServiceData)msg.obj);break;
//创建Service
private void handleCreateService(CreateServiceData data) {unscheduleGcIdler();LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);Service service = null;try {//反射创建Servicejava.lang.ClassLoader cl = packageInfo.getClassLoader();service = packageInfo.getAppFactory().instantiateService(cl, data.info.name, data.intent);} catch (Exception e) {}try {//创建ContextContextImpl context = ContextImpl.createAppContext(this, packageInfo);context.setOuterContext(service);//调用makeApplicationApplication app = packageInfo.makeApplication(false, mInstrumentation);//调用service的attach 绑定ActivityThread token Application 以及AMSservice.attach(context, this, data.info.name, data.token, app,ActivityManager.getService());//调用service的onCreateservice.onCreate();//存入到mService中去mServices.put(data.token, service);try {//告诉AMS创建完成ActivityManager.getService().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}} catch (Exception e) {}
}public final void attach(Context context,ActivityThread thread, String className, IBinder token,Application application, Object activityManager) {attachBaseContext(context);mThread = thread; // NOTE: unused - remove?mClassName = className;mToken = token;mApplication = application;mActivityManager = (IActivityManager)activityManager;mStartCompatibility = getApplicationInfo().targetSdkVersion< Build.VERSION_CODES.ECLAIR;
}到AMS 处理服务创建public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {synchronized(this) {if (!(token instanceof ServiceRecord)) {throw new IllegalArgumentException("Invalid service token");}mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);}
}//AMS开启Service成功
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {boolean inDestroying = mDestroyingServices.contains(r);if (r != null) {//在这里把炸弹拆除serviceDoneExecutingLocked(r, inDestroying, inDestroying);}
}
发送的args
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,boolean oomAdjusted) throws TransactionTooLargeException {final int N = r.pendingStarts.size();if (N == 0) {//不是0return;}ArrayList<ServiceStartArgs> args = new ArrayList<>();while (r.pendingStarts.size() > 0) {ServiceRecord.StartItem si = r.pendingStarts.remove(0);if (si.intent == null && N > 1) {continue;}si.deliveredTime = SystemClock.uptimeMillis();r.deliveredStarts.add(si);si.deliveryCount++;//埋炸弹bumpServiceExecutingLocked(r, execInFg, "start");if (!oomAdjusted) {oomAdjusted = true;mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);}if (r.fgRequired && !r.fgWaiting) {//前台Serviceif (!r.isForeground) {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));}//执行ActivityThread的scheduleServiceArgsr.app.thread.scheduleServiceArgs(r, slice);
}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;//给mH发送SERVICE_ARGSsendMessage(H.SERVICE_ARGS, s);}
}case SERVICE_ARGS:handleServiceArgs((ServiceArgsData)msg.obj);break;//处理Args
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) {//这里是false 所以会执行onStartCommandres = s.onStartCommand(data.args, data.flags, data.startId);} else {}QueuedWork.waitToFinish();try {//通知AMS 拆除炸弹ActivityManager.getService().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);} catch (RemoteException e) {}} catch (Exception e) {}}
}
进程创建之后,会调用AMS
的attachApplication
接着处理service(ActiveService)
,之前创建之后会添加到mPendingServices
中,现在继续处理调用realStartServiceLocked
来开启Service,在开启的过程中会埋入一个炸弹(给Handler发送一个SERVICE_TIMEOUT_MSG
) 如果超时未处理会弹出ANR
,然后调用app.thread.scheduleCreateService
通知客户端创建反射Service、Context
调用onCreate
把Service
存入到mService
中,调用AMS
的serviceDoneExecuting
进行炸弹的拆除。 然后再埋炸弹 调用app.thread.scheduleServiceArgs
调用service.onStartCommand
再通知AMS 拆除炸弹。 这样Service就运行起来了。我们再看看Service的onStop。
还是回到ContextImpl
public boolean stopService(Intent service) {return stopServiceCommon(service, mUser);
}private boolean stopServiceCommon(Intent service, UserHandle user) {validateServiceIntent(service);service.prepareToLeaveProcess(this);//调用AMS的stopServiceint res = ActivityManager.getService().stopService(mMainThread.getApplicationThread(), service,service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());return res != 0;
}public int stopService(IApplicationThread caller, Intent service,String resolvedType, int userId) {enforceNotIsolatedCaller("stopService");synchronized(this) {//调用ActiveService的stopServiceLockedreturn mServices.stopServiceLocked(caller, service, resolvedType, userId);}
}int stopServiceLocked(IApplicationThread caller, Intent service,String resolvedType, int userId) {//获取到调用这的ProcessRecordfinal ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);//获取ServiceRecord ServiceLookupResult r = retrieveServiceLocked(service, null, resolvedType, null,Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false, false);if (r != null) {if (r.record != null) {final long origId = Binder.clearCallingIdentity();try {//调用stopServiceLockedstopServiceLocked(r.record);} finally {Binder.restoreCallingIdentity(origId);}return 1;}return -1;}return 0;
}private void stopServiceLocked(ServiceRecord service) {if (service.delayed) {service.delayedStop = true;return;}synchronized (service.stats.getBatteryStats()) {service.stats.stopRunningLocked();}service.startRequested = false;if (service.tracker != null) {service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),SystemClock.uptimeMillis());}service.callStart = false;bringDownServiceIfNeededLocked(service, false, false);
}private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,boolean hasConn) {if (isServiceNeededLocked(r, knowConn, hasConn)) {return;}if (mPendingServices.contains(r)) {return;}bringDownServiceLocked(r);
}private final void bringDownServiceLocked(ServiceRecord r) {if (r.app != null && r.app.thread != null) {boolean needOomAdj = false;//执行unBindfor (int i = r.bindings.size() - 1; i >= 0; i--) {IntentBindRecord ibr = r.bindings.valueAt(i);if (ibr.hasBound) {try {bumpServiceExecutingLocked(r, false, "bring down unbind");needOomAdj = true;ibr.hasBound = false;ibr.requested = false;r.app.thread.scheduleUnbindService(r,ibr.intent.getIntent());} catch (Exception e) {serviceProcessGoneLocked(r);}}}if (needOomAdj) {mAm.updateOomAdjLocked(r.app, true,OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);}}r.fgRequired = false;r.fgWaiting = false;ServiceState stracker = r.getTracker();if (stracker != null) {stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),r.lastActivity);}mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);if (r.app != null) {Message msg = mAm.mHandler.obtainMessage(ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);msg.obj = r.app;msg.getData().putCharSequence(ActivityManagerService.SERVICE_RECORD_KEY, r.toString());mAm.mHandler.sendMessage(msg);}}
//记录销毁时间r.destroyTime = SystemClock.uptimeMillis();final ServiceMap smap = getServiceMapLocked(r.userId);//从map中移除ServiceRecord found = smap.mServicesByInstanceName.remove(r.instanceName);//移除smap.mServicesByIntent.remove(r.intent);r.totalRestartCount = 0;r.isForeground = false;r.foregroundId = 0;r.foregroundNoti = null;r.clearDeliveredStartsLocked();r.pendingStarts.clear();smap.mDelayedStartList.remove(r);if (r.app != null) {synchronized (r.stats.getBatteryStats()) {r.stats.stopLaunchedLocked();}r.app.services.remove(r);r.app.updateBoundClientUids();if (r.whitelistManager) {updateWhitelistManagerLocked(r.app);}if (r.app.thread != null) {updateServiceForegroundLocked(r.app, false);try {//埋炸弹bumpServiceExecutingLocked(r, false, "destroy");mDestroyingServices.add(r);r.destroying = true;mAm.updateOomAdjLocked(r.app, true,OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);//到客户端执行scheduleStopServicer.app.thread.scheduleStopService(r);} catch (Exception e) {serviceProcessGoneLocked(r);}} else {}} if (r.bindings.size() > 0) {//清空bindingsr.bindings.clear();}if (r.restarter instanceof ServiceRestarter) {((ServiceRestarter)r.restarter).setService(null);}int memFactor = mAm.mProcessStats.getMemFactorLocked();long now = SystemClock.uptimeMillis();if (r.tracker != null) {r.tracker.setStarted(false, memFactor, now);r.tracker.setBound(false, memFactor, now);if (r.executeNesting == 0) {r.tracker.clearCurrentOwner(r, false);r.tracker = null;}}smap.ensureNotStartingBackgroundLocked(r);
}public final void scheduleStopService(IBinder token) {sendMessage(H.STOP_SERVICE, token);
}case STOP_SERVICE:handleStopService((IBinder)msg.obj);schedulePurgeIdler();//清空待清理的资源break;private void handleStopService(IBinder token) {
//从mService中移除掉 只是从map中移除掉了引用,所以我们需要注意Service内部的thread 以及变量不要引起内存泄漏或者线程没有停止Service s = mServices.remove(token);if (s != null) {try {//调用s的onDestorys.onDestroy();s.detachAndCleanUp();Context context = s.getBaseContext();if (context instanceof ContextImpl) {final String who = s.getClassName();((ContextImpl) context).scheduleFinalCleanup(who, "Service");}QueuedWork.waitToFinish();try {//调用AMS的serviceDoneExecuting 拆除炸弹ActivityManager.getService().serviceDoneExecuting(token, SERVICE_DONE_EXECUTING_STOP, 0, 0);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}} catch (Exception e) {}} else {}
}
stop的流程和start的流程差不多,需要注意的是stop
只是从map中移除了
,我们需要自己释放资源。
相关文章:

Android Framework—Service
介绍 Service是一种可以在后台执行长时间运行操作而不提供界面的应用组件。服务可以由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可以通过绑定到服务与之进行交互,甚至是执行进程之间的通信…...

leetcode (重排数组使得)连续子数组的权值和最小
题目描述:请重新排列某个仅包含2和3的数组,使得数组的所有连续子数组权值之和最小数组的权值定义为,数组中所有元素之积的因子个数,例如:rank([2,3])4 x p 1 c 1 p 2 c 2 p 3 c 3 ⋅ ⋅ ⋅ p k c k r a n k ( c 1 1 ) ( c …...

JSP计算机等级考试查询系统(源代码+论文+答辩PPT)
第一章 引言 计算机等级考试查询系统是有其开发的必要性的,它的应用将大大节省了学校的人力资源,从而从人工劳动中解脱出来。我们这次开发的软件系统一共包括了三个部分:等级考试的报名系统、查询系统和管理系统。其中管理系统是另外两部分…...

python 基础系列篇:七、以函数方式编写一个数字华容道
python 基础系列篇:七、以函数方式编写一个数字华容道 数字华容道游戏分析开始编写完整代码代码解说定义方法的规律 小结 数字华容道 嗯,就是一个简单的益智游戏,把数字按照特定规律排列,并比矩阵少一个格,用来进行移…...

2023年前端面试题
1.position都有哪些属性 2.1px等于多少rem,rem根据根元素的大小,根元素是谁 3.Es6操作数组的方法 4.防抖和节流以及应用场景 5.Vue和ajax最大的区别是什么(Vue和ajax怎么操作dom的,vue虚拟dom) 6.js数据类型有哪些&…...

快速入门量化交易
本文首发自「慕课网」,想了解更多IT干货内容,程序员圈内热闻,欢迎关注"慕课网"! 原作者:袁霄|慕课网讲师 近来“量化交易”这个词听得越来越频繁,多数人对量化交易的第一印象是“高大上的技术”…...

Mongodb oplog
在MongoDB复制集中,oplog信息存储在oplog.rs集合中。 oplog.rs集合是一个固定大小的集合(capped collection),它位于local数据库中。 当我们在源MongoDB实例上启用了复制(replication)功能,MongoDB会自动在local数据库中创建oplog.rs集合。此后,所有在该实例上的写操作都会生…...

python基础篇: python字符串方法都有哪些?你知道多少?
❝ Python提供了丰富的字符串处理方法,可以方便地对字符串进行操作、处理和转换。在本文中,我们将介绍Python中常用的字符串方法。 ❞ python中字符串内置方法很多,可以通过dir()方式查看具体有哪些方法,下表是python字符串的全部…...

chmod 命令 (chmod 0660)
chmod的作用: 用于设置文件所有者和文件关联组的命令,就是控制用户的权限命令 注意事项: chown 需要超级用户 root 的权限才能执行此命令。 自己常用chmod 命令是 chmod 777 * 给所有文件权限 chmod 777 文件名 给单独文件权限 这个777 是怎么来的, 或者chmod 0660 这…...

Qt应用开发常用功能
Qt判断当前操作系统? #ifdef Q_OS_MAC //mac ... #endif#ifdef Q_OS_LINUX //linux ... #endif#ifdef Q_OS_WIN32 //win ... #endif#ifdef __arm__ //arm ... #endifQt实现应用程序关闭和重启? //关机按钮-点击槽函数 void SystemD::on_shutdownButton…...

麻了,部门新来的00后给我卷崩溃了...
今天上班开早会就是新人见面仪式,听说来了个很厉害的大佬,年纪还不大,是上家公司离职过来的,薪资已经达到中高等水平,很多人都好奇不已,能拿到这个薪资应该人不简单,果然,自我介绍的…...

代码随想录算法训练营第56天|583. 两个字符串的删除操作,72. 编辑距离
代码随想录算法训练营第56天|583. 两个字符串的删除操作,72. 编辑距离 583. 两个字符串的删除操作72. 编辑距离 583. 两个字符串的删除操作 题目链接:583. 两个字符串的删除操作,难度:中等 【实现代码】 class Solution { publi…...

【嵌入式笔/面试】嵌入式软件基础题和真题总结——操作系统
在学习的时候找到几个十分好的工程和个人博客,先码一下,内容都摘自其中,有些重难点做了补充! 才鲸 / 嵌入式软件笔试题汇总 嵌入式与Linux那些事 阿秀的学习笔记 小林coding 百问网linux 嵌入式软件面试合集 2022年春招实习十四面…...

2023浙江省赛“信息安全管理与评估“--Web渗透测试(高职组)
2022全国职业技能大赛“信息安全管理与评估”(高职组)任务书 2022全国职业技能大赛“信息安全管理与评估”任务书第一阶段竞赛项目试题第二阶段竞赛项目试题第三阶段竞赛项目试题任务2:Web渗透测试2022全国职业技能大赛“信息安全管理与评估”任务书 第一阶段竞赛项目试题 …...

垃圾收集器面试总结(二)
G1 收集器 G1 (Garbage-First) 是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器。 以极高概率满足 GC 停顿时间要求的同时,还具备高吞吐量性能特征。 被视为 JDK1.7 中 HotSpot 虚拟机的一个重要进化特征。它具备以下特点: 并行与并发&am…...

语音交友app开发中的用户积分系统
引言 在当今数字时代,语音交友app已成为一种流行的社交工具。它们给用户提供了一个平台,在这里他们可以结交新朋友,分享他们的生活和信仰,并建立深厚的人际关系。然而,市场上存在大量的语音交友app,这使得…...

Nature:惊人的突破!科学家们成功破译人类嗅觉感应机制的奥秘!
加州大学旧金山分校(UCSF)的科学家们创造了第一张关于气味分子如何激活人类气味受体的分子水平的3D图片,这是破译嗅觉的关键一步,该成果打破了长期以来研究人员对嗅觉理解的僵局。 该研究成果于2023年3月15日发表在《Nature》&…...
WPF教程(九)--数据绑定(2)--绑定模式
一、绑定模式 绑定模式以及模式的使用效果。 示例如下是根据ListBox中的选中项,去改变TextBlock的背景色。将 TextBlock 的背景色绑定到在 ListBox 中选择的颜色。在下面的代码中针对TextBlock的 Background 属性使用绑定语法绑定从 ListBox 中选择的值。代码如下。…...

湿法冶金以及铼提取工艺,湿法冶金工艺特点及工艺流程
湿法冶金是利用浸出剂在一定温度压力下与矿石接触,把矿石中有用的金属溶解后再从溶液中回收有价金属的一种工艺,因为其过程大都是在水溶液中进行,所以又被称为“水法冶金”。 01 湿法冶金工艺特点及工艺流程 湿法冶金作为解决我国金属矿产资…...

kafka集群搭建
1.本次搭建涉及3台centos7主机,防火墙与selinux服务均关闭 2.主机参数如下表所示 nameIPportserviceA10.1.60.1122128、2888、3888、9092kafka、zookeeperB10.1.60.1142128、2888、3888、9092kafka、zookeeperC10.1.60.1152128、2888、3888、9092kafka、zookeeper…...

【UE】将存档的值显示在控件蓝图上
上一篇博客(【UE】保存游戏的demo)已经实现了存档功能,本篇博客介绍的是如何将存档的值显示在控件蓝图上。 效果 可以看到我们存档的值显示在文本控件上 步骤 1. 新建一个蓝图类,父类为“HUD” 命名为“NewHudClassBP” 2. 在世…...

考研数据结构代码篇
文章目录 数据结构线性表基本操作顺序表的定义顺序表基本操作 单纯上传一下数据结构中可能考察的代码,规格很乱,过几天改规格,提前水一篇 数据结构 线性表 基本操作 InitList(&L) // 初始化表。构造一个空的线性表L࿰…...

css-设置单行文本溢出省略号,使用overflow:hidden属性之后的出现的问题几解决办法。
1 设置单行文本溢出后出现省略号 必要:需要设置固定宽度,不允许换行 width: 200px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; 2 设置N行文本…...

js的方法
字符串方法: substring(startIndex, endIndex):从指定的字符串中提取字符并返回新字符串,不包括结束位置的字符。substr(startIndex, length):从指定字符串中提取指定长度的字符并返回新字符串。indexOf(searchValue, startIndex…...
[NSSRound#11] 密码学个人赛
这个比赛没有参加,跟别人要了些数据跑一下,其实交互这东西基本上一样,跑通就行. ez_enc 这题有点骗人,给了一堆AB串,一开始以为是培根密码,结果出来很乱.再看长度:192 应该就是01替换 a ABAABBBAABABAABBABABAABBABAAAABBABABABAAABAAABBAABBBBABBABBABBABABABAABBAABBABAA…...

玩转树莓派四、修改国内源提高更新速度
树莓派的软件包源默认连接的是官方源,速度不是很快,我们可以更换为第三方源以提高下载速度和体验。 首先通过命令 lsb_release -a 获取到版本号为 bullseye piRpi4B2G:/etc/apt $ lsb_release -a No LSB modules are available. Distributor ID: Debian Descripti…...

苹果手机网速慢怎么办?这些方法帮你解决网速慢的问题!
案例:苹果手机数据网络信号差,怎么解决? 【家人们,苹果手机不知咋回事,网速很慢,想要在某宝买个东西都得卡个半天。哭了!有没有什么方法解决?】 苹果手机作为一款高端智能手机&…...

linux_时序竞态-pause函数-sigsuspend函数-异步I/O-可重入函数-不可重入函数
接上一篇:linux_信号捕捉-signal函数-sigaction函数-sigaction结构体 今天来分享时序竞态的知识,关于时序竞态的问题,肯定会和cpu有关,也会学习两个函数,pause函数,sigsuspend函数, 也会分享什么…...

Tomcat的负载均衡和动静分离
---------------------NginxTomcat负载均衡、动静分离------------------------- Nginx 服务器:192.168.80.10:80 Tomcat服务器1:192.168.80.100:80 Tomcat服务器2:192.168.80.101:8080 192.168.80.101:8081 1.部署Nginx 负载均衡器 system…...

C++每日一练:最长递增区间 阿波罗的魔力宝石 投篮
文章目录 前言一、最长递增区间二、阿波罗的魔力宝石三、投篮总结 前言 今天的题太简单,甚至 “最长递增区间” 和 “投篮” 就是一个问题。实在没事干,也给做了!直接上代码算了… 提示:以下是本篇文章正文内容 一、最长递增区间…...