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