当前位置: 移动技术网 > IT编程>移动开发>Android > Android Service绑定过程完整分析

Android Service绑定过程完整分析

2019年07月24日  | 移动技术网IT编程  | 我要评论

当年情下载,北方影院姐妹无常,医临异界

通常我们使用service都要和它通信,当想要与service通信的时候,那么service要处于绑定状态的。然后客户端可以拿到一个binder与服务端进行通信,这个过程是很自然的。

那你真的了解过service的绑定过程吗?为什么可以是binder和service通信?
同样的先看一张图大致了解一下,灰色背景框起来的是同一个类的方法,如下:

我们知道调用context的bindservice方法即可绑定一个service,而contextimpl是context的实现类。那接下来就从源码的角度分析service的绑定过程。

当然是从contextimpl的bindservice方法开始,如下:

@override
public boolean bindservice(intent service, serviceconnection conn,
  int flags) {
 warnifcallingfromsystemprocess();
 return bindservicecommon(service, conn, flags, mmainthread.gethandler(),
   process.myuserhandle());
}

在bindservice方法中又会转到bindservicecommon方法,将intent,serviceconnection对象传进。

那就看看bindservicecommon方法的实现。

private boolean bindservicecommon(intent service, serviceconnection conn, int flags, handler
    handler, userhandle user) {
  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 = activitymanagernative.getdefault().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();
  }
}

在上述代码中,调用了mpackageinfo(loadedapk对象)的getservicedispatcher方法。从getservicedispatcher方法的名字可以看出是获取一个“服务分发者”。其实是根据这个“服务分发者”获取到一个binder对象的。

那现在就看到getservicedispatcher方法的实现。

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) {
      sd = map.get(c);
    }
    if (sd == null) {
      sd = new servicedispatcher(c, context, handler, flags);
      if (map == null) {
        map = new arraymap<serviceconnection, loadedapk.servicedispatcher>();
        mservices.put(context, map);
      }
      map.put(c, sd);
    } else {
      sd.validate(context, handler);
    }
    return sd.getiserviceconnection();
  }
}

从getservicedispatcher方法的实现可以知道,serviceconnection和servicedispatcher构成了映射关系。当存储集合不为空的时候,根据传进的key,也就是serviceconnection,来取出对应的servicedispatcher对象。
当取出servicedispatcher对象后,最后一行代码是关键,

return sd.getiserviceconnection();

调用了servicedispatcher对象的getiserviceconnection方法。这个方法肯定是获取一个iserviceconnection的。

iserviceconnection getiserviceconnection() {
  return miserviceconnection;
}

那么miserviceconnection是什么?现在就可以来看下servicedispatcher类了。servicedispatcher是loadedapk的内部类,里面封装了innerconnection和serviceconnection。如下:

static final class servicedispatcher {
  private final servicedispatcher.innerconnection miserviceconnection;
  private final serviceconnection mconnection;
  private final context mcontext;
  private final handler mactivitythread;
  private final serviceconnectionleaked mlocation;
  private final int mflags;

  private runtimeexception munbindlocation;

  private boolean mforgotten;

  private static class connectioninfo {
    ibinder binder;
    ibinder.deathrecipient deathmonitor;
  }

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

  private final arraymap<componentname, servicedispatcher.connectioninfo> mactiveconnections
    = new arraymap<componentname, servicedispatcher.connectioninfo>();

  servicedispatcher(serviceconnection conn,
      context context, handler activitythread, int flags) {
    miserviceconnection = new innerconnection(this);
    mconnection = conn;
    mcontext = context;
    mactivitythread = activitythread;
    mlocation = new serviceconnectionleaked(null);
    mlocation.fillinstacktrace();
    mflags = flags;
  }

  //代码省略

}

先看到servicedispatcher的构造方法,一个servicedispatcher关联一个innerconnection对象。而innerconnection呢?,它是一个binder,有一个很重要的connected方法。至于为什么要用binder,因为与service通信可能是跨进程的。

好,到了这里先总结一下:调用bindservice方法绑定服务,会转到bindservicecommon方法。
在bindservicecommon方法中,会调用loadedapk的getservicedispatcher方法,并将serviceconnection传进, 根据这个serviceconnection取出与其映射的servicedispatcher对象,最后调用这个servicedispatcher对象的getiserviceconnection方法获取与其关联的innerconnection对象并返回。简单点理解就是用serviceconnection换来了innerconnection。

现在回到bindservicecommon方法,可以看到绑定service的过程会转到activitymanagernative.getdefault()的bindservice方法,其实从抛出的异常类型remoteexception也可以知道与service通信可能是跨进程的,这个是很好理解的。

而activitymanagernative.getdefault()是activitymanagerservice,那么继续跟进activitymanagerservice的bindservice方法即可,如下:

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

在上述代码中,绑定service的过程转到activeservices的bindservicelocked方法,那就跟进activeservices的bindservicelocked方法瞧瞧。如下:

int bindservicelocked(iapplicationthread caller, ibinder token, intent service,
    string resolvedtype, final iserviceconnection connection, int flags,
    string callingpackage, final int userid) throws transactiontoolargeexception {

    //代码省略

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

     //代码省略

    if ((flags&context.bind_auto_create) != 0) {
      s.lastactivity = systemclock.uptimemillis();
      if (bringupservicelocked(s, service.getflags(), callerfg, false,
          permissionsreviewrequired) != null) {
        return 0;
      }
    }

    //代码省略

  return 1;
}

