美文网首页
[Android]从一个简单的AIDL实现看binder原理(三

[Android]从一个简单的AIDL实现看binder原理(三

作者: dafasoft | 来源:发表于2020-11-20 12:47 被阅读0次

参考链接:

从一个简单的AIDL实现看binder原理(一)简单的AIDL实现
从一个简单的AIDL实现看binder原理(二)bindService的调用过程

BindService时Binder的转换

我们分析上面链接中的aidl实现案例,在bindService时打印一下日志:

/*** MainActivity */
ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d("ipcLog", "service = " + service.getClass().getName());
            proxy = IAIDLInterface.Stub.asInterface(service);
            Log.d("ipcLog", "proxy = " + proxy.getClass().getName());
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

/*** RemoteService */
@Nullable
    @Override
    public IBinder onBind(Intent intent) {
        StudentStub stub = new StudentStub();
        Log.d("ipcLog", "stub = " + stub.getClass());
        return stub;
    }
    public class StudentStub extends IAIDLInterface.Stub {
        @Override
        public List<Student> getStudent() throws RemoteException {
            return studentList;
        }

        @Override
        public void setStudent(Student student) throws RemoteException {
            studentList.add(student);
        }
    }

打印出的日志结果:
在org.hrcy.ipctest进程中:


image.png

在org.hrcy.ipctest:remote进程中:


image.png

在demo中我们可以看到,StudentStub 继承于IAIDLInterface.Stub, IAIDLInterface.Stub 继承于android.os.Binder 也就是说 StudentStub是一个Binder对象,而在MainActivity打印出的log中我们看到,onServiceConnected方法接收到的是个BinderProxy,我们需要知道这个转换是在哪里发生的

我们回顾一下上一篇博文:

bindService的调用过程

在这边文章里,我们找到了Service最终执行的地方,但是具体是怎么执行的还没有具体分析,下面我们分析一下onBind方法的具体执行

从ActivityThread#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) {
                        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);
                }
            }
        }
    }

我们看第15行,从之前的分析我们可以知道,s.onBind方法执行的就是Service的onBind方法,在这里,onBind方法返回了一个Binder对象,接着执行了

 ActivityManager.getService().publishService(data.token, data.intent, binder);

将获得的binder对象发送了出去,ActivityManager.getService()其实就是ActivityManagerService,这里是一个IPC的过程,具体细节不表,我们直接转到ActivityManagerService中看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);
        }
    }

在代码的第11行,这里转到了ActiveServices#publishServiceLocked执行,我们看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;
                    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找到要进行通信的进程信息
                            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 {
                                // 通过connectionRecord中的conn与目标进程建立连接
                                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);
        }
    }

这个方法主要是通过需要ConnectionRecord找到与Service进行绑定的目标进程,那么就会有同学发问了,这个ConnectionRecord是在哪里进行添加记录的呢?答案就是在我们在发起bindService的过程中,在上篇博文中我们讲到,在我们发戚bindService的过程中,会执行ActivityServices#bindServiceLocked方法,我们回顾一下这个方法:

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) throws TransactionTooLargeException {
        
           // 省略1万字

            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 (activity != null) {
                if (activity.connections == null) {
                    activity.connections = new HashSet<ConnectionRecord>();
                }
                activity.connections.add(c);
            }
            b.client.connections.add(c);
            if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
                b.client.hasAboveClient = true;
            }
            if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
                s.whitelistManager = true;
            }
            if (s.app != null) {
                updateServiceClientActivitiesLocked(s.app, c, true);
            }
            clist = mServiceConnections.get(binder);
            if (clist == null) {
                clist = new ArrayList<ConnectionRecord>();
                mServiceConnections.put(binder, clist);
            }
            clist.add(c);

           // 省略1万字

        return 1;
    }

去掉其他代码后,这部分就是在启动Service时记录的启动Service的进程和该进程的其他信息,看到这里我们就能理解bindService的执行时序了:


bindService执行的大致过程

回到之前的分析,在通过ConnectionRecord找到目标进城后,就要进行IPC调用对目标进程进行关联了,继续循着ActiveServices#publishServiceLocked方法进行分析,通过ConnectionRecord找到目标进程的IServiceConnection,IServiceConnection类长这样:


image.png

看到这种格式就知道,IServiceConnection类是AIDL生成的,它Service端的实现是InnerConnection,
InnerConnection是ServiceDispatcher的内部类,ServiceDispatcher是LoadedApk的内部类,LoadedApk是目标进程APK在内存中的具体实现,回到ActiveServices#publishServiceLocked方法的解析,在这个方法中调用
c.conn.connected(r.name, service, false),这是一次IPC过程,从AMS进程跨进程调用到了启动要绑定Service的进程,那么connected方法的实现就一定是在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);
                }
            }
        }

在connected这里调用了ServiceDispatcher#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);
            }
        }

在这里调用了doConnected方法:

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

            synchronized (this) {
                if (mForgotten) {
                    // We unbound before receiving the connection; ignore
                    // any connection received.
                    return;
                }
                old = mActiveConnections.get(name);
                if (old != null && old.binder == service) {
                    // Huh, already have this one.  Oh well!
                    return;
                }

                if (service != null) {
                    // A new service is being connected... set it all up.
                    info = new ConnectionInfo();
                    info.binder = service;
                    info.deathMonitor = new DeathMonitor(name, service);
                    try {
                        service.linkToDeath(info.deathMonitor, 0);
                        mActiveConnections.put(name, info);
                    } catch (RemoteException e) {
                        // This service was dead before we got it...  just
                        // don't do anything with it.
                        mActiveConnections.remove(name);
                        return;
                    }

                } else {
                    // The named service is being disconnected... clean up.
                    mActiveConnections.remove(name);
                }

                if (old != null) {
                    old.binder.unlinkToDeath(old.deathMonitor, 0);
                }
            }

            // If there was an old service, it is now disconnected.
            if (old != null) {
                mConnection.onServiceDisconnected(name);
            }
            if (dead) {
                mConnection.onBindingDied(name);
            }
            // If there is a new service, it is now connected.
            if (service != null) {
                mConnection.onServiceConnected(name, service);
            }
        }

看这个方法的最后一句,我们终于找到了onServiceConnected的执行了

我们看一下bindService具体执行的时序图:


image.png

可以看到,bindService的整个执行进行了四次进程跨越,可以说是非常复杂了,但是我们在这个过程中依然没有分析出来Binder是在什么时机转换为BinderProxy的,篇幅有限,下一节再讲吧

相关文章

网友评论

      本文标题:[Android]从一个简单的AIDL实现看binder原理(三

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