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