AndroidService

2018-08-01


《Android开发艺术探索》9.3章
Service分为两种工作状态,一种是启动状态,主要用于执行后台计算;另一种是绑定态,主要用于其他组件和 Service的交互。需要注意的是, Service的这两种状态是可以共存的,即 Service既可以处于启动状态也可以同时处于绑定状态。
通过 ContextstartService方法即可启动一个 Service:

Intent intent = new Intent(content,Service.class);
startService(intent);

通过ContextbindService方法可以绑定一个Service

Intent intent = new Intent(content,Service.class);
bindService(intent,connection,BIND_AUTO_CREATE);
Service启动过程

Service的启动时从ContextWrapperstartService开始的:

@Override
    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }

mBaseContext的实现类ContextImpl在Activity启动的时候会通过attach方法关联一个ContextImpl,这个ContextImpl就是上面的mBase,从ContextWrapper的实现来看,大部分的实现都是通过mBase来实现的,这是一种典型的桥接模式。在ContextImplstartService方法中又调用了startServiceCommon

 @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }
private ComponentName startServiceCommon(Intent service, boolean requireForeground,UserHandle user) {

    validateServiceIntent(service);
    service.prepareToLeaveProcess(this);
    //api 27
    ComponentName cn = ActivityManager.getService().startService(
        mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                    getContentResolver()), requireForeground,
                    getOpPackageName(), user.getIdentifier());
    //api 25
    //ComponentName cn = ActivityManagerNative.getDefault().startService(
     //   mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
      //  getContentResolver()), getOpPackageName(), user.getIdentifier());

    return cn;

}

startServiceCommon中通过getService这个对象来启动一个服务,这个对象就是AMS,需要注意的是,在上述代码中通过AMS来启动服务的过程是一个跨进程调用。AMS的startService如下:

@Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, String callingPackage, int userId)
            throws TransactionTooLargeException {
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid, callingPackage, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }

AMS会通过mServices来完成service的启动过程,mServices的对象类型是ActiveServicesActiveServices是一个辅助AMS进行Service管理的类,包括Service的启动、绑定和停止。在startService方法的尾部会调用startServiceInnerLocked方法

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();
        }
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
        return r.name;
    }

上述代码中ServiceRecord是描述一个Service记录,ServiceRecord一直贯穿整个Service流程,startServiceInnerLocked并没有完成启动Service的完整流程,而是将后续的过程交给了bringUpServiceLocked,在该方法中又调用了realStartServiceLocked方法:

private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
       
        r.app = app;
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

        final boolean newService = app.services.add(r);
        bumpServiceExecutingLocked(r, execInFg, "create");
        mAm.updateLruProcessLocked(app, false, null);
        mAm.updateOomAdjLocked();

        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);
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app);
            throw e;
        } finally {
            if (!created) {
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);

                // Cleanup.
                if (newService) {
                    app.services.remove(r);
                    r.app = null;
                }

                // Retry.
                if (!inDestroying) {
                    scheduleServiceRestartLocked(r, false);
                }
            }
        }

        if (r.whitelistManager) {
            app.whitelistManager = true;
        }

        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null, true);

        // 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.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null));
        }

        sendServiceArgsLocked(r, execInFg, true);

        if (r.delayed) {
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
            getServiceMap(r.userId).mDelayedStartList.remove(r);
            r.delayed = false;
        }

        if (r.delayedStop) {
            // Oh and hey we've already been asked to stop!
            r.delayedStop = false;
            if (r.startRequested) {
                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                        "Applying delayed stop (from start): " + r);
                stopServiceLocked(r);
            }
        }
    }

realStartServiceLocked方法中,首先通过app.threadscheduleCreateService方法来创建Service对象并调用其onCreate,接着再通过sendServiceArgsLocked方法来调用Service的其他方法,比如onStartCommand,这两个过程均是进程间通信。app.thread对象是IApplicationThread类型,它实际上是一个Binder,它的具体实现是ApplicationThreadApplicationThreadNative。由于ApplicationThread继承了ApplicationThreadNative,因此只需要看ApplicationThreadService启动过程的处理即可,这对应着它的scheduleCreateService方法,如下所示:

 public 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;

            sendMessage(H.CREATE_SERVICE, s);
        }

