blob: d26cd28f962d87aa63c013139fe5439e9829d7d2 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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_TAG "JavaBinder"
18//#define LOG_NDEBUG 0
19
20#include "android_util_Binder.h"
21#include "JNIHelp.h"
22
23#include <fcntl.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024#include <stdio.h>
Brad Fitzpatrickad8fd282010-03-25 02:01:32 -070025#include <sys/stat.h>
Brad Fitzpatrickad8fd282010-03-25 02:01:32 -070026#include <sys/types.h>
Brad Fitzpatrick8f26b322010-03-25 00:25:37 -070027#include <unistd.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028
29#include <utils/Atomic.h>
Mathias Agopian07952722009-05-19 19:08:10 -070030#include <binder/IInterface.h>
31#include <binder/IPCThreadState.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032#include <utils/Log.h>
Brad Fitzpatrick2c5da312010-03-24 16:14:09 -070033#include <utils/SystemClock.h>
34#include <cutils/logger.h>
Mathias Agopian07952722009-05-19 19:08:10 -070035#include <binder/Parcel.h>
36#include <binder/ProcessState.h>
37#include <binder/IServiceManager.h>
Brad Fitzpatrick5348c012010-03-25 12:43:56 -070038#include <utils/threads.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039
40#include <android_runtime/AndroidRuntime.h>
41
42//#undef LOGV
43//#define LOGV(...) fprintf(stderr, __VA_ARGS__)
44
45using namespace android;
46
47// ----------------------------------------------------------------------------
48
49static struct bindernative_offsets_t
50{
51 // Class state.
52 jclass mClass;
53 jmethodID mExecTransact;
54
55 // Object state.
56 jfieldID mObject;
57
58} gBinderOffsets;
59
60// ----------------------------------------------------------------------------
61
62static struct binderinternal_offsets_t
63{
64 // Class state.
65 jclass mClass;
66 jmethodID mForceGc;
67
68} gBinderInternalOffsets;
69
70// ----------------------------------------------------------------------------
71
72static struct debug_offsets_t
73{
74 // Class state.
75 jclass mClass;
76
77} gDebugOffsets;
78
79// ----------------------------------------------------------------------------
80
81static struct weakreference_offsets_t
82{
83 // Class state.
84 jclass mClass;
85 jmethodID mGet;
86
87} gWeakReferenceOffsets;
88
89static struct error_offsets_t
90{
91 jclass mClass;
92} gErrorOffsets;
93
94// ----------------------------------------------------------------------------
95
96static struct binderproxy_offsets_t
97{
98 // Class state.
99 jclass mClass;
100 jmethodID mConstructor;
101 jmethodID mSendDeathNotice;
102
103 // Object state.
104 jfieldID mObject;
105 jfieldID mSelf;
106
107} gBinderProxyOffsets;
108
109// ----------------------------------------------------------------------------
110
111static struct parcel_offsets_t
112{
113 jfieldID mObject;
114 jfieldID mOwnObject;
115} gParcelOffsets;
116
117static struct log_offsets_t
118{
119 // Class state.
120 jclass mClass;
121 jmethodID mLogE;
122} gLogOffsets;
123
124static struct file_descriptor_offsets_t
125{
126 jclass mClass;
127 jmethodID mConstructor;
128 jfieldID mDescriptor;
129} gFileDescriptorOffsets;
130
131static struct parcel_file_descriptor_offsets_t
132{
133 jclass mClass;
134 jmethodID mConstructor;
135} gParcelFileDescriptorOffsets;
136
137// ****************************************************************************
138// ****************************************************************************
139// ****************************************************************************
140
141static volatile int32_t gNumRefsCreated = 0;
142static volatile int32_t gNumProxyRefs = 0;
143static volatile int32_t gNumLocalRefs = 0;
144static volatile int32_t gNumDeathRefs = 0;
145
146static void incRefsCreated(JNIEnv* env)
147{
148 int old = android_atomic_inc(&gNumRefsCreated);
149 if (old == 200) {
150 android_atomic_and(0, &gNumRefsCreated);
151 env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
152 gBinderInternalOffsets.mForceGc);
153 } else {
154 LOGV("Now have %d binder ops", old);
155 }
156}
157
158static JavaVM* jnienv_to_javavm(JNIEnv* env)
159{
160 JavaVM* vm;
161 return env->GetJavaVM(&vm) >= 0 ? vm : NULL;
162}
163
164static JNIEnv* javavm_to_jnienv(JavaVM* vm)
165{
166 JNIEnv* env;
167 return vm->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0 ? env : NULL;
168}
169
170static void report_exception(JNIEnv* env, jthrowable excep, const char* msg)
171{
172 env->ExceptionClear();
173
174 jstring tagstr = env->NewStringUTF(LOG_TAG);
175 jstring msgstr = env->NewStringUTF(msg);
176
177 if ((tagstr == NULL) || (msgstr == NULL)) {
178 env->ExceptionClear(); /* assume exception (OOM?) was thrown */
179 LOGE("Unable to call Log.e()\n");
180 LOGE("%s", msg);
181 goto bail;
182 }
183
184 env->CallStaticIntMethod(
185 gLogOffsets.mClass, gLogOffsets.mLogE, tagstr, msgstr, excep);
186 if (env->ExceptionCheck()) {
187 /* attempting to log the failure has failed */
188 LOGW("Failed trying to log exception, msg='%s'\n", msg);
189 env->ExceptionClear();
190 }
191
192 if (env->IsInstanceOf(excep, gErrorOffsets.mClass)) {
193 /*
194 * It's an Error: Reraise the exception, detach this thread, and
195 * wait for the fireworks. Die even more blatantly after a minute
196 * if the gentler attempt doesn't do the trick.
197 *
198 * The GetJavaVM function isn't on the "approved" list of JNI calls
199 * that can be made while an exception is pending, so we want to
200 * get the VM ptr, throw the exception, and then detach the thread.
201 */
202 JavaVM* vm = jnienv_to_javavm(env);
203 env->Throw(excep);
204 vm->DetachCurrentThread();
205 sleep(60);
206 LOGE("Forcefully exiting");
207 exit(1);
208 *((int *) 1) = 1;
209 }
210
211bail:
212 /* discard local refs created for us by VM */
213 env->DeleteLocalRef(tagstr);
214 env->DeleteLocalRef(msgstr);
215}
216
217class JavaBBinderHolder;
218
219class JavaBBinder : public BBinder
220{
221public:
222 JavaBBinder(JNIEnv* env, jobject object)
223 : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))
224 {
225 LOGV("Creating JavaBBinder %p\n", this);
226 android_atomic_inc(&gNumLocalRefs);
227 incRefsCreated(env);
228 }
229
230 bool checkSubclass(const void* subclassID) const
231 {
232 return subclassID == &gBinderOffsets;
233 }
234
235 jobject object() const
236 {
237 return mObject;
238 }
239
240protected:
241 virtual ~JavaBBinder()
242 {
243 LOGV("Destroying JavaBBinder %p\n", this);
244 android_atomic_dec(&gNumLocalRefs);
245 JNIEnv* env = javavm_to_jnienv(mVM);
246 env->DeleteGlobalRef(mObject);
247 }
248
249 virtual status_t onTransact(
250 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
251 {
252 JNIEnv* env = javavm_to_jnienv(mVM);
253
254 LOGV("onTransact() on %p calling object %p in env %p vm %p\n", this, mObject, env, mVM);
255
256 //printf("Transact from %p to Java code sending: ", this);
257 //data.print();
258 //printf("\n");
259 jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
260 code, (int32_t)&data, (int32_t)reply, flags);
261 jthrowable excep = env->ExceptionOccurred();
262 if (excep) {
263 report_exception(env, excep,
264 "*** Uncaught remote exception! "
265 "(Exceptions are not yet supported across processes.)");
266 res = JNI_FALSE;
267
268 /* clean up JNI local ref -- we don't return to Java code */
269 env->DeleteLocalRef(excep);
270 }
271
272 //aout << "onTransact to Java code; result=" << res << endl
273 // << "Transact from " << this << " to Java code returning "
274 // << reply << ": " << *reply << endl;
275 return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
276 }
277
278 virtual status_t dump(int fd, const Vector<String16>& args)
279 {
280 return 0;
281 }
282
283private:
284 JavaVM* const mVM;
285 jobject const mObject;
286};
287
288// ----------------------------------------------------------------------------
289
290class JavaBBinderHolder : public RefBase
291{
292public:
293 JavaBBinderHolder(JNIEnv* env, jobject object)
294 : mObject(object)
295 {
296 LOGV("Creating JavaBBinderHolder for Object %p\n", object);
297 }
298 ~JavaBBinderHolder()
299 {
300 LOGV("Destroying JavaBBinderHolder for Object %p\n", mObject);
301 }
302
303 sp<JavaBBinder> get(JNIEnv* env)
304 {
305 AutoMutex _l(mLock);
306 sp<JavaBBinder> b = mBinder.promote();
307 if (b == NULL) {
308 b = new JavaBBinder(env, mObject);
309 mBinder = b;
310 LOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%d\n",
311 b.get(), b->getWeakRefs(), mObject, b->getWeakRefs()->getWeakCount());
312 }
313
314 return b;
315 }
316
317 sp<JavaBBinder> getExisting()
318 {
319 AutoMutex _l(mLock);
320 return mBinder.promote();
321 }
322
323private:
324 Mutex mLock;
325 jobject mObject;
326 wp<JavaBBinder> mBinder;
327};
328
329// ----------------------------------------------------------------------------
330
331class JavaDeathRecipient : public IBinder::DeathRecipient
332{
333public:
334 JavaDeathRecipient(JNIEnv* env, jobject object)
335 : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)),
336 mHoldsRef(true)
337 {
338 incStrong(this);
339 android_atomic_inc(&gNumDeathRefs);
340 incRefsCreated(env);
341 }
342
343 void binderDied(const wp<IBinder>& who)
344 {
345 JNIEnv* env = javavm_to_jnienv(mVM);
346
347 LOGV("Receiving binderDied() on JavaDeathRecipient %p\n", this);
348
349 env->CallStaticVoidMethod(gBinderProxyOffsets.mClass,
350 gBinderProxyOffsets.mSendDeathNotice, mObject);
351 jthrowable excep = env->ExceptionOccurred();
352 if (excep) {
353 report_exception(env, excep,
354 "*** Uncaught exception returned from death notification!");
355 }
356
357 clearReference();
358 }
359
360 void clearReference()
361 {
362 bool release = false;
363 mLock.lock();
364 if (mHoldsRef) {
365 mHoldsRef = false;
366 release = true;
367 }
368 mLock.unlock();
369 if (release) {
370 decStrong(this);
371 }
372 }
373
374protected:
375 virtual ~JavaDeathRecipient()
376 {
377 //LOGI("Removing death ref: recipient=%p\n", mObject);
378 android_atomic_dec(&gNumDeathRefs);
379 JNIEnv* env = javavm_to_jnienv(mVM);
380 env->DeleteGlobalRef(mObject);
381 }
382
383private:
384 JavaVM* const mVM;
385 jobject const mObject;
386 Mutex mLock;
387 bool mHoldsRef;
388};
389
390// ----------------------------------------------------------------------------
391
392namespace android {
393
394static void proxy_cleanup(const void* id, void* obj, void* cleanupCookie)
395{
396 android_atomic_dec(&gNumProxyRefs);
397 JNIEnv* env = javavm_to_jnienv((JavaVM*)cleanupCookie);
398 env->DeleteGlobalRef((jobject)obj);
399}
400
401static Mutex mProxyLock;
402
403jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
404{
405 if (val == NULL) return NULL;
406
407 if (val->checkSubclass(&gBinderOffsets)) {
408 // One of our own!
409 jobject object = static_cast<JavaBBinder*>(val.get())->object();
410 //printf("objectForBinder %p: it's our own %p!\n", val.get(), object);
411 return object;
412 }
413
414 // For the rest of the function we will hold this lock, to serialize
415 // looking/creation of Java proxies for native Binder proxies.
416 AutoMutex _l(mProxyLock);
417
418 // Someone else's... do we know about it?
419 jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
420 if (object != NULL) {
421 jobject res = env->CallObjectMethod(object, gWeakReferenceOffsets.mGet);
422 if (res != NULL) {
423 LOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
424 return res;
425 }
426 LOGV("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
427 android_atomic_dec(&gNumProxyRefs);
428 val->detachObject(&gBinderProxyOffsets);
429 env->DeleteGlobalRef(object);
430 }
431
432 object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
433 if (object != NULL) {
434 LOGV("objectForBinder %p: created new %p!\n", val.get(), object);
435 // The proxy holds a reference to the native object.
436 env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
437 val->incStrong(object);
438
439 // The native object needs to hold a weak reference back to the
440 // proxy, so we can retrieve the same proxy if it is still active.
441 jobject refObject = env->NewGlobalRef(
442 env->GetObjectField(object, gBinderProxyOffsets.mSelf));
443 val->attachObject(&gBinderProxyOffsets, refObject,
444 jnienv_to_javavm(env), proxy_cleanup);
445
446 // Note that a new object reference has been created.
447 android_atomic_inc(&gNumProxyRefs);
448 incRefsCreated(env);
449 }
450
451 return object;
452}
453
454sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
455{
456 if (obj == NULL) return NULL;
457
458 if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
459 JavaBBinderHolder* jbh = (JavaBBinderHolder*)
460 env->GetIntField(obj, gBinderOffsets.mObject);
461 return jbh != NULL ? jbh->get(env) : NULL;
462 }
463
464 if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
465 return (IBinder*)
466 env->GetIntField(obj, gBinderProxyOffsets.mObject);
467 }
468
469 LOGW("ibinderForJavaObject: %p is not a Binder object", obj);
470 return NULL;
471}
472
473Parcel* parcelForJavaObject(JNIEnv* env, jobject obj)
474{
475 if (obj) {
476 Parcel* p = (Parcel*)env->GetIntField(obj, gParcelOffsets.mObject);
477 if (p != NULL) {
478 return p;
479 }
480 jniThrowException(env, "java/lang/IllegalStateException", "Parcel has been finalized!");
481 }
482 return NULL;
483}
484
485jobject newFileDescriptor(JNIEnv* env, int fd)
486{
487 jobject object = env->NewObject(
488 gFileDescriptorOffsets.mClass, gFileDescriptorOffsets.mConstructor);
489 if (object != NULL) {
490 //LOGI("Created new FileDescriptor %p with fd %d\n", object, fd);
491 env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, fd);
492 }
493 return object;
494}
495
496jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc)
497{
498 return env->NewObject(
499 gParcelFileDescriptorOffsets.mClass, gParcelFileDescriptorOffsets.mConstructor, fileDesc);
500}
501
502void signalExceptionForError(JNIEnv* env, jobject obj, status_t err)
503{
504 switch (err) {
505 case UNKNOWN_ERROR:
506 jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
507 break;
508 case NO_MEMORY:
509 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
510 break;
511 case INVALID_OPERATION:
512 jniThrowException(env, "java/lang/UnsupportedOperationException", NULL);
513 break;
514 case BAD_VALUE:
515 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
516 break;
517 case BAD_INDEX:
518 jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
519 break;
520 case BAD_TYPE:
521 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
522 break;
523 case NAME_NOT_FOUND:
524 jniThrowException(env, "java/util/NoSuchElementException", NULL);
525 break;
526 case PERMISSION_DENIED:
527 jniThrowException(env, "java/lang/SecurityException", NULL);
528 break;
529 case NOT_ENOUGH_DATA:
530 jniThrowException(env, "android/os/ParcelFormatException", "Not enough data");
531 break;
532 case NO_INIT:
533 jniThrowException(env, "java/lang/RuntimeException", "Not initialized");
534 break;
535 case ALREADY_EXISTS:
536 jniThrowException(env, "java/lang/RuntimeException", "Item already exists");
537 break;
538 case DEAD_OBJECT:
539 jniThrowException(env, "android/os/DeadObjectException", NULL);
540 break;
541 case UNKNOWN_TRANSACTION:
542 jniThrowException(env, "java/lang/RuntimeException", "Unknown transaction code");
543 break;
544 case FAILED_TRANSACTION:
545 LOGE("!!! FAILED BINDER TRANSACTION !!!");
546 //jniThrowException(env, "java/lang/OutOfMemoryError", "Binder transaction too large");
547 break;
548 default:
549 LOGE("Unknown binder error code. 0x%x", err);
550 }
551}
552
553}
554
555// ----------------------------------------------------------------------------
556
557static jint android_os_Binder_getCallingPid(JNIEnv* env, jobject clazz)
558{
559 return IPCThreadState::self()->getCallingPid();
560}
561
562static jint android_os_Binder_getCallingUid(JNIEnv* env, jobject clazz)
563{
564 return IPCThreadState::self()->getCallingUid();
565}
566
567static jlong android_os_Binder_clearCallingIdentity(JNIEnv* env, jobject clazz)
568{
569 return IPCThreadState::self()->clearCallingIdentity();
570}
571
572static void android_os_Binder_restoreCallingIdentity(JNIEnv* env, jobject clazz, jlong token)
573{
574 IPCThreadState::self()->restoreCallingIdentity(token);
575}
576
577static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
578{
579 IPCThreadState::self()->flushCommands();
580}
581
582static void android_os_Binder_init(JNIEnv* env, jobject clazz)
583{
584 JavaBBinderHolder* jbh = new JavaBBinderHolder(env, clazz);
585 if (jbh == NULL) {
586 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
587 return;
588 }
589 LOGV("Java Binder %p: acquiring first ref on holder %p", clazz, jbh);
590 jbh->incStrong(clazz);
591 env->SetIntField(clazz, gBinderOffsets.mObject, (int)jbh);
592}
593
594static void android_os_Binder_destroy(JNIEnv* env, jobject clazz)
595{
596 JavaBBinderHolder* jbh = (JavaBBinderHolder*)
597 env->GetIntField(clazz, gBinderOffsets.mObject);
Jeff Brown582763a2010-03-24 18:56:57 -0700598 if (jbh != NULL) {
599 env->SetIntField(clazz, gBinderOffsets.mObject, 0);
600 LOGV("Java Binder %p: removing ref on holder %p", clazz, jbh);
601 jbh->decStrong(clazz);
602 } else {
603 // Encountering an uninitialized binder is harmless. All it means is that
604 // the Binder was only partially initialized when its finalizer ran and called
605 // destroy(). The Binder could be partially initialized for several reasons.
606 // For example, a Binder subclass constructor might have thrown an exception before
607 // it could delegate to its superclass's constructor. Consequently init() would
608 // not have been called and the holder pointer would remain NULL.
609 LOGV("Java Binder %p: ignoring uninitialized binder", clazz);
610 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611}
612
613// ----------------------------------------------------------------------------
614
615static const JNINativeMethod gBinderMethods[] = {
616 /* name, signature, funcPtr */
617 { "getCallingPid", "()I", (void*)android_os_Binder_getCallingPid },
618 { "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },
619 { "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },
620 { "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity },
621 { "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
622 { "init", "()V", (void*)android_os_Binder_init },
623 { "destroy", "()V", (void*)android_os_Binder_destroy }
624};
625
626const char* const kBinderPathName = "android/os/Binder";
627
628static int int_register_android_os_Binder(JNIEnv* env)
629{
630 jclass clazz;
631
632 clazz = env->FindClass(kBinderPathName);
633 LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Binder");
634
635 gBinderOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
636 gBinderOffsets.mExecTransact
637 = env->GetMethodID(clazz, "execTransact", "(IIII)Z");
638 assert(gBinderOffsets.mExecTransact);
639
640 gBinderOffsets.mObject
641 = env->GetFieldID(clazz, "mObject", "I");
642 assert(gBinderOffsets.mObject);
643
644 return AndroidRuntime::registerNativeMethods(
645 env, kBinderPathName,
646 gBinderMethods, NELEM(gBinderMethods));
647}
648
649// ****************************************************************************
650// ****************************************************************************
651// ****************************************************************************
652
653namespace android {
654
655jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz)
656{
657 return gNumLocalRefs;
658}
659
660jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz)
661{
662 return gNumProxyRefs;
663}
664
665jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz)
666{
667 return gNumDeathRefs;
668}
669
670}
671
672// ****************************************************************************
673// ****************************************************************************
674// ****************************************************************************
675
676static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
677{
678 sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
679 return javaObjectForIBinder(env, b);
680}
681
682static void android_os_BinderInternal_joinThreadPool(JNIEnv* env, jobject clazz)
683{
684 sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
685 android::IPCThreadState::self()->joinThreadPool();
686}
687
Dianne Hackborn887f3552009-12-07 17:59:37 -0800688static void android_os_BinderInternal_disableBackgroundScheduling(JNIEnv* env,
689 jobject clazz, jboolean disable)
690{
691 IPCThreadState::disableBackgroundScheduling(disable ? true : false);
692}
693
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694static void android_os_BinderInternal_handleGc(JNIEnv* env, jobject clazz)
695{
696 LOGV("Gc has executed, clearing binder ops");
697 android_atomic_and(0, &gNumRefsCreated);
698}
699
700// ----------------------------------------------------------------------------
701
702static const JNINativeMethod gBinderInternalMethods[] = {
703 /* name, signature, funcPtr */
704 { "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },
705 { "joinThreadPool", "()V", (void*)android_os_BinderInternal_joinThreadPool },
Dianne Hackborn887f3552009-12-07 17:59:37 -0800706 { "disableBackgroundScheduling", "(Z)V", (void*)android_os_BinderInternal_disableBackgroundScheduling },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 { "handleGc", "()V", (void*)android_os_BinderInternal_handleGc }
708};
709
710const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";
711
712static int int_register_android_os_BinderInternal(JNIEnv* env)
713{
714 jclass clazz;
715
716 clazz = env->FindClass(kBinderInternalPathName);
717 LOG_FATAL_IF(clazz == NULL, "Unable to find class com.android.internal.os.BinderInternal");
718
719 gBinderInternalOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
720 gBinderInternalOffsets.mForceGc
721 = env->GetStaticMethodID(clazz, "forceBinderGc", "()V");
722 assert(gBinderInternalOffsets.mForceGc);
723
724 return AndroidRuntime::registerNativeMethods(
725 env, kBinderInternalPathName,
726 gBinderInternalMethods, NELEM(gBinderInternalMethods));
727}
728
729// ****************************************************************************
730// ****************************************************************************
731// ****************************************************************************
732
733static jboolean android_os_BinderProxy_pingBinder(JNIEnv* env, jobject obj)
734{
735 IBinder* target = (IBinder*)
736 env->GetIntField(obj, gBinderProxyOffsets.mObject);
737 if (target == NULL) {
738 return JNI_FALSE;
739 }
740 status_t err = target->pingBinder();
741 return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
742}
743
744static jstring android_os_BinderProxy_getInterfaceDescriptor(JNIEnv* env, jobject obj)
745{
746 IBinder* target = (IBinder*) env->GetIntField(obj, gBinderProxyOffsets.mObject);
747 if (target != NULL) {
Brad Fitzpatrick2c5da312010-03-24 16:14:09 -0700748 const String16& desc = target->getInterfaceDescriptor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 return env->NewString(desc.string(), desc.size());
750 }
751 jniThrowException(env, "java/lang/RuntimeException",
752 "No binder found for object");
753 return NULL;
754}
755
756static jboolean android_os_BinderProxy_isBinderAlive(JNIEnv* env, jobject obj)
757{
758 IBinder* target = (IBinder*)
759 env->GetIntField(obj, gBinderProxyOffsets.mObject);
760 if (target == NULL) {
761 return JNI_FALSE;
762 }
763 bool alive = target->isBinderAlive();
764 return alive ? JNI_TRUE : JNI_FALSE;
765}
766
Brad Fitzpatrick2c5da312010-03-24 16:14:09 -0700767static int getprocname(pid_t pid, char *buf, size_t len) {
768 char filename[20];
769 FILE *f;
770
771 sprintf(filename, "/proc/%d/cmdline", pid);
772 f = fopen(filename, "r");
773 if (!f) { *buf = '\0'; return 1; }
774 if (!fgets(buf, len, f)) { *buf = '\0'; return 2; }
775 fclose(f);
776 return 0;
777}
778
779static bool push_eventlog_string(char** pos, const char* end, const char* str) {
780 jint len = strlen(str);
781 int space_needed = 1 + sizeof(len) + len;
782 if (end - *pos < space_needed) {
783 LOGW("not enough space for string. remain=%d; needed=%d",
784 (end - *pos), space_needed);
785 return false;
786 }
787 **pos = EVENT_TYPE_STRING;
788 (*pos)++;
789 memcpy(*pos, &len, sizeof(len));
790 *pos += sizeof(len);
791 memcpy(*pos, str, len);
792 *pos += len;
793 return true;
794}
795
796static bool push_eventlog_int(char** pos, const char* end, jint val) {
797 int space_needed = 1 + sizeof(val);
798 if (end - *pos < space_needed) {
799 LOGW("not enough space for int. remain=%d; needed=%d",
800 (end - *pos), space_needed);
801 return false;
802 }
803 **pos = EVENT_TYPE_INT;
804 (*pos)++;
805 memcpy(*pos, &val, sizeof(val));
806 *pos += sizeof(val);
807 return true;
808}
809
810// From frameworks/base/core/java/android/content/EventLogTags.logtags:
811#define LOGTAG_BINDER_OPERATION 52004
812
813static void conditionally_log_binder_call(int64_t start_millis,
814 IBinder* target, jint code) {
815 int duration_ms = static_cast<int>(uptimeMillis() - start_millis);
816
817 int sample_percent;
818 if (duration_ms >= 500) {
819 sample_percent = 100;
820 } else {
821 sample_percent = 100 * duration_ms / 500;
822 if (sample_percent == 0) {
823 return;
824 }
825 if (sample_percent < (random() % 100 + 1)) {
826 return;
827 }
828 }
829
830 char process_name[40];
831 getprocname(getpid(), process_name, sizeof(process_name));
832 String8 desc(target->getInterfaceDescriptor());
833
834 char buf[LOGGER_ENTRY_MAX_PAYLOAD];
835 buf[0] = EVENT_TYPE_LIST;
836 buf[1] = 5;
837 char* pos = &buf[2];
838 char* end = &buf[LOGGER_ENTRY_MAX_PAYLOAD - 1]; // leave room for final \n
839 if (!push_eventlog_string(&pos, end, desc.string())) return;
840 if (!push_eventlog_int(&pos, end, code)) return;
841 if (!push_eventlog_int(&pos, end, duration_ms)) return;
842 if (!push_eventlog_string(&pos, end, process_name)) return;
843 if (!push_eventlog_int(&pos, end, sample_percent)) return;
844 *(pos++) = '\n'; // conventional with EVENT_TYPE_LIST apparently.
845 android_bWriteLog(LOGTAG_BINDER_OPERATION, buf, pos - buf);
846}
847
Brad Fitzpatrickad8fd282010-03-25 02:01:32 -0700848// We only measure binder call durations to potentially log them if
849// we're on the main thread. Unfortunately sim-eng doesn't seem to
850// have gettid, so we just ignore this and don't log if we can't
851// get the thread id.
852static bool should_time_binder_calls() {
Brad Fitzpatrick5348c012010-03-25 12:43:56 -0700853#ifdef HAVE_GETTID
854 return (getpid() == androidGetTid());
Brad Fitzpatrickad8fd282010-03-25 02:01:32 -0700855#else
856#warning no gettid(), so not logging Binder calls...
857 return false;
858#endif
859}
860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
862 jint code, jobject dataObj,
863 jobject replyObj, jint flags)
864{
865 if (dataObj == NULL) {
866 jniThrowException(env, "java/lang/NullPointerException", NULL);
867 return JNI_FALSE;
868 }
869
870 Parcel* data = parcelForJavaObject(env, dataObj);
871 if (data == NULL) {
872 return JNI_FALSE;
873 }
874 Parcel* reply = parcelForJavaObject(env, replyObj);
875 if (reply == NULL && replyObj != NULL) {
876 return JNI_FALSE;
877 }
878
879 IBinder* target = (IBinder*)
880 env->GetIntField(obj, gBinderProxyOffsets.mObject);
881 if (target == NULL) {
882 jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
883 return JNI_FALSE;
884 }
885
886 LOGV("Java code calling transact on %p in Java object %p with code %d\n",
887 target, obj, code);
Brad Fitzpatrick2c5da312010-03-24 16:14:09 -0700888
889 // Only log the binder call duration for things on the Java-level main thread.
Brad Fitzpatrickad8fd282010-03-25 02:01:32 -0700890 // But if we don't
891 const bool time_binder_calls = should_time_binder_calls();
892
Brad Fitzpatrick2c5da312010-03-24 16:14:09 -0700893 int64_t start_millis;
Brad Fitzpatrickad8fd282010-03-25 02:01:32 -0700894 if (time_binder_calls) {
Brad Fitzpatrick2c5da312010-03-24 16:14:09 -0700895 start_millis = uptimeMillis();
896 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 //printf("Transact from Java code to %p sending: ", target); data->print();
898 status_t err = target->transact(code, *data, reply, flags);
899 //if (reply) printf("Transact from Java code to %p received: ", target); reply->print();
Brad Fitzpatrickad8fd282010-03-25 02:01:32 -0700900 if (time_binder_calls) {
Brad Fitzpatrick2c5da312010-03-24 16:14:09 -0700901 conditionally_log_binder_call(start_millis, target, code);
902 }
903
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 if (err == NO_ERROR) {
905 return JNI_TRUE;
906 } else if (err == UNKNOWN_TRANSACTION) {
907 return JNI_FALSE;
908 }
909
910 signalExceptionForError(env, obj, err);
911 return JNI_FALSE;
912}
913
914static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj,
915 jobject recipient, jint flags)
916{
917 if (recipient == NULL) {
918 jniThrowException(env, "java/lang/NullPointerException", NULL);
919 return;
920 }
921
922 IBinder* target = (IBinder*)
923 env->GetIntField(obj, gBinderProxyOffsets.mObject);
924 if (target == NULL) {
925 LOGW("Binder has been finalized when calling linkToDeath() with recip=%p)\n", recipient);
926 assert(false);
927 }
928
929 LOGV("linkToDeath: binder=%p recipient=%p\n", target, recipient);
930
931 if (!target->localBinder()) {
932 sp<JavaDeathRecipient> jdr = new JavaDeathRecipient(env, recipient);
933 status_t err = target->linkToDeath(jdr, recipient, flags);
934 if (err != NO_ERROR) {
935 // Failure adding the death recipient, so clear its reference
936 // now.
937 jdr->clearReference();
938 signalExceptionForError(env, obj, err);
939 }
940 }
941}
942
943static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj,
944 jobject recipient, jint flags)
945{
946 jboolean res = JNI_FALSE;
947 if (recipient == NULL) {
948 jniThrowException(env, "java/lang/NullPointerException", NULL);
949 return res;
950 }
951
952 IBinder* target = (IBinder*)
953 env->GetIntField(obj, gBinderProxyOffsets.mObject);
954 if (target == NULL) {
955 LOGW("Binder has been finalized when calling linkToDeath() with recip=%p)\n", recipient);
956 return JNI_FALSE;
957 }
958
959 LOGV("unlinkToDeath: binder=%p recipient=%p\n", target, recipient);
960
961 if (!target->localBinder()) {
962 wp<IBinder::DeathRecipient> dr;
963 status_t err = target->unlinkToDeath(NULL, recipient, flags, &dr);
964 if (err == NO_ERROR && dr != NULL) {
965 sp<IBinder::DeathRecipient> sdr = dr.promote();
966 JavaDeathRecipient* jdr = static_cast<JavaDeathRecipient*>(sdr.get());
967 if (jdr != NULL) {
968 jdr->clearReference();
969 }
970 }
971 if (err == NO_ERROR || err == DEAD_OBJECT) {
972 res = JNI_TRUE;
973 } else {
974 jniThrowException(env, "java/util/NoSuchElementException",
975 "Death link does not exist");
976 }
977 }
978
979 return res;
980}
981
982static void android_os_BinderProxy_destroy(JNIEnv* env, jobject obj)
983{
984 IBinder* b = (IBinder*)
985 env->GetIntField(obj, gBinderProxyOffsets.mObject);
986 LOGV("Destroying BinderProxy %p: binder=%p\n", obj, b);
987 env->SetIntField(obj, gBinderProxyOffsets.mObject, 0);
988 b->decStrong(obj);
989 IPCThreadState::self()->flushCommands();
990}
991
992// ----------------------------------------------------------------------------
993
994static const JNINativeMethod gBinderProxyMethods[] = {
995 /* name, signature, funcPtr */
996 {"pingBinder", "()Z", (void*)android_os_BinderProxy_pingBinder},
997 {"isBinderAlive", "()Z", (void*)android_os_BinderProxy_isBinderAlive},
998 {"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
999 {"transact", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
1000 {"linkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
1001 {"unlinkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
1002 {"destroy", "()V", (void*)android_os_BinderProxy_destroy},
1003};
1004
1005const char* const kBinderProxyPathName = "android/os/BinderProxy";
1006
1007static int int_register_android_os_BinderProxy(JNIEnv* env)
1008{
1009 jclass clazz;
1010
1011 clazz = env->FindClass("java/lang/ref/WeakReference");
1012 LOG_FATAL_IF(clazz == NULL, "Unable to find class java.lang.ref.WeakReference");
1013 gWeakReferenceOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
1014 gWeakReferenceOffsets.mGet
1015 = env->GetMethodID(clazz, "get", "()Ljava/lang/Object;");
1016 assert(gWeakReferenceOffsets.mGet);
1017
1018 clazz = env->FindClass("java/lang/Error");
1019 LOG_FATAL_IF(clazz == NULL, "Unable to find class java.lang.Error");
1020 gErrorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
1021
1022 clazz = env->FindClass(kBinderProxyPathName);
1023 LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.BinderProxy");
1024
1025 gBinderProxyOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
1026 gBinderProxyOffsets.mConstructor
1027 = env->GetMethodID(clazz, "<init>", "()V");
1028 assert(gBinderProxyOffsets.mConstructor);
1029 gBinderProxyOffsets.mSendDeathNotice
1030 = env->GetStaticMethodID(clazz, "sendDeathNotice", "(Landroid/os/IBinder$DeathRecipient;)V");
1031 assert(gBinderProxyOffsets.mSendDeathNotice);
1032
1033 gBinderProxyOffsets.mObject
1034 = env->GetFieldID(clazz, "mObject", "I");
1035 assert(gBinderProxyOffsets.mObject);
1036 gBinderProxyOffsets.mSelf
1037 = env->GetFieldID(clazz, "mSelf", "Ljava/lang/ref/WeakReference;");
1038 assert(gBinderProxyOffsets.mSelf);
1039
1040 return AndroidRuntime::registerNativeMethods(
1041 env, kBinderProxyPathName,
1042 gBinderProxyMethods, NELEM(gBinderProxyMethods));
1043}
1044
1045// ****************************************************************************
1046// ****************************************************************************
1047// ****************************************************************************
1048
1049static jint android_os_Parcel_dataSize(JNIEnv* env, jobject clazz)
1050{
1051 Parcel* parcel = parcelForJavaObject(env, clazz);
1052 return parcel ? parcel->dataSize() : 0;
1053}
1054
1055static jint android_os_Parcel_dataAvail(JNIEnv* env, jobject clazz)
1056{
1057 Parcel* parcel = parcelForJavaObject(env, clazz);
1058 return parcel ? parcel->dataAvail() : 0;
1059}
1060
1061static jint android_os_Parcel_dataPosition(JNIEnv* env, jobject clazz)
1062{
1063 Parcel* parcel = parcelForJavaObject(env, clazz);
1064 return parcel ? parcel->dataPosition() : 0;
1065}
1066
1067static jint android_os_Parcel_dataCapacity(JNIEnv* env, jobject clazz)
1068{
1069 Parcel* parcel = parcelForJavaObject(env, clazz);
1070 return parcel ? parcel->dataCapacity() : 0;
1071}
1072
1073static void android_os_Parcel_setDataSize(JNIEnv* env, jobject clazz, jint size)
1074{
1075 Parcel* parcel = parcelForJavaObject(env, clazz);
1076 if (parcel != NULL) {
1077 const status_t err = parcel->setDataSize(size);
1078 if (err != NO_ERROR) {
1079 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1080 }
1081 }
1082}
1083
1084static void android_os_Parcel_setDataPosition(JNIEnv* env, jobject clazz, jint pos)
1085{
1086 Parcel* parcel = parcelForJavaObject(env, clazz);
1087 if (parcel != NULL) {
1088 parcel->setDataPosition(pos);
1089 }
1090}
1091
1092static void android_os_Parcel_setDataCapacity(JNIEnv* env, jobject clazz, jint size)
1093{
1094 Parcel* parcel = parcelForJavaObject(env, clazz);
1095 if (parcel != NULL) {
1096 const status_t err = parcel->setDataCapacity(size);
1097 if (err != NO_ERROR) {
1098 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1099 }
1100 }
1101}
1102
1103static void android_os_Parcel_writeNative(JNIEnv* env, jobject clazz,
1104 jobject data, jint offset,
1105 jint length)
1106{
1107 Parcel* parcel = parcelForJavaObject(env, clazz);
1108 if (parcel == NULL) {
1109 return;
1110 }
1111 void *dest;
1112
1113 const status_t err = parcel->writeInt32(length);
1114 if (err != NO_ERROR) {
1115 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1116 }
1117
1118 dest = parcel->writeInplace(length);
1119
1120 if (dest == NULL) {
1121 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1122 return;
1123 }
1124
1125 jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)data, 0);
1126 if (ar) {
1127 memcpy(dest, ar, length);
1128 env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0);
1129 }
1130}
1131
1132
1133static void android_os_Parcel_writeInt(JNIEnv* env, jobject clazz, jint val)
1134{
1135 Parcel* parcel = parcelForJavaObject(env, clazz);
1136 if (parcel != NULL) {
1137 const status_t err = parcel->writeInt32(val);
1138 if (err != NO_ERROR) {
1139 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1140 }
1141 }
1142}
1143
1144static void android_os_Parcel_writeLong(JNIEnv* env, jobject clazz, jlong val)
1145{
1146 Parcel* parcel = parcelForJavaObject(env, clazz);
1147 if (parcel != NULL) {
1148 const status_t err = parcel->writeInt64(val);
1149 if (err != NO_ERROR) {
1150 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1151 }
1152 }
1153}
1154
1155static void android_os_Parcel_writeFloat(JNIEnv* env, jobject clazz, jfloat val)
1156{
1157 Parcel* parcel = parcelForJavaObject(env, clazz);
1158 if (parcel != NULL) {
1159 const status_t err = parcel->writeFloat(val);
1160 if (err != NO_ERROR) {
1161 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1162 }
1163 }
1164}
1165
1166static void android_os_Parcel_writeDouble(JNIEnv* env, jobject clazz, jdouble val)
1167{
1168 Parcel* parcel = parcelForJavaObject(env, clazz);
1169 if (parcel != NULL) {
1170 const status_t err = parcel->writeDouble(val);
1171 if (err != NO_ERROR) {
1172 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1173 }
1174 }
1175}
1176
1177static void android_os_Parcel_writeString(JNIEnv* env, jobject clazz, jstring val)
1178{
1179 Parcel* parcel = parcelForJavaObject(env, clazz);
1180 if (parcel != NULL) {
1181 status_t err = NO_MEMORY;
1182 if (val) {
1183 const jchar* str = env->GetStringCritical(val, 0);
1184 if (str) {
1185 err = parcel->writeString16(str, env->GetStringLength(val));
1186 env->ReleaseStringCritical(val, str);
1187 }
1188 } else {
1189 err = parcel->writeString16(NULL, 0);
1190 }
1191 if (err != NO_ERROR) {
1192 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1193 }
1194 }
1195}
1196
1197static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jobject clazz, jobject object)
1198{
1199 Parcel* parcel = parcelForJavaObject(env, clazz);
1200 if (parcel != NULL) {
1201 const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
1202 if (err != NO_ERROR) {
1203 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1204 }
1205 }
1206}
1207
1208static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
1209{
1210 Parcel* parcel = parcelForJavaObject(env, clazz);
1211 if (parcel != NULL) {
1212 const status_t err = parcel->writeDupFileDescriptor(
1213 env->GetIntField(object, gFileDescriptorOffsets.mDescriptor));
1214 if (err != NO_ERROR) {
1215 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1216 }
1217 }
1218}
1219
1220static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jobject clazz)
1221{
1222 jbyteArray ret = NULL;
1223
1224 Parcel* parcel = parcelForJavaObject(env, clazz);
1225 if (parcel != NULL) {
1226 int32_t len = parcel->readInt32();
1227
1228 // sanity check the stored length against the true data size
1229 if (len >= 0 && len <= (int32_t)parcel->dataAvail()) {
1230 ret = env->NewByteArray(len);
1231
1232 if (ret != NULL) {
1233 jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
1234 if (a2) {
1235 const void* data = parcel->readInplace(len);
1236 memcpy(a2, data, len);
1237 env->ReleasePrimitiveArrayCritical(ret, a2, 0);
1238 }
1239 }
1240 }
1241 }
1242
1243 return ret;
1244}
1245
1246static jint android_os_Parcel_readInt(JNIEnv* env, jobject clazz)
1247{
1248 Parcel* parcel = parcelForJavaObject(env, clazz);
1249 if (parcel != NULL) {
1250 return parcel->readInt32();
1251 }
1252 return 0;
1253}
1254
1255static jlong android_os_Parcel_readLong(JNIEnv* env, jobject clazz)
1256{
1257 Parcel* parcel = parcelForJavaObject(env, clazz);
1258 if (parcel != NULL) {
1259 return parcel->readInt64();
1260 }
1261 return 0;
1262}
1263
1264static jfloat android_os_Parcel_readFloat(JNIEnv* env, jobject clazz)
1265{
1266 Parcel* parcel = parcelForJavaObject(env, clazz);
1267 if (parcel != NULL) {
1268 return parcel->readFloat();
1269 }
1270 return 0;
1271}
1272
1273static jdouble android_os_Parcel_readDouble(JNIEnv* env, jobject clazz)
1274{
1275 Parcel* parcel = parcelForJavaObject(env, clazz);
1276 if (parcel != NULL) {
1277 return parcel->readDouble();
1278 }
1279 return 0;
1280}
1281
1282static jstring android_os_Parcel_readString(JNIEnv* env, jobject clazz)
1283{
1284 Parcel* parcel = parcelForJavaObject(env, clazz);
1285 if (parcel != NULL) {
1286 size_t len;
1287 const char16_t* str = parcel->readString16Inplace(&len);
1288 if (str) {
1289 return env->NewString(str, len);
1290 }
1291 return NULL;
1292 }
1293 return NULL;
1294}
1295
1296static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jobject clazz)
1297{
1298 Parcel* parcel = parcelForJavaObject(env, clazz);
1299 if (parcel != NULL) {
1300 return javaObjectForIBinder(env, parcel->readStrongBinder());
1301 }
1302 return NULL;
1303}
1304
1305static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jobject clazz)
1306{
1307 Parcel* parcel = parcelForJavaObject(env, clazz);
1308 if (parcel != NULL) {
1309 int fd = parcel->readFileDescriptor();
1310 if (fd < 0) return NULL;
1311 fd = dup(fd);
1312 if (fd < 0) return NULL;
1313 jobject object = env->NewObject(
1314 gFileDescriptorOffsets.mClass, gFileDescriptorOffsets.mConstructor);
1315 if (object != NULL) {
1316 //LOGI("Created new FileDescriptor %p with fd %d\n", object, fd);
1317 env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, fd);
1318 }
1319 return object;
1320 }
1321 return NULL;
1322}
1323
1324static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jobject clazz,
1325 jstring name, jint mode)
1326{
1327 if (name == NULL) {
1328 jniThrowException(env, "java/lang/NullPointerException", NULL);
1329 return NULL;
1330 }
1331 const jchar* str = env->GetStringCritical(name, 0);
1332 if (str == NULL) {
1333 // Whatever, whatever.
1334 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1335 return NULL;
1336 }
1337 String8 name8(str, env->GetStringLength(name));
1338 env->ReleaseStringCritical(name, str);
1339 int flags=0;
1340 switch (mode&0x30000000) {
1341 case 0:
1342 case 0x10000000:
1343 flags = O_RDONLY;
1344 break;
1345 case 0x20000000:
1346 flags = O_WRONLY;
1347 break;
1348 case 0x30000000:
1349 flags = O_RDWR;
1350 break;
1351 }
1352
1353 if (mode&0x08000000) flags |= O_CREAT;
1354 if (mode&0x04000000) flags |= O_TRUNC;
1355 if (mode&0x02000000) flags |= O_APPEND;
1356
1357 int realMode = S_IRWXU|S_IRWXG;
1358 if (mode&0x00000001) realMode |= S_IROTH;
1359 if (mode&0x00000002) realMode |= S_IWOTH;
1360
1361 int fd = open(name8.string(), flags, realMode);
1362 if (fd < 0) {
1363 jniThrowException(env, "java/io/FileNotFoundException", NULL);
1364 return NULL;
1365 }
1366 jobject object = newFileDescriptor(env, fd);
1367 if (object == NULL) {
1368 close(fd);
1369 }
1370 return object;
1371}
1372
1373static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
1374{
1375 int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
1376 if (fd >= 0) {
1377 env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1);
1378 //LOGI("Closing ParcelFileDescriptor %d\n", fd);
1379 close(fd);
1380 }
1381}
1382
1383static void android_os_Parcel_freeBuffer(JNIEnv* env, jobject clazz)
1384{
1385 int32_t own = env->GetIntField(clazz, gParcelOffsets.mOwnObject);
1386 if (own) {
1387 Parcel* parcel = parcelForJavaObject(env, clazz);
1388 if (parcel != NULL) {
1389 //LOGI("Parcel.freeBuffer() called for C++ Parcel %p\n", parcel);
1390 parcel->freeData();
1391 }
1392 }
1393}
1394
1395static void android_os_Parcel_init(JNIEnv* env, jobject clazz, jint parcelInt)
1396{
1397 Parcel* parcel = (Parcel*)parcelInt;
1398 int own = 0;
1399 if (!parcel) {
1400 //LOGI("Initializing obj %p: creating new Parcel\n", clazz);
1401 own = 1;
1402 parcel = new Parcel;
1403 } else {
1404 //LOGI("Initializing obj %p: given existing Parcel %p\n", clazz, parcel);
1405 }
1406 if (parcel == NULL) {
1407 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1408 return;
1409 }
1410 //LOGI("Initializing obj %p from C++ Parcel %p, own=%d\n", clazz, parcel, own);
1411 env->SetIntField(clazz, gParcelOffsets.mOwnObject, own);
1412 env->SetIntField(clazz, gParcelOffsets.mObject, (int)parcel);
1413}
1414
1415static void android_os_Parcel_destroy(JNIEnv* env, jobject clazz)
1416{
1417 int32_t own = env->GetIntField(clazz, gParcelOffsets.mOwnObject);
1418 if (own) {
1419 Parcel* parcel = parcelForJavaObject(env, clazz);
1420 env->SetIntField(clazz, gParcelOffsets.mObject, 0);
1421 //LOGI("Destroying obj %p: deleting C++ Parcel %p\n", clazz, parcel);
1422 delete parcel;
1423 } else {
1424 env->SetIntField(clazz, gParcelOffsets.mObject, 0);
1425 //LOGI("Destroying obj %p: leaving C++ Parcel %p\n", clazz);
1426 }
1427}
1428
1429static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jobject clazz)
1430{
1431 Parcel* parcel = parcelForJavaObject(env, clazz);
1432 if (parcel == NULL) {
1433 return NULL;
1434 }
1435
1436 // do not marshall if there are binder objects in the parcel
1437 if (parcel->objectsCount())
1438 {
1439 jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall a Parcel that contained Binder objects.");
1440 return NULL;
1441 }
1442
1443 jbyteArray ret = env->NewByteArray(parcel->dataSize());
1444
1445 if (ret != NULL)
1446 {
1447 jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
1448 if (array != NULL)
1449 {
1450 memcpy(array, parcel->data(), parcel->dataSize());
1451 env->ReleasePrimitiveArrayCritical(ret, array, 0);
1452 }
1453 }
1454
1455 return ret;
1456}
1457
1458static void android_os_Parcel_unmarshall(JNIEnv* env, jobject clazz, jbyteArray data, jint offset, jint length)
1459{
1460 Parcel* parcel = parcelForJavaObject(env, clazz);
1461 if (parcel == NULL || length < 0) {
1462 return;
1463 }
1464
1465 jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
1466 if (array)
1467 {
1468 parcel->setDataSize(length);
1469 parcel->setDataPosition(0);
1470
1471 void* raw = parcel->writeInplace(length);
1472 memcpy(raw, (array + offset), length);
1473
1474 env->ReleasePrimitiveArrayCritical(data, array, 0);
1475 }
1476}
1477
1478static void android_os_Parcel_appendFrom(JNIEnv* env, jobject clazz, jobject parcel, jint offset, jint length)
1479{
1480 Parcel* thisParcel = parcelForJavaObject(env, clazz);
1481 if (thisParcel == NULL) {
1482 return;
1483 }
1484 Parcel* otherParcel = parcelForJavaObject(env, parcel);
1485 if (otherParcel == NULL) {
1486 return;
1487 }
1488
1489 (void) thisParcel->appendFrom(otherParcel, offset, length);
1490}
1491
1492static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jobject clazz)
1493{
1494 jboolean ret = JNI_FALSE;
1495 Parcel* parcel = parcelForJavaObject(env, clazz);
1496 if (parcel != NULL) {
1497 if (parcel->hasFileDescriptors()) {
1498 ret = JNI_TRUE;
1499 }
1500 }
1501 return ret;
1502}
1503
1504static void android_os_Parcel_writeInterfaceToken(JNIEnv* env, jobject clazz, jstring name)
1505{
1506 Parcel* parcel = parcelForJavaObject(env, clazz);
1507 if (parcel != NULL) {
1508 // In the current implementation, the token is just the serialized interface name that
1509 // the caller expects to be invoking
1510 const jchar* str = env->GetStringCritical(name, 0);
1511 if (str != NULL) {
1512 parcel->writeInterfaceToken(String16(str, env->GetStringLength(name)));
1513 env->ReleaseStringCritical(name, str);
1514 }
1515 }
1516}
1517
1518static void android_os_Parcel_enforceInterface(JNIEnv* env, jobject clazz, jstring name)
1519{
1520 jboolean ret = JNI_FALSE;
1521
1522 Parcel* parcel = parcelForJavaObject(env, clazz);
1523 if (parcel != NULL) {
1524 const jchar* str = env->GetStringCritical(name, 0);
1525 if (str) {
1526 bool isValid = parcel->enforceInterface(String16(str, env->GetStringLength(name)));
1527 env->ReleaseStringCritical(name, str);
1528 if (isValid) {
1529 return; // everything was correct -> return silently
1530 }
1531 }
1532 }
1533
1534 // all error conditions wind up here
1535 jniThrowException(env, "java/lang/SecurityException",
1536 "Binder invocation to an incorrect interface");
1537}
1538
1539// ----------------------------------------------------------------------------
1540
1541static const JNINativeMethod gParcelMethods[] = {
1542 {"dataSize", "()I", (void*)android_os_Parcel_dataSize},
1543 {"dataAvail", "()I", (void*)android_os_Parcel_dataAvail},
1544 {"dataPosition", "()I", (void*)android_os_Parcel_dataPosition},
1545 {"dataCapacity", "()I", (void*)android_os_Parcel_dataCapacity},
1546 {"setDataSize", "(I)V", (void*)android_os_Parcel_setDataSize},
1547 {"setDataPosition", "(I)V", (void*)android_os_Parcel_setDataPosition},
1548 {"setDataCapacity", "(I)V", (void*)android_os_Parcel_setDataCapacity},
1549 {"writeNative", "([BII)V", (void*)android_os_Parcel_writeNative},
1550 {"writeInt", "(I)V", (void*)android_os_Parcel_writeInt},
1551 {"writeLong", "(J)V", (void*)android_os_Parcel_writeLong},
1552 {"writeFloat", "(F)V", (void*)android_os_Parcel_writeFloat},
1553 {"writeDouble", "(D)V", (void*)android_os_Parcel_writeDouble},
1554 {"writeString", "(Ljava/lang/String;)V", (void*)android_os_Parcel_writeString},
1555 {"writeStrongBinder", "(Landroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
1556 {"writeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},
1557 {"createByteArray", "()[B", (void*)android_os_Parcel_createByteArray},
1558 {"readInt", "()I", (void*)android_os_Parcel_readInt},
1559 {"readLong", "()J", (void*)android_os_Parcel_readLong},
1560 {"readFloat", "()F", (void*)android_os_Parcel_readFloat},
1561 {"readDouble", "()D", (void*)android_os_Parcel_readDouble},
1562 {"readString", "()Ljava/lang/String;", (void*)android_os_Parcel_readString},
1563 {"readStrongBinder", "()Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
1564 {"internalReadFileDescriptor", "()Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
1565 {"openFileDescriptor", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
1566 {"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
1567 {"freeBuffer", "()V", (void*)android_os_Parcel_freeBuffer},
1568 {"init", "(I)V", (void*)android_os_Parcel_init},
1569 {"destroy", "()V", (void*)android_os_Parcel_destroy},
1570 {"marshall", "()[B", (void*)android_os_Parcel_marshall},
1571 {"unmarshall", "([BII)V", (void*)android_os_Parcel_unmarshall},
1572 {"appendFrom", "(Landroid/os/Parcel;II)V", (void*)android_os_Parcel_appendFrom},
1573 {"hasFileDescriptors", "()Z", (void*)android_os_Parcel_hasFileDescriptors},
1574 {"writeInterfaceToken", "(Ljava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
1575 {"enforceInterface", "(Ljava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
1576};
1577
1578const char* const kParcelPathName = "android/os/Parcel";
1579
1580static int int_register_android_os_Parcel(JNIEnv* env)
1581{
1582 jclass clazz;
1583
1584 clazz = env->FindClass("android/util/Log");
1585 LOG_FATAL_IF(clazz == NULL, "Unable to find class android.util.Log");
1586 gLogOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
1587 gLogOffsets.mLogE = env->GetStaticMethodID(
1588 clazz, "e", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I");
1589 assert(gLogOffsets.mLogE);
1590
1591 clazz = env->FindClass("java/io/FileDescriptor");
1592 LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
1593 gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
1594 gFileDescriptorOffsets.mConstructor
1595 = env->GetMethodID(clazz, "<init>", "()V");
1596 gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
1597 LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
1598 "Unable to find descriptor field in java.io.FileDescriptor");
1599
1600 clazz = env->FindClass("android/os/ParcelFileDescriptor");
1601 LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
1602 gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
1603 gParcelFileDescriptorOffsets.mConstructor
1604 = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
1605
1606 clazz = env->FindClass(kParcelPathName);
1607 LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Parcel");
1608
1609 gParcelOffsets.mObject
1610 = env->GetFieldID(clazz, "mObject", "I");
1611 gParcelOffsets.mOwnObject
1612 = env->GetFieldID(clazz, "mOwnObject", "I");
1613
1614 return AndroidRuntime::registerNativeMethods(
1615 env, kParcelPathName,
1616 gParcelMethods, NELEM(gParcelMethods));
1617}
1618
1619int register_android_os_Binder(JNIEnv* env)
1620{
1621 if (int_register_android_os_Binder(env) < 0)
1622 return -1;
1623 if (int_register_android_os_BinderInternal(env) < 0)
1624 return -1;
1625 if (int_register_android_os_BinderProxy(env) < 0)
1626 return -1;
1627 if (int_register_android_os_Parcel(env) < 0)
1628 return -1;
1629 return 0;
1630}
1631
1632namespace android {
1633
1634// Returns the Unix file descriptor for a ParcelFileDescriptor object
1635int getParcelFileDescriptorFD(JNIEnv* env, jobject object)
1636{
1637 return env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
1638}
1639
1640}