返回介绍

2.3 远程服务的获取与使用

发布于 2024-12-23 21:29:01 字数 7440 浏览 0 评论 0 收藏 0

客户端要使用远程服务,需要绑定服务 ( bindService ) 并建立服务连接 ( ServiceConnection )。

// MainActivity.java
public class MainActivity extends AppCompatActivity {
  private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
      IRemoteService remoteService = IRemoteService.Stub.asInterface(service);
      try {
        remoteService.addUser(new User(1, "neo"));
      } catch (RemoteException e) {
        e.printStackTrace();
      }
    }
    ...
  };
  ...
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ...
    Intent intent = new Intent().setComponent(new ComponentName(
        "org.xdty.remoteservice",
        "org.xdty.remoteservice.RemoteService"));
    bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
  }
}

我们可以看出,客户端通过 binderService() 方法,获取远程服务并在服务连接 ServiceConnectiononServiceConnected() 回调中得到了 IBinder service 实例, 最后通过上文提到的 IRemoteService.Stub.asInterface(service) 方法得到远程服务 IRemoteService 的实例。通过 IRemoteService.addUser() 方法我们可以像调用本地方法一样调用远程方法。在来看 IRemoteService.addUser() 的实现:

// IRemoteService.java
public static org.xdty.remoteservice.IRemoteService asInterface(android.os.IBinder obj) {
  ...
  return new org.xdty.remoteservice.IRemoteService.Stub.Proxy(obj);
}

private static class Proxy implements org.xdty.remoteservice.IRemoteService {
  private android.os.IBinder mRemote;

  Proxy(android.os.IBinder remote) {
    mRemote = remote;
  }

  @Override
  public android.os.IBinder asBinder() {
    return mRemote;
  }
  ...
  @Override
  public void addUser(org.xdty.remoteservice.User user)
      throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
      _data.writeInterfaceToken(DESCRIPTOR);
      if ((user != null)) {
        _data.writeInt(1);
        user.writeToParcel(_data, 0);
      } else {
        _data.writeInt(0);
      }
      mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
      _reply.readException();
    } finally {
      _reply.recycle();
      _data.recycle();
    }
  }
}

可以看到客户端调用 remoteService.addUser(new User(1, "neo")) 方法实际上是通过 IBinder service 实例的 transact() 方法,发送了与服务端约定好的命令 Stub.TRANSACTION_addUser ,并将参数按格式打包进 Parcel 对象。

服务端则在 onTransact() 方法中收到命令后会对命令和参数重新解析:

// IRemoteService.java
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply,
    int flags) throws android.os.RemoteException {
  switch (code) {
    ...
    case TRANSACTION_addUser: {
      data.enforceInterface(DESCRIPTOR);
      org.xdty.remoteservice.User _arg0;
      if ((0 != data.readInt())) {
        _arg0 = org.xdty.remoteservice.User.CREATOR.createFromParcel(data);
      } else {
        _arg0 = null;
      }
      this.addUser(_arg0);
      reply.writeNoException();
      return true;
    }
  }
  return super.onTransact(code, data, reply, flags);
}

可以看到在 onTransact() 中,最终 this.addUser(_arg0) 调用了上文提到的服务端的实现 IRemoteService.Stub.addUser()

远程 Binder 对象 mRemote 是由客户端绑定服务时 onServiceConnected() 返回的。继续追踪 bindService()

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

可以看到最后是通过 ActivityManagerNative.getDefault().bindService() 来绑定服务

// bindServiceCommon()
int res = ActivityManagerNative.getDefault().bindService(
  mMainThread.getApplicationThread(), getActivityToken(), service,
  service.resolveTypeIfNeeded(getContentResolver()),
  sd, flags, getOpPackageName(), user.getIdentifier());

// ActivityManagerNative.getDefault().bindService()
public int bindService(IApplicationThread caller, IBinder token,
    Intent service, String resolvedType, IServiceConnection connection,
    int flags,  String callingPackage, int userId) throws RemoteException {
  ...
  data.writeStrongBinder(connection.asBinder());
  ...
  mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
  ...
}

追踪到 ActivityManagerNative.getDefault().bindService() ,可以发现 ActivityManagerIServiceConnection 也是一个 AIDL 实现。通过它的 ActivityManagerProxy.bindService() 将绑定请求发送给本地层。

再从 onServiceConnected() 回调追踪, onServiceConnected() 是由 LoadedApk.ServiceDispatcher.doConnected() 回调的。

关于更多的 bindService() 远程服务创建及 ServiceConnection 回调, 请参考 Android 应用程序绑定服务(bindService)的过程源代码分析

利用进程间通信,我们可以实现简单的应用插件功能。关于 AIDL 在实际项目中的应用,可以参考 CallerInfo Plugin 的实现。

从上面分析可以看出, AIDL 的本质是对 Binder 的又一次抽象和封装,实际的进程间通信仍是由 Binder 完成的。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文