android_os_HwBinder.cpp revision c0631d0bb72781b81dabd66064ee5a5dda2d6103
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/BpBase.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::BpBase(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    const char *ifaceName = env->GetStringUTFChars(ifaceNameObj, NULL);
306    if (ifaceName == NULL) {
307        return NULL; // XXX exception already pending?
308    }
309    const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL);
310    if (serviceName == NULL) {
311        env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
312        return NULL; // XXX exception already pending?
313    }
314
315    LOG(INFO) << "looking for service '"
316              << serviceName
317              << "'";
318
319    auto manager = hardware::defaultServiceManager();
320
321    if (manager == nullptr) {
322        LOG(ERROR) << "Could not get hwservicemanager.";
323        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
324        return NULL;
325    }
326
327    Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceName, serviceName);
328
329    if (!ret.isOk()) {
330        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
331    }
332
333    sp<hardware::IBinder> service = hardware::toBinder<
334            hidl::base::V1_0::IBase, hidl::base::V1_0::BpBase>(ret);
335
336    env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
337    ifaceName = NULL;
338    env->ReleaseStringUTFChars(serviceNameObj, serviceName);
339    serviceName = NULL;
340
341    if (service == NULL) {
342        signalExceptionForError(env, NAME_NOT_FOUND);
343        return NULL;
344    }
345
346    LOG(INFO) << "Starting thread pool.";
347    ::android::hardware::ProcessState::self()->startThreadPool();
348
349    return JHwRemoteBinder::NewObject(env, service);
350}
351
352static JNINativeMethod gMethods[] = {
353    { "native_init", "()J", (void *)JHwBinder_native_init },
354    { "native_setup", "()V", (void *)JHwBinder_native_setup },
355
356    { "transact",
357        "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
358        (void *)JHwBinder_native_transact },
359
360    { "registerService", "(Ljava/util/ArrayList;Ljava/lang/String;)V",
361        (void *)JHwBinder_native_registerService },
362
363    { "getService", "(Ljava/lang/String;Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;",
364        (void *)JHwBinder_native_getService },
365};
366
367namespace android {
368
369int register_android_os_HwBinder(JNIEnv *env) {
370    jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
371    gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
372    gArrayListMethods.size = GetMethodIDOrDie(env, arrayListClass, "size", "()I");
373    gArrayListMethods.get = GetMethodIDOrDie(env, arrayListClass, "get", "(I)Ljava/lang/Object;");
374
375    jclass errorClass = FindClassOrDie(env, "java/lang/Error");
376    gErrorClass = MakeGlobalRefOrDie(env, errorClass);
377
378    return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
379}
380
381}  // namespace android
382