通过发送消息给Handler H来完成的。H会接收这个CREATE_ SERVICE消息并通过ActivityThreadhandleCreateService方法来完成Service的最终启动,handleCreateService的源码如下所示:

private void handleCreateService(CreateServiceData data) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;

            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();

            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            service.onCreate();
            mServices.put(data.token, service);
            ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
    }

handleCreateService主要完成了以下几件事:
首先通过类加载器创建了Service实例,接着创建ContextImpl对象和Application对象 并通过service.attach方法建立联系,最后调用service.onCreate方法,并将service存储在ActivityThread中的一个列表mServices

 final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();

由于serviceonCreate方法执行了,也就意味着Service已经启动了。除此之外,ActivityThead中还会通过handleServiceArgs方法调用ServiceonStartCommand方法。

Service绑定过程

和启动过程一样,也是从ContextWrapper开始的:

@Override
public boolean bindService(Intent service, ServiceConnection conn,
        int flags) {
    return mBase.bindService(service, conn, flags);
}

然后是ContextImplbindService方法调用bindServiceCommon方法,然后远程调用AMS的bindService:

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler handler, UserHandle user) {
    // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
    IServiceConnection sd;
    if (conn == null) {
        throw new IllegalArgumentException("connection is null");
    }
    if (mPackageInfo != null) {
        sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
    } else {
        throw new RuntimeException("Not supported in system context");
    }
    validateServiceIntent(service);
    try {
        IBinder token = getActivityToken();
        if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                && mPackageInfo.getApplicationInfo().targetSdkVersion
                < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            flags |= BIND_WAIVE_PRIORITY;
        }
        service.prepareToLeaveProcess(this);
        int res = ActivityManager.getService().bindService(
            mMainThread.getApplicationThread(), getActivityToken(), service,
            service.resolveTypeIfNeeded(getContentResolver()),
            sd, flags, getOpPackageName(), user.getIdentifier());
        if (res < 0) {
            throw new SecurityException(
                    "Not allowed to bind to service " + service);
        }
        return res != 0;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

在该方法中,首先将客户端的ServiceConnection转化为ServiceDispatcher.InnerConnection对象,因为服务绑定是跨进程的,所以ServiceConnection对象必须借助Binder对象才能让远程服务端调用自己的方法。ServiceDispatcher起着连接ServiceConnectionInnerConnection的作用。这个过程由LoadedApk.getServiceDispatcher方法完成:

public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
            if (map != null) {
                if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
                sd = map.get(c);
            }
            if (sd == null) {
                sd = new ServiceDispatcher(c, context, handler, flags);
                if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
                if (map == null) {
                    map = new ArrayMap<>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();
        }
    }

在上面的代码中,mServices是一个ArrayMap,它存储了一个应用当前活动的ServiceConnectionServiceDispatcher的映射关系,其声明如下:

private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
        = new ArrayMap<>();

系统首先会查找是否存在相同的ServiceConnection,如果不存在就重新创建一个ServiceDispatcher对象,并将其存储在mServices中,其中映射关系的key是ServiceConnection,value是ServiceDispatcher,在ServiceDispatcher的内部又保存了ServiceConnectionInnerConnection对象。当Service和客户端建立连接后,系统会通过InnerConnection来调用ServiceConnection中的onServiceConnected方法,这个过程有可能是跨进程的。当ServiceDispatcher创建好了以后,getServiceDispatcher会 返回其保存的InnerConnection对象。
接着调用AMS的bindService 方法,该方法又调用了bindServiceLocked–>bringUpServiceLocked–>realStartServiceLocked,这个过程和上面的StartService过程逻辑类似,最终都是通过ApplicationThread来完成Service的实例创建并调用onCreate方法。和启动Service过程不同的是,绑定过程会调用app.threadscheduleBindService方法,这个过程的实现在ActivityServicerequestServiceBindingsLocked方法中:

 private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
            throws TransactionTooLargeException {
        for (int i=r.bindings.size()-1; i>=0; i--) {
            IntentBindRecord ibr = r.bindings.valueAt(i);
            if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
                break;
            }
        }
    }

该方法用到了r.bindings。它是一个ArrayMap,保存了客户端的bind消息:

final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings = new ArrayMap<Intent.FilterComparison, IntentBindRecord>();

具体保存方法在AMS一开始的方法bindServiceLocked中:

AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);

