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
}
}