必威体育Betway必威体育官网
当前位置:首页 > IT技术

Android组件管理框架—后台服务Service之bindService方式启动流程(Android P)

时间:2019-10-16 17:43:21来源:IT技术作者:seo实验室小编阅读:54次「手机版」
 

bindservice

一 前言

通过startservice来启动一个service,通常该service是无法返回结果的(这也是与bindservice的区别之一),服务开启, 这个服务和开启他的调用者之间就没有任何的关系了,调用者的生命周期和它的生命周期也没有关系(所以,service在任务完成的时调用stopSelf或stopsService来结束该服务)。

通过bindservice来和service绑定,绑定后可以和service交互,发送请求,得到结果甚至执行IPC通信。由于调用者和绑定者绑在一起,调用者一旦退出该服务也就终止了。

可以先看Android组件管理框架—后台服务Service之startService方式启动流程(android p)。

二 图示调用流程

图示调用流程展示的是主要调用流程。

代码具体流程

调用者调用bindService后将会调用下面的方法。

1 frameworks/base/core/java/android/content/contextWrAPPer.java

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

这里mBase变量是ContextImpl类型,是在创建activity的时候,new 一个ContextImpl对象,赋值给activity的。

2 frameworks/base/core/java/android/app/ContextImpl.java

@Override
public boolean bindService(Intent service, ServiceConnection conn,
        int flags) {
    warnIfcallingFromSystemProcess();
    return bindServiceCommon(service, conn, flags, mMainThread.gethandler(), getUser());
}

看bindServiceCommon里的mMainThread.getHandler,其中mMainTharead是activitythread的实例,可以先看下 mMainThread.getHandler的方法。

3 frameworks/base/core/java/android/app/ActivityThread.java

final H mH = new H();
final Handler getHandler() {
    return mH;
}

这个是ActivityThread的内部类H的实例,H类继承Hander。

接着看上面的bindServiceCommon方法。

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) {
            //位置1
            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);
        //位置2
        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();
    }
}

先看位置1的mPackageInfo.getServiceDispatcher 。

4 frameworks/base/core/java/android/app/LoadedApk.java

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();
    }
}

在getServiceDispatcher函数中,传进来的参数context是一个调用bindService的activity实例,先以它为Key值在mServices中查看是否已经存在相应的ServiceDispatcher实例,如果有则不用创建直接取出。在该情景中,需要创建一个新的ServiceDispatcher。在创建新的ServiceDispatcher实例过程中,将上面传下来ServiceConnection参数c和Hanlder参数保存在ServiceDispatcher实例的内部,并创建一个InnerConnection对象,它是一个Binder对象,会传递给ActivityManagerService,ActivityManagerServic后续则要通过该Binder对象和ServiceConnection通信。函数getServiceDispatcher最后就是返回了一个InnerConnection对象给ContextImpl.bindService函数。回到ContextImpl.bindService函数中,它接着就要调用ActivityManagerService的远程接口来进一步处理。

看一下ServiceDispatcher,是LoadedApk的内部类。

static final class ServiceDispatcher {
    private final ServiceDispatcher.InnerConnection mIServiceConnection;
    private final ServiceConnection mConnection;
    private final Context mContext;
    private final Handler mActivityThread;
    private final ServiceConnectionLeaked mLocation;
    private final int mFlags;

    private RuntimeException mUnbindLocation;

    private boolean mForgotten;

    private static class ConnectionInfo {
        IBinder binder;
        IBinder.DeathRecipient deathmonitor;
    }

    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);
            }
        }
    }
    ...
}

LoadedApk、ServiceDispatcher、ServiceDispatcher.InnerConnection、ServiceConnection之间的具体关系暂不讨论。

再看位置2的ActivityManager.getService().bindService,返回的ActivityManagerService实例和startActivity的流程是一样的,所以直接看ActivityManagerService的bindService方法。

5 frameworks/base/core/java/android/app/ActivityManager.java

6 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

调用到系统进程来了。

public int bindService(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, IServiceConnection connection, int flags, String callingPackage,
        int userId) throws transactionTooLargeException {
    enforceNotIsolatedCaller("bindService");

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

    if (callingPackage == null) {
        throw new IllegalArgumentException("callingPackage cannot be null");
    }

    synchronized(this) {
        //位置1
        return mServices.bindServiceLocked(caller, token, service,
                resolvedType, connection, flags, callingPackage, userId);
    }
}

位置1的mServices是ActiveServices的实例,看它的调用方法bindServiceLocked。

