美文网首页源码分析
Android系统源码--bindService()过程

Android系统源码--bindService()过程

作者: 风咏而归 | 来源:发表于2018-05-11 12:34 被阅读0次

    前言

    在做Android开发过程中,我们经常使用bindService()绑定服务,并且通过返回的Binder对象进行多进程间通信。

    ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // service是怎么来的?
            media = IMedia.Stub.asInterface(service);
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
            media = null;
        }
    };
    Intent intent = new Intent(this, MediaService.class);
    bindService(intent, conn, Context.BIND_AUTO_CREATE);
    

    但是我很好奇这个Binder对象service是怎么被返回的?带着这个疑问去系统源码里寻找答案,然后就有了这篇bindService()过程分析。

    第一步 android.app.ContextImpl.java

    首先bindService(intent, conn, Context.BIND_AUTO_CREATE)实际上是调用了ContextImpl里的bindService(...)方法

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

    接着又调用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) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } 
       ...
       int res = ActivityManager.getService().bindService(
            mMainThread.getApplicationThread(), getActivityToken(), service,
            service.resolveTypeIfNeeded(getContentResolver()),
            sd, flags, getOpPackageName(), user.getIdentifier());
       ...
       return res != 0;
    }
    

    通过调用ActivityManager.getService().bindService(...)跨进程进入到ActivityManagerServicebindService(...)方法,第三步将接着这里分析。
    另外,bindService(...)传入了一个重要的参数sd,那么sd是怎么获取的?它的具体类型是什么呢?请看第二步

    第二步 android.app.LoadedApk.java

    首先mPackageInfo是一个LoadedApk类型对象,sd是通过调用mPackageInfogetServiceDispatcher(...)方法获取的

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

    直接进入到LoadedApk.ServiceDispatchergetIServiceConnection()方法

    static final class ServiceDispatcher {
    
        private final Handler mActivityThread;
    
        ServiceDispatcher(ServiceConnection conn,
                Context context, Handler activityThread, int flags) {
            // mIServiceConnection的类型是InnerConnection
            mIServiceConnection = new InnerConnection(this);
            mConnection = conn;
            mContext = context;
            mActivityThread = activityThread;
            mLocation = new ServiceConnectionLeaked(null);
            mLocation.fillInStackTrace();
            mFlags = flags;
        }
    
        IServiceConnection getIServiceConnection() {
            return 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);
                }
            }
        }
    }
    

    通过上面的代码可知,sdServiceDispatcher.InnerConnection类型的对象,这个sd后面的讲解还会用到。

    第三步 com.android.server.am.ActivityManagerService.java

    第一步中ContextImpl通过跨进程通信进入到了ActivityManagerServicebindService(...)方法

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

    然后mServices是一个ActiveServices对象、bindService (...)就直接转交给了ActiveServicesbindServiceLocked(...)

    第四步 com.android.server.am.ActiveServices.java

    bindServiceLocked(...)的代码很长,只列出了关键部分

    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) throws TransactionTooLargeException {
            
                    ...
                    
            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired) != null) {
                    return 0;
                }
            }
            
            ...
    
            ConnectionRecord c = new ConnectionRecord(b, activity,
            connection, flags, clientLabel, clientIntent);
            
            if (s.app != null && b.intent.received) {
                // Service is already running, so we can immediately
                // publish the connection.
                try {
                    c.conn.connected(s.name, b.intent.binder, false);
                } catch (Exception e) {
                    Slog.w(TAG, "Failure sending service " + s.shortName
                            + " to connection " + c.conn.asBinder()
                            + " (in " + c.binding.client.processName + ")", e);
                }
    
                // If this is the first app connected back to this binding,
                // and the service had previously asked to be told when
                // rebound, then do so.
                if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                    requestServiceBindingLocked(s, b.intent, callerFg, true);
                }
            } else if (!b.intent.requested) {
                requestServiceBindingLocked(s, b.intent, callerFg, false);
            }
            ...      
    }                  
    

    从最开始的调用bindService(intent, conn, Context.BIND_AUTO_CREATE)可知传进来的参数flags的位Context.BIND_AUTO_CREATE为1,所以会执行bringUpServiceLocked (...)去启动服务,然后就直接返回了。

    如果不为1会继续往下,创建一个ConnectionRecord对象ccconn为传入的参数connection,这个conn实际上就是第二步中的sd对象,即ServiceDispatcher.InnerConnection类型对象。

    接下来判断如果服务已经在运行、则会直接调用c.conn.connected(...)发布连接,发布连接的过程将在第六步中分析。

    第五步 com.android.server.am.ActiveServices.java

    接着第四步的bringUpServiceLocked (...)分析

    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.versionCode, mAm.mProcessStats);
                    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.
            }
        } else {
            ...
        }
        
    }
    

    如果进程已启动,会调用realStartServiceLocked(...)继续去启动服务

    private final void realStartServiceLocked(ServiceRecord r,
             ProcessRecord app, boolean execInFg) throws RemoteException {
        
         try {
             ...
             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 {
             ...
         }
    
         requestServiceBindingsLocked(r, execInFg);
    
         updateServiceClientActivitiesLocked(app, null, true);
         
    }
    

    app.thread是应用程序端ApplicationThread的一个远程Binder对象,是在第一步中调用ActivityManager.getService().bindService(...)传入的mMainThread.getApplicationThread()
    通过它服务端ActivityManagerService可以调用应用程序端ApplicationThread中的方法。

    app.thread.scheduleCreateService这个方法通过多进程通信让应用程序去创建Service对象,并调用它的onCreate()方法。

    requestServiceBindingsLocked(...)会辗转调用到r.app.thread.scheduleBindService(...),接下来就调用到了ApplicationThreadscheduleBindService(...)方法

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

    发送一个Handler消息给ActivityThread.H类对象

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

    接下来就调用到了ActivityThreadhandleBindService()方法

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

    然后通过ActivityManager.getService().publishService(...)又回到了ActivityManagerServicepublishService()方法

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

    接着又回到了ActiveServicespublishServiceLocked()方法

    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 {
                                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类型对象c,然后调用c.conn.connected(...)发布连接。前面第四步中已提到过如果服务已经在运行,也会直接调用c.conn.connected(...)来发布连接,接下来就在第六步中具体分析c.conn.connected(...)

    第六步 android.app.LoadedApk.ServiceDispatcher.InnerConnection.java

    c.conn其实就是sd,是在第一步中通过ActivityManager.getService().bindService(...)方法传入的,由于ActivityManager.getService().bindService(...)是一个跨进程通信方法,从sdc.conn其实在native层传输时有一次转换,这样c.conn可以从服务端调用到应用端的方法。然后sd是一个ServiceDispatcher.InnerConnection类型对象。

    InnerConnection继承于IServiceConnection.Stub,可知c.conn确实是一个Binder对象,调用c.conn.connected(...),此时这个connected(...)方法已经被执行在应用端了

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

    判断mActivityThread是否存在,注意mActivityThread是一个Handler对象,并不是ActivityThread对象,是第一步中的bindServiceCommon (...)方法传入的mMainThread.getHandler(),并创建了ServiceDispatcher以及ServiceDispatcher.InnerConnection对象。

    如果mActivityThread存在,则让RunConnectionrun()方法运行于UI线程,否则直接调用doConnected(...)方法

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

    最后调用mConnection.onServiceConnected(name, service)service就是这样被传递回应用端的。

    相关文章

      网友评论

        本文标题:Android系统源码--bindService()过程

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