美文网首页
bindService源码分析

bindService源码分析

作者: _浮生若梦 | 来源:发表于2020-06-08 09:52 被阅读0次
image.png

声明:图是借来的。
按时序图的顺序分析:

Activity

Activity是ContextWrapper的间接子类,在Activity中调用bindService其实是调用的ContextWrapper类中的bindService方法:

ContextWrapper:
Context mBase;
...
public boolean bindService(Intent service, ServiceConnection conn,
        int flags) {
    return mBase.bindService(service, conn, flags);
}

mBase是Context对象,在Context类中bindService是一个抽象方法,所以这里调用的是Context实现类即ContextImpl类的bindService方法:

ContextImpl.java:
public boolean bindService(Intent service, ServiceConnection conn,
        int flags) {
    warnIfCallingFromSystemProcess();
    return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), getUser());
}

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

在bindServiceCommon中,mPackageInfo为LoadedApk的实例,在ContextImpl实例化的时候初始化,一般不为null,所以会执行sd = mPackageInfo.getServiceDispatcher:

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

sd.getIServiceConnection返回的真实类型是ServiceDispatcher.InnerConnection。

LoadedApk.java:
ServiceDispatcher:
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);
            }
        }
    }

    IServiceConnection getIServiceConnection() {
        return mIServiceConnection;
    }
...
}

这里先记住,在ContextImpl中的bindServiceCommon方法中,sd得到的是ServiceDispatcher.InnerConnection类型的实例,这个实例中包含了传来的ServiceConnection。接下来回到ContextImpl中的bindServiceCommon中,看看接下来做了些什么:

int res = ActivityManager.getService().bindService(
            mMainThread.getApplicationThread(), getActivityToken(), service,
            service.resolveTypeIfNeeded(getContentResolver()),
            sd, flags, getOpPackageName(), user.getIdentifier());

ActivityManager.getService返回的就是AMS,所以这里调用的是AMS中的bindService,继续跟代码,发现调用的是ActiveServices中的requestServiceBIndingLocked方法:

ActivityManagerService.java:
public int bindService(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, IServiceConnection connection, int flags, String callingPackage,
        int userId) throws TransactionTooLargeException {
    ...

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

ActiveServices.java:
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
        boolean execInFg, boolean rebind) throws TransactionTooLargeException {
    ...
            r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                    r.app.repProcState);
           ...
    return true;
}

到这里看到了比较眼熟的东西:r.app.thread.scheduleBindService,其实就是ActivityThread的scheduleBindService:

ActivityThread.java:
public final void scheduleBindService(IBinder token, Intent intent,
            boolean rebind, int processState) {
        ...
        sendMessage(H.BIND_SERVICE, s);
    }

通过handler,然后调用:

private void handleBindService(BindServiceData data) {
     ...
                    ActivityManager.getService().publishService(
                            data.token, data.intent, binder);
    ...
}

经过上面的分析,我们已经知道,这里其实就是调用的AMS中的publishService方法:

ActivityManagerService.java:
public void publishService(IBinder token, Intent intent, IBinder service) {
    ...
        mServices.publishServiceLocked((ServiceRecord)token, intent, service);
    }
}

ActiveServices.java:
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
    ...
                            c.conn.connected(r.name, service, false);
    ...
}

到最后,会从传来的参数中获取到conn对象,然后调用connected方法,这里就是回调的ServiceDispatcher.InnerConnection类的connected方法,然后调用ServiceDispatcher中的connected方法,进而回调从Activity中传入的ServiceConnection的回调方法如onServiceConnected等。
至此,bindservice流程分析完毕。

相关文章

网友评论

      本文标题:bindService源码分析

      本文链接:https://www.haomeiwen.com/subject/wlxltktx.html