android_os_HwBinder.cpp revision 60bf84a129fe742ac2737527336069c487f285f0
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
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    bool isOneway = (flags & TF_ONE_WAY) != 0;
131    ScopedLocalRef<jobject> replyObj(env, nullptr);
132    sp<JHwParcel> replyContext = nullptr;
133
134    ScopedLocalRef<jobject> requestObj(env, JHwParcel::NewObject(env));
135    JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
136            const_cast<hardware::Parcel *>(&data), false /* assumeOwnership */);
137
138
139    if (!isOneway) {
140        replyObj.reset(JHwParcel::NewObject(env));
141
142        replyContext = JHwParcel::GetNativeContext(env, replyObj.get());
143
144        replyContext->setParcel(reply, false /* assumeOwnership */);
145        replyContext->setTransactCallback(callback);
146    }
147
148    env->CallVoidMethod(
149            mObject,
150            gFields.onTransactID,
151            code,
152            requestObj.get(),
153            replyObj.get(),
154            flags);
155
156    if (env->ExceptionCheck()) {
157        jthrowable excep = env->ExceptionOccurred();
158        env->ExceptionDescribe();
159
160        if (env->IsInstanceOf(excep, gErrorClass)) {
161            /* It's an error */
162            LOG(ERROR) << "Forcefully exiting";
163            exit(1);
164        } else {
165            env->ExceptionClear();
166            LOG(ERROR) << "Uncaught exception!";
167        }
168
169        env->DeleteLocalRef(excep);
170    }
171
172    status_t err = OK;
173
174    if (!isOneway) {
175        if (!replyContext->wasSent()) {
176            // The implementation never finished the transaction.
177            err = UNKNOWN_ERROR;  // XXX special error code instead?
178
179            reply->setDataPosition(0 /* pos */);
180        }
181
182        // Release all temporary storage now that scatter-gather data
183        // has been consolidated, either by calling the TransactCallback,
184        // if wasSent() == true or clearing the reply parcel (setDataOffset above).
185        replyContext->getStorage()->release(env);
186
187        // We cannot permanently pass ownership of "data" and "reply" over to their
188        // Java object wrappers (we don't own them ourselves).
189        replyContext->setParcel(
190                NULL /* parcel */, false /* assumeOwnership */);
191
192    }
193
194    JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
195            NULL /* parcel */, false /* assumeOwnership */);
196
197    return err;
198}
199
200}  // namespace android
201
202////////////////////////////////////////////////////////////////////////////////
203
204using namespace android;
205
206static void releaseNativeContext(void *nativeContext) {
207    sp<JHwBinder> binder = (JHwBinder *)nativeContext;
208
209    if (binder != NULL) {
210        binder->decStrong(NULL /* id */);
211    }
212}
213
214static jlong JHwBinder_native_init(JNIEnv *env) {
215    JHwBinder::InitClass(env);
216
217    return reinterpret_cast<jlong>(&releaseNativeContext);
218}
219
220static void JHwBinder_native_setup(JNIEnv *env, jobject thiz) {
221    sp<JHwBinder> context = new JHwBinder(env, thiz);
222
223    JHwBinder::SetNativeContext(env, thiz, context);
224}
225
226static void JHwBinder_native_transact(
227        JNIEnv * /* env */,
228        jobject /* thiz */,
229        jint /* code */,
230        jobject /* requestObj */,
231        jobject /* replyObj */,
232        jint /* flags */) {
233    CHECK(!"Should not be here");
234}
235
236static void JHwBinder_native_registerService(
237        JNIEnv *env,
238        jobject thiz,
239        jobject interfaceChainArrayList,
240        jstring serviceNameObj) {
241    if (serviceNameObj == NULL) {
242        jniThrowException(env, "java/lang/NullPointerException", NULL);
243        return;
244    }
245
246    const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL);
247    if (serviceName == NULL) {
248        return;  // XXX exception already pending?
249    }
250
251    jint numInterfaces = env->CallIntMethod(interfaceChainArrayList,
252                                            gArrayListMethods.size);
253    hidl_string *strings = new hidl_string[numInterfaces];
254
255    for (jint i = 0; i < numInterfaces; i++) {
256        jstring strObj = static_cast<jstring>(
257            env->CallObjectMethod(interfaceChainArrayList,
258                                  gArrayListMethods.get,
259                                  i)
260        );
261        const char * str = env->GetStringUTFChars(strObj, nullptr);
262        strings[i] = hidl_string(str);
263        env->ReleaseStringUTFChars(strObj, str);
264    }
265
266    hidl_vec<hidl_string> interfaceChain;
267    interfaceChain.setToExternal(strings, numInterfaces, true /* shouldOwn */);
268
269    sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz);
270
271    /* TODO(b/33440494) this is not right */
272    sp<hidl::base::V1_0::IBase> base = new hidl::base::V1_0::BpHwBase(binder);
273
274    auto manager = hardware::defaultServiceManager();
275
276    if (manager == nullptr) {
277        LOG(ERROR) << "Could not get hwservicemanager.";
278        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
279        return;
280    }
281
282    Return<bool> ret = manager->add(interfaceChain, serviceName, base);
283
284    env->ReleaseStringUTFChars(serviceNameObj, serviceName);
285    serviceName = NULL;
286
287    bool ok = ret.isOk() && ret;
288
289    if (ok) {
290        LOG(INFO) << "Starting thread pool.";
291        ::android::hardware::ProcessState::self()->startThreadPool();
292    }
293
294    signalExceptionForError(env, (ok ? OK : UNKNOWN_ERROR), true /* canThrowRemoteException */);
295}
296
297static jobject JHwBinder_native_getService(
298        JNIEnv *env,
299        jclass /* clazzObj */,
300        jstring ifaceNameObj,
301        jstring serviceNameObj) {
302
303    if (ifaceNameObj == NULL) {
304        jniThrowException(env, "java/lang/NullPointerException", NULL);
305        return NULL;
306    }
307    if (serviceNameObj == NULL) {
308        jniThrowException(env, "java/lang/NullPointerException", NULL);
309        return NULL;
310    }
311
312    auto manager = hardware::defaultServiceManager();
313
314    if (manager == nullptr) {
315        LOG(ERROR) << "Could not get hwservicemanager.";
316        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
317        return NULL;
318    }
319
320    const char *ifaceName = env->GetStringUTFChars(ifaceNameObj, NULL);
321    if (ifaceName == NULL) {
322        return NULL; // XXX exception already pending?
323    }
324    const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL);
325    if (serviceName == NULL) {
326        env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
327        return NULL; // XXX exception already pending?
328    }
329
330    LOG(INFO) << "Looking for service "
331              << ifaceName
332              << "/"
333              << serviceName;
334
335    Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceName, serviceName);
336
337    env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
338    ifaceName = NULL;
339    env->ReleaseStringUTFChars(serviceNameObj, serviceName);
340    serviceName = NULL;
341
342    if (!ret.isOk()) {
343        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
344        return NULL;
345    }
346
347    sp<hardware::IBinder> service = hardware::toBinder<
348            hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase>(ret);
349
350    if (service == NULL) {
351        signalExceptionForError(env, NAME_NOT_FOUND);
352        return NULL;
353    }
354
355    LOG(INFO) << "Starting thread pool.";
356    ::android::hardware::ProcessState::self()->startThreadPool();
357
358    return JHwRemoteBinder::NewObject(env, service);
359}
360
361static JNINativeMethod gMethods[] = {
362    { "native_init", "()J", (void *)JHwBinder_native_init },
363    { "native_setup", "()V", (void *)JHwBinder_native_setup },
364
365    { "transact",
366        "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
367        (void *)JHwBinder_native_transact },
368
369    { "registerService", "(Ljava/util/ArrayList;Ljava/lang/String;)V",
370        (void *)JHwBinder_native_registerService },
371
372    { "getService", "(Ljava/lang/String;Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;",
373        (void *)JHwBinder_native_getService },
374};
375
376namespace android {
377
378int register_android_os_HwBinder(JNIEnv *env) {
379    jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
380    gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
381    gArrayListMethods.size = GetMethodIDOrDie(env, arrayListClass, "size", "()I");
382    gArrayListMethods.get = GetMethodIDOrDie(env, arrayListClass, "get", "(I)Ljava/lang/Object;");
383
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