IPC :进程间通信

2024-07-02  本文已影响0人  xqiiitan

IPC ,目标Service常驻后台。

应用层, binder驱动,binder

native层。
service_manager.c
binder.c
binder.h

2.IPC 进程间通信小示例

IPC,aidl,Binder驱动。
app之间通信的协议叫 aidl,app进程之间不共享,需要通信。

2.1 服务端

package com.tom.joke;
// Declare any non-default types here with import statements
interface UserAidl {
    String getUserName();
    String getUserPwd();
}

<!--隐式启动A应用调用B应用 service-->
<service android:name=".MessageService"
    android:exported="true">
    <intent-filter>
        <action android:name="com.study.aidl.user"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</service>

// 服务端。
public class MessageService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    private final UserAidl.Stub mBinder = new UserAidl.Stub() {
        @Override
        public String getUserName() throws RemoteException {
            return "Darren@163.com";
        }
        @Override
        public String getUserPwd() throws RemoteException {
            return "19940223";
        }
    };
}

// 启动一个服务,等待B应用来连接。调用
private void startServiceForB() {
    startService(new Intent(this, MessageService.class));
}

2.2 Client端

// A应用端。client端。
public class MainActivity extends AppCompatActivity {
    private ServiceConnection mServiceConn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d("Service", "onServiceConnected "+ name.getClassName());
            // 连接好了
            mUserAidl = UserAidl.Stub.asInterface(service);
            Toast.makeText(MainActivity.this, "onServiceConnected:" , Toast.LENGTH_LONG).show();
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d("Service", "onServiceDisconnected "+ name.getClassName());
            // 断开连接
            Toast.makeText(MainActivity.this, "onServiceDisconnected:" , Toast.LENGTH_LONG).show();
        }
    };
    // 客户端一定要获取aidl的实例,这个实例时服务端返回的。
    private UserAidl mUserAidl;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bindService();
    }

    @Override
    protected void onDestroy() {
        unBindService();
        super.onDestroy();
    }
    private void bindService() {
        Intent intent = new Intent();
        intent.setAction("com.study.aidl.user");
        // 5.0后,为了安全问题,禁止了隐式声明Intent来启动Service
        // 也禁止使用 IntentFilter,否则就会抛异常。
        intent.setPackage("com.tom.joke"); // 目标apk的包名
        bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);
    }
    public void unBindService() {
        if (mUserAidl != null) {
            unbindService(mServiceConn);
        }
    }

    // 获取用户名,获取密码
    public void getUserName(View view) {
        if (mUserAidl != null) {
            try {
                String name = mUserAidl.getUserName();
                Toast.makeText(this, "userName:" + name, Toast.LENGTH_LONG).show();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
    public void getPassword(View view) {
        if (mUserAidl != null) {
            try {
                String password = mUserAidl.getUserPwd();
                Toast.makeText(this, "password:" + password, Toast.LENGTH_LONG).show();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
}

3.应用层具体的流程

C/S 每端都会有Stub 和 Proxy。中间有ServiceManager。

// Binder.java
/**
 * Default implementation rewinds the parcels and calls onTransact. On
 * the remote side, transact calls into the binder to do the IPC.
 */
public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
        int flags) throws RemoteException {
    if (false) Log.v("Binder", "Transact: " + code + " to " + this);

    if (data != null) {
        data.setDataPosition(0);
    }
    boolean r = onTransact(code, data, reply, flags);
    if (reply != null) {
        reply.setDataPosition(0);
    }
    return r;
}

总结:client端调用 transact() 方法,最后调用服务端的onTransact()

3.1 bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);

就会调用进入 MessageService,绑定后 拿到mBinder对象。 mBinder 是 new UserAidl.Stub()
Stub 继承自 android.os.Binder
onServiceConnected 里面拿到的 IBinder,实际就是 MessageService里面的 mBinder。
mUserAidl = UserAidl.Stub.asInterface(service); // service就是服务端给我们的IBinder
return new com.tom.joke.UserAidl.Stub.Proxy(obj); // 最终拿到Proxy

// Client客户端
@Override public java.lang.String getUserName() throws android.os.RemoteException
{
  _data.writeInterfaceToken(DESCRIPTOR);
  // 1.调用的是 IBinder 服务端返回的实例 mRemote。 传入code值。
  boolean _status = mRemote.transact(Stub.TRANSACTION_getUserName, _data, _reply, 0);
  // 5. Service端onTransact,执行结束。可拿到_status状态。
  _reply.readException();
   // 6. 把值从_reply中读出来。读取用户名数据
  _result = _reply.readString(); 
  return _result; // 7. 将值返回。
}

// 8. 拿到步骤7 返回的值。用于打印。

// Server 服务端
// 上面的transact方法,就回来到服务端的onTransact方法。服务端准备数据
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
  java.lang.String descriptor = DESCRIPTOR;
  switch (code)
  {
    case INTERFACE_TRANSACTION:
    {
      reply.writeString(descriptor);
      return true;
    }
    case TRANSACTION_getUserName:
    {
      data.enforceInterface(descriptor);
      java.lang.String _result = this.getUserName(); // 2.拿到用户名,用于返回。
      reply.writeNoException();
      reply.writeString(_result); // 3.写入数据,将用户名数据写入到reply,这个reply是客户端传进来的。
      return true; // 4.返回状态true。
    }
上一篇 下一篇

猜你喜欢

热点阅读