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