android_os_HwBinder.cpp revision 2cbce4ad8748e3cd086d7cc207a5ebd86685523c
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 bool isOneway = (flags & TF_ONE_WAY) != 0; 132 ScopedLocalRef<jobject> replyObj(env, nullptr); 133 sp<JHwParcel> replyContext = nullptr; 134 135 ScopedLocalRef<jobject> requestObj(env, JHwParcel::NewObject(env)); 136 JHwParcel::GetNativeContext(env, requestObj.get())->setParcel( 137 const_cast<hardware::Parcel *>(&data), false /* assumeOwnership */); 138 139 140 if (!isOneway) { 141 replyObj.reset(JHwParcel::NewObject(env)); 142 143 replyContext = JHwParcel::GetNativeContext(env, replyObj.get()); 144 145 replyContext->setParcel(reply, false /* assumeOwnership */); 146 replyContext->setTransactCallback(callback); 147 } 148 149 env->CallVoidMethod( 150 mObject, 151 gFields.onTransactID, 152 code, 153 requestObj.get(), 154 replyObj.get(), 155 flags); 156 157 if (env->ExceptionCheck()) { 158 jthrowable excep = env->ExceptionOccurred(); 159 env->ExceptionDescribe(); 160 161 if (env->IsInstanceOf(excep, gErrorClass)) { 162 /* It's an error */ 163 LOG(ERROR) << "Forcefully exiting"; 164 exit(1); 165 } else { 166 env->ExceptionClear(); 167 LOG(ERROR) << "Uncaught exception!"; 168 } 169 170 env->DeleteLocalRef(excep); 171 } 172 173 status_t err = OK; 174 175 if (!isOneway) { 176 if (!replyContext->wasSent()) { 177 // The implementation never finished the transaction. 178 err = UNKNOWN_ERROR; // XXX special error code instead? 179 180 reply->setDataPosition(0 /* pos */); 181 } 182 183 // Release all temporary storage now that scatter-gather data 184 // has been consolidated, either by calling the TransactCallback, 185 // if wasSent() == true or clearing the reply parcel (setDataOffset above). 186 replyContext->getStorage()->release(env); 187 188 // We cannot permanently pass ownership of "data" and "reply" over to their 189 // Java object wrappers (we don't own them ourselves). 190 replyContext->setParcel( 191 NULL /* parcel */, false /* assumeOwnership */); 192 193 } 194 195 JHwParcel::GetNativeContext(env, requestObj.get())->setParcel( 196 NULL /* parcel */, false /* assumeOwnership */); 197 198 return err; 199} 200 201} // namespace android 202 203//////////////////////////////////////////////////////////////////////////////// 204 205using namespace android; 206 207static void releaseNativeContext(void *nativeContext) { 208 sp<JHwBinder> binder = (JHwBinder *)nativeContext; 209 210 if (binder != NULL) { 211 binder->decStrong(NULL /* id */); 212 } 213} 214 215static jlong JHwBinder_native_init(JNIEnv *env) { 216 JHwBinder::InitClass(env); 217 218 return reinterpret_cast<jlong>(&releaseNativeContext); 219} 220 221static void JHwBinder_native_setup(JNIEnv *env, jobject thiz) { 222 sp<JHwBinder> context = new JHwBinder(env, thiz); 223 224 JHwBinder::SetNativeContext(env, thiz, context); 225} 226 227static void JHwBinder_native_transact( 228 JNIEnv * /* env */, 229 jobject /* thiz */, 230 jint /* code */, 231 jobject /* requestObj */, 232 jobject /* replyObj */, 233 jint /* flags */) { 234 CHECK(!"Should not be here"); 235} 236 237static void JHwBinder_native_registerService( 238 JNIEnv *env, 239 jobject thiz, 240 jobject interfaceChainArrayList, 241 jstring serviceNameObj) { 242 if (serviceNameObj == NULL) { 243 jniThrowException(env, "java/lang/NullPointerException", NULL); 244 return; 245 } 246 247 const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL); 248 if (serviceName == NULL) { 249 return; // XXX exception already pending? 250 } 251 252 jint numInterfaces = env->CallIntMethod(interfaceChainArrayList, 253 gArrayListMethods.size); 254 hidl_string *strings = new hidl_string[numInterfaces]; 255 256 for (jint i = 0; i < numInterfaces; i++) { 257 jstring strObj = static_cast<jstring>( 258 env->CallObjectMethod(interfaceChainArrayList, 259 gArrayListMethods.get, 260 i) 261 ); 262 const char * str = env->GetStringUTFChars(strObj, nullptr); 263 strings[i] = hidl_string(str); 264 env->ReleaseStringUTFChars(strObj, str); 265 } 266 267 hidl_vec<hidl_string> interfaceChain; 268 interfaceChain.setToExternal(strings, numInterfaces, true /* shouldOwn */); 269 270 sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz); 271 272 /* TODO(b/33440494) this is not right */ 273 sp<hidl::base::V1_0::IBase> base = new hidl::base::V1_0::BpHwBase(binder); 274 275 auto manager = hardware::defaultServiceManager(); 276 277 if (manager == nullptr) { 278 LOG(ERROR) << "Could not get hwservicemanager."; 279 signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */); 280 return; 281 } 282 283 Return<bool> ret = manager->add(interfaceChain, serviceName, base); 284 285 env->ReleaseStringUTFChars(serviceNameObj, serviceName); 286 serviceName = NULL; 287 288 bool ok = ret.isOk() && ret; 289 290 if (ok) { 291 LOG(INFO) << "Starting thread pool."; 292 ::android::hardware::ProcessState::self()->startThreadPool(); 293 } 294 295 signalExceptionForError(env, (ok ? OK : UNKNOWN_ERROR), true /* canThrowRemoteException */); 296} 297 298static jobject JHwBinder_native_getService( 299 JNIEnv *env, 300 jclass /* clazzObj */, 301 jstring ifaceNameObj, 302 jstring serviceNameObj) { 303 304 using ::android::vintf::operator<<; 305 306 if (ifaceNameObj == NULL) { 307 jniThrowException(env, "java/lang/NullPointerException", NULL); 308 return NULL; 309 } 310 if (serviceNameObj == NULL) { 311 jniThrowException(env, "java/lang/NullPointerException", NULL); 312 return NULL; 313 } 314 315 auto manager = hardware::defaultServiceManager(); 316 317 if (manager == nullptr) { 318 LOG(ERROR) << "Could not get hwservicemanager."; 319 signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */); 320 return NULL; 321 } 322 323 const char *ifaceNameCStr = env->GetStringUTFChars(ifaceNameObj, NULL); 324 if (ifaceNameCStr == NULL) { 325 return NULL; // XXX exception already pending? 326 } 327 std::string ifaceName(ifaceNameCStr); 328 env->ReleaseStringUTFChars(ifaceNameObj, ifaceNameCStr); 329 ::android::hardware::hidl_string ifaceNameHStr; 330 ifaceNameHStr.setToExternal(ifaceName.c_str(), ifaceName.size()); 331 332 const char *serviceNameCStr = env->GetStringUTFChars(serviceNameObj, NULL); 333 if (serviceNameCStr == NULL) { 334 return NULL; // XXX exception already pending? 335 } 336 std::string serviceName(serviceNameCStr); 337 env->ReleaseStringUTFChars(serviceNameObj, serviceNameCStr); 338 ::android::hardware::hidl_string serviceNameHStr; 339 serviceNameHStr.setToExternal(serviceName.c_str(), serviceName.size()); 340 341 LOG(INFO) << "Looking for service " 342 << ifaceName 343 << "/" 344 << serviceName; 345 346 ::android::vintf::Transport transport = 347 ::android::hardware::getTransport(ifaceName, serviceName); 348 if ( transport != ::android::vintf::Transport::EMPTY 349 && transport != ::android::vintf::Transport::HWBINDER) { 350 LOG(ERROR) << "service " << ifaceName << " declares transport method " 351 << transport << " but framework expects " 352 << ::android::vintf::Transport::HWBINDER; 353 signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */); 354 return NULL; 355 } 356 357 Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceNameHStr, serviceNameHStr); 358 359 if (!ret.isOk()) { 360 signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */); 361 return NULL; 362 } 363 364 sp<hardware::IBinder> service = hardware::toBinder< 365 hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase>(ret); 366 367 if (service == NULL) { 368 signalExceptionForError(env, NAME_NOT_FOUND); 369 return NULL; 370 } 371 372 LOG(INFO) << "Starting thread pool."; 373 ::android::hardware::ProcessState::self()->startThreadPool(); 374 375 return JHwRemoteBinder::NewObject(env, service); 376} 377 378static JNINativeMethod gMethods[] = { 379 { "native_init", "()J", (void *)JHwBinder_native_init }, 380 { "native_setup", "()V", (void *)JHwBinder_native_setup }, 381 382 { "transact", 383 "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V", 384 (void *)JHwBinder_native_transact }, 385 386 { "registerService", "(Ljava/util/ArrayList;Ljava/lang/String;)V", 387 (void *)JHwBinder_native_registerService }, 388 389 { "getService", "(Ljava/lang/String;Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;", 390 (void *)JHwBinder_native_getService }, 391}; 392 393namespace android { 394 395int register_android_os_HwBinder(JNIEnv *env) { 396 jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList"); 397 gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass); 398 gArrayListMethods.size = GetMethodIDOrDie(env, arrayListClass, "size", "()I"); 399 gArrayListMethods.get = GetMethodIDOrDie(env, arrayListClass, "get", "(I)Ljava/lang/Object;"); 400 401 jclass errorClass = FindClassOrDie(env, "java/lang/Error"); 402 gErrorClass = MakeGlobalRefOrDie(env, errorClass); 403 404 return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods)); 405} 406 407} // namespace android 408