将connection对象封装在connectionrecord中,这里的connection就是上面提到的innerconnection对象。这一步很重要的。

然后调用了bringupservicelocked方法,那么就探探这个bringupservicelocked方法,

private string bringupservicelocked(servicerecord r, int intentflags, boolean execinfg,
    boolean whilerestarting, boolean permissionsreviewrequired)
    throws transactiontoolargeexception {

    //代码省略

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

    //代码省略

  return null;
}

可以看到调用了realstartservicelocked方法,真正去启动service了。

那么跟进realstartservicelocked方法探探,如下:

private final void realstartservicelocked(servicerecord r,
    processrecord app, boolean execinfg) throws remoteexception {

   //代码省略

   app.thread.schedulecreateservice(r, r.serviceinfo,
       mam.compatibilityinfoforpackagelocked(r.serviceinfo.applicationinfo),
    app.repprocstate);
    r.postnotification();
    created = true;

   //代码省略

  requestservicebindingslocked(r, execinfg);

  updateserviceclientactivitieslocked(app, null, true);

  // if the service is in the started state, and there are no
  // pending arguments, then fake up one so its onstartcommand() will
  // be called.
  if (r.startrequested && r.callstart && r.pendingstarts.size() == 0) {
    r.pendingstarts.add(new servicerecord.startitem(r, false, r.makenextstartid(),
        null, null));
  }

  sendserviceargslocked(r, execinfg, true);

//代码省略
}

这里会调用app.thread的schedulecreateservice方法去创建一个service,然后会回调service的生命周期方法,然而绑定service呢?
在上述代码中,找到一个requestservicebindingslocked方法,从名字看是请求绑定服务的意思,那么就是它没错了。

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

咦,我再按住ctrl+鼠标左键,点进去requestservicebindinglocked方法。如下:

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 ((!i.requested || rebind) && i.apps.size() > 0) {
    try {
      bumpserviceexecutinglocked(r, execinfg, "bind");
      r.app.forceprocessstateupto(activitymanager.process_state_service);
      r.app.thread.schedulebindservice(r, i.intent.getintent(), rebind,
          r.app.repprocstate);
      if (!rebind) {
        i.requested = true;
      }
      i.hasbound = true;
      i.dorebind = false;
    }

  //代码省略

  return true;
}

r.app.thread调用了schedulebindservice方法来绑定服务,而r.app.thread是applicationthread,现在关注到 applicationthread即可,schedulebindservice方法如下:

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

封装了待绑定的service的信息,并发送了一个消息给主线程,

public void handlemessage(message msg) {
  if (debug_messages) slog.v(tag, ">>> handling: " + codetostring(msg.what));
  switch (msg.what) {

  //代码省略

    case bind_service:
      trace.tracebegin(trace.trace_tag_activity_manager, "servicebind");
      handlebindservice((bindservicedata)msg.obj);
      trace.traceend(trace.trace_tag_activity_manager);
      break;

  //代码省略

  }
}

调用了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);
          activitymanagernative.getdefault().publishservice(
              data.token, data.intent, binder);
        } else {
          s.onrebind(data.intent);
          activitymanagernative.getdefault().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);
      }
    }
  }
}

根据token获取到service,然后service回调onbind方法。结束了?

可是onbind方法返回了一个binder是用来干嘛的?
我们再看看activitymanagernative.getdefault()调用了publishservice方法做了什么工作,此时又回到了activitymanagerservice。

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方法,那看到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;
        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);
            }

  //代码省略

}

c.conn是什么? 它是一个innerconnection对象,对,就是那个那个binder,上面也贴出了代码,在activeservices的bindservicelocked方法中,innerconnection对象被封装在connectionrecord中。那么现在它调用了connected方法,就很好理解了。

innerconnection的connected方法如下:

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) {
  if (mactivitythread != null) {
    mactivitythread.post(new runconnection(name, service, 0));
  } else {
    doconnected(name, service);
  }
}

从而activitythread会投递一个消息到主线程,此时就解决了跨进程通信。
那么你应该猜到了runconnection一定有在主线程回调的onserviceconnected方法,

private final class runconnection implements runnable {
  runconnection(componentname name, ibinder service, int command) {
    mname = name;
    mservice = service;
    mcommand = command;
  }

  public void run() {
    if (mcommand == 0) {
      doconnected(mname, mservice);
    } else if (mcommand == 1) {
      dodeath(mname, mservice);
    }
  }

  final componentname mname;
  final ibinder mservice;
  final int mcommand;
}

咦,还不出现?继续跟进doconnected方法,

public void doconnected(componentname name, ibinder service) {
  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 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);
  }
}

在最后一个if判断,终于找到了onserviceconnected方法!

总结一下,当service回调onbind方法,其实还没有结束,会转到activitymanagerservice,然后又会在activeservices的publishservicelocked方法中,从connectionrecord中取出innerconnection对象。有了innerconnection对象后,就回调了它的connected。在innerconnection的connected方法中,又会调用servicedispatcher的connected方法,在servicedispatcher的connected方法向主线程扔了一个消息,切换到了主线程,之后就在主线程中回调了客户端传进的serviceconnected对象的onserviceconnected方法。

至此, service的绑定过程分析完毕。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网