7 frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, final IServiceConnection connection, int flags,
        String callingPackage, final int userId) throws TransactionTooLargeException {
    if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
            + " type=" + resolvedType + " conn=" + connection.asBinder()
            + " flags=0x" + integer.toHexString(flags));
    final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
    if (callerApp == null) {
        throw new SecurityException(
                "Unable to find app for caller " + caller
                + " (pid=" + Binder.getCallingPid()
                + ") when binding service " + service);
    }

    ActivityRecord activity = null;
    if (token != null) {
        activity = ActivityRecord.isInStackLocked(token);
        if (activity == null) {
            Slog.w(TAG, "Binding with unknown activity: " + token);
            return 0;
        }
    }

    int clientLabel = 0;
    PendingIntent clientIntent = null;
    final boolean isCallerSystem = callerApp.info.uid == Process.SYSTEM_UID;
    //retrieveServiceLocked解析service这个Intent,也是解析Androidmanifest.xml定义的
    //Service标签的intent-filter相关内容,将解析结果放在res.record中。
    ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType,
                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true);
    ...
    try {
        ...
        mAm.startassociationLocked(callerApp.uid, callerApp.processName, callerApp.curProcState,
                s.appInfo.uid, s.name, s.processName);
        // Once the apps have become associated, if one of them is caller is ephemeral
        // the target app should now be able to see the calling app
        mAm.grantEphemeralAccessLocked(callerApp.userId, service,
                s.appInfo.uid, UserHandle.getAppId(callerApp.uid));

        AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
        ConnectionRecord c = new ConnectionRecord(b, activity,
                connection, flags, clientLabel, clientIntent);

        IBinder binder = connection.asBinder();
        ArrayList<ConnectionRecord> clist = s.connections.get(binder);
        if (clist == null) {
            clist = new ArrayList<ConnectionRecord>();
            s.connections.put(binder, clist);
        }
        clist.add(c);
        b.connections.add(c);
        ...
        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
            s.lastActivity = SystemClock.uptimeMillis();
            //位置1
            if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                    permissionsreviewrequired) != null) {
                return 0;
            }
        }
        ...
    } finally {
        Binder.restoreCallingIdentity(origId);
    }

    return 1;
}

函数首先根据传进来的参数token是启动service的activity在ActivityManagerService里面的一个令牌,通过这个令牌就可以将这个activity对应的的ActivityRecord取回来。

看位置1的bringUpServiceLocked。

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting, boolean permissionsReviewRequired)
        throws TransactionTooLargeException {
    //Slog.i(TAG, "bring up service:");
    //r.dump("  ");

    if (r.app != null && r.app.thread != null) {
        sendServiceArgsLocked(r, execInFg, false);
        return null;
    }
    ...
    final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
    final String procName = r.processName;
    String hostingType = "service";
    ProcessRecord app;

    if (!isolated) {
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                    + " app=" + app);
        if (app != null && app.thread != null) {
            try {
                app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
                //位置1
                realStartServiceLocked(r, app, execInFg);
                return null;
            } catch (TransactionTooLargeException e) {
                throw e;
            } 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.
        }
    ...
    }
    ...
    return null;
}

看位置1的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);
    updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
    mAm.updateOomAdjLocked();

    boolean created = false;
    try {
        ...
        //位置1
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.repProcState);
        r.postnotification();
        created = true;
    ...
    }

    if (r.whitelistManager) {
        app.whitelistManager = true;
    }
    //位置2
    requestServiceBindingsLocked(r, execInFg);
    ...
    //位置3
    sendServiceArgsLocked(r, execInFg, true);
    ...
}

位置1的scheduleCreateService与startService的流程是一样的,可以回看之前的Android组件管理框架—后台服务Service之startService方式启动流程(Android P)。位置1的scheduleCreateService方法最终会调到Service的onCreate方法;位置3的scheduleCreateService方法最终会调到Service的onStartCommond方法。我们看位置2的requestServiceBindingsLocked方法。

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);
        //位置1
        if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
            break;
        }
    }
}

看位置1的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);
            //位置1
            r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                    r.app.repProcState);
            ...
        }
        ...
    return true;
} 

看位置1的app.thread.scheduleBindService,r.app.thread是ApplicationThread的实例,ApplicationThread是ActivityThread的内部类。

8 frameworks/base/core/java/android/app/ActivityThread.java

调用到调用者对应的进程。

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;

    if (DEBUG_SERVICE)
        Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
                    + Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
    sendmessage(H.BIND_SERVICE, s);
}

发送消息H.BIND_SERVICE。H也是ActivityThread的内部类,并继承Handler。

case BIND_SERVICE:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
    handleBindService((BindServiceData)msg.obj);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;

接收到这个消息后进行处理,调用handleBindService方法。

 private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (DEBUG_SERVICE)
            Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                try {
                    if (!data.rebind) {
                        //位置1
                        IBinder binder = s.onBind(data.intent);
                        //位置2
                        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);
                }
            }
        }
    }

位置1的onBind方法。

9 frameworks/base/core/java/android/app/Service.java

