Binder의 onTransact를 통해 직접 크로스 프로세스 통신을 완성합니다

5861 단어

1. 세부 코드:


서버 구현:
public class IPCService extends Service {
 
    private static final String DESCRIPTOR = "IPCService";
    private final String[] names = { "B ", "  ", "  ", "J ", "  " };
    private MyBinder mBinder = new MyBinder();
 
    private class MyBinder extends Binder {
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code) {
            case 0x001: {
                data.enforceInterface(DESCRIPTOR);
                int num = data.readInt();
                reply.writeNoException();
                reply.writeString(names[num]);
                return true;
            }
            }
            return super.onTransact(code, data, reply, flags);
        }
    }
 
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

onTransact에는 네 개의 매개 변수인 코드, 데이터,replay,flags가 있습니다.
  • code는 성형의 유일한 표지로서 어떤 방법을 집행하는지 구분하는 데 사용되며 클라이언트는 이 파라미터를 전달하여 서비스 측에 어떤 방법을 집행하는지 알려준다.
  • 데이터 클라이언트가 전달한 매개 변수;
  • replay 서버가 되돌아오는 값;
  • flags는 반환값이 있는지 여부를 표시하고 0은 (양방향), 1은 없음(단방향)이다.

  • 클라이언트 구현:
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
     
        private EditText edit_num;
        private Button btn_query;
        private TextView txt_result;
        private IBinder mIBinder;
        private ServiceConnection PersonConnection = new ServiceConnection() {
            @Override
            public void onServiceDisconnected(ComponentName name) {
                mIBinder = null;
            }
     
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mIBinder = service;
            }
        };
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            bindViews();
     
            //     Service
            Intent service = new Intent("android.intent.action.IPCService");
            service.setPackage("com.jay.ipcserver");
            bindService(service, PersonConnection, BIND_AUTO_CREATE);
            btn_query.setOnClickListener(this);
        }
     
        private void bindViews() {
            edit_num = (EditText) findViewById(R.id.edit_num);
            btn_query = (Button) findViewById(R.id.btn_query);
            txt_result = (TextView) findViewById(R.id.txt_result);
        }
     
        @Override
        public void onClick(View v) {
            int num = Integer.parseInt(edit_num.getText().toString());
            if (mIBinder == null) {
                Toast.makeText(this, "               ", Toast.LENGTH_SHORT).show();
            } else {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                String _result = null;
                try {
                    _data.writeInterfaceToken("IPCService");
                    _data.writeInt(num);
                    mIBinder.transact(0x001, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                    txt_result.setText(_result);
                    edit_num.setText("");
                } catch (RemoteException e) {
                    e.printStackTrace();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }
    }
    

    2.transact와 onTransact의 차이


    Transact와 onTransact에 대해서 얘기를 하려면 iBinder에 대해서 얘기를 해야 돼요.
    Ibinder가 뭘까요?우선 안드로이드의 원격 호출(크로스 프로세스 호출)은 Ibinder를 통해 이루어진 것이고 다음은android 개발 문서에 대한 번역이다.
    Ibinder는 원격 대상의 기본 인터페이스로 고성능을 위해 설계된 경량급 원격 호출 메커니즘의 핵심 부분이다.그러나 이것은 원격 호출뿐만 아니라 프로세스 내 호출에도 사용된다.이 인터페이스는 원격 대상과 상호작용하는 프로토콜을 정의합니다.이 인터페이스를 직접 실현하지 말고 비더에서 파생시켜야 한다.
    Ibinder의 주요 API는transact()이며, 이에 대응하는 또 다른 방법은Binder이다.onTransact().첫 번째 방법은 원격 Ibinder 대상에게 호출을 보낼 수 있고, 두 번째 방법은 원격 대상이 받은 호출에 응답할 수 있도록 한다.Ibinder의 API는 상대방의Binder까지transact () 와 같이 동기화됩니다.onTransact () 방법은 호출이 완료된 후에야 되돌아옵니다.호출은 프로세스 내에서 발생할 때 의심할 여지없이 이와 같으며, 프로세스 간에는 IPC의 도움말 아래에서도 같은 효과가 있다.
    transact()를 통해 전송되는 데이터는 Parcel이며, Parcel은 데이터 외에 그 내용을 설명하는 메타데이터도 있는 일반적인 버퍼입니다.메타데이터는 한 프로세스에서 다른 프로세스로 버퍼가 이동할 때 이 인용을 저장할 수 있도록 Ibinder 대상의 인용을 관리하는 데 사용됩니다.이렇게 하면 하나의 Ibinder가 Parcel에 기록되어 다른 프로세스로 전송될 때, 다른 프로세스가 같은 Ibinder의 인용을 원래의 프로세스로 되돌려보내면, 원래의 프로세스가 보내는 Ibinder의 인용을 받아들일 수 있다.이 메커니즘은 Ibinder와 Binder를 고유 플래그처럼 프로세스 간에 관리합니다.
    시스템은 모든 프로세스를 위해 상호작용 라인을 저장하는 스레드 탱크를 유지한다.이 인터랙티브 스레드는 다른 프로세스에서 보낸 모든 IPC 호출을 전송하는 데 사용됩니다.예를 들어 IPC가 프로세스 A에서 프로세스 B로 보내면 A에서 호출된 루틴 (이것은 루틴 풀에 있지 않을 것) 이transact ()에 막힌다.프로세스 B의 상호작용 스레드 탱크의 한 스레드가 이 호출을 받았습니다. Binder를 호출합니다.onTransact (), 완성되면 Parcel을 결과로 되돌려줍니다.그리고 프로세스 A의 대기 스레드는 반환된 Parcel을 받은 후에 계속 실행될 수 있습니다.실제로 다른 프로세스는 현재 프로세스의 한 라인처럼 보이지만 현재 프로세스가 만든 것은 아닙니다.
    Binder 메커니즘은 프로세스 간의 귀속 호출도 지원합니다.예를 들어 프로세스 A는 자신의 Ibinder의transact ()를 실행하고 프로세스 B의 Binder를 호출하며 프로세스 B는 Binder에 있습니다.Transact () 에서transact () 로 프로세스 A에 호출을 시작하면, 프로세스 A는 호출이 되돌아오기를 기다리는 동안 Binder를 사용합니다.onTransact () 는 프로세스 B의 transact () 에 응답합니다.어쨌든 Binder가 만들어낸 결과는 크로스 프로세스의 호출이 프로세스 내의 호출과 다를 것이 없다는 것을 느끼게 하는 것이다.
    원격 객체를 조작할 때 객체가 유효한지 확인하는 세 가지 방법이 있습니다.
    1 transact () 방법은 Ibinder가 있는 프로세스가 존재하지 않을 때 RemoteException 이상을 던집니다.
    2 대상 프로세스가 존재하지 않으면 pingBinder () 를 호출할 때false를 되돌려줍니다.
    3 링크 To Death () 방법으로 Ibinder에 Ibinder를 등록할 수 있습니다.DeathRecipient, Ibinder가 대표하는 프로세스가 종료될 때 호출됩니다.
    원격 호출을 지원하려면 Binder 클래스에서 클래스를 파생시켜야 합니다.Binder는 Ibinder 인터페이스를 구현합니다.그러나 일반적으로 이런 것을 직접 실현할 필요가 없고, 당신의 필요에 따라 개발 패키지의 도구로 생성됩니다. 이 도구는AIDL이라고 합니다.AIDL 언어를 통해 원격 대상을 정의하는 방법을 정의한 다음 AIDL 도구로 Binder의 파생 클래스를 생성한 다음 사용할 수 있습니다.그러나, 그러나, 물론, 사용자 정의 RPC 호출을 실현하기 위해 Binder 클래스에서 직접 파생하거나, 원시 Binder 대상을 프로세스 간에 공유하는 영패로 실례화할 수도 있다.
      

    좋은 웹페이지 즐겨찾기