android_os_HwBinder.cpp revision 35eb7994f81c3507583bccc6f43fc0258f3a1e91
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_runtime/AndroidRuntime.h> 28#include <hidl/IServiceManager.h> 29#include <hidl/Status.h> 30#include <hwbinder/ProcessState.h> 31#include <nativehelper/ScopedLocalRef.h> 32 33#include "core_jni_helpers.h" 34 35using android::AndroidRuntime; 36 37#define PACKAGE_PATH "android/os" 38#define CLASS_NAME "HwBinder" 39#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME 40 41namespace android { 42 43static struct fields_t { 44 jfieldID contextID; 45 jmethodID onTransactID; 46 47} gFields; 48 49// static 50void JHwBinder::InitClass(JNIEnv *env) { 51 ScopedLocalRef<jclass> clazz( 52 env, FindClassOrDie(env, CLASS_PATH)); 53 54 gFields.contextID = 55 GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J"); 56 57 gFields.onTransactID = 58 GetMethodIDOrDie( 59 env, 60 clazz.get(), 61 "onTransact", 62 "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V"); 63} 64 65// static 66sp<JHwBinder> JHwBinder::SetNativeContext( 67 JNIEnv *env, jobject thiz, const sp<JHwBinder> &context) { 68 sp<JHwBinder> old = 69 (JHwBinder *)env->GetLongField(thiz, gFields.contextID); 70 71 if (context != NULL) { 72 context->incStrong(NULL /* id */); 73 } 74 75 if (old != NULL) { 76 old->decStrong(NULL /* id */); 77 } 78 79 env->SetLongField(thiz, gFields.contextID, (long)context.get()); 80 81 return old; 82} 83 84// static 85sp<JHwBinder> JHwBinder::GetNativeContext( 86 JNIEnv *env, jobject thiz) { 87 return (JHwBinder *)env->GetLongField(thiz, gFields.contextID); 88} 89 90JHwBinder::JHwBinder(JNIEnv *env, jobject thiz) { 91 jclass clazz = env->GetObjectClass(thiz); 92 CHECK(clazz != NULL); 93 94 mClass = (jclass)env->NewGlobalRef(clazz); 95 mObject = env->NewWeakGlobalRef(thiz); 96} 97 98JHwBinder::~JHwBinder() { 99 JNIEnv *env = AndroidRuntime::getJNIEnv(); 100 101 env->DeleteWeakGlobalRef(mObject); 102 mObject = NULL; 103 104 env->DeleteGlobalRef(mClass); 105 mClass = NULL; 106} 107 108status_t JHwBinder::onTransact( 109 uint32_t code, 110 const hardware::Parcel &data, 111 hardware::Parcel *reply, 112 uint32_t flags, 113 TransactCallback callback) { 114 JNIEnv *env = AndroidRuntime::getJNIEnv(); 115 116 ScopedLocalRef<jobject> requestObj(env, JHwParcel::NewObject(env)); 117 JHwParcel::GetNativeContext(env, requestObj.get())->setParcel( 118 const_cast<hardware::Parcel *>(&data), false /* assumeOwnership */); 119 120 ScopedLocalRef<jobject> replyObj(env, JHwParcel::NewObject(env)); 121 122 sp<JHwParcel> replyContext = 123 JHwParcel::GetNativeContext(env, replyObj.get()); 124 125 replyContext->setParcel(reply, false /* assumeOwnership */); 126 replyContext->setTransactCallback(callback); 127 128 env->CallVoidMethod( 129 mObject, 130 gFields.onTransactID, 131 code, 132 requestObj.get(), 133 replyObj.get(), 134 flags); 135 136 status_t err = OK; 137 138 if (!replyContext->wasSent()) { 139 // The implementation never finished the transaction. 140 err = UNKNOWN_ERROR; // XXX special error code instead? 141 142 reply->setDataPosition(0 /* pos */); 143 } 144 145 // Release all temporary storage now that scatter-gather data 146 // has been consolidated, either by calling the TransactCallback, 147 // if wasSent() == true or clearing the reply parcel (setDataOffset above). 148 replyContext->getStorage()->release(env); 149 150 // We cannot permanently pass ownership of "data" and "reply" over to their 151 // Java object wrappers (we don't own them ourselves). 152 153 JHwParcel::GetNativeContext(env, requestObj.get())->setParcel( 154 NULL /* parcel */, false /* assumeOwnership */); 155 156 replyContext->setParcel( 157 NULL /* parcel */, false /* assumeOwnership */); 158 159 return err; 160} 161 162} // namespace android 163 164//////////////////////////////////////////////////////////////////////////////// 165 166using namespace android; 167 168static void releaseNativeContext(void *nativeContext) { 169 sp<JHwBinder> binder = (JHwBinder *)nativeContext; 170 171 if (binder != NULL) { 172 binder->decStrong(NULL /* id */); 173 } 174} 175 176static jlong JHwBinder_native_init(JNIEnv *env) { 177 JHwBinder::InitClass(env); 178 179 return reinterpret_cast<jlong>(&releaseNativeContext); 180} 181 182static void JHwBinder_native_setup(JNIEnv *env, jobject thiz) { 183 sp<JHwBinder> context = new JHwBinder(env, thiz); 184 185 JHwBinder::SetNativeContext(env, thiz, context); 186} 187 188static void JHwBinder_native_transact( 189 JNIEnv * /* env */, 190 jobject /* thiz */, 191 jint /* code */, 192 jobject /* requestObj */, 193 jobject /* replyObj */, 194 jint /* flags */) { 195 CHECK(!"Should not be here"); 196} 197 198static void JHwBinder_native_registerService( 199 JNIEnv *env, 200 jobject thiz, 201 jstring serviceNameObj, 202 jint versionMajor, 203 jint versionMinor) { 204 if (serviceNameObj == NULL) { 205 jniThrowException(env, "java/lang/NullPointerException", NULL); 206 return; 207 } 208 209 if (versionMajor < 0 210 || versionMajor > 65535 211 || versionMinor < 0 212 || versionMinor > 65535) { 213 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 214 return; 215 } 216 217 const jchar *serviceName = env->GetStringCritical(serviceNameObj, NULL); 218 219 if (serviceName == NULL) { 220 return; // XXX exception already pending? 221 } 222 223 const hardware::hidl_version kVersion = 224 hardware::make_hidl_version(versionMajor, versionMinor); 225 226 sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz); 227 228 status_t err = hardware::defaultServiceManager()->addService( 229 String16( 230 reinterpret_cast<const char16_t *>(serviceName), 231 env->GetStringLength(serviceNameObj)), 232 binder, 233 kVersion); 234 235 env->ReleaseStringCritical(serviceNameObj, serviceName); 236 serviceName = NULL; 237 238 if (err == OK) { 239 LOG(INFO) << "Starting thread pool."; 240 ::android::hardware::ProcessState::self()->startThreadPool(); 241 } 242 243 signalExceptionForError(env, err); 244} 245 246static jobject JHwBinder_native_getService( 247 JNIEnv *env, 248 jclass /* clazzObj */, 249 jstring serviceNameObj, 250 jint versionMajor, 251 jint versionMinor) { 252 if (serviceNameObj == NULL) { 253 jniThrowException(env, "java/lang/NullPointerException", NULL); 254 return NULL; 255 } 256 257 if (versionMajor < 0 258 || versionMajor > 65535 259 || versionMinor < 0 260 || versionMinor > 65535) { 261 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 262 return NULL; 263 } 264 265 const jchar *serviceName = env->GetStringCritical(serviceNameObj, NULL); 266 267 if (serviceName == NULL) { 268 return NULL; // XXX exception already pending? 269 } 270 271 const hardware::hidl_version kVersion = 272 hardware::make_hidl_version(versionMajor, versionMinor); 273 274 LOG(INFO) << "looking for service '" 275 << String8(String16( 276 reinterpret_cast<const char16_t *>(serviceName), 277 env->GetStringLength(serviceNameObj))).string() 278 << "'"; 279 280 sp<hardware::IBinder> service = 281 hardware::defaultServiceManager()->getService( 282 String16( 283 reinterpret_cast<const char16_t *>(serviceName), 284 env->GetStringLength(serviceNameObj)), 285 kVersion); 286 287 env->ReleaseStringCritical(serviceNameObj, serviceName); 288 serviceName = NULL; 289 290 if (service == NULL) { 291 signalExceptionForError(env, NAME_NOT_FOUND); 292 return NULL; 293 } 294 295 LOG(INFO) << "Starting thread pool."; 296 ::android::hardware::ProcessState::self()->startThreadPool(); 297 298 return JHwRemoteBinder::NewObject(env, service); 299} 300 301static JNINativeMethod gMethods[] = { 302 { "native_init", "()J", (void *)JHwBinder_native_init }, 303 { "native_setup", "()V", (void *)JHwBinder_native_setup }, 304 305 { "transact", 306 "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V", 307 (void *)JHwBinder_native_transact }, 308 309 { "registerService", "(Ljava/lang/String;II)V", 310 (void *)JHwBinder_native_registerService }, 311 312 { "getService", "(Ljava/lang/String;II)L" PACKAGE_PATH "/IHwBinder;", 313 (void *)JHwBinder_native_getService }, 314}; 315 316namespace android { 317 318int register_android_os_HwBinder(JNIEnv *env) { 319 return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods)); 320} 321 322} // namespace android 323