/**
* Return the communication channel to the service.  May return null if 
* clients can not bind to the service.  The returned
* {@link android.os.IBinder} is usually for a complex interface
* that has been <a href="{@docRoot}guide/components/aidl.html">described using
* aidl</a>.
* 
* <p><em>Note that unlike other application components, calls on to the
* IBinder interface returned here may not happen on the main thread
* of the process</em>.  More information about the main thread can be found in
* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and
* Threads</a>.</p>
* 
* @param intent The Intent that was used to bind to this service,
* as given to {@link android.content.Context#bindService
* Context.bindService}.  Note that any extras that were included with
* the Intent at that point will <em>not</em> be seen here.
* 
* @return Return an IBinder through which clients can call on to the 
*         service.
*/
@Nullable
public abstract IBinder onBind(Intent intent);

位置2的ActivityManager.getService().publishService。

10 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

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

mServices.publishServiceLocked。

11 frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
    final long origId = Binder.clearCallingIdentity();
    try {
        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
                + " " + intent + ": " + service);
        if (r != null) {
            Intent.FilterComparison filter
                    = new Intent.FilterComparison(intent);
            IntentBindRecord b = r.bindings.get(filter);
            if (b != null && !b.received) {
                b.binder = service;
                b.requested = true;
                b.received = true;
                for (int conni=r.connections.size()-1; conni>=0; conni--) {
                    ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                    for (int i=0; i<clist.size(); i++) {
                        ConnectionRecord c = clist.get(i);
                        if (!filter.equals(c.binding.intent.intent)) {
                            if (DEBUG_SERVICE) Slog.v(
                                    TAG_SERVICE, "Not publishing to: " + c);
                            if (DEBUG_SERVICE) Slog.v(
                                    TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
                            if (DEBUG_SERVICE) Slog.v(
                                    TAG_SERVICE, "Published intent: " + intent);
                            continue;
                        }
                        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                        try {
                            //位置1
                            c.conn.connected(r.name, service, false);
                        } catch (Exception e) {
                            Slog.w(TAG, "Failure sending service " + r.name +
                                    " to connection " + c.conn.asBinder() +
                                    " (in " + c.binding.client.processName + ")", e);
                        }
                    }
                }
            }
            
            serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
        }
    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}

位置1的 c.conn.connected。conn,它的类型是IServiceConnection,是一个Binder对象的远程接口,也是前面创建的LoadedApk.ServiceDispatcher.InnerConnection对象。

12 frameworks/base/core/java/android/app/LoadedApk.java

InnerConnection是LoadedApk的内部类。

static final class ServiceDispatcher {
    private final ServiceDispatcher.InnerConnection mIServiceConnection;
    ...

    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);
            }
        }
    }
    ...
}

sd.connected。

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

mActivityThread.post。

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);
        }
    }
    ...
}

doConnected。

public void doConnected(ComponentName name, IBinder service, boolean dead) {
    ServiceDispatcher.ConnectionInfo old;
    ServiceDispatcher.ConnectionInfo info;

    synchronized (this) {
    ...
    // If there is a new service, it is now connected.
    if (service != null) {
        mConnection.onServiceConnected(name, service);
    }
}

mConnection.onServiceConnected(name, service),把service这个Binder对象传到activity中。

service 已经onCreate()和onBind(),同时,绑定服务时,服务返回的Binder对象也接收到了。

三 总结

ServiceDispatcher    类似于一个Dispatcher的作用,这个类的作用就是当client bind某个service成功之后,负责向client分配service IBinder的;以及当client unbind service时,负责通知client unbind service的状态。

InnerConnection     它是一个Binder对象,会传递给ActivityManagerService,ActivityManagerServic后续则要通过该Binder对象和ServiceConnection通信。

相关阅读

Android获取应用签名(开发版SHA1和发布版SHA1)

当我们需要接入百度地图等一系列需要开发版SHA1和发布版SHA1才能创建完成应用的时候,如果找不到开发版SHA1和发布版SHA1是不是很苦

android:state_pressed是什么意思?

是当控件被按下的时候控件的表示,可以实现按下按钮时,按钮变成领一个模样,松开之后又恢复原样。类似的还有:android:state_focused是

Android模块添加依赖后无法找到的原因(implementation

Android模块添加依赖后无法找到的原因(implementation和api的区别) 场景: Android3.0以上,例如在BaseLibrary中添加了 dependencies {

几种常见的Web service服务(接口)简介

Web service服务(接口)一.定义Web service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用

Android 网络编程(一) 网络基本知识的了解

文章目录引言OSI 七层网络模型物理层数据链路层网络层传输层会话层表达层应用层TCP/IP 四层模型IP 协议TCP 协议TCP 的三次握手与

分享到:

栏目导航

推荐阅读

热门阅读