android_os_HwBinder.cpp revision b747440d2f662ef6191591fbf9166b0201e0c16c
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/IHwBase.h> 30#include <android_runtime/AndroidRuntime.h> 31#include <hidl/ServiceManagement.h> 32#include <hidl/Status.h> 33#include <hwbinder/ProcessState.h> 34#include <nativehelper/ScopedLocalRef.h> 35 36#include "core_jni_helpers.h" 37 38using android::AndroidRuntime; 39using android::hardware::hidl_vec; 40using android::hardware::hidl_string; 41 42#define PACKAGE_PATH "android/os" 43#define CLASS_NAME "HwBinder" 44#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME 45 46namespace android { 47 48static jclass gArrayListClass; 49static struct { 50 jmethodID size; 51 jmethodID get; 52} gArrayListMethods; 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 126 ScopedLocalRef<jobject> requestObj(env, JHwParcel::NewObject(env)); 127 JHwParcel::GetNativeContext(env, requestObj.get())->setParcel( 128 const_cast<hardware::Parcel *>(&data), false /* assumeOwnership */); 129 130 ScopedLocalRef<jobject> replyObj(env, JHwParcel::NewObject(env)); 131 132 sp<JHwParcel> replyContext = 133 JHwParcel::GetNativeContext(env, replyObj.get()); 134 135 replyContext->setParcel(reply, false /* assumeOwnership */); 136 replyContext->setTransactCallback(callback); 137 138 env->CallVoidMethod( 139 mObject, 140 gFields.onTransactID, 141 code, 142 requestObj.get(), 143 replyObj.get(), 144 flags); 145 146 status_t err = OK; 147 148 if (!replyContext->wasSent()) { 149 // The implementation never finished the transaction. 150 err = UNKNOWN_ERROR; // XXX special error code instead? 151 152 reply->setDataPosition(0 /* pos */); 153 } 154 155 // Release all temporary storage now that scatter-gather data 156 // has been consolidated, either by calling the TransactCallback, 157 // if wasSent() == true or clearing the reply parcel (setDataOffset above). 158 replyContext->getStorage()->release(env); 159 160 // We cannot permanently pass ownership of "data" and "reply" over to their 161 // Java object wrappers (we don't own them ourselves). 162 163 JHwParcel::GetNativeContext(env, requestObj.get())->setParcel( 164 NULL /* parcel */, false /* assumeOwnership */); 165 166 replyContext->setParcel( 167 NULL /* parcel */, false /* assumeOwnership */); 168 169 return err; 170} 171 172} // namespace android 173 174//////////////////////////////////////////////////////////////////////////////// 175 176using namespace android; 177 178static void releaseNativeContext(void *nativeContext) { 179 sp<JHwBinder> binder = (JHwBinder *)nativeContext; 180 181 if (binder != NULL) { 182 binder->decStrong(NULL /* id */); 183 } 184} 185 186static jlong JHwBinder_native_init(JNIEnv *env) { 187 JHwBinder::InitClass(env); 188 189 return reinterpret_cast<jlong>(&releaseNativeContext); 190} 191 192static void JHwBinder_native_setup(JNIEnv *env, jobject thiz) { 193 sp<JHwBinder> context = new JHwBinder(env, thiz); 194 195 JHwBinder::SetNativeContext(env, thiz, context); 196} 197 198static void JHwBinder_native_transact( 199 JNIEnv * /* env */, 200 jobject /* thiz */, 201 jint /* code */, 202 jobject /* requestObj */, 203 jobject /* replyObj */, 204 jint /* flags */) { 205 CHECK(!"Should not be here"); 206} 207 208static void JHwBinder_native_registerService( 209 JNIEnv *env, 210 jobject thiz, 211 jobject interfaceChainArrayList, 212 jstring serviceNameObj) { 213 if (serviceNameObj == NULL) { 214 jniThrowException(env, "java/lang/NullPointerException", NULL); 215 return; 216 } 217 218 const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL); 219 if (serviceName == NULL) { 220 return; // XXX exception already pending? 221 } 222 223 jint numInterfaces = env->CallIntMethod(interfaceChainArrayList, 224 gArrayListMethods.size); 225 hidl_string *strings = new hidl_string[numInterfaces]; 226 227 for (jint i = 0; i < numInterfaces; i++) { 228 jstring strObj = static_cast<jstring>( 229 env->CallObjectMethod(interfaceChainArrayList, 230 gArrayListMethods.get, 231 i) 232 ); 233 const char * str = env->GetStringUTFChars(strObj, nullptr); 234 strings[i] = hidl_string(str); 235 env->ReleaseStringUTFChars(strObj, str); 236 } 237 238 hidl_vec<hidl_string> interfaceChain; 239 interfaceChain.setToExternal(strings, numInterfaces, true /* shouldOwn */); 240 241 using android::hidl::manager::V1_0::IServiceManager; 242 243 sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz); 244 245 sp<hidl::base::V1_0::IBase> base = hidl::base::V1_0::IHwBase::asInterface(binder); 246 if (base.get() == nullptr) { 247 LOG(ERROR) << "IBinder object cannot be casted to the base interface."; 248 signalExceptionForError(env, UNKNOWN_ERROR); 249 return; 250 } 251 252 bool ok = hardware::defaultServiceManager()->add( 253 interfaceChain, 254 serviceName, 255 base); 256 257 env->ReleaseStringUTFChars(serviceNameObj, serviceName); 258 serviceName = NULL; 259 260 if (ok) { 261 LOG(INFO) << "Starting thread pool."; 262 ::android::hardware::ProcessState::self()->startThreadPool(); 263 } 264 265 signalExceptionForError(env, (ok ? OK : UNKNOWN_ERROR)); 266} 267 268static jobject JHwBinder_native_getService( 269 JNIEnv *env, 270 jclass /* clazzObj */, 271 jstring ifaceNameObj, 272 jstring serviceNameObj) { 273 274 if (ifaceNameObj == NULL) { 275 jniThrowException(env, "java/lang/NullPointerException", NULL); 276 return NULL; 277 } 278 if (serviceNameObj == NULL) { 279 jniThrowException(env, "java/lang/NullPointerException", NULL); 280 return NULL; 281 } 282 283 const char *ifaceName = env->GetStringUTFChars(ifaceNameObj, NULL); 284 if (ifaceName == NULL) { 285 return NULL; // XXX exception already pending? 286 } 287 const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL); 288 if (serviceName == NULL) { 289 env->ReleaseStringUTFChars(ifaceNameObj, ifaceName); 290 return NULL; // XXX exception already pending? 291 } 292 293 LOG(INFO) << "looking for service '" 294 << serviceName 295 << "'"; 296 297 sp<hardware::IBinder> service; 298 hardware::defaultServiceManager()->get( 299 ifaceName, 300 serviceName, 301 [&service](sp<hidl::base::V1_0::IBase> out) { 302 service = hardware::toBinder< 303 hidl::base::V1_0::IBase, hidl::base::V1_0::IHwBase 304 >(out); 305 }); 306 307 env->ReleaseStringUTFChars(ifaceNameObj, ifaceName); 308 ifaceName = NULL; 309 env->ReleaseStringUTFChars(serviceNameObj, serviceName); 310 serviceName = NULL; 311 312 if (service == NULL) { 313 signalExceptionForError(env, NAME_NOT_FOUND); 314 return NULL; 315 } 316 317 LOG(INFO) << "Starting thread pool."; 318 ::android::hardware::ProcessState::self()->startThreadPool(); 319 320 return JHwRemoteBinder::NewObject(env, service); 321} 322 323static JNINativeMethod gMethods[] = { 324 { "native_init", "()J", (void *)JHwBinder_native_init }, 325 { "native_setup", "()V", (void *)JHwBinder_native_setup }, 326 327 { "transact", 328 "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V", 329 (void *)JHwBinder_native_transact }, 330 331 { "registerService", "(Ljava/util/ArrayList;Ljava/lang/String;)V", 332 (void *)JHwBinder_native_registerService }, 333 334 { "getService", "(Ljava/lang/String;Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;", 335 (void *)JHwBinder_native_getService }, 336}; 337 338namespace android { 339 340int register_android_os_HwBinder(JNIEnv *env) { 341 jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList"); 342 gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass); 343 gArrayListMethods.size = GetMethodIDOrDie(env, arrayListClass, "size", "()I"); 344 gArrayListMethods.get = GetMethodIDOrDie(env, arrayListClass, "get", "(I)Ljava/lang/Object;"); 345 346 return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods)); 347} 348 349} // namespace android 350