android_os_HwBinder.cpp revision 0382be2f32a78c3ee5f1601bb0a4cef8ae9c0903
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "android_os_HwBinder" 19#include <android-base/logging.h> 20 21#include "android_os_HwBinder.h" 22 23#include "android_os_HwParcel.h" 24#include "android_os_HwRemoteBinder.h" 25 26#include <JNIHelp.h> 27#include <android/hidl/manager/1.0/IServiceManager.h> 28#include <android/hidl/base/1.0/IBase.h> 29#include <android/hidl/base/1.0/BpHwBase.h> 30#include <android_runtime/AndroidRuntime.h> 31#include <hidl/ServiceManagement.h> 32#include <hidl/Status.h> 33#include <hidl/HidlTransportSupport.h> 34#include <hwbinder/ProcessState.h> 35#include <nativehelper/ScopedLocalRef.h> 36#include <vintf/parse_string.h> 37 38#include "core_jni_helpers.h" 39 40using android::AndroidRuntime; 41using android::hardware::hidl_vec; 42using android::hardware::hidl_string; 43template<typename T> 44using Return = android::hardware::Return<T>; 45 46#define PACKAGE_PATH "android/os" 47#define CLASS_NAME "HwBinder" 48#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME 49 50namespace android { 51 52static jclass gArrayListClass; 53static struct { 54 jmethodID size; 55 jmethodID get; 56} gArrayListMethods; 57 58static jclass gErrorClass; 59 60static struct fields_t { 61 jfieldID contextID; 62 jmethodID onTransactID; 63} gFields; 64 65// static 66void JHwBinder::InitClass(JNIEnv *env) { 67 ScopedLocalRef<jclass> clazz( 68 env, FindClassOrDie(env, CLASS_PATH)); 69 70 gFields.contextID = 71 GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J"); 72 73 gFields.onTransactID = 74 GetMethodIDOrDie( 75 env, 76 clazz.get(), 77 "onTransact", 78 "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V"); 79} 80 81// static 82sp<JHwBinder> JHwBinder::SetNativeContext( 83 JNIEnv *env, jobject thiz, const sp<JHwBinder> &context) { 84 sp<JHwBinder> old = 85 (JHwBinder *)env->GetLongField(thiz, gFields.contextID); 86 87 if (context != NULL) { 88 context->incStrong(NULL /* id */); 89 } 90 91 if (old != NULL) { 92 old->decStrong(NULL /* id */); 93 } 94 95 env->SetLongField(thiz, gFields.contextID, (long)context.get()); 96 97 return old; 98} 99 100// static 101sp<JHwBinder> JHwBinder::GetNativeContext( 102 JNIEnv *env, jobject thiz) { 103 return (JHwBinder *)env->GetLongField(thiz, gFields.contextID); 104} 105 106JHwBinder::JHwBinder(JNIEnv *env, jobject thiz) { 107 jclass clazz = env->GetObjectClass(thiz); 108 CHECK(clazz != NULL); 109 110 mClass = (jclass)env->NewGlobalRef(clazz); 111 mObject = env->NewWeakGlobalRef(thiz); 112} 113 114JHwBinder::~JHwBinder() { 115 JNIEnv *env = AndroidRuntime::getJNIEnv(); 116 117 env->DeleteWeakGlobalRef(mObject); 118 mObject = NULL; 119 120 env->DeleteGlobalRef(mClass); 121 mClass = NULL; 122} 123 124status_t JHwBinder::onTransact( 125 uint32_t code, 126 const hardware::Parcel &data, 127 hardware::Parcel *reply, 128 uint32_t flags, 129 TransactCallback callback) { 130 JNIEnv *env = AndroidRuntime::getJNIEnv(); 131 132 ScopedLocalRef<jobject> requestObj(env, JHwParcel::NewObject(env)); 133 JHwParcel::GetNativeContext(env, requestObj.get())->setParcel( 134 const_cast<hardware::Parcel *>(&data), false /* assumeOwnership */); 135 136 ScopedLocalRef<jobject> replyObj(env, JHwParcel::NewObject(env)); 137 138 sp<JHwParcel> replyContext = 139 JHwParcel::GetNativeContext(env, replyObj.get()); 140 141 replyContext->setParcel(reply, false /* assumeOwnership */); 142 replyContext->setTransactCallback(callback); 143 144 env->CallVoidMethod( 145 mObject, 146 gFields.onTransactID, 147 code, 148 requestObj.get(), 149 replyObj.get(), 150 flags); 151 152 if (env->ExceptionCheck()) { 153 jthrowable excep = env->ExceptionOccurred(); 154 env->ExceptionDescribe(); 155 156 if (env->IsInstanceOf(excep, gErrorClass)) { 157 /* It's an error */ 158 LOG(ERROR) << "Forcefully exiting"; 159 exit(1); 160 } else { 161 env->ExceptionClear(); 162 LOG(ERROR) << "Uncaught exception!"; 163 } 164 165 env->DeleteLocalRef(excep); 166 } 167 168 status_t err = OK; 169 170 if (!replyContext->wasSent()) { 171 // The implementation never finished the transaction. 172 err = UNKNOWN_ERROR; // XXX special error code instead? 173 174 reply->setDataPosition(0 /* pos */); 175 } 176 177 // Release all temporary storage now that scatter-gather data 178 // has been consolidated, either by calling the TransactCallback, 179 // if wasSent() == true or clearing the reply parcel (setDataOffset above). 180 replyContext->getStorage()->release(env); 181 182 // We cannot permanently pass ownership of "data" and "reply" over to their 183 // Java object wrappers (we don't own them ourselves). 184 185 JHwParcel::GetNativeContext(env, requestObj.get())->setParcel( 186 NULL /* parcel */, false /* assumeOwnership */); 187 188 replyContext->setParcel( 189 NULL /* parcel */, false /* assumeOwnership */); 190 191 return err; 192} 193 194} // namespace android 195 196//////////////////////////////////////////////////////////////////////////////// 197 198using namespace android; 199 200static void releaseNativeContext(void *nativeContext) { 201 sp<JHwBinder> binder = (JHwBinder *)nativeContext; 202 203 if (binder != NULL) { 204 binder->decStrong(NULL /* id */); 205 } 206} 207 208static jlong JHwBinder_native_init(JNIEnv *env) { 209 JHwBinder::InitClass(env); 210 211 return reinterpret_cast<jlong>(&releaseNativeContext); 212} 213 214static void JHwBinder_native_setup(JNIEnv *env, jobject thiz) { 215 sp<JHwBinder> context = new JHwBinder(env, thiz); 216 217 JHwBinder::SetNativeContext(env, thiz, context); 218} 219 220static void JHwBinder_native_transact( 221 JNIEnv * /* env */, 222 jobject /* thiz */, 223 jint /* code */, 224 jobject /* requestObj */, 225 jobject /* replyObj */, 226 jint /* flags */) { 227 CHECK(!"Should not be here"); 228} 229 230static void JHwBinder_native_registerService( 231 JNIEnv *env, 232 jobject thiz, 233 jobject interfaceChainArrayList, 234 jstring serviceNameObj) { 235 if (serviceNameObj == NULL) { 236 jniThrowException(env, "java/lang/NullPointerException", NULL); 237 return; 238 } 239 240 const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL); 241 if (serviceName == NULL) { 242 return; // XXX exception already pending? 243 } 244 245 jint numInterfaces = env->CallIntMethod(interfaceChainArrayList, 246 gArrayListMethods.size); 247 hidl_string *strings = new hidl_string[numInterfaces]; 248 249 for (jint i = 0; i < numInterfaces; i++) { 250 jstring strObj = static_cast<jstring>( 251 env->CallObjectMethod(interfaceChainArrayList, 252 gArrayListMethods.get, 253 i) 254 ); 255 const char * str = env->GetStringUTFChars(strObj, nullptr); 256 strings[i] = hidl_string(str); 257 env->ReleaseStringUTFChars(strObj, str); 258 } 259 260 hidl_vec<hidl_string> interfaceChain; 261 interfaceChain.setToExternal(strings, numInterfaces, true /* shouldOwn */); 262 263 sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz); 264 265 /* TODO(b/33440494) this is not right */ 266 sp<hidl::base::V1_0::IBase> base = new hidl::base::V1_0::BpHwBase(binder); 267 268 auto manager = hardware::defaultServiceManager(); 269 270 if (manager == nullptr) { 271 LOG(ERROR) << "Could not get hwservicemanager."; 272 signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */); 273 return; 274 } 275 276 Return<bool> ret = manager->add(interfaceChain, serviceName, base); 277 278 env->ReleaseStringUTFChars(serviceNameObj, serviceName); 279 serviceName = NULL; 280 281 bool ok = ret.isOk() && ret; 282 283 if (ok) { 284 LOG(INFO) << "Starting thread pool."; 285 ::android::hardware::ProcessState::self()->startThreadPool(); 286 } 287 288 signalExceptionForError(env, (ok ? OK : UNKNOWN_ERROR), true /* canThrowRemoteException */); 289} 290 291static jobject JHwBinder_native_getService( 292 JNIEnv *env, 293 jclass /* clazzObj */, 294 jstring ifaceNameObj, 295 jstring serviceNameObj) { 296 297 using ::android::vintf::operator<<; 298 299 if (ifaceNameObj == NULL) { 300 jniThrowException(env, "java/lang/NullPointerException", NULL); 301 return NULL; 302 } 303 if (serviceNameObj == NULL) { 304 jniThrowException(env, "java/lang/NullPointerException", NULL); 305 return NULL; 306 } 307 308 auto manager = hardware::defaultServiceManager(); 309 310 if (manager == nullptr) { 311 LOG(ERROR) << "Could not get hwservicemanager."; 312 signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */); 313 return NULL; 314 } 315 316 const char *ifaceNameCStr = env->GetStringUTFChars(ifaceNameObj, NULL); 317 if (ifaceNameCStr == NULL) { 318 return NULL; // XXX exception already pending? 319 } 320 std::string ifaceName(ifaceNameCStr); 321 env->ReleaseStringUTFChars(ifaceNameObj, ifaceNameCStr); 322 ::android::hardware::hidl_string ifaceNameHStr; 323 ifaceNameHStr.setToExternal(ifaceName.c_str(), ifaceName.size()); 324 325 const char *serviceNameCStr = env->GetStringUTFChars(serviceNameObj, NULL); 326 if (serviceNameCStr == NULL) { 327 return NULL; // XXX exception already pending? 328 } 329 std::string serviceName(serviceNameCStr); 330 env->ReleaseStringUTFChars(serviceNameObj, serviceNameCStr); 331 ::android::hardware::hidl_string serviceNameHStr; 332 serviceNameHStr.setToExternal(serviceName.c_str(), serviceName.size()); 333 334 LOG(INFO) << "Looking for service " 335 << ifaceName 336 << "/" 337 << serviceName; 338 339 ::android::vintf::Transport transport = 340 ::android::hardware::getTransport(ifaceName); 341 if ( transport != ::android::vintf::Transport::EMPTY 342 && transport != ::android::vintf::Transport::HWBINDER) { 343 LOG(ERROR) << "service " << ifaceName << " declares transport method " 344 << transport << " but framework expects " 345 << ::android::vintf::Transport::HWBINDER; 346 signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */); 347 return NULL; 348 } 349 350 Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceNameHStr, serviceNameHStr); 351 352 if (!ret.isOk()) { 353 signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */); 354 return NULL; 355 } 356 357 sp<hardware::IBinder> service = hardware::toBinder< 358 hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase>(ret); 359 360 if (service == NULL) { 361 signalExceptionForError(env, NAME_NOT_FOUND); 362 return NULL; 363 } 364 365 LOG(INFO) << "Starting thread pool."; 366 ::android::hardware::ProcessState::self()->startThreadPool(); 367 368 return JHwRemoteBinder::NewObject(env, service); 369} 370 371static JNINativeMethod gMethods[] = { 372 { "native_init", "()J", (void *)JHwBinder_native_init }, 373 { "native_setup", "()V", (void *)JHwBinder_native_setup }, 374 375 { "transact", 376 "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V", 377 (void *)JHwBinder_native_transact }, 378 379 { "registerService", "(Ljava/util/ArrayList;Ljava/lang/String;)V", 380 (void *)JHwBinder_native_registerService }, 381 382 { "getService", "(Ljava/lang/String;Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;", 383 (void *)JHwBinder_native_getService }, 384}; 385 386namespace android { 387 388int register_android_os_HwBinder(JNIEnv *env) { 389 jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList"); 390 gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass); 391 gArrayListMethods.size = GetMethodIDOrDie(env, arrayListClass, "size", "()I"); 392 gArrayListMethods.get = GetMethodIDOrDie(env, arrayListClass, "get", "(I)Ljava/lang/Object;"); 393 394 jclass errorClass = FindClassOrDie(env, "java/lang/Error"); 395 gErrorClass = MakeGlobalRefOrDie(env, errorClass); 396 397 return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods)); 398} 399 400} // namespace android 401