requestServiceBindingsLocked方法中调用了了requestServiceBindingLocked方法:

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
        if (r.app == null || r.app.thread == null) {
            // If service is not currently running, can't yet bind.
            return false;
        }
        if (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested
                + " rebind=" + rebind);
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
                if (!rebind) {
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            } catch (TransactionTooLargeException e) {
                // Keep the executeNesting count accurate.
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                throw e;
            } catch (RemoteException e) {
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                return false;
            }
        }
        return true;
    }

在上述代码中,app.thread这个对象多次出现过,它实际上就是ApplicationThreadApplicationThread的一系列以schedule开头的方法,其内部都是通过Handler H来中转的,对于scheduleBindService方法来说也是如此,它的实现如下所示:

public final void scheduleBindService(IBinder token, Intent intent,
                boolean rebind, int processState) {
            updateProcessState(processState, false);
            BindServiceData s = new BindServiceData();
            s.token = token;
            s.intent = intent;
            s.rebind = rebind;
            sendMessage(H.BIND_SERVICE, s);
        }

在H内部,接收到BIND_SERVICE这类消息时,会交给ActivityThreadhandleBindService方法来处理。在handleBindService中,首先根据Servicetoken取出Service对象,然后调用ServiceonBind方法,ServiceonBind方法会返回一个Binder对象给客户端使用,原则上来说,ServiceonBind方法被调用以后,Service就处于绑定状态了,但是onBind方法是Service的方法,这个时候客户端并不知道已经成功连接Service了,所以还必须调用客户端的ServiceConnection中的onServiceConnected,这个过程是由ActivityManager.getService()publishService方法来完成的,而前面多次提到,ActivityManager.getService()就是AMS。handleBindService的实现过程如下所示。

private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                try {
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to bind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }

Service有一个特性,当多次绑定同一个Service时,Service的onBind方法只会执行一次,除非Service被终止了。当Service的onBind执行以后,系统还需要告知客户端已经成功连接Service了。根据上面的分析,这个过程由AMS的publishService方法来实现:

public void publishService(IBinder token, Intent intent, IBinder service) {
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                throw new IllegalArgumentException("Invalid service token");
            }
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
    }

从_上面代码可以看出,AMS的publishService方法将具体的工作交给了ActiveServices类型的mServices对象来处理。ActiveServicespublishServiceLocked方法看起来很复杂,但其实核心代码就只有一- 句话: c.conn.connected(r.name,service), 其中c的类型是ConnectionRecordc.comn的类型是ServiceDispatcher.InnerConnection, service就是Service的onBind方法返回的Binder对象。为了分析具体的逻辑,下面看一下ServiceDispatcher.InnerConnection的定义:

private static class InnerConnection extends IServiceConnection.Stub {
            final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

            InnerConnection(LoadedApk.ServiceDispatcher sd) {
                mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
            }

            public void connected(ComponentName name, IBinder service, boolean dead)
                    throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service, dead);
                }
            }
        }

InnerConnection的定义可以看出来,它的connected方法又调用了ServiceDispatcherconnected方法

public void connected(ComponentName name, IBinder service, boolean dead) {
            if (mActivityThread != null) {
                mActivityThread.post(new RunConnection(name, service, 0, dead));
            } else {
                doConnected(name, service, dead);
            }
        }

对于Service的绑定过程来讲,ServiceDispatcher中的mActivityThread就是一个handler,它就是ActivityThread中的H,从Service的创建过程来讲,mActivityTHread不会为null,这样一来,RunConnection就可以经由Hpost方法从而运行在主线程中,因此,客户端的ServiceConnection中的方法回调是在主线程中执行的。

private final class RunConnection implements Runnable {
            RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
                mName = name;
                mService = service;
                mCommand = command;
                mDead = dead;
            }

            public void run() {
                if (mCommand == 0) {
                    doConnected(mName, mService, mDead);
                } else if (mCommand == 1) {
                    doDeath(mName, mService);
                }
            }

            final ComponentName mName;
            final IBinder mService;
            final int mCommand;
            final boolean mDead;
        }

很显然,RunConnectionrun方法也是简单调用了ServiceDispatcherdoConnected方法,由于ServiceDispatcher内部保存了客户端的ServiceConnection对象,因此它可以很方便地调用ServiceConnection对象的onServiceConnected方法,如下所示。
至此,bindService的过程完成。


以上

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值