Android跨进程通信IPC之21--binderServic

2018-08-27  本文已影响195人  凯玲之恋

移步系列Android跨进程通信IPC系列
app是没有权限向ServiceManager注册service的。
bindService要负责找到service的代理binder并传递到app进程。这期间涉及到binder实体的跨进程传输,也就是所谓的匿名binder。因为这些binder并没有在ServiceManager中注册。

1 ServiceConnection

public interface ServiceConnection {

    public void onServiceConnected(ComponentName name, IBinder service);

    public void onServiceDisconnected(ComponentName name);
}

2 bindService的过程

整个过程大体上是这样的:

  1. 检查要绑定的额service是否启动,没有的话,要先启动service,然后执行service的生命周期方法。
  2. 执行绑定,先将远端service的binder传递到AMS中,然后AMS在将其传递到客户端组件进程中

3 bindService的过程分析

ContextImpl.bindService():

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

ContextImpl.bindServiceCommon():

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            UserHandle user) {
        IServiceConnection sd;
      ................
        if (mPackageInfo != null) {
          //从LoadedApk中拿到一个binder实体
          //首先会把ServiceConnection转成Binder对象
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                    mMainThread.getHandler(), flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        //  Android5.0之后不允许使用隐式调用
        // 这里对传入的intetn进行检查,如果是android5.0以上,
        //是隐式intent的话抛出异常
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            ....................
            service.prepareToLeaveProcess();
            // 向AMS发起跨进程调用其bindService方法
            int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
          ..............................
            return res != 0;
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
    }

3.1 LoadedApk.getServiceDispatcher()

public final IServiceConnection getServiceDispatcher(ServiceConnection c,
           Context context, Handler handler, int flags) {
       synchronized (mServices) {
           LoadedApk.ServiceDispatcher sd = null;
            // 先从LoadedApk.mService中查找,
            // 看看发起绑定操作的组件是否已经存在一个用来处理传入的
            //ServiceConnection接口对象的ServiceDispatcher
           ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
           if (map != null) {
              // 存在的话直接返回这个ServiceDispatcher
               sd = map.get(c);
           }
           if (sd == null) {
              // 不存在的话创建一个ServiceDispatcher
              // 这里要注意第三个参数handler,是主线程的handler
              // 保存在了ServiceDispatcher.mActivityThread中
               sd = new ServiceDispatcher(c, context, handler, flags);
               if (map == null) {
                   map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
                   mServices.put(context, map);
               }
                // 将创建的ServiceDispatcher缓存到LoadedApk.mService
               map.put(c, sd);
           } else {
               sd.validate(context, handler);
           }
           return sd.getIServiceConnection();
       }
   }

3.1.1 ServiceDispatcher

static final class ServiceDispatcher {
    // 一个binder实体对象
    private final ServiceDispatcher.InnerConnection mIServiceConnection;
    // 逻辑连接建立时,执行的回调接口对象
    private final ServiceConnection mConnection;
    // 所在的组件,即client
    private final Context mContext;
    // 进程主线程即UI线程中的handler
    private final Handler mActivityThread;
    private final ServiceConnectionLeaked mLocation;
    // 绑定service时,传入的flag,例如BIND_AUTO_CREATE
    private final int mFlags;

    private RuntimeException mUnbindLocation;
    private boolean mDied;
    private boolean mForgotten;
    // 因为一个ServiceConnection可以被bindService方法多次调用,用来启动不同的service,
    // 那么ServiceDispatcher中自然要存储这些连接信息了:
    // ConnectionInfo很简单只有两个属性成员
    // IBinder binder;远端service的引用binder
    // IBinder.DeathRecipient deathMonitor; 远端binder的死亡通知方法
    private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
       = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
................
  }

ServiceDispatcher.InnerConnection是一个继承自 IServiceConnection.Stub的binder实体类:

3.1.2 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) throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service);
                }
            }
}

其中ServiceDispatcher.connected():

public void connected(ComponentName name, IBinder service) {
    // 这里的mActivityThread是主线程的handler
    // 也就是说,实际上ServiceConnection中的回调是在主线程中执行的
      if (mActivityThread != null) {
          mActivityThread.post(new RunConnection(name, service, 0));
      } else {
          doConnected(name, service);
      }
}

