美文网首页
Android进程间通信(六)——普通进程的bindServic

Android进程间通信(六)——普通进程的bindServic

作者: Boahui | 来源:发表于2021-07-15 21:49 被阅读0次

    ServiceConnection 的onServiceConnected返回的IBinder的流程

    代码参考Android进程间通信(一)——Binder机制和AIDL的理解,首先我们在客户端,通过bindService来获取指定应用的服务的IBinder对象。下面通过分析bindService的流程来确定返回的IBinder是哪个类
    源码github地址

        private ServiceConnection serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                isConnection = true;
                //调用IShowMessageAidlInterface.Stub.asInterface静态方法,将service转换为一接口
                mServer = IShowMessageAidlInterface.Stub.asInterface(service);
                Log.d("Client"," onServiceConnected success");
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                isConnection = false;
            }
        };
        private void attemptToBindService() {
            Intent intent = new Intent();
            intent.setClassName("com.binder.server", "com.binder.server.RemoteServiceUseAidl");
            bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
        }
    

    bindeService实际是调用ContextWrapper的bindService方法

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

    mBase的赋值是通过

        protected void attachBaseContext(Context base) {
            if (mBase != null) {
                throw new IllegalStateException("Base context already set");
            }
            mBase = base;
        }
    

    Activity的attach方法中调用了attachBaseContext

     final void attach(Context context, ActivityThread aThread,
                Instrumentation instr, IBinder token, int ident,
                Application application, Intent intent, ActivityInfo info,
                CharSequence title, Activity parent, String id,
                NonConfigurationInstances lastNonConfigurationInstances,
                Configuration config, String referrer, IVoiceInteractor voiceInteractor,
                Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
            attachBaseContext(context);
    

    可见传入了一个Context



    我们知道Context的实现类是ContextImpl,我们看下ContextImpl的bindService

        public boolean bindService(Intent service, ServiceConnection conn, int flags) {
            this.warnIfCallingFromSystemProcess();
            return this.bindServiceCommon(service, conn, flags, Process.myUserHandle());
        }
    

    bindServiceCommon

      private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, UserHandle user) {
            if (conn == null) {
                throw new IllegalArgumentException("connection is null");
            } else if (this.mPackageInfo != null) {
                IServiceConnection sd = this.mPackageInfo.getServiceDispatcher(conn, this.getOuterContext(), this.mMainThread.getHandler(), flags);
                this.validateServiceIntent(service);
    
                try {
                    IBinder token = this.getActivityToken();
                    if (token == null && (flags & 1) == 0 && this.mPackageInfo != null && this.mPackageInfo.getApplicationInfo().targetSdkVersion < 14) {
                        flags |= 32;
                    }
    
                    service.prepareToLeaveProcess();
                    int res = ActivityManagerNative.getDefault().bindService(this.mMainThread.getApplicationThread(), this.getActivityToken(), service, service.resolveTypeIfNeeded(this.getContentResolver()), sd, flags, user.getIdentifier());
                    if (res < 0) {
                        throw new SecurityException("Not allowed to bind to service " + service);
                    } else {
                        return res != 0;
                    }
                } catch (RemoteException var8) {
                    return false;
                }
            } else {
                throw new RuntimeException("Not supported in system context");
            }
        }
    

    注意这个IServiceConnection类,这个是一个IInteface接口,具有跨进程的能力,这个跨进程的IServiceConnection中也都一个Stub Binder类,作为服务端 ,Proxy在客户端作为代理,调用服务端。IServiceConnection.Stub的子类实现了connected方法。

    public interface IServiceConnection extends IInterface {
        void connected(ComponentName var1, IBinder var2) throws RemoteException;
    
        public abstract static class Stub extends Binder implements IServiceConnection {
            private static final String DESCRIPTOR = "android.app.IServiceConnection";
            static final int TRANSACTION_connected = 1;
    
            public Stub() {
                this.attachInterface(this, "android.app.IServiceConnection");
            }
    
            public static IServiceConnection asInterface(IBinder obj) {
                if (obj == null) {
                    return null;
                } else {
                    IInterface iin = obj.queryLocalInterface("android.app.IServiceConnection");
                    return (IServiceConnection)(iin != null && iin instanceof IServiceConnection ? (IServiceConnection)iin : new IServiceConnection.Stub.Proxy(obj));
                }
            }
    
            public IBinder asBinder() {
                return this;
            }
    
            public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
                switch(code) {
                case 1:
                    data.enforceInterface("android.app.IServiceConnection");
                    ComponentName _arg0;
                    if (0 != data.readInt()) {
                        _arg0 = (ComponentName)ComponentName.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
    
                    IBinder _arg1 = data.readStrongBinder();
                    this.connected(_arg0, _arg1);
                    return true;
                case 1598968902:
                    reply.writeString("android.app.IServiceConnection");
                    return true;
                default:
                    return super.onTransact(code, data, reply, flags);
                }
            }
    
            private static class Proxy implements IServiceConnection {
                private IBinder mRemote;
    
                Proxy(IBinder remote) {
                    this.mRemote = remote;
                }
    
                public IBinder asBinder() {
                    return this.mRemote;
                }
    
                public String getInterfaceDescriptor() {
                    return "android.app.IServiceConnection";
                }
    
                public void connected(ComponentName name, IBinder service) throws RemoteException {
                    Parcel _data = Parcel.obtain();
    
                    try {
                        _data.writeInterfaceToken("android.app.IServiceConnection");
                        if (name != null) {
                            _data.writeInt(1);
                            name.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }
    
                        _data.writeStrongBinder(service);
                        this.mRemote.transact(1, _data, (Parcel)null, 1);
                    } finally {
                        _data.recycle();
                    }
    
                }
            }
        }
    }
    
    

    我们知道,只有InnerConnection继承了IServiceConnection.Stub

            private static class InnerConnection extends Stub {//InnerConnection服务端的具体实现
                final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
    
                InnerConnection(LoadedApk.ServiceDispatcher sd) {
                    this.mDispatcher = new WeakReference(sd);
                }
                public void connected(ComponentName name, IBinder service) throws RemoteException {
                    LoadedApk.ServiceDispatcher sd = (LoadedApk.ServiceDispatcher)this.mDispatcher.get();
                    if (sd != null) {
                        sd.connected(name, service);
                    }
    
                }
            }
    
    static final class ServiceDispatcher {
            private final ServiceConnection mConnection;
            public void connected(ComponentName name, IBinder service) {
                if (this.mActivityThread != null) {
                    this.mActivityThread.post(new LoadedApk.ServiceDispatcher.RunConnection(name, service, 0));
                } else {
                    this.doConnected(name, service);
                }
    
            }
    
            private final class RunConnection implements Runnable {
                final ComponentName mName;
                final IBinder mService;
                final int mCommand;
    
                RunConnection(ComponentName name, IBinder service, int command) {
                    this.mName = name;
                    this.mService = service;
                    this.mCommand = command;
                }
    
                public void run() {
                    if (this.mCommand == 0) {
                        ServiceDispatcher.this.doConnected(this.mName, this.mService);
                    } else if (this.mCommand == 1) {
                        ServiceDispatcher.this.doDeath(this.mName, this.mService);
                    }
    
                }
            }
    

    ServiceDispatcher

     public void doConnected(ComponentName name, IBinder service) {
                LoadedApk.ServiceDispatcher.ConnectionInfo old;
                synchronized(this) {
                    if (this.mForgotten) {
                        return;
                    }
    
                    old = (LoadedApk.ServiceDispatcher.ConnectionInfo)this.mActiveConnections.get(name);
                    if (old != null && old.binder == service) {
                        return;
                    }
    
                    if (service != null) {
                        this.mDied = false;
                        LoadedApk.ServiceDispatcher.ConnectionInfo info = new LoadedApk.ServiceDispatcher.ConnectionInfo();
                        info.binder = service;
                        info.deathMonitor = new LoadedApk.ServiceDispatcher.DeathMonitor(name, service);
    
                        try {
                            service.linkToDeath(info.deathMonitor, 0);
                            this.mActiveConnections.put(name, info);
                        } catch (RemoteException var8) {
                            this.mActiveConnections.remove(name);
                            return;
                        }
                    } else {
                        this.mActiveConnections.remove(name);
                    }
    
                    if (old != null) {
                        old.binder.unlinkToDeath(old.deathMonitor, 0);
                    }
                }
    
                if (old != null) {
                    this.mConnection.onServiceDisconnected(name);//
                }
    
                if (service != null) {
                    this.mConnection.onServiceConnected(name, service);//回调到客户端端的ServiceConnection.onServiceConnected
                }
    
            }
    

    我们再看下 IServiceConnection sd = this.mPackageInfo.getServiceDispatcher(conn, this.getOuterContext(), this.mMainThread.getHandler(), flags);
    做了什么

        public final IServiceConnection getServiceDispatcher(ServiceConnection c, Context context, Handler handler, int flags) {
            synchronized(this.mServices) {
                LoadedApk.ServiceDispatcher sd = null;
                ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = (ArrayMap)this.mServices.get(context);
                if (map != null) {
                    sd = (LoadedApk.ServiceDispatcher)map.get(c);
                }
    
                if (sd == null) {
                    sd = new LoadedApk.ServiceDispatcher(c, context, handler, flags);
                    if (map == null) {
                        map = new ArrayMap();
                        this.mServices.put(context, map);
                    }
    
                    map.put(c, sd);
                } else {
                    sd.validate(context, handler);
                }
    
                return sd.getIServiceConnection();
            }
        }
    

    LoadedApk.ServiceDispatcher用于封装ServiceConnection,服务端通过IServiceConnection 通过跨进程将服务的IBinder对象发送给客户端,相当于回调。目前我们已经知道ServiceConnection的onServiceConnected是通过跨进程被调用的。下面我们继续看客户端发送流程

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

    ActivityManager.java

        public static IActivityManager getService() {
            return IActivityManagerSingleton.get();
        }
    
        private static final Singleton<IActivityManager> IActivityManagerSingleton =
                new Singleton<IActivityManager>() {
                    @Override
                    protected IActivityManager create() {
                        final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);//从ServiceManager获取AMS的IBinder,返回一个IActivityManager的代理对象
                        final IActivityManager am = IActivityManager.Stub.asInterface(b);
                        return am;
                    }
                };
    
    

    所以,bindService实际是通过Binder跨进程调用到了AMS中的bindService
    ActivityManagerService

     final ActiveServices mServices;
     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) {
                return mServices.bindServiceLocked(caller, token, service,
                        resolvedType, connection, flags, callingPackage, userId);
            }
        }
    

    ActiveServices

    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
                String resolvedType, final IServiceConnection connection, int flags,
                String instanceName, String callingPackage, final int userId)
                throws TransactionTooLargeException {
    ......
        AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
                //c持有IServiceConnection
                ConnectionRecord c = new ConnectionRecord(b, activity,
                        connection, flags, clientLabel, clientIntent,
                        callerApp.uid, callerApp.processName, callingPackage);
    
                IBinder binder = connection.asBinder();
                //ServiceRecord持有binder和ConnectionRecord
                s.addConnection(binder, c);
                b.connections.add(c);
                if (activity != null) {
                    activity.addConnection(c);
                }
                b.client.connections.add(c);
    
                if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                    s.lastActivity = SystemClock.uptimeMillis();
                    //1、s为ServiceRecord持有IServiceConnection
                    if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                            permissionsReviewRequired) != null) {
                        return 0;
                    }
    
    
        private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
                boolean whileRestarting, boolean permissionsReviewRequired)
                throws TransactionTooLargeException {
     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);
    
                        //2、启动服务
                        realStartServiceLocked(r, app, execInFg);
                        return null;
                    } catch (TransactionTooLargeException e) {
                        throw e;
                    } catch (RemoteException e) {
                        Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
                    }
    
                    // If a dead object exception was thrown -- fall through to
                    // restart the application.
                }
    
      private final void realStartServiceLocked(ServiceRecord r,
                ProcessRecord app, boolean execInFg) throws RemoteException {
            if (app.thread == null) {
    ......
      //3、app.thread=ApplicationThread  Binder通信
                //r ServiceRecord 是Binder子类  通过跨进程通信,将ServiceRecord传递给服务端App  
              //ProcessRecord app 
             // thread 为IApplicationThread,这是一个AIDL文件,具体的实现是IApplicationThread.Stub的子类ApplicationThread
                app.thread.scheduleCreateService(r, r.serviceInfo,
                        mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                        app.getReportedProcState());
             
    .....
    

    我们看ApplicationThread是如何创建Service的

    public final void scheduleCreateService(IBinder token,
                    ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
                updateProcessState(processState, false);
                CreateServiceData s = new CreateServiceData();
                //token表示ServiceRecord Binder
                s.token = token;
                s.info = info;
                s.compatInfo = compatInfo;
    
                sendMessage(H.CREATE_SERVICE, s);
            }
    //查找CREATE_SERVICE对应的case
      case CREATE_SERVICE:
                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
                        handleCreateService((CreateServiceData)msg.obj);
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        break;
    
     //data持有ServiceRecord
        @UnsupportedAppUsage
        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;
            try {
                java.lang.ClassLoader cl = packageInfo.getClassLoader();
                service = packageInfo.getAppFactory()
                        .instantiateService(cl, data.info.name, data.intent);//创建一个Service对象
            } catch (Exception e) {
                if (!mInstrumentation.onException(service, e)) {
                    throw new RuntimeException(
                        "Unable to instantiate service " + data.info.name
                        + ": " + e.toString(), e);
                }
            }
    
            try {
                if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
    
                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,
                        ActivityManager.getService());
                service.onCreate();//调用service的onCreate
                mServices.put(data.token, service);//保存创建好的Service到mServices中
    

    到目前为止,服务端的Service创建完成,并且调用了onCreate方法。继续看

    private final void realStartServiceLocked(ServiceRecord r,
               ProcessRecord app, boolean execInFg) throws RemoteException {
           if (app.thread == null) {
    ........
    //开始进行Service的绑定
           requestServiceBindingsLocked(r, execInFg);
    ........
    
        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;
                }
            }
        }
    
    
        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);
                    //服务端执行scheduleBindService
                    r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                            r.app.getReportedProcState());
    

    app.thread.scheduleBindService仍然是调用到服务端进程的ApplicationThread的scheduleBindService

     public final void scheduleBindService(IBinder token, Intent intent,
                    boolean rebind, int processState) {
                updateProcessState(processState, false);
                BindServiceData s = new BindServiceData();
                //token ServiceRecord
                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);
            }
    

    找到BIND_SERVICE对应的case

          break;
                    case BIND_SERVICE:
                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                        handleBindService((BindServiceData)msg.obj);
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        break;
    
     private void handleBindService(BindServiceData data) {
            Service s = mServices.get(data.token);//在handCreateService中创建完Service就保存到mService中了
            //s为通过bindService创建好的Service
            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) {
                            IBinder binder = s.onBind(data.intent);
                            //跨进程调用toekn为客户端进程,binder为IBinder
                            ActivityManager.getService().publishService(
                                    data.token, data.intent, binder);
                        } else {
    

    服务端调用AMS进程的publishService

        final ActiveServices mServices;
        //token为客户端的token,service为服务端的Service
        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);
            }
        }
    

    调用ActiveServices 的publishServiceLocked

    
        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;
                        ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
                        for (int conni = connections.size() - 1; conni >= 0; conni--) {
                            ArrayList<ConnectionRecord> clist = 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 {
                                    //从AMS中,拿到IServiceConnection.调用connected就调用到了客户端ServiceConnection onServiceConnected
                                    c.conn.connected(r.name, service, false);
    

    至此服务端把Service通过Binder传递给了客户端。我们发现整个流程涉及了客户端进程、AMS进程、服务端进程。
    涉及的Binder子类有AMS,IServiceConnection,AppicationThread,服务端。所以说Binder是Android中重要的机制,因为系统跨进程到处都需要用到Binder通信。

    相关文章

      网友评论

          本文标题:Android进程间通信(六)——普通进程的bindServic

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