Android AIDL 의 인 스 턴 스 와 원 리 를 분석 합 니 다.
쉽게 말 하면 AIDL 은 하나의 인 터 페 이 스 를 정의 하 는 것 입 니 다.클 라 이언 트(호출 단)는 bindService 를 통 해 원 격 서버 와 연결 을 만 들 고 이 연결 을 만 들 때 IBinder 대상 을 되 돌려 줍 니 다.이 대상 은 서버 Binder 의 BinderProxy 입 니 다.연결 을 만 들 때 클 라 이언 트 는 asInterface 함 수 를 통 해 이 BinderProxy 대상 을 원가 의 Proxy 로 포장 하고 Proxy 류 의 mRemote 필드 에 값 을 부여 합 니 다.로 컬 은 mRemote 를 통 해 원 격 방법 을 호출 할 수 있 습 니 다.
2..aidl 파일 만 들 기
먼저 Android Studio,new AIDL file 을 엽 니 다.구체 적 인 코드 는 다음 과 같다.
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
basic Types 방법 은 인터페이스 가 자체 적 으로 가지 고 있 지만,aidl 에 서 는 이러한 기본 적 인 유형의 매개 변수 만 사용 할 수 있 습 니 다:int,long,boolean,float,double,String;basic Types 방법 외 에 도 우 리 는 자신의 방법 을 추가 할 수 있 습 니 다.따라서 basic Types 방법 을 삭제 하고 자신의 방법 을 추가 할 수 있 습 니 다.
3.자바 파일 생 성
방법 을 추가 한 후.aidl 파일 을 선택 하고 팝 업 메뉴 에서 Synchronize LocalAIDLS...Service.java 를 선택 하면 자동 으로 자바 코드 를 생 성 합 니 다.
코드 를 포맷 한 후 다음 과 같 습 니 다.
package com.example.databasetest;
public interface IMyAidlInterface extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.example.databasetest.IMyAidlInterface {
private static final java.lang.String DESCRIPTOR = "com.example.databasetest.IMyAidlInterface";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.databasetest.IMyAidlInterface interface,
* generating a proxy if needed.
*/
public static com.example.databasetest.IMyAidlInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.databasetest.IMyAidlInterface))) {
return ((com.example.databasetest.IMyAidlInterface) iin);
}
return new com.example.databasetest.IMyAidlInterface.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_basicTypes: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0 != data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.databasetest.IMyAidlInterface {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean) ? (1) : (0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString); // ,proxy , ,
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}
만약.aidl 파일 을 수정 해 야 한다 면,수정 후 build->make procject 를 선택 하면 해당 하 는 자바 파일 을 다시 생 성 할 수 있 습 니 다.생 성 된 이 자바 류 에 대해 서 는 갓 접촉 한 사람들 이 이해 하지 못 하 는 경우 가 많 습 니 다.여기 서 설명 이 필요 합 니 다.
복잡 한 데 이 터 를 전달 해 야 한다 면 Parcelable 인 터 페 이 스 를 실현 하고 직렬 화 할 수 있 습 니 다.
public class Info implements Parcelable {
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Info() {
}
public Info(Parcel in) {
content = in.readString();
}
public static final Creator<Info> CREATOR = new Creator<Info>() {
@Override
public Info createFromParcel(Parcel in) {
return new Info(in);
}
@Override
public Info[] newArray(int size) {
return new Info[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(content);
}
/**
* Parcel,
*
* @param dest
*/
public void readFromParcel(Parcel dest) {
// , writeToParcel()
content = dest.readString();
}
//
@Override
public String toString() {
return "content : " + content;
}
}
이 동시에 info.aidl 파일 을 만들어 데이터 도 전달 할 수 있 음 을 나타 낸다.
package com.viii.aidlclient;
// :Info.Info.java
// Info AIDL
// parcelable
parcelable Info;
이렇게 하면 info 대상 을 사용 할 수 있 습 니 다.앞의 기본 형식 변수 에 의 해 제어 되 지 않 습 니 다.5.서비스 구축
이 어 새로운 Service 는 메 시 지 를 받 고 AndroidManifest.xml 에 서 비 스 를 등록 합 니 다.
public class MyService extends Service {
private static final String TAG = "MyService";
// private MyBinder mMyBinder = new MyBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind: "); // mBinder
return null;
}
@Override
public void onCreate() {
Log.d(TAG, "onCreate: ");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
// , stub, ,
private final IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
//
}
};
}
이 럴 때 basic Types 방법 으로 구체 적 인 함수 코드 를 추가 하여 원 하 는 기능 을 실현 할 수 있 습 니 다.로 컬 에서 프 록 시 를 가 져 온 후에 basic Types 를 호출 하면 서버 호출 이 실 행 됩 니 다.
6.서비스 획득
이어서 mainactivity 에서 연결 합 니 다.
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private IMyAidlInterface mService;
private boolean mIsBound;
private AdditionServiceConnection mServiceConnection;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
doBindService() ;
}/**
* bind service
*/
private void doBindService() {
mServiceConnection = new AdditionServiceConnection();
Intent intent = new Intent(this, MyService.class);
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
}
/**
* unbind service
*/
private void doUnbindService() {
if (mIsBound) {
unbindService(mServiceConnection);
mServiceConnection = null;
mIsBound = false;
}
}
/**
* ServiceConection
*/
class AdditionServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) { // , service 。
mService = IMyAidlInterface.Stub.asInterface((IBinder) service);
mIsBound = true;
try {
//
service.linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
Log.d(TAG, "onServiceConnected: ");
}
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
mIsBound = false;
Log.d(TAG, "onServiceDisconnected: ");
}
}
/**
* Binder
*/
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (mService == null) {
return;
}
mService.asBinder().unlinkToDeath(mDeathRecipient, 0);
mService = null;
//
doBindService();
}
};
@Override
protected void onStop() {
super.onStop();
doUnbindService();
}
}
원 격 서비스의 binder 를 받 은 후에 우 리 는 관련 방법 으로 자신의 기능 을 실현 할 수 있 습 니 다.여기까지 AIDL 하나 가 우리 에 게 이 루어 졌 다.
7.호출 과정 분석
asInterface 방법 을 보 세 요.저 희 는 bid 하나의 Service 를 받 은 후에 onServiceConnection 의 리 셋 에서 이 방법 을 통 해 원 격 서 비 스 를 받 았 습 니 다.이 방법 은 무엇 을 했 습 니까?
/**
* Cast an IBinder object into an com.example.databasetest.IMyAidlInterface interface,
* generating a proxy if needed.
*/
public static com.example.databasetest.IMyAidlInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.databasetest.IMyAidlInterface))) {
return ((com.example.databasetest.IMyAidlInterface) iin);
} // , , ,
return new com.example.databasetest.IMyAidlInterface.Stub.Proxy(obj);
}
먼저 함수 의 인자IBinder
유형의 obj 를 보십시오.이 대상 은 우리 에 게 구동 되 는 것 입 니 다.Binder 로 컬 대상 이 라면 Binder 유형 입 니 다.Binder 대리 대상 이 라면BinderProxy
유형 입 니 다.Binder 로 컬 대상 을 찾 아 보 겠 습 니 다.찾 으 면 Client 와 Server 가 같은 프로 세 스 에 있 음 을 설명 합 니 다.이 매개 변 수 는 로 컬 대상 이 고 형식 변환 을 직접 강제 한 다음 에 돌아 갑 니 다.찾 을 수 없다 면 원 격 대상(다른 프로 세 스 에 있 음)임 을 설명 합 니 다.원 격 대상 에 대한 접근 을 위해 서 는 Binder 프 록 시 대상 을 만들어 야 합 니 다.일반적으로 원 격 서비스 대상 과 통신 을 한다 면 여기 서 돌아 오 는 것 은 반드시 Binder 대리 대상 입 니 다.이 IBinder 매개 변 수 는 실제 적 으로 BinderProxy 입 니 다.
에 이 드 의 basic Types 방법 에 대한 우리 의 실현 을 살 펴 보 자.Stub 류 에서 basic Types 는 추상 적 인 방법 으로 우 리 는 이 유형 을 계승 하여 실현 해 야 한다.클 라 이언 트 와 서버 가 같은 프로 세 스에 있다 면 이 방법 을 직접 호출 하 는 것 입 니 다.그렇다면 원 격 호출 이 라면 그 사이 에 무슨 일이 일 어 났 을 까?Client 는 어떻게 서버 로 호출 합 니까?
원 격 방법 에 대한 호출 은 Binder 대 리 를 통 해 이 루어 졌 습 니 다.이 예 에서
Proxy
클래스 입 니 다.Proxy
basic Types 방법 에 대한 실현 은 다음 과 같다.
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean) ? (1) : (0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
// ,
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
그것 은 먼저 Parcel 로 데 이 터 를 서열 화한 다음 에 transact 방법 을 호출 했다.이 transact 는 도대체 무엇 을 했 습 니까?이 프 록 시 클래스 는 asInterface 방법 에서 생 성 되 었 습 니 다.앞에서 언급 한 바 와 같이 Binder 에이전트 라면 드라이브 가 되 돌아 오 는 IBinder 가 실제 BinderProxy 라 는 것 을 설명 합 니 다.따라서 우리 프 록 시 클래스 의 mRemote 실제 유형 은 BinderProxy 여야 합 니 다.Binder Proxy 의 transact 방법 을 봅 시다.(Binder.java 의 내부 클래스)
public native boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
이것 은 현지 방법 이다.그것 의 실현 은 native 층 에 있 습 니 다.구체 적 으로 프레임 워 크/base/core/jni/androidutil_Binder.cpp 파일 에서 일련의 함수 호출 이 진행 되 었 습 니 다.호출 체인 이 너무 길 어서 여기 서 제시 하지 않 습 니 다.알 아야 할 것 은 토 크 위 드 드라이버 함수 로 최종 호출 되 었 습 니 다.이 함수 의 이름 을 보면 통신 과정 은 구동 에 맡 겨 야 한 다 는 것 을 알 수 있다.이 함 수 는 마지막 으로 ioctl 시스템 을 통 해 호출 되 었 습 니 다.Client 프로 세 스 는 커 널 상태 에 빠 졌 습 니 다.Client 는 basicTypes 방법의 스 레 드 를 걸 어 되 돌아 오 기 를 기다 리 고 있 습 니 다.일련의 작업 이 끝 난 후에 서버 프로 세 스 를 깨 우 고 서버 프로 세 스 로 컬 대상 의 onTransact 함 수 를 호출 했 습 니 다.Binder 로 컬 대상 의 onTransact 방법 을 다시 봅 니 다.
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_basicTypes: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0 != data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
서버 프로 세 스에 서 onTransact 는 호출 번호(AIDL 함수 마다 하나의 번호 가 있 습 니 다.프로 세 스 를 뛰 어 넘 을 때 함 수 를 전달 하지 않 고 전달 번호 에 따라 어떤 함 수 를 호출 하 는 지 알려 줍 니 다)에 따라 관련 함 수 를 호출 합 니 다.이 예 에서 Binder 로 컬 대상 의 basic Types 방법 을 호출 하 였 습 니 다.이 방법 은 결 과 를 드라이버 에 되 돌려 주 고 걸 려 있 는 Client 프로 세 스 의 스 레 드 를 깨 우 고 결 과 를 되 돌려 줍 니 다.그래서 크로스 프로 세 스 호출 이 완료 되 었 습 니 다.
이로써 AIDL 이라는 통신 방식 의 각 유형 과 각 역할 에 대해 어느 정도 알 게 되 었 을 것 이다.이것 은 항상 고정된 모델 입 니 다.크로스 프로 세 스 전달 이 필요 한 대상 은 반드시 IBinder 에서 계승 합 니 다.만약 에 Binder 로 컬 대상 이 라면 반드시 Binder 를 계승 하여 IInterface 를 실현 합 니 다.만약 에 대리 대상 이 라면 IInterface 를 실현 하고 IBinder 참조 가 있 습 니 다.
프 록 시 와 스 텁 는 다르다.이들 은 모두 Binder 이자 IInterface 이지 만 스 텁 는 계승(is 관계),프 록 시 는 조합(has 관계)을 사용한다.그들 은 모두 모든 IInterface 함 수 를 실현 했다.
다른 것 은 Stub 가 정책 모드 를 사용 하여 가상 함수(하위 클래스 구현 대기)를 호출 하고 Proxy 는 조합 모드 를 사용 합 니 다.왜 Stub 는 계승 을 사용 하고 Proxy 는 조합 을 사용 합 니까?사실 Stub 자 체 는 IBinder(Binder)입 니 다.그 자체 가 프로 세 스 경 계 를 넘 어 전송 할 수 있 는 대상 이기 때문에 IBinder 를 계승 하여 transact 라 는 함 수 를 실현 하여 프로 세 스 를 뛰 어 넘 는 능력 을 가 져 야 합 니 다(이 능력 은 구동 에 의 해 부 여 됩 니 다).
프 록 시 클래스 가 조합 을 사용 하 는 이 유 는 자신 이 무엇 인지 에 관심 이 없고 프로 세 스 전송 을 뛰 어 넘 을 필요 가 없 기 때 문 입 니 다.이 능력 만 가지 면 됩 니 다.이 능력 을 가지 기 위해 서 는 IBinder 에 대한 인용 만 유지 해 야 합 니 다.
이상 은 안 드 로 이 드 AIDL 의 인 스 턴 스 와 원 리 를 분석 하 는 상세 한 내용 입 니 다.안 드 로 이 드 AIDL 에 관 한 자 료 는 다른 관련 글 을 주목 하 세 요!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.