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