欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android Service绑定过程完整分析

程序员文章站 2024-03-04 08:45:17
通常我们使用service都要和它通信,当想要与service通信的时候,那么service要处于绑定状态的。然后客户端可以拿到一个binder与服务端进行通信,这个过程是...

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

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

Android 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的绑定过程分析完毕。

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