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 <cstring>
27 
28 #include <nativehelper/JNIHelp.h>
29 #include <android/hidl/manager/1.0/IServiceManager.h>
30 #include <android/hidl/base/1.0/IBase.h>
31 #include <android/hidl/base/1.0/BpHwBase.h>
32 #include <android_runtime/AndroidRuntime.h>
33 #include <hidl/ServiceManagement.h>
34 #include <hidl/Status.h>
35 #include <hidl/HidlTransportSupport.h>
36 #include <hwbinder/IPCThreadState.h>
37 #include <hwbinder/ProcessState.h>
38 #include <nativehelper/ScopedLocalRef.h>
39 #include <nativehelper/ScopedUtfChars.h>
40 #include <vintf/parse_string.h>
41 #include <utils/misc.h>
42 
43 #include "core_jni_helpers.h"
44 
45 using android::AndroidRuntime;
46 using android::hardware::hidl_vec;
47 using android::hardware::hidl_string;
48 using android::hardware::IPCThreadState;
49 using android::hardware::ProcessState;
50 template<typename T>
51 using Return = android::hardware::Return<T>;
52 
53 #define PACKAGE_PATH    "android/os"
54 #define CLASS_NAME      "HwBinder"
55 #define CLASS_PATH      PACKAGE_PATH "/" CLASS_NAME
56 
57 namespace android {
58 
59 static jclass gErrorClass;
60 
61 static struct fields_t {
62     jfieldID contextID;
63     jmethodID onTransactID;
64 } gFields;
65 
66 struct JHwBinderHolder : public RefBase {
JHwBinderHolderandroid::JHwBinderHolder67     JHwBinderHolder() {}
68 
getandroid::JHwBinderHolder69     sp<JHwBinder> get(JNIEnv *env, jobject obj) {
70         Mutex::Autolock autoLock(mLock);
71 
72         sp<JHwBinder> binder = mBinder.promote();
73 
74         if (binder == NULL) {
75             binder = new JHwBinder(env, obj);
76             mBinder = binder;
77         }
78 
79         return binder;
80     }
81 
82 private:
83     Mutex mLock;
84     wp<JHwBinder> mBinder;
85 
86     DISALLOW_COPY_AND_ASSIGN(JHwBinderHolder);
87 };
88 
89 // static
InitClass(JNIEnv * env)90 void JHwBinder::InitClass(JNIEnv *env) {
91     ScopedLocalRef<jclass> clazz(
92             env, FindClassOrDie(env, CLASS_PATH));
93 
94     gFields.contextID =
95         GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J");
96 
97     gFields.onTransactID =
98         GetMethodIDOrDie(
99                 env,
100                 clazz.get(),
101                 "onTransact",
102                 "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V");
103 }
104 
105 // static
SetNativeContext(JNIEnv * env,jobject thiz,const sp<JHwBinderHolder> & context)106 sp<JHwBinderHolder> JHwBinder::SetNativeContext(
107         JNIEnv *env, jobject thiz, const sp<JHwBinderHolder> &context) {
108     sp<JHwBinderHolder> old =
109         (JHwBinderHolder *)env->GetLongField(thiz, gFields.contextID);
110 
111     if (context != NULL) {
112         context->incStrong(NULL /* id */);
113     }
114 
115     if (old != NULL) {
116         old->decStrong(NULL /* id */);
117     }
118 
119     env->SetLongField(thiz, gFields.contextID, (long)context.get());
120 
121     return old;
122 }
123 
124 // static
GetNativeBinder(JNIEnv * env,jobject thiz)125 sp<JHwBinder> JHwBinder::GetNativeBinder(
126         JNIEnv *env, jobject thiz) {
127     JHwBinderHolder *holder =
128         reinterpret_cast<JHwBinderHolder *>(
129                 env->GetLongField(thiz, gFields.contextID));
130 
131     return holder->get(env, thiz);
132 }
133 
JHwBinder(JNIEnv * env,jobject thiz)134 JHwBinder::JHwBinder(JNIEnv *env, jobject thiz) {
135     jclass clazz = env->GetObjectClass(thiz);
136     CHECK(clazz != NULL);
137 
138     mObject = env->NewGlobalRef(thiz);
139 }
140 
~JHwBinder()141 JHwBinder::~JHwBinder() {
142     JNIEnv *env = AndroidRuntime::getJNIEnv();
143 
144     env->DeleteGlobalRef(mObject);
145     mObject = NULL;
146 }
147 
onTransact(uint32_t code,const hardware::Parcel & data,hardware::Parcel * reply,uint32_t flags,TransactCallback callback)148 status_t JHwBinder::onTransact(
149         uint32_t code,
150         const hardware::Parcel &data,
151         hardware::Parcel *reply,
152         uint32_t flags,
153         TransactCallback callback) {
154     JNIEnv *env = AndroidRuntime::getJNIEnv();
155     bool isOneway = (flags & IBinder::FLAG_ONEWAY) != 0;
156     ScopedLocalRef<jobject> replyObj(env, nullptr);
157     sp<JHwParcel> replyContext = nullptr;
158 
159     ScopedLocalRef<jobject> requestObj(env, JHwParcel::NewObject(env));
160     JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
161             const_cast<hardware::Parcel *>(&data), false /* assumeOwnership */);
162 
163 
164     if (!isOneway) {
165         replyObj.reset(JHwParcel::NewObject(env));
166 
167         replyContext = JHwParcel::GetNativeContext(env, replyObj.get());
168 
169         replyContext->setParcel(reply, false /* assumeOwnership */);
170         replyContext->setTransactCallback(callback);
171     }
172 
173     env->CallVoidMethod(
174             mObject,
175             gFields.onTransactID,
176             code,
177             requestObj.get(),
178             replyObj.get(),
179             flags);
180 
181     if (env->ExceptionCheck()) {
182         jthrowable excep = env->ExceptionOccurred();
183         env->ExceptionDescribe();
184         env->ExceptionClear();
185 
186         // It is illegal to call IsInstanceOf if there is a pending exception.
187         // Attempting to do so results in a JniAbort which crashes the entire process.
188         if (env->IsInstanceOf(excep, gErrorClass)) {
189             /* It's an error */
190             LOG(ERROR) << "Forcefully exiting";
191             _exit(1);
192         } else {
193             LOG(ERROR) << "Uncaught exception!";
194         }
195 
196         env->DeleteLocalRef(excep);
197     }
198 
199     status_t err = OK;
200 
201     if (!isOneway) {
202         if (!replyContext->wasSent()) {
203             // The implementation never finished the transaction.
204             err = UNKNOWN_ERROR;  // XXX special error code instead?
205 
206             reply->setDataPosition(0 /* pos */);
207         }
208 
209         // Release all temporary storage now that scatter-gather data
210         // has been consolidated, either by calling the TransactCallback,
211         // if wasSent() == true or clearing the reply parcel (setDataOffset above).
212         replyContext->getStorage()->release(env);
213 
214         // We cannot permanently pass ownership of "data" and "reply" over to their
215         // Java object wrappers (we don't own them ourselves).
216         replyContext->setParcel(
217                 NULL /* parcel */, false /* assumeOwnership */);
218 
219     }
220 
221     JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
222             NULL /* parcel */, false /* assumeOwnership */);
223 
224     return err;
225 }
226 
validateCanUseHwBinder(const sp<hardware::IBinder> & binder)227 bool validateCanUseHwBinder(const sp<hardware::IBinder>& binder) {
228     if (binder != nullptr && binder->localBinder() != nullptr) {
229         // untested/unsupported/inefficient
230         // see b/129150021, doesn't work with scatter-gather
231         //
232         // explicitly disabling until it is supported
233         // (note, even if this is fixed to work with scatter gather, we would also need
234         // to convert this to the Java object rather than re-wrapping with a proxy)
235         LOG(ERROR) << "Local Java Binder not supported.";
236         return false;
237     }
238 
239     return true;
240 }
241 
242 }  // namespace android
243 
244 ////////////////////////////////////////////////////////////////////////////////
245 
246 using namespace android;
247 
releaseNativeContext(void * nativeContext)248 static void releaseNativeContext(void *nativeContext) {
249     sp<JHwBinderHolder> context = static_cast<JHwBinderHolder *>(nativeContext);
250 
251     if (context != NULL) {
252         context->decStrong(NULL /* id */);
253     }
254 }
255 
JHwBinder_native_init(JNIEnv * env)256 static jlong JHwBinder_native_init(JNIEnv *env) {
257     JHwBinder::InitClass(env);
258 
259     return reinterpret_cast<jlong>(&releaseNativeContext);
260 }
261 
JHwBinder_native_setup(JNIEnv * env,jobject thiz)262 static void JHwBinder_native_setup(JNIEnv *env, jobject thiz) {
263     sp<JHwBinderHolder> context = new JHwBinderHolder;
264     JHwBinder::SetNativeContext(env, thiz, context);
265 }
266 
JHwBinder_native_transact(JNIEnv *,jobject,jint,jobject,jobject,jint)267 static void JHwBinder_native_transact(
268         JNIEnv * /* env */,
269         jobject /* thiz */,
270         jint /* code */,
271         jobject /* requestObj */,
272         jobject /* replyObj */,
273         jint /* flags */) {
274     CHECK(!"Should not be here");
275 }
276 
JHwBinder_native_registerService(JNIEnv * env,jobject thiz,jstring serviceNameObj)277 static void JHwBinder_native_registerService(
278         JNIEnv *env,
279         jobject thiz,
280         jstring serviceNameObj) {
281     ScopedUtfChars str(env, serviceNameObj);
282     if (str.c_str() == nullptr) {
283         return;  // NPE will be pending.
284     }
285 
286     sp<hardware::IBinder> binder = JHwBinder::GetNativeBinder(env, thiz);
287     sp<hidl::base::V1_0::IBase> base = new hidl::base::V1_0::BpHwBase(binder);
288 
289     bool ok = hardware::details::registerAsServiceInternal(base, str.c_str()) == OK;
290 
291     if (ok) {
292         LOG(INFO) << "HwBinder: Starting thread pool for " << str.c_str();
293         ::android::hardware::ProcessState::self()->startThreadPool();
294     }
295 
296     // avoiding richer error exceptions to stick with legacy behavior
297     signalExceptionForError(env, (ok ? OK : UNKNOWN_ERROR), true /*canThrowRemoteException*/);
298 }
299 
JHwBinder_native_getService(JNIEnv * env,jclass,jstring ifaceNameObj,jstring serviceNameObj,jboolean retry)300 static jobject JHwBinder_native_getService(
301         JNIEnv *env,
302         jclass /* clazzObj */,
303         jstring ifaceNameObj,
304         jstring serviceNameObj,
305         jboolean retry) {
306 
307     using ::android::hidl::base::V1_0::IBase;
308     using ::android::hardware::details::getRawServiceInternal;
309 
310     std::string ifaceName;
311     {
312         ScopedUtfChars str(env, ifaceNameObj);
313         if (str.c_str() == nullptr) {
314             return nullptr;  // NPE will be pending.
315         }
316         ifaceName = str.c_str();
317     }
318 
319     std::string serviceName;
320     {
321         ScopedUtfChars str(env, serviceNameObj);
322         if (str.c_str() == nullptr) {
323             return nullptr;  // NPE will be pending.
324         }
325         serviceName = str.c_str();
326     }
327 
328     sp<IBase> ret = getRawServiceInternal(ifaceName, serviceName, retry /* retry */, false /* getStub */);
329     sp<hardware::IBinder> service = hardware::toBinder<hidl::base::V1_0::IBase>(ret);
330 
331     if (service == nullptr || !validateCanUseHwBinder(service)) {
332         signalExceptionForError(env, NAME_NOT_FOUND);
333         return nullptr;
334     }
335 
336     LOG(INFO) << "HwBinder: Starting thread pool for getting: " << ifaceName << "/" << serviceName;
337     ::android::hardware::ProcessState::self()->startThreadPool();
338 
339     return JHwRemoteBinder::NewObject(env, service);
340 }
341 
JHwBinder_native_configureRpcThreadpool(JNIEnv *,jclass,jlong maxThreads,jboolean callerWillJoin)342 void JHwBinder_native_configureRpcThreadpool(JNIEnv *, jclass,
343         jlong maxThreads, jboolean callerWillJoin) {
344     CHECK(maxThreads > 0);
345     ProcessState::self()->setThreadPoolConfiguration(maxThreads, callerWillJoin /*callerJoinsPool*/);
346 }
347 
JHwBinder_native_joinRpcThreadpool()348 void JHwBinder_native_joinRpcThreadpool() {
349     IPCThreadState::self()->joinThreadPool();
350 }
351 
JHwBinder_report_sysprop_change(JNIEnv *,jclass)352 static void JHwBinder_report_sysprop_change(JNIEnv * /*env*/, jclass /*clazz*/)
353 {
354     report_sysprop_change();
355 }
356 
357 static JNINativeMethod gMethods[] = {
358     { "native_init", "()J", (void *)JHwBinder_native_init },
359     { "native_setup", "()V", (void *)JHwBinder_native_setup },
360 
361     { "transact",
362         "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
363         (void *)JHwBinder_native_transact },
364 
365     { "registerService", "(Ljava/lang/String;)V",
366         (void *)JHwBinder_native_registerService },
367 
368     { "getService", "(Ljava/lang/String;Ljava/lang/String;Z)L" PACKAGE_PATH "/IHwBinder;",
369         (void *)JHwBinder_native_getService },
370 
371     { "configureRpcThreadpool", "(JZ)V",
372         (void *)JHwBinder_native_configureRpcThreadpool },
373 
374     { "joinRpcThreadpool", "()V",
375         (void *)JHwBinder_native_joinRpcThreadpool },
376 
377     { "native_report_sysprop_change", "()V",
378         (void *)JHwBinder_report_sysprop_change },
379 };
380 
381 namespace android {
382 
register_android_os_HwBinder(JNIEnv * env)383 int register_android_os_HwBinder(JNIEnv *env) {
384     jclass errorClass = FindClassOrDie(env, "java/lang/Error");
385     gErrorClass = MakeGlobalRefOrDie(env, errorClass);
386 
387     return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
388 }
389 
390 }  // namespace android
391