Android8.0 Binder之面向HAL服務(二)
上一篇我們從Binder在系統native層的服務管理與提供機制,它與Framework的native層的實現大不相同,但是實現思想是一致的,都是需要藉助Binder驅動來實現服務的管理與跨程序使用。只不過,由於業務層需要導致實現上的不同,比如HAL層的Binder框架並沒有將通訊和業務絞和起來,所以在業務邏輯處理上更為複雜,當然複雜是為了更好的適應業務需求。那麼我們不妨回到Java層看看Java的HwBinder是如何為使用者提供便利操作的,首先我們來看基本的HwBinder在Java層的框架。
1. Binder頂層協議
public interface IHwBinder {
// These MUST match their corresponding libhwbinder/IBinder.h definition !!!
public static final int FIRST_CALL_TRANSACTION = 1;
public static final int FLAG_ONEWAY = 1;
public void transact( //通訊操作函式
int code, HwParcel request, HwParcel reply, int flags)
throws RemoteException;
public IHwInterface queryLocalInterface(String descriptor); //查詢服務描述符
.....
}
HwRemoteBinder 實現了 IHwBinder 介面
public class HwRemoteBinder implements IHwBinder {
private static final String TAG = "HwRemoteBinder";
private static final NativeAllocationRegistry sNativeRegistry;
public HwRemoteBinder() {
native_setup_empty();
sNativeRegistry.registerNativeAllocation(
this ,
mNativeContext);
}
@Override
public IHwInterface queryLocalInterface(String descriptor) {
return null; //返回為空
}
@Override
public native final void transact( //未實現
int code, HwParcel request, HwParcel reply, int flags)
throws RemoteException;
}
......
private static native final long native_init();
private native final void native_setup_empty();
......
private long mNativeContext;
}
HwBinder 實現了 IHwBinder 介面
public abstract class HwBinder implements IHwBinder {
private static final String TAG = "HwBinder";
private static final NativeAllocationRegistry sNativeRegistry;
public HwBinder() {
native_setup();
sNativeRegistry.registerNativeAllocation(
this,
mNativeContext);
}
@Override
public final native void transact( //未實現
int code, HwParcel request, HwParcel reply, int flags)
throws RemoteException;
public abstract void onTransact(// 新增
int code, HwParcel request, HwParcel reply, int flags)
throws RemoteException;
public native final void registerService(String serviceName)
throws RemoteException;
public static native final IHwBinder getService(
String iface,
String serviceName)
throws RemoteException, NoSuchElementException;
// Returns address of the "freeFunction".
private static native final long native_init();
private native final void native_setup();
......
private long mNativeContext;
}
IHwInterface 介面
public interface IHwInterface {
public IHwBinder asBinder();
}
在 frameworks\base\core\jni\android_os_HwBinder.cpp 檔案中可以看到登錄檔
static JNINativeMethod gMethods[] = {
{ "native_init", "()J", (void *)JHwBinder_native_init },
{ "native_setup", "()V", (void *)JHwBinder_native_setup },
{ "transact",
"(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
(void *)JHwBinder_native_transact },
{ "registerService", "(Ljava/lang/String;)V",
(void *)JHwBinder_native_registerService },
{ "getService", "(Ljava/lang/String;Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;",
(void *)JHwBinder_native_getService },
};
static jlong JHwBinder_native_init(JNIEnv *env) {
JHwBinder::InitClass(env);
return reinterpret_cast<jlong>(&releaseNativeContext);
}
初始化類
void JHwBinder::InitClass(JNIEnv *env) {
ScopedLocalRef<jclass> clazz(
env, FindClassOrDie(env, CLASS_PATH));
gFields.contextID =
GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J");
gFields.onTransactID =
GetMethodIDOrDie(
env,
clazz.get(),
"onTransact",
"(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V");
}
static void JHwBinder_native_setup(JNIEnv *env, jobject thiz) {
sp<JHwBinder> context = new JHwBinder(env, thiz);
JHwBinder::SetNativeContext(env, thiz, context);
}
設定上下文
sp<JHwBinder> JHwBinder::SetNativeContext(
JNIEnv *env, jobject thiz, const sp<JHwBinder> &context) {
sp<JHwBinder> old =
(JHwBinder *)env->GetLongField(thiz, gFields.contextID);
if (context != NULL) {
context->incStrong(NULL /* id */);
}
if (old != NULL) {
old->decStrong(NULL /* id */);
}
env->SetLongField(thiz, gFields.contextID, (long)context.get());
return old;
}
獲取服務流程
static jobject JHwBinder_native_getService(
JNIEnv *env,
jclass /* clazzObj */,
jstring ifaceNameObj,
jstring serviceNameObj) {
using ::android::hidl::base::V1_0::IBase;
using ::android::hidl::manager::V1_0::IServiceManager;
.......
auto manager = hardware::defaultServiceManager(); //獲取服務管家
if (manager == nullptr) {
LOG(ERROR) << "Could not get hwservicemanager.";
signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
return NULL;
}
const char *ifaceNameCStr = env->GetStringUTFChars(ifaceNameObj, NULL);
if (ifaceNameCStr == NULL) {
return NULL; // XXX exception already pending?
}
std::string ifaceName(ifaceNameCStr);
env->ReleaseStringUTFChars(ifaceNameObj, ifaceNameCStr);
::android::hardware::hidl_string ifaceNameHStr;
ifaceNameHStr.setToExternal(ifaceName.c_str(), ifaceName.size());
const char *serviceNameCStr = env->GetStringUTFChars(serviceNameObj, NULL);
if (serviceNameCStr == NULL) {
return NULL; // XXX exception already pending?
}
std::string serviceName(serviceNameCStr);
env->ReleaseStringUTFChars(serviceNameObj, serviceNameCStr);
::android::hardware::hidl_string serviceNameHStr;
serviceNameHStr.setToExternal(serviceName.c_str(), serviceName.size());
//查詢Binder型別
Return<IServiceManager::Transport> transportRet =
manager->getTransport(ifaceNameHStr, serviceNameHStr);
if (!transportRet.isOk()) {
signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
return NULL;
}
IServiceManager::Transport transport = transportRet;
#ifdef __ANDROID_TREBLE__
#ifdef __ANDROID_DEBUGGABLE__
const char* testingOverride = std::getenv("TREBLE_TESTING_OVERRIDE");
const bool vintfLegacy = (transport == IServiceManager::Transport::EMPTY)
&& testingOverride && !strcmp(testingOverride, "true");
#else // __ANDROID_TREBLE__ but not __ANDROID_DEBUGGABLE__
const bool vintfLegacy = false;
#endif // __ANDROID_DEBUGGABLE__
#else // not __ANDROID_TREBLE__
const bool vintfLegacy = (transport == IServiceManager::Transport::EMPTY);
#endif // __ANDROID_TREBLE__";
if (transport != IServiceManager::Transport::HWBINDER && !vintfLegacy) {
LOG(ERROR) << "service " << ifaceName << " declares transport method "
<< toString(transport) << " but framework expects hwbinder.";
signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
return NULL;
}
Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceNameHStr, serviceNameHStr); //返回服務
if (!ret.isOk()) {
signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
return NULL;
}
sp<hardware::IBinder> service = hardware::toBinder< //轉換為Binder
hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase>(ret);
if (service == NULL) {
signalExceptionForError(env, NAME_NOT_FOUND);
return NULL;
}
LOG(INFO) << "Starting thread pool.";
::android::hardware::ProcessState::self()->startThreadPool();
return JHwRemoteBinder::NewObject(env, service); //建立BpBinder物件並返回
}
可以看到獲取服務最終還是需要呼叫native層的Binder框架來處理,這一點可Framework層中的Binder(Java)設計思想是一致的
2. Power.hal生成的服務介面
由於定義了.hal檔案,通過編譯會生成對響應的服務程式碼,out/target/gen/JAVA_LIBRARIES/android.hardware.power-V1.0-java_intermediates目錄下IPower.java檔案
public static IPower getService(String serviceName) throws android.os.RemoteException {
return IPower.asInterface(android.os.HwBinder.getService("[email protected]::IPower",serviceName));
}
static IPower asInterface(android.os.IHwBinder binder) { //查詢
if (binder == null) {
return null;
}
android.os.IHwInterface iface =
binder.queryLocalInterface(kInterfaceName);
if ((iface != null) && (iface instanceof IPower)) {
return (IPower)iface;
}
IPower proxy = new IPower.Proxy(binder); //Proxy內部類
try {
for (String descriptor : proxy.interfaceChain()) {
if (descriptor.equals(kInterfaceName)) {
return proxy;
}
}
} catch (android.os.RemoteException e) {
}
return null;
}
內部類,返回遠端Binder代理物件
public static final class Proxy implements IPower {
private android.os.IHwBinder mRemote;
public Proxy(android.os.IHwBinder remote) {
mRemote = java.util.Objects.requireNonNull(remote);
}
@Override
public android.os.IHwBinder asBinder() {
return mRemote;
}
......
}
內部類,通過Stub呼叫
public static abstract class Stub extends android.os.HwBinder implements IBase {
@Override
public android.os.IHwBinder asBinder() {
return this;
}
@Override
public final java.util.ArrayList<String> interfaceChain() {
return new java.util.ArrayList<String>(java.util.Arrays.asList(
IBase.kInterfaceName));
}
@Override
public final String interfaceDescriptor() {
return IBase.kInterfaceName;
}
......
@Override
public void onTransact(int _hidl_code, android.os.HwParcel _hidl_request, final android.os.HwParcel _hidl_reply, int _hidl_flags)
throws android.os.RemoteException {
}
}
由此可以看出HIDL生成的服務程式碼與AIDL是相似的,繼續看會發現IPower繼承了android.hidl.base.V1_0.IBase.java, IBase繼承自android.os.IHwInterface.java
本篇跟蹤了Java層仍然需要通過native層的Binder框架來使用Hw層服務的,流程和Framework層的Binder呼叫大致一樣,較為簡單,今天就到此為止。