Service的几种启动方式:
1、startService
public class myActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); startService(new Intent (IMediaScannerService.class.getName()); //"com.android.providers.media.MediaScannerService" }
StartService()方法主要用于启动一个服务执行后台任务,不进行通信。调用者和服务之间没有联系,即使调用者退出了,服务依然在运行。
2.bindService
public class myActivity extends Activity { ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { } @Override public void onServiceConnected(ComponentName name, IBinder service) { } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); bindService(new Intent (IMediaScannerService.class.getName(),conn,Context.BIND_AUTO_CREATE); }
使用bindService()方法来绑定服务,调用者和绑定者绑在一起,调用者一旦退出如果没有其他用户使用则服务也就终止了。
3.隐式启动服务Implicitly start service
When a service is referenced,it will be started automatically.
For example,the MediaScannerService will be started with following code:
import android.media.MediaScannerConnection; MediaScannerConnection.MediaScannerConnectionClient client= new MediaScannerConnection.MediaScannerConnectionClient(){ public void onMediaScannerConnected(){ conn.scanFile("/mnt//sdcard/test.jpg"); } public void onScanComplete(){ conn.disconnect(); //close the connection here } } MediaScannerConnection conn=new MediaScannerConnection(getContext(),client); conn.connect(); //here will trigger start MediaScannnerService
4.通过广播启动服务
下面通过广播action ACTION_MEDIA_SCANNER_SCAN_FILE从而启动Service并扫描单个文件。
Uri data = Uri.parse("file:///"+fName); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data));
下图描述了当一个服务所在进程已经启动,但服务尚未启动时,调用startService时的调用顺序。
由图可知,在14步时,发出SERVICE_TIMEOUT消息,在29步时,删除此消息。如果此超时消息未能及时删除,则在消息处理时将显示为anr。目前此消息超时时间设为20s。
ActivityManagerService.java
public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType) { ... synchronized(this) { final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); ComponentName res = startServiceLocked(caller, service,resolvedType, callingPid, callingUid); //入口 Binder.restoreCallingIdentity(origId); return res; } } ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid) { synchronized(this) { if (DEBUG_SERVICE) Slog.v(TAG, "startService: " + service + " type=" + resolvedType + " args=" + service.getExtras()); if (caller != null) { final ProcessRecord callerApp = getRecordForAppLocked(caller); if (callerApp == null) { throw new SecurityException( "Unable to find app for caller " + caller + " (pid=" + Binder.getCallingPid() + ") when starting service " + service); } } ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, callingPid, callingUid); if (res == null) { return null; } if (res.record == null) { return new ComponentName("!", res.permission != null ? res.permission : "private to package"); } ServiceRecord r = res.record; int targetPermissionUid = checkGrantUriPermissionFromIntentLocked( callingUid, r.packageName, service); if (unscheduleServiceRestartLocked(r)) { if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r); } r.startRequested = true; r.callStart = false; r.lastStartId++; if (r.lastStartId < 1) { r.lastStartId = 1; } r.pendingStarts.add(new ServiceRecord.StartItem(r, r.lastStartId, service, targetPermissionUid)); r.lastActivity = SystemClock.uptimeMillis(); synchronized (r.stats.getBatteryStats()) { r.stats.startRunningLocked(); } if (!bringUpServiceLocked(r, service.getFlags(), false)) { return new ComponentName("!", "Service process is bad"); } return r.name; } } private final boolean bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean whileRestarting) { if (r.app != null && r.app.thread != null) { //如果Service已经在运行 sendServiceArgsLocked(r, false); return true; } if (!whileRestarting && r.restartDelay > 0) { // If waiting for a restart, then do nothing. return true; } // We are now bringing the service up, so no longer in the // restarting state. mRestartingServices.remove(r); final String appName = r.processName; ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid); if (app != null && app.thread != null) { //如果Service所在进程已经运行 try { realStartServiceLocked(r, app); return true; } catch (RemoteException e) { Slog.w(TAG, "Exception when starting service " + r.shortName, e); } // If a dead object exception was thrown -- fall through to // restart the application. } // Not running -- get it started, and enqueue this service record // to be executed when the app comes up. if (startProcessLocked(appName, r.appInfo, true, intentFlags, "service", r.name, false) == null) { //进程尚未启动,启动进程并指定启动对应service bringDownServiceLocked(r, true); return false; } if (!mPendingServices.contains(r)) { mPendingServices.add(r); } return true; }
以下发出超时消息,此消息必须在规定时间内被删除,否则出现anr。SERVICE_TIMEOUT=20*1000ms.
private final void bumpServiceExecutingLocked(ServiceRecord r, String why) { long now = SystemClock.uptimeMillis(); if (r.executeNesting == 0 && r.app != null) { if (r.app.executingServices.size() == 0) { Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG); msg.obj = r.app; mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT); //规定最迟处理时间 } r.app.executingServices.add(r); } r.executeNesting++; r.executingStart = now; }
下面函数将从AM启动Service
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app) throws RemoteException { if (app.thread == null) { //检查所在进程是否存在 throw new RemoteException(); } r.app = app; r.restartTime = r.lastActivity = SystemClock.uptimeMillis(); //记录启动时间 app.services.add(r); bumpServiceExecutingLocked(r, "create"); //发送超时消息 updateLruProcessLocked(app, true, true); boolean created = false; try { mStringBuilder.setLength(0); r.intent.getIntent().toShortString(mStringBuilder, false, true); synchronized (r.stats.getBatteryStats()) { r.stats.startLaunchedLocked(); //电池数据统计启动 } ensurePackageDexOpt(r.serviceInfo.packageName); //??? app.thread.scheduleCreateService(r, r.serviceInfo); //通知Service所在进程创建Service r.postNotification(); created = true; } finally { if (!created) { app.services.remove(r); scheduleServiceRestartLocked(r, false); } } requestServiceBindingsLocked(r); //等待Service运行成功才返回? // 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.lastStartId++; if (r.lastStartId < 1) { r.lastStartId = 1; } r.pendingStarts.add(new ServiceRecord.StartItem(r, r.lastStartId, null, -1)); } sendServiceArgsLocked(r, true); //引起Service.onStartCommand被调用 }
下面函数将消息SERVICE_ARGS发送到Service进程的消息队列,在此将传来的Intent传给指定Service:
private final void sendServiceArgsLocked(ServiceRecord r, boolean oomAdjusted) { final int N = r.pendingStarts.size(); if (N == 0) { return; } while (r.pendingStarts.size() > 0) { try { ServiceRecord.StartItem si = r.pendingStarts.remove(0); if (si.intent == null) { // If somehow we got a dummy start at the front, then // just drop it here. continue; } si.deliveredTime = SystemClock.uptimeMillis(); r.deliveredStarts.add(si); si.deliveryCount++; if (si.targetPermissionUid >= 0) { grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid, r.packageName, si.intent, si.getUriPermissionsLocked()); } bumpServiceExecutingLocked(r, "start"); //启动超时消息 if (!oomAdjusted) { oomAdjusted = true; updateOomAdjLocked(r.app); } int flags = 0; if (si.deliveryCount > 0) { flags |= Service.START_FLAG_RETRY; } if (si.doneExecutingCount > 0) { flags |= Service.START_FLAG_REDELIVERY; } r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent); //发送Intent到Service所在进程消息队列,引起Service.onStartCommand被调用 } catch (RemoteException e) { // Remote process gone... we'll let the normal cleanup take // care of this. break; } catch (Exception e) { Slog.w(TAG, "Unexpected exception", e); break; } } }
r.app.thread.scheduleServiceArgs将发送消息SERVICE_ARGS到ActivityThread.Handler,在此将调用handleServiceArgs来完成
ActivityThread.java
private final void handleServiceArgs(ServiceArgsData data) { Service s = mServices.get(data.token); if (s != null) { try { if (data.args != null) { data.args.setExtrasClassLoader(s.getClassLoader()); } int res = s.onStartCommand(data.args, data.flags, data.startId); //调用Service.onStartCommand方法 QueuedWork.waitToFinish(); //等待本进程所有异步操作完成 try { ActivityManagerNative.getDefault().serviceDoneExecuting( data.token, 1, data.startId, res); //通知操作完成,并删除超时消息 } catch (RemoteException e) { // nothing to do. } ensureJitEnabled(); //确保JIT优化启动(如果未启动则启动),但为何在此做?? } catch (Exception e) { if (!mInstrumentation.onException(s, e)) { throw new RuntimeException( "Unable to start service " + s + " with " + data.args + ": " + e.toString(), e); } } } }
每当AM需要异步执行Service操作时,在操作完后均需调用函数serviceDoneExecuting以防止Service操作超时。
public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) { r.executeNesting--; if (r.executeNesting <= 0 && r.app != null) { r.app.executingServices.remove(r); if (r.app.executingServices.size() == 0) { //为何? mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app); //删除所有object=r.app的超时消息 } if (inStopping) { mStoppingServices.remove(r); r.bindings.clear(); } updateOomAdjLocked(r.app); //检查是否需要kill app以避免OOM } }