blob: 1d5d6d59639a0f2385e8601a52ddf64431cd09ae [file] [log] [blame]
Andreas Huberdab5fc62016-08-15 09:25:02 -07001/*
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 "JHwRemoteBinder"
19#include <android-base/logging.h>
20
21#include "android_os_HwRemoteBinder.h"
22
23#include "android_os_HwParcel.h"
24
25#include <JNIHelp.h>
26#include <android_runtime/AndroidRuntime.h>
Martijn Coenenaa2c32f2016-09-01 01:37:05 +020027#include <hidl/Status.h>
Andreas Huberdab5fc62016-08-15 09:25:02 -070028#include <nativehelper/ScopedLocalRef.h>
29
30#include "core_jni_helpers.h"
31
32using android::AndroidRuntime;
33
34#define PACKAGE_PATH "android/os"
35#define CLASS_NAME "HwRemoteBinder"
36#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME
37
38namespace android {
39
40static struct fields_t {
41 jfieldID contextID;
42 jmethodID constructID;
43
44} gFields;
45
46// static
47void JHwRemoteBinder::InitClass(JNIEnv *env) {
48 ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
49
50 gFields.contextID =
51 GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J");
52
53 gFields.constructID = GetMethodIDOrDie(env, clazz.get(), "<init>", "()V");
54}
55
56// static
57sp<JHwRemoteBinder> JHwRemoteBinder::SetNativeContext(
58 JNIEnv *env, jobject thiz, const sp<JHwRemoteBinder> &context) {
59 sp<JHwRemoteBinder> old =
60 (JHwRemoteBinder *)env->GetLongField(thiz, gFields.contextID);
61
62 if (context != NULL) {
63 context->incStrong(NULL /* id */);
64 }
65
66 if (old != NULL) {
67 old->decStrong(NULL /* id */);
68 }
69
70 env->SetLongField(thiz, gFields.contextID, (long)context.get());
71
72 return old;
73}
74
75// static
76sp<JHwRemoteBinder> JHwRemoteBinder::GetNativeContext(
77 JNIEnv *env, jobject thiz) {
78 return (JHwRemoteBinder *)env->GetLongField(thiz, gFields.contextID);
79}
80
81// static
82jobject JHwRemoteBinder::NewObject(
83 JNIEnv *env, const sp<hardware::IBinder> &binder) {
84 ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
85
86 // XXX Have to look up the constructor here because otherwise that static
87 // class initializer isn't called and gFields.constructID is undefined :(
88
89 jmethodID constructID = GetMethodIDOrDie(env, clazz.get(), "<init>", "()V");
90
91 jobject obj = env->NewObject(clazz.get(), constructID);
92 JHwRemoteBinder::GetNativeContext(env, obj)->setBinder(binder);
93
94 return obj;
95}
96
97JHwRemoteBinder::JHwRemoteBinder(
98 JNIEnv *env, jobject thiz, const sp<hardware::IBinder> &binder)
99 : mBinder(binder) {
100 jclass clazz = env->GetObjectClass(thiz);
101 CHECK(clazz != NULL);
102
103 mClass = (jclass)env->NewGlobalRef(clazz);
104 mObject = env->NewWeakGlobalRef(thiz);
105}
106
107JHwRemoteBinder::~JHwRemoteBinder() {
108 JNIEnv *env = AndroidRuntime::getJNIEnv();
109
110 env->DeleteWeakGlobalRef(mObject);
111 mObject = NULL;
112
113 env->DeleteGlobalRef(mClass);
114 mClass = NULL;
115}
116
117sp<hardware::IBinder> JHwRemoteBinder::getBinder() {
118 return mBinder;
119}
120
121void JHwRemoteBinder::setBinder(const sp<hardware::IBinder> &binder) {
122 mBinder = binder;
123}
124
125} // namespace android
126
127////////////////////////////////////////////////////////////////////////////////
128
129using namespace android;
130
131static void releaseNativeContext(void *nativeContext) {
132 sp<JHwRemoteBinder> binder = (JHwRemoteBinder *)nativeContext;
133
134 if (binder != NULL) {
135 binder->decStrong(NULL /* id */);
136 }
137}
138
139static jlong JHwRemoteBinder_native_init(JNIEnv *env) {
140 JHwRemoteBinder::InitClass(env);
141
142 return reinterpret_cast<jlong>(&releaseNativeContext);
143}
144
145static void JHwRemoteBinder_native_setup_empty(JNIEnv *env, jobject thiz) {
146 sp<JHwRemoteBinder> context =
147 new JHwRemoteBinder(env, thiz, NULL /* service */);
148
149 JHwRemoteBinder::SetNativeContext(env, thiz, context);
150}
151
152static void JHwRemoteBinder_native_transact(
153 JNIEnv *env,
154 jobject thiz,
155 jint code,
156 jobject requestObj,
157 jobject replyObj,
158 jint flags) {
159 sp<hardware::IBinder> binder =
160 JHwRemoteBinder::GetNativeContext(env, thiz)->getBinder();
161
162 if (requestObj == NULL) {
163 jniThrowException(env, "java/lang/NullPointerException", NULL);
164 return;
165 }
166
167 const hardware::Parcel *request =
168 JHwParcel::GetNativeContext(env, requestObj)->getParcel();
169
170 hardware::Parcel *reply =
171 JHwParcel::GetNativeContext(env, replyObj)->getParcel();
172
173 status_t err = binder->transact(code, *request, reply, flags);
174 signalExceptionForError(env, err);
175}
176
177static JNINativeMethod gMethods[] = {
178 { "native_init", "()J", (void *)JHwRemoteBinder_native_init },
179
180 { "native_setup_empty", "()V",
181 (void *)JHwRemoteBinder_native_setup_empty },
182
183 { "transact",
184 "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
185 (void *)JHwRemoteBinder_native_transact },
186};
187
188namespace android {
189
190int register_android_os_HwRemoteBinder(JNIEnv *env) {
191 return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
192}
193
194} // namespace android
195