android_os_HwBinder.cpp revision 781c083f32c1b6cf3403977f3f917e81757d4e7a
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, jobject thiz, jstring serviceNameObj) {
200    if (serviceNameObj == NULL) {
201        jniThrowException(env, "java/lang/NullPointerException", NULL);
202        return;
203    }
204
205    const jchar *serviceName = env->GetStringCritical(serviceNameObj, NULL);
206
207    if (serviceName == NULL) {
208        return;  // XXX exception already pending?
209    }
210
211    const hardware::hidl_version kVersion = hardware::make_hidl_version(1, 0);
212
213    sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz);
214
215    status_t err = hardware::defaultServiceManager()->addService(
216                String16(
217                    reinterpret_cast<const char16_t *>(serviceName),
218                    env->GetStringLength(serviceNameObj)),
219                binder,
220                kVersion);
221
222    env->ReleaseStringCritical(serviceNameObj, serviceName);
223    serviceName = NULL;
224
225    if (err == OK) {
226        LOG(INFO) << "Starting thread pool.";
227        ::android::hardware::ProcessState::self()->startThreadPool();
228    }
229
230    signalExceptionForError(env, err);
231}
232
233static jobject JHwBinder_native_getService(
234        JNIEnv *env, jclass /* clazzObj */, jstring serviceNameObj) {
235    if (serviceNameObj == NULL) {
236        jniThrowException(env, "java/lang/NullPointerException", NULL);
237        return NULL;
238    }
239
240    const jchar *serviceName = env->GetStringCritical(serviceNameObj, NULL);
241
242    if (serviceName == NULL) {
243        return NULL;  // XXX exception already pending?
244    }
245
246    const hardware::hidl_version kVersion = hardware::make_hidl_version(1, 0);
247
248    LOG(INFO) << "looking for service '"
249              << String8(String16(
250                          reinterpret_cast<const char16_t *>(serviceName),
251                          env->GetStringLength(serviceNameObj))).string()
252              << "'";
253
254    sp<hardware::IBinder> service =
255        hardware::defaultServiceManager()->getService(
256                String16(
257                    reinterpret_cast<const char16_t *>(serviceName),
258                    env->GetStringLength(serviceNameObj)),
259                kVersion);
260
261    env->ReleaseStringCritical(serviceNameObj, serviceName);
262    serviceName = NULL;
263
264    if (service == NULL) {
265        signalExceptionForError(env, NAME_NOT_FOUND);
266        return NULL;
267    }
268
269    LOG(INFO) << "Starting thread pool.";
270    ::android::hardware::ProcessState::self()->startThreadPool();
271
272    return JHwRemoteBinder::NewObject(env, service);
273}
274
275static JNINativeMethod gMethods[] = {
276    { "native_init", "()J", (void *)JHwBinder_native_init },
277    { "native_setup", "()V", (void *)JHwBinder_native_setup },
278
279    { "transact",
280        "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
281        (void *)JHwBinder_native_transact },
282
283    { "registerService", "(Ljava/lang/String;)V",
284        (void *)JHwBinder_native_registerService },
285
286    { "getService", "(Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;",
287        (void *)JHwBinder_native_getService },
288};
289
290namespace android {
291
292int register_android_os_HwBinder(JNIEnv *env) {
293    return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
294}
295
296}  // namespace android
297