android_os_HwBinder.cpp revision f8202e464e09618c2b780d331541f32cc186598e
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/BpHwBase.h>
30#include <android_runtime/AndroidRuntime.h>
31#include <hidl/ServiceManagement.h>
32#include <hidl/Status.h>
33#include <hidl/HidlTransportSupport.h>
34#include <hwbinder/ProcessState.h>
35#include <nativehelper/ScopedLocalRef.h>
36#include <vintf/parse_string.h>
37
38#include "core_jni_helpers.h"
39
40using android::AndroidRuntime;
41using android::hardware::hidl_vec;
42using android::hardware::hidl_string;
43template<typename T>
44using Return = android::hardware::Return<T>;
45
46#define PACKAGE_PATH    "android/os"
47#define CLASS_NAME      "HwBinder"
48#define CLASS_PATH      PACKAGE_PATH "/" CLASS_NAME
49
50namespace android {
51
52static jclass gErrorClass;
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    bool isOneway = (flags & TF_ONE_WAY) != 0;
126    ScopedLocalRef<jobject> replyObj(env, nullptr);
127    sp<JHwParcel> replyContext = nullptr;
128
129    ScopedLocalRef<jobject> requestObj(env, JHwParcel::NewObject(env));
130    JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
131            const_cast<hardware::Parcel *>(&data), false /* assumeOwnership */);
132
133
134    if (!isOneway) {
135        replyObj.reset(JHwParcel::NewObject(env));
136
137        replyContext = JHwParcel::GetNativeContext(env, replyObj.get());
138
139        replyContext->setParcel(reply, false /* assumeOwnership */);
140        replyContext->setTransactCallback(callback);
141    }
142
143    env->CallVoidMethod(
144            mObject,
145            gFields.onTransactID,
146            code,
147            requestObj.get(),
148            replyObj.get(),
149            flags);
150
151    if (env->ExceptionCheck()) {
152        jthrowable excep = env->ExceptionOccurred();
153        env->ExceptionDescribe();
154        env->ExceptionClear();
155
156        // It is illegal to call IsInstanceOf if there is a pending exception.
157        // Attempting to do so results in a JniAbort which crashes the entire process.
158        if (env->IsInstanceOf(excep, gErrorClass)) {
159            /* It's an error */
160            LOG(ERROR) << "Forcefully exiting";
161            exit(1);
162        } else {
163            LOG(ERROR) << "Uncaught exception!";
164        }
165
166        env->DeleteLocalRef(excep);
167    }
168
169    status_t err = OK;
170
171    if (!isOneway) {
172        if (!replyContext->wasSent()) {
173            // The implementation never finished the transaction.
174            err = UNKNOWN_ERROR;  // XXX special error code instead?
175
176            reply->setDataPosition(0 /* pos */);
177        }
178
179        // Release all temporary storage now that scatter-gather data
180        // has been consolidated, either by calling the TransactCallback,
181        // if wasSent() == true or clearing the reply parcel (setDataOffset above).
182        replyContext->getStorage()->release(env);
183
184        // We cannot permanently pass ownership of "data" and "reply" over to their
185        // Java object wrappers (we don't own them ourselves).
186        replyContext->setParcel(
187                NULL /* parcel */, false /* assumeOwnership */);
188
189    }
190
191    JHwParcel::GetNativeContext(env, requestObj.get())->setParcel(
192            NULL /* parcel */, false /* assumeOwnership */);
193
194    return err;
195}
196
197}  // namespace android
198
199////////////////////////////////////////////////////////////////////////////////
200
201using namespace android;
202
203static void releaseNativeContext(void *nativeContext) {
204    sp<JHwBinder> binder = (JHwBinder *)nativeContext;
205
206    if (binder != NULL) {
207        binder->decStrong(NULL /* id */);
208    }
209}
210
211static jlong JHwBinder_native_init(JNIEnv *env) {
212    JHwBinder::InitClass(env);
213
214    return reinterpret_cast<jlong>(&releaseNativeContext);
215}
216
217static void JHwBinder_native_setup(JNIEnv *env, jobject thiz) {
218    sp<JHwBinder> context = new JHwBinder(env, thiz);
219
220    JHwBinder::SetNativeContext(env, thiz, context);
221}
222
223static void JHwBinder_native_transact(
224        JNIEnv * /* env */,
225        jobject /* thiz */,
226        jint /* code */,
227        jobject /* requestObj */,
228        jobject /* replyObj */,
229        jint /* flags */) {
230    CHECK(!"Should not be here");
231}
232
233static void JHwBinder_native_registerService(
234        JNIEnv *env,
235        jobject thiz,
236        jstring serviceNameObj) {
237    if (serviceNameObj == NULL) {
238        jniThrowException(env, "java/lang/NullPointerException", NULL);
239        return;
240    }
241
242    const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL);
243    if (serviceName == NULL) {
244        return;  // XXX exception already pending?
245    }
246
247    sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz);
248
249    /* TODO(b/33440494) this is not right */
250    sp<hidl::base::V1_0::IBase> base = new hidl::base::V1_0::BpHwBase(binder);
251
252    auto manager = hardware::defaultServiceManager();
253
254    if (manager == nullptr) {
255        LOG(ERROR) << "Could not get hwservicemanager.";
256        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
257        return;
258    }
259
260    Return<bool> ret = manager->add(serviceName, base);
261
262    env->ReleaseStringUTFChars(serviceNameObj, serviceName);
263    serviceName = NULL;
264
265    bool ok = ret.isOk() && ret;
266
267    if (ok) {
268        LOG(INFO) << "Starting thread pool.";
269        ::android::hardware::ProcessState::self()->startThreadPool();
270    }
271
272    signalExceptionForError(env, (ok ? OK : UNKNOWN_ERROR), true /* canThrowRemoteException */);
273}
274
275static jobject JHwBinder_native_getService(
276        JNIEnv *env,
277        jclass /* clazzObj */,
278        jstring ifaceNameObj,
279        jstring serviceNameObj) {
280
281    using ::android::hidl::base::V1_0::IBase;
282    using ::android::hidl::manager::V1_0::IServiceManager;
283
284    if (ifaceNameObj == NULL) {
285        jniThrowException(env, "java/lang/NullPointerException", NULL);
286        return NULL;
287    }
288    if (serviceNameObj == NULL) {
289        jniThrowException(env, "java/lang/NullPointerException", NULL);
290        return NULL;
291    }
292
293    auto manager = hardware::defaultServiceManager();
294
295    if (manager == nullptr) {
296        LOG(ERROR) << "Could not get hwservicemanager.";
297        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
298        return NULL;
299    }
300
301    const char *ifaceNameCStr = env->GetStringUTFChars(ifaceNameObj, NULL);
302    if (ifaceNameCStr == NULL) {
303        return NULL; // XXX exception already pending?
304    }
305    std::string ifaceName(ifaceNameCStr);
306    env->ReleaseStringUTFChars(ifaceNameObj, ifaceNameCStr);
307    ::android::hardware::hidl_string ifaceNameHStr;
308    ifaceNameHStr.setToExternal(ifaceName.c_str(), ifaceName.size());
309
310    const char *serviceNameCStr = env->GetStringUTFChars(serviceNameObj, NULL);
311    if (serviceNameCStr == NULL) {
312        return NULL; // XXX exception already pending?
313    }
314    std::string serviceName(serviceNameCStr);
315    env->ReleaseStringUTFChars(serviceNameObj, serviceNameCStr);
316    ::android::hardware::hidl_string serviceNameHStr;
317    serviceNameHStr.setToExternal(serviceName.c_str(), serviceName.size());
318
319    LOG(INFO) << "Looking for service "
320              << ifaceName
321              << "/"
322              << serviceName;
323
324    Return<IServiceManager::Transport> transportRet =
325            manager->getTransport(ifaceNameHStr, serviceNameHStr);
326
327    if (!transportRet.isOk()) {
328        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
329        return NULL;
330    }
331
332    IServiceManager::Transport transport = transportRet;
333
334    if (   transport != IServiceManager::Transport::EMPTY
335        && transport != IServiceManager::Transport::HWBINDER) {
336        LOG(ERROR) << "service " << ifaceName << " declares transport method "
337                   << toString(transport) << " but framework expects hwbinder.";
338        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
339        return NULL;
340    }
341
342    Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceNameHStr, serviceNameHStr);
343
344    if (!ret.isOk()) {
345        signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
346        return NULL;
347    }
348
349    sp<hardware::IBinder> service = hardware::toBinder<
350            hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase>(ret);
351
352    if (service == NULL) {
353        signalExceptionForError(env, NAME_NOT_FOUND);
354        return NULL;
355    }
356
357    LOG(INFO) << "Starting thread pool.";
358    ::android::hardware::ProcessState::self()->startThreadPool();
359
360    return JHwRemoteBinder::NewObject(env, service);
361}
362
363static JNINativeMethod gMethods[] = {
364    { "native_init", "()J", (void *)JHwBinder_native_init },
365    { "native_setup", "()V", (void *)JHwBinder_native_setup },
366
367    { "transact",
368        "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V",
369        (void *)JHwBinder_native_transact },
370
371    { "registerService", "(Ljava/lang/String;)V",
372        (void *)JHwBinder_native_registerService },
373
374    { "getService", "(Ljava/lang/String;Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;",
375        (void *)JHwBinder_native_getService },
376};
377
378namespace android {
379
380int register_android_os_HwBinder(JNIEnv *env) {
381    jclass errorClass = FindClassOrDie(env, "java/lang/Error");
382    gErrorClass = MakeGlobalRefOrDie(env, errorClass);
383
384    return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
385}
386
387}  // namespace android
388