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