3.1.3 ConnectionInfo

private static class ConnectionInfo {
  // 远端service的代理binder
  IBinder binder;
  // 远端service 死亡通知回调
  IBinder.DeathRecipient deathMonitor;
}

3.2 AMS中绑定service过程

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

    ..............
    synchronized(this) {
      // mServices是ActiveService
        return mServices.bindServiceLocked(caller, token, service,
                resolvedType, connection, flags, callingPackage, userId);
    }
}
int bindServiceLocked(
         IApplicationThread caller, // 客户端进程ActivityThread.mAppThread的代理binder
         IBinder token,
         Intent service,// 客户端绑定service时的intent
         String resolvedType,
         IServiceConnection connection, //客户端进程的中ServiceDispatcher.InnerConnection的代理binder
         int flags,
         String callingPackage, int userId) throws TransactionTooLargeException {

ActiveService.bindServiceLocked()startService的ActiveService.startServiceLocked()方法中有很多相似的逻辑。

3.2.1 bindServiceLocked绑定前的准备工作

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
           String resolvedType, IServiceConnection connection, int flags,
           String callingPackage, int userId) throws TransactionTooLargeException {
  ...............
  // 得到service对应的ServiceRecord
  ServiceLookupResult res =
      retrieveServiceLocked(service, resolvedType, callingPackage,
              Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
  ServiceRecord s = res.record;
  ....
  // 根据传入的intent和发起者进程,查找到一个合适的AppBindRecord对象,
  // 查找不到就创建一个,下面会介绍规则
  AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
  // 为本次连接创建ConnectionRecord对象
  ConnectionRecord c = new ConnectionRecord(b, activity,
          connection, flags, clientLabel, clientIntent);
  // 客户端进程的中ServiceDispatcher.InnerConnection的代理binder
  IBinder binder = connection.asBinder();
  // 将创建的逻辑连接对象ConnectionRecord,记录在ServiceRecord中
  ArrayList<ConnectionRecord> clist = s.connections.get(binder);
  if (clist == null) {
      clist = new ArrayList<ConnectionRecord>();
      s.connections.put(binder, clist);
  }
  clist.add(c);
  // 同时记录在AppBindRecord.connections中
  b.connections.add(c);
  // AppBindRecord.client是ProcessRecord,代表客户端的进程
  b.client.connections.add(c);
  .......
  // 除了ServiceRecord.connections记录了该service连接信息外
  // ActiveService.mServiceConnections记录了当前系统中所有的连接信息
  // 所以也要将创建的连接对象,加入ActiveService.mServiceConnections
  clist = mServiceConnections.get(binder);
  if (clist == null) {
      clist = new ArrayList<ConnectionRecord>();
      mServiceConnections.put(binder, clist);
  }
  clist.add(c);
 ............

在前面关于service机制介绍的文章中提到过ServiceRecord中有一些数据成员是bindservice时用到的:

final class ServiceRecord extends Binder {
    ...............
    final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
                = new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();// IBinder -> ConnectionRecord of all bound clients
    // service所在的进程
    ProcessRecord app;      // where this service is running or null.
}

AMS描述绑定service时的intent的IntentBindRecord类

final class IntentBindRecord {
    // 绑定的service在AMS中的代表
    final ServiceRecord service;
    /** The intent that is bound.*/
    final Intent.FilterComparison intent; //
    /** All apps that have bound to this Intent. */
    final ArrayMap<ProcessRecord, AppBindRecord> apps
            = new ArrayMap<ProcessRecord, AppBindRecord>();
    // service的binder代理binder
    IBinder binder;

其中IntentBindRecord.service 最终会保存绑定的service的ServiceRecord;

3.2.1.1 ServiceRecord.retrieveAppBindingLocked()

public AppBindRecord retrieveAppBindingLocked(
           Intent intent,// 客户端发起绑定操作时传入的intent
           ProcessRecord app // 客户端组件进程) {
       // 为传入的intent创建一个Intent.FilterComparison
       Intent.FilterComparison filter = new Intent.FilterComparison(intent);
       // 查找传入的intent是否已经有IntentBindRecord
       IntentBindRecord i = bindings.get(filter);
       if (i == null) {
          // 没有的话创建
           i = new IntentBindRecord(this, filter);
           //并缓存到ServiceRecord.bings中
           bindings.put(filter, i);
       }
       // 查找客户端的组件是否已经绑定过该service
       AppBindRecord a = i.apps.get(app);
       // 绑定过的话,返回找到的AppBindRecord
       if (a != null) {
           return a;
       }
       // 没有的话创建一个AppBindRecord对象
       a = new AppBindRecord(this, i, app);
       // 并缓存到IntentBindRecord.apps中
       i.apps.put(app, a);
       return a;
   }

retrieveAppBindingLocked()另一个主要作用是查找并创建AppBindRecord对象。
AMS用于描述绑定service的客户端整体信息的AppBindRecord类

final class AppBindRecord {
    // 所在的service
    final ServiceRecord service;    // The running service.
    // 客户端发起的bindservice时传入的intent,AMS会为其创建一个对应的IntentBindRecord
    final IntentBindRecord intent;  // The intent we are bound to.
    // 客户端进程
    final ProcessRecord client;     // Who has started/bound the service.
    // 客户端所在的app,其他组件绑定该service的逻辑连接
    final ArraySet<ConnectionRecord> connections = new ArraySet<>();
                                    // All ConnectionRecord for this client.

AMS通过ServiceRecord.retrieveAppBindingLocked()来查找并创建一个合适的AppBindRecord对象。

3.2.1.2 为本次连接创建ConnectionRecord对象

ConnectionRecord用来描述一个连接信息,即绑定信息,要对客户端和service端进行描述。
  1. 客户端所在的进程在AMS中的代表ProcessRecord.connections
  2. ActiveService.mServiceConnections,这里面记录了AMS中所有app的service的连接
  3. AppBindRecord.connections中

之所以要在这么多地方做记录,可能是为了在不同的场合下迅速查找到连接吧。

了解了以上内容后,就可以通过下图简明的描述客户端进程和AMS之间的关系:


2780242-c11bbd267ebbd52a.png

3.2.2 bringUpServiceLocked 执行service生命周期方法

在做好前面的准备工作之后,binderservice()就开始准备与Service建立连接了。那么自然要先对service进行一些操作,说白了就是执行service的生命周期方法,这是由bringUpServiceLocked()方法来负责的。

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
           String resolvedType, IServiceConnection connection, int flags,
           String callingPackage, int userId) throws TransactionTooLargeException {
.................
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
    s.lastActivity = SystemClock.uptimeMillis();
    // 只有当要绑定的service所在的进程还启动的时候,该方法返回非null
    // 因为启动进程需要一段时间,所以就要先退出来
    // 这里暂时假设service所在的进程已经启动
    if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
        return 0;
    }
}
....................

此时可以分为两大情况:

如果没有在AMS中找到名字为ServiceRecord.processName的进程,那么就要先创建进程了,这里不考虑这种情况。

3.2.2.1 绑定service bindServiceLocked

绑定实际上就是想办法拿到service的binder,并将其传递到客户端组件进程,另外还要对前面准备工作期间创建的数据结构设置相关的字段。

这部分代码如下:

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
           String resolvedType, IServiceConnection connection, int flags,
           String callingPackage, int userId) throws TransactionTooLargeException {
.................
// b.intent.received为true,表明已经拿到了service的binder
f (s.app != null && b.intent.received) {
        // Service is already running, so we can immediately
        // publish the connection.
        try {
            // 这里就可以直接远程调用客户端组件中onServiceConnected()方法将service的binder传递过去了
            c.conn.connected(s.name, b.intent.binder);
        } 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);
    }

    getServiceMap(s.userId).ensureNotStartingBackground(s);

} finally {
    Binder.restoreCallingIdentity(origId);
}

