안 드 로 이 드 학습 소개 Binder 의 간단 한 사용
최근 회사 프로젝트 수요 로 원 격 스케줄 링 시작 클 라 이언 트 입력 법 입력 내용 이 필요 합 니 다.
이것 이 바로 대체적인 수요 절차 이다.이 편 은 먼저 원 격 과 서비스 제어 단 통신 을 말한다.먼저 제어 서버 에서 서 비 스 를 정의 하고 ServiceManager 에 가입 하여 서 비 스 를 추가 합 니 다.
여기 서 저 는 원 격 단 과 서비스 제어 단 통신(주로 C++를 통 해 ServiceManager 에 서 비 스 를 등록 합 니 다)을 설명 합 니 다.
우선 서비스 제어 단 이 ServiceManager 에 등 록 된 서비스 IBinder 대상 을 얻 고 자바 반사 체 제 를 통 해 Ibinder 인터페이스 대상 을 얻어 야 합 니 다.
public static IBinder getRemoteBinder(){
try {
Class<?> serviceManager = Class.forName("android.os.ServiceManager");
Method getService = serviceManager.getMethod("getService", String.class);
IBinder iBinder = (IBinder) getService.invoke(serviceManager.newInstance(), "InputService");
if(iBinder==null){
Log.e(PinyinIME.TAG,"getService InputService : is empty");
printServerList();//
}
return iBinder;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return null;
}
// android.os.ServiceManager
/**
* Returns a reference to a service with the given name.
*
* @param name the name of the service to get
* @return a reference to the service, or <code>null</code> if the service doesn't exist
*/
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
IBinder 대상 역할 을 가 져 오 는 것 은 크로스 프로 세 스 입 니 다.예 를 들 어 입력 법 프로그램 은 어떻게 편집 상자 와 통신 합 니까?어떻게 어떤 제어 입력 법 으로 팝 업 을 통 해 숨 겼 습 니까?또한 이 IBinder 를 통 해 통신 을 했 습 니 다.원본 코드 를 뒤 집 는 것 을 믿 지 않 습 니 다.여 기 는 상세 한 소 개 를 하지 않 습 니 다.서비스 제어 단 은 C++층 에 서 비 스 를 주입 합 니 다.
class IServiceManager : public IInterface
{
public:
DECLARE_META_INTERFACE(ServiceManager);
/**
* Retrieve an existing service, blocking for a few seconds
* if it doesn't yet exist.
*/
virtual sp<IBinder> getService( const String16& name) const = 0;
/**
* Retrieve an existing service, non-blocking.
*/
virtual sp<IBinder> checkService( const String16& name) const = 0;
/**
* Register a service.
*/
virtual status_t addService( const String16& name,
const sp<IBinder>& service,
bool allowIsolated = false) = 0;
/**
* Return list of all existing services.
*/
virtual Vector<String16> listServices() = 0;
enum {
GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION,
};
};
// C++ IBinder , onTransact
virtual status_t onTransact(uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0)
{
LOGD("enter MyService onTransact and the code is %d", code);
switch (code)
{
case BINDER_HANDLE:
LOGD("MyService interface handle");
reply->writeCString("handle reply");
break;
case BINDER_SET_SCREEN:
LOGD("MyService interface set screen");
reply->writeCString("set screen reply");
break;
case BINDER_SET_CHAR:
{//call cb
LOGD("MyService interface set char before");
reply->writeCString("set char reply");
cb = data.readStrongBinder();
if (cb != NULL)
{
LOGD("MyService interface set char : %s", data.readCString());
Parcel in, out;
in.writeInterfaceToken(String16(BINDER_NAME));
in.writeInt32(n++);
in.writeString16(String16("This is a string."));
cb->transact(1, in, &out, 0);
show();
}
break;
}
default:
return BBinder::onTransact(code, data, reply, flags);
}
return 0;
}
이렇게 하면 우 리 는 방금 IBinder 대상 과 의 통신 을 얻 을 수 있 습 니 다.여기 서 저 는 예 만 말씀 드 리 겠 습 니 다.원 격 엔 드 장치 입력 법 이 활성화 되 었 을 때 저 는 입력 법 입력 유형 과 입력 법 이 보 여 준 다기 능 키 를 서비스 제어 단 에 전달 합 니 다.
// , onStartInputView(EditorInfo,boolean)
Parcel data = Parcel.obtain();
data.writeInt(editorInfo.inputType);
data.writeInt(editorInfo.imeOptions);
Log.d(TAG, "isActives:" + isActives);
if (isActives) {
if (mController != null) {
mController.startInput(data, Parcel.obtain());
} else {
isNeedActives = true;
tmp = data;
mController = new Controller(remoteBinder,this);
}
} else {
isNeedActives = true;
tmp = data;
if (mController != null) {
mController.serviceConnection();
} else {
mController = new Controller(remoteBinder,this);
}
}
// int Parce
/**
*
*
* @param data
*
* @param reply
*/
public void startInput(final Parcel data, final Parcel reply) {
Log.d(PinyinIME.TAG, getClass().getName() + ":\t startInput");
if (!PinyinIME.isActives) {
Log.d(PinyinIME.TAG, "not yet check success , start input failure");
dealHandler.sendEmptyMessage(Constant.HANDER_RELINK);
return;
}
new Thread(new Runnable() {
@Override
public void run() {
if (remoteBinder != null && remoteBinder.isBinderAlive()) {
try {
if (remoteBinder.transact(
Constant.INPUT_METHOD_ACTIVATION, data, reply,
IBinder.FLAG_ONEWAY)) {
PinyinIME.isNeedActives = false;
Log.d(PinyinIME.TAG,
"input method to activate, notify the success");
} else {
Log.d(PinyinIME.TAG,
"input method to activate, notify the failure");
}
} catch (RemoteException e) {
e.printStackTrace();
} finally {
data.recycle();
reply.recycle();
}
}else{
dealHandler.sendEmptyMessage(Constant.HANDER_RELINK);
}
}
}).start();
}
이렇게 하면 우 리 는 얻 은 Ibinder 대상 의 transact 방법 을 통 해 통신 할 수 있다.
//code , ,
// ,
// , ,
//0 ,FLAG_ONEWAY
public boolean transact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException;
우리 가ibinder.transact(int,parce,parce,int)
방법 을 호출 하면 이것 은 등 록 된 서비스 중의 IBinder 대상onTransact(int,parce,parce,int)
방법 이 응답 할 것 이다.그러면 우 리 는 원 격 단 과 서비스 제어 단 통신 을 실현 할 수 있다.여기까지 문제 가 있 습 니 다.서비스 제어 단 이 클 라 이언 트 가 입력 한 내용 을 받 으 면 어떻게 합 니까?원 격 입력 법 에 내용 을 편집 상자 에 입력 하 라 고 알려 야 합 니까?
사실은 간단 합 니 다.우 리 는 원 격 입력 법 프로그램 에서 Ibinder 대상 을 실현 하고 서비스 통제 단 에 전달 하면 실현 할 수 있 습 니 다.구체 적 으로 어떻게 전달 합 니까?
// ibinder 。
package com.redfinger.inputmethod.server;
import com.android.inputmethod.pinyin.PinyinIME;
import android.annotation.SuppressLint;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
import android.view.KeyEvent;
public interface InputBinder extends IInterface{
public static class Stub extends Binder implements InputBinder{
private static final java.lang.String DESCRIPTOR = "com.redfinger.inputmethod.service.InputBinder";
public PinyinIME pinyinIME;
public Stub(PinyinIME pinyinIME) {
this.pinyinIME = pinyinIME;
this.attachInterface(this, DESCRIPTOR);
}
public InputBinder asInterface(IBinder obj){
if(obj == null){
return null;
}
IInterface iInterface = obj.queryLocalInterface(DESCRIPTOR);
if(iInterface!=null&&iInterface instanceof InputBinder){
return (InputBinder)iInterface;
}
return new Stub.Proxy(obj);
}
@Override
public IBinder asBinder() {
return this;
}
@SuppressLint({ "NewApi", "Recycle" })
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
switch (code) {
case Constant.CONNECTION_HANDSHAKE2:
String dataString = data.readString();
Log.d(PinyinIME.TAG, "The second handshake start [data = "+dataString +"]");
if("CONNECTION_RESPONED".equals(dataString)){
Parcel parcel = Parcel.obtain();
parcel.writeString("CONNECTION_FINISH");
pinyinIME.getRemoteBinder().transact(Constant.CONNECTION_HANDSHAKE3, parcel, Parcel.obtain(), IBinder.FLAG_ONEWAY);
PinyinIME.isActives = true;
Log.d(PinyinIME.TAG, "The third handshake success");
if (PinyinIME.isNeedActives) {
PinyinIME.mController.startInput(pinyinIME.getTmp(), Parcel.obtain());
}
if (PinyinIME.isNeedCloseInputMethod) {
PinyinIME.mController.finishInput();
}
}else{
Log.d(PinyinIME.TAG, "The third handshake failure , agent connect ! ");
PinyinIME.mController.serviceConnection();
}
break;
case Constant.FUNCTION_INPUT:
....
switch (keyCode) {
case 14:
pinyinIME.simulateKeyEventDownUp(KeyEvent.KEYCODE_DEL);
return true;
case 28:
pinyinIME.simulateKeyEventDownUp(KeyEvent.KEYCODE_ENTER);
return true;
case 65:
pinyinIME.requestHideSelfFromClient = true;
pinyinIME.requestHideSelf(0);
break;
}
break;
case Constant.CHARACTER_INPUT:
....
return true;
case Constant.DISCONNECTION:
....
break;
case Constant.INPUT_METHOD_PLATFORM:
....
break;
}
return super.onTransact(code, data, reply, flags);
}
public static class Proxy implements InputBinder{
private android.os.IBinder mRemote;
public Proxy(android.os.IBinder mRemote) {
this.mRemote = mRemote;
}
@Override
public IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
}
static final int receiveChar = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
}
특이 한 변화 가 AIDL 파일 의 내용 과 같 지 않 습 니까?에 이 드 는 사실 안 드 로 이 드 가 직접 써 준 ibinder 코드 와 같 습 니 다.이렇게 하면 우 리 는 서비스 제어 단 ibinder 대상 에 우리 자신의 ibinder 대상 을 기록 하고 과거 에 그 가 transact 방법 을 통 해 입력 법 프로그램 ibinder 대상 과 통신 하도록 전달 할 수 있다.
//Parce , ibinder 。
public final void writeStrongBinder(IBinder val) {
nativeWriteStrongBinder(mNativePtr, val);
}
이렇게 하면 우 리 는 InputBinder 류 에서 되 돌아 오 는 데 이 터 를 처리 할 수 있다.총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 면 댓 글 을 남 겨 주 십시오.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.