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