这里分两种情况:

final class IntentBindRecord {
  /** Binder published from service. */
  IBinder binder;
  /** Set when we have initiated a request for this binder. */
  boolean requested;
  /** Set when we have received the requested binder. */
  boolean received;
  /** Set when we still need to tell the service all clients are unbound. */
  boolean hasBound;
}

这里分析第二种情况,时序图如下:


2780242-52921787ad1c7e6b.png

3.2.2.2 requestServiceBindingLocked

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {

        ..............
        // 传入的rebind为false还是true,取决于AMS调用service.onUnbind()返回值
        // 如果希望客户端下一次绑定到服务时接收 onRebind() 调用(而不是接收 onBind() 调用),onUnbind()返回true
        // service首次被绑定时,rebind肯定为false
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                // 跨进程调用service所在进程的scheduleBindService()方法,执行绑定操作,这是一个异步方法,会立即返回
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
                if (!rebind) {
                    // 只要service被绑定过了,IntentBindRecord.requested就会被设置为true
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            } catch (TransactionTooLargeException e) {
              .................
            } catch (RemoteException e) {
              .................
            }
        }
        return true;
    }
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 {
                    // 传入flase时执行onBind()
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        ActivityManagerNative.getDefault().publishService(
                                data.token, data.intent, binder);
                    } else {
                      // 传入true时执行onRebind()
                        s.onRebind(data.intent);
                        ActivityManagerNative.getDefault().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to bind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }

