Service启动过程过程详解

时间:2021-09-13 04:22:11

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时的调用顺序。


Service启动过程过程详解

由图可知,在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
}
}