现在的位置: 首页 > 综合 > 正文

Service启动过程过程详解

2013年10月19日 ⁄ 综合 ⁄ 共 9595字 ⁄ 字号 评论关闭

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



抱歉!评论已关闭.