这里考虑首次绑定时的情况,所以rebind肯定为false,那么service调用过onBind()之后,又通过AMS的代理,跨进程调用AMS的publishService()将service的binder传递到AMS中,然后在传递到客户端。

3.2.2.3 publishServiceLocked

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
.......
IntentBindRecord b = r.bindings.get(filter);
// 初次绑定
if (b != null && !b.received) {
      // 保存service的代理binder
      b.binder = service;
      // 设置下面的两个标志为true
      b.requested = true;
      b.received = true;
      // 一般情况下,首次绑定时,connections.size为1
      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 {
                   // 将service的binder传递到客户端
                   c.conn.connected(r.name, service);
               } catch (Exception e) {
                   Slog.w(TAG, "Failure sending service " + r.name +
                         " to connection " + c.conn.asBinder() +
                         " (in " + c.binding.client.processName + ")", e);
               }
           }
       }
   }
...........

3.2.2.4 bindServiceLocked

那么当首次绑定之后,又有其他客户端组件来绑定这个service,那么在bindServiceLocked()方法中,会直接跨进程调用客户端的connected():

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, IServiceConnection connection, int flags,
        String callingPackage, int userId) throws TransactionTooLargeException {
        ................
        if (s.app != null && b.intent.received) {
              // Service is already running, so we can immediately
              // publish the connection.
              try {
                  // 直接跨进程调用客户端的connected()
                  // 不在需要跨进程调用service.onBind()
                  c.conn.connected(s.name, b.intent.binder);
              } catch (Exception e) {
                  Slog.w(TAG, "Failure sending service " + s.shortName
                          + " to connection " + c.conn.asBinder()
                          + " (in " + c.binding.client.processName + ")", e);
              }
        ..........................

}

在看客户端进程的connected()

3.2.2.5 connected()

public void connected(ComponentName name, IBinder service) throws RemoteException {
    // 先得到处理ServiceConnection的ServiceDispatcher
    LoadedApk.ServiceDispatcher sd = mDispatcher.get();
    if (sd != null) {
        sd.connected(name, service);
    }
}
public void connected(ComponentName name, IBinder service) {
   // mActivityThread是在创建 ServiceDispatcher对象时,传入的组件所在进程的主线程的handler
   // 也就是说RunConnection是在组件所在的主线程中执行的
   if (mActivityThread != null) {
       mActivityThread.post(new RunConnection(name, service, 0));
   } else {
       doConnected(name, service);
   }
}

RunConnection.run()中会调用LoadedApk.doConnected()方法:

public void run() {
    if (mCommand == 0) {
        doConnected(mName, mService);
    } else if (mCommand == 1) {
        doDeath(mName, mService);
    }
}

3.2.2.6 LoadedApk.doConnected():

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

    synchronized (this) {
        .....................
        ServiceDispatcher.ConnectionInfo old;
        //很有意思,也就是说同一组件中对同一个service重复绑定,onServiceConnected()只会执行一次
        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.
            mDied = false;
            info = new ConnectionInfo();
            info.binder = service;
            info.deathMonitor = new DeathMonitor(name, service);
            try {
                // 设置死亡回调
                service.linkToDeath(info.deathMonitor, 0);
                // 将info保存在LoadedApk.mActiveConnections
                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 not disconnected.
    if (old != null) {
        mConnection.onServiceDisconnected(name);
    }
    // If there is a new service, it is now connected.
    if (service != null) {
      // 执行回调
        mConnection.onServiceConnected(name, service);
    }
}

doConnected()比较有意思的是下面的代码:

ServiceDispatcher.ConnectionInfo old;
old = mActiveConnections.get(name);
      if (old != null && old.binder == service) {
          // Huh, already have this one.  Oh well!
          return;
}

mActiveConnections来自ServiceDispatcher:

private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
            = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();

ServiceDispatcher.mActiveConnections用来记录该LoadedApk中的组件所绑定的service的连接信息。key是service的组件名,value是ServiceDispatcher.ConnectionInfo。

ConnectionInfo中记录了service的代理binder以及死亡通知回调。

private static class ConnectionInfo {
  // 远端service的代理binder
  IBinder binder;
  // 远端service 死亡通知回调
  IBinder.DeathRecipient deathMonitor;
}

connected(ComponentName name, IBinder service)方法的第一个参数是service的组件名,第二个参数是service的代理binder。

4 unbindeService

现在在看一下unbindeService()的过程,直接看AMS.unbindServiceLocked(),整个过程大体上就是找到相关的连接对象ConnectionRecord,将其从相关的map中移除,然后根据情况决定是否调用serive.onUnbind生命周期方法

4.1 unbindServiceLocked

boolean unbindServiceLocked(IServiceConnection connection) {
       // 得到ServiceDispatcher.InnerConnection的binder
       IBinder binder = connection.asBinder();
       if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindService: conn=" + binder);
       // 前面说了ActiveService.mServiceConnections,这里面记录了AMS中所有app的service的连接
       // 自然也包括同一组件内使用同一个ServiceConnection绑定同一个service的情况
       ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
       // 说明没有使用该ServiceConnection接口对象绑定过service
       // 所以无需unbind
       if (clist == null) {
           Slog.w(TAG, "Unbind failed: could not find connection for "
                 + connection.asBinder());
           return false;
       }

       final long origId = Binder.clearCallingIdentity();
       try {
           // 依次取出同一组件内使用该ServiceConnection接口对象绑定的service的连接信息对象ConnectionRecord
           // 这里要注意的是,这相当于在发起unbindService()操作的组件中,对所有使用该ServiceConnection接口对象绑定的sercvice
           // 发起unbindService操作
           while (clist.size() > 0) {
               ConnectionRecord r = clist.get(0);
               removeConnectionLocked(r, null, null);
               if (clist.size() > 0 && clist.get(0) == r) {
                   // In case it didn't get removed above, do it now.
                   Slog.wtf(TAG, "Connection " + r + " not removed for binder " + binder);
                   clist.remove(0);
               }
               if (r.binding.service.app != null) {
                   // This could have made the service less important.
                   if ((r.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
                       r.binding.service.app.treatLikeActivity = true;
                       mAm.updateLruProcessLocked(r.binding.service.app,
                               r.binding.service.app.hasClientActivities
                               || r.binding.service.app.treatLikeActivity, null);
                   }
                   mAm.updateOomAdjLocked(r.binding.service.app);
               }
           }
       } finally {
           Binder.restoreCallingIdentity(origId);
       }

       return true;
   }

4.2 removeConnectionLocked():

void removeConnectionLocked(
        ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
        IBinder binder = c.conn.asBinder();
        AppBindRecord b = c.binding;
        ServiceRecord s = b.service;
        // 从ServiceRecord中取出所有绑定该service的连接
        ArrayList<ConnectionRecord> clist = s.connections.get(binder);
        if (clist != null) {
            // 将使用要unbindService()的ServiceConnection创建的连接
            // 从ServiceRecord.connections中移除
            clist.remove(c);
            if (clist.size() == 0) {
                s.connections.remove(binder);
            }
        }
        // 将使用要unbindService()的ServiceConnection创建的连接
        // 从AppBindRecord.connections中移除
        b.connections.remove(c);
        if (c.activity != null && c.activity != skipAct) {
            if (c.activity.connections != null) {
                c.activity.connections.remove(c);
            }
        }
        if (b.client != skipApp) {
            b.client.connections.remove(c);
            if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
                b.client.updateHasAboveClientLocked();
            }
            if (s.app != null) {
                updateServiceClientActivitiesLocked(s.app, c, true);
            }
        }
        clist = mServiceConnections.get(binder);
        if (clist != null) {
            // 将使用要unbindService()的ServiceConnection创建的连接
            // 从ActiveService.mServiceConnections中移除
            clist.remove(c);
            if (clist.size() == 0) {
                mServiceConnections.remove(binder);
            }
        }

        mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name);

        // 如果AppBindRecord.connections.size为0
        // 表示某客户端已经没有组件与该service绑定了
        // 那么将客户端从IntentBindRecord.apps中移除
        if (b.connections.size() == 0) {
            b.intent.apps.remove(b.client);
        }

        if (!c.serviceDead) {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Disconnecting binding " + b.intent
                    + ": shouldUnbind=" + b.intent.hasBound);
            // 如果IntentBindRecord.apps.size为0,表示没有客户端与该service绑定了
            // 那么开始回调service进程的scheduleUnbindService(),执行service.unbind()
            if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                    && b.intent.hasBound) {
                try {
                    bumpServiceExecutingLocked(s, false, "unbind");
                    if (b.client != s.app && (c.flags&Context.BIND_WAIVE_PRIORITY) == 0
                            && s.app.setProcState <= ActivityManager.PROCESS_STATE_RECEIVER) {
                        // If this service's process is not already in the cached list,
                        // then update it in the LRU list here because this may be causing
                        // it to go down there and we want it to start out near the top.
                        mAm.updateLruProcessLocked(s.app, false, null);
                    }
                    mAm.updateOomAdjLocked(s.app);
                    b.intent.hasBound = false;
                    // Assume the client doesn't want to know about a rebind;
                    // we will deal with that later if it asks for one.
                    b.intent.doRebind = false;
                    s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
                } catch (Exception e) {
                    Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
                    serviceProcessGoneLocked(s);
                }
            }

            if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
                boolean hasAutoCreate = s.hasAutoCreateConnections();
                if (!hasAutoCreate) {
                    if (s.tracker != null) {
                        s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
                                SystemClock.uptimeMillis());
                    }
                }
                // 根据情况决定是否调用service.onDestroy()方法
                bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
            }
        }
    }

scheduleUnbindService()会导致下面的方法在service的主线程中执行:

4.3 scheduleUnbindService()

private void handleUnbindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                // 执行service.onUnbind()生命周期方法
                boolean doRebind = s.onUnbind(data.intent);
                try {
                    if (doRebind) {
                        // 如果onUnbind()的返回值设置为true的话,
                        // 调用AMS.unbindFinished()
                        ActivityManagerNative.getDefault().unbindFinished(
                                data.token, data.intent, doRebind);
                    } else {
                        ActivityManagerNative.getDefault().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                } catch (RemoteException ex) {
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to unbind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }

unbindeService()代码就说道这里,接下来总结下:

这里比较有趣的是,假设同一组件内使用sc重复绑定的一个servcie N次,那么这一次unbindeService(),当对于该该组件绑定该service来说执行了N次unbindeService操作。

5 生命周期的总结:

service的生命周期方法都运行在主线程中,所以如果要在生命周期中执行耗时操作,请额外开启线程。

参考

Android6.0之App的Service组件运行机制之bindService
Android 7.0 中 Service bind 流程详解

上一篇 下一篇

猜你喜欢

热点阅读