diff options
41 files changed, 1555 insertions, 833 deletions
diff --git a/api/current.txt b/api/current.txt index 0603a63a79e9..a6bdf5a40c71 100644 --- a/api/current.txt +++ b/api/current.txt @@ -27495,9 +27495,19 @@ package android.widget { ctor public Spinner(android.content.Context, android.util.AttributeSet); ctor public Spinner(android.content.Context, android.util.AttributeSet, int); ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int); + method public int getDropDownHorizontalOffset(); + method public int getDropDownVerticalOffset(); + method public int getDropDownWidth(); + method public int getGravity(); + method public android.graphics.drawable.Drawable getPopupBackground(); method public java.lang.CharSequence getPrompt(); method public void onClick(android.content.DialogInterface, int); + method public void setDropDownHorizontalOffset(int); + method public void setDropDownVerticalOffset(int); + method public void setDropDownWidth(int); method public void setGravity(int); + method public void setPopupBackgroundDrawable(android.graphics.drawable.Drawable); + method public void setPopupBackgroundResource(int); method public void setPrompt(java.lang.CharSequence); method public void setPromptId(int); field public static final int MODE_DIALOG = 0; // 0x0 @@ -27518,14 +27528,26 @@ package android.widget { ctor public Switch(android.content.Context); ctor public Switch(android.content.Context, android.util.AttributeSet); ctor public Switch(android.content.Context, android.util.AttributeSet, int); + method public int getSwitchMinWidth(); + method public int getSwitchPadding(); method public java.lang.CharSequence getTextOff(); method public java.lang.CharSequence getTextOn(); + method public android.graphics.drawable.Drawable getThumbDrawable(); + method public int getThumbTextPadding(); + method public android.graphics.drawable.Drawable getTrackDrawable(); method public void onMeasure(int, int); + method public void setSwitchMinWidth(int); + method public void setSwitchPadding(int); method public void setSwitchTextAppearance(android.content.Context, int); method public void setSwitchTypeface(android.graphics.Typeface, int); method public void setSwitchTypeface(android.graphics.Typeface); method public void setTextOff(java.lang.CharSequence); method public void setTextOn(java.lang.CharSequence); + method public void setThumbDrawable(android.graphics.drawable.Drawable); + method public void setThumbResource(int); + method public void setThumbTextPadding(int); + method public void setTrackDrawable(android.graphics.drawable.Drawable); + method public void setTrackResource(int); } public class TabHost extends android.widget.FrameLayout implements android.view.ViewTreeObserver.OnTouchModeChangeListener { diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 6fbeee36e03a..954ae66c7f91 100755 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -645,7 +645,7 @@ public class ValueAnimator extends Animator { // onAnimate to process the next frame of the animations. if (!mAnimationScheduled && (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty())) { - mChoreographer.postAnimationCallback(this); + mChoreographer.postAnimationCallback(this, null); mAnimationScheduled = true; } } diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 215e836bf735..6c1445df74a0 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -28,6 +28,8 @@ import java.util.regex.Pattern; import java.util.zip.CRC32; import java.util.zip.CheckedInputStream; +import libcore.io.Os; +import libcore.io.StructStat; /** * Tools for managing files. Not for public consumption. @@ -52,8 +54,10 @@ public class FileUtils { /** * File status information. This class maps directly to the POSIX stat structure. + * @deprecated use {@link StructStat} instead. * @hide */ + @Deprecated public static final class FileStatus { public int dev; public int ino; @@ -77,7 +81,9 @@ public class FileUtils { * exists. * @return true if the file exists and false if it does not exist. If you do not have * permission to stat the file, then this method will return false. + * @deprecated use {@link Os#stat(String)} instead. */ + @Deprecated public static boolean getFileStatus(String path, FileStatus status) { StrictMode.noteDiskRead(); return getFileStatusNative(path, status); @@ -90,6 +96,10 @@ public class FileUtils { public static native int setPermissions(String file, int mode, int uid, int gid); + /** + * @deprecated use {@link Os#stat(String)} instead. + */ + @Deprecated public static native int getPermissions(String file, int[] outPermissions); public static native int setUMask(int mask); diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 15e3af42c4e3..1507387d78fa 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -180,9 +180,14 @@ public final class Parcel { private static final String TAG = "Parcel"; @SuppressWarnings({"UnusedDeclaration"}) - private int mObject; // used by native code - @SuppressWarnings({"UnusedDeclaration"}) - private int mOwnObject; // used by native code + private int mNativePtr; // used by native code + + /** + * Flag indicating if {@link #mNativePtr} was allocated by this object, + * indicating that we're responsible for its lifecycle. + */ + private boolean mOwnsNativeParcelObject; + private RuntimeException mStack; private static final int POOL_SIZE = 6; @@ -224,6 +229,48 @@ public final class Parcel { private static final int EX_ILLEGAL_STATE = -5; private static final int EX_HAS_REPLY_HEADER = -128; // special; see below + private static native int nativeDataSize(int nativePtr); + private static native int nativeDataAvail(int nativePtr); + private static native int nativeDataPosition(int nativePtr); + private static native int nativeDataCapacity(int nativePtr); + private static native void nativeSetDataSize(int nativePtr, int size); + private static native void nativeSetDataPosition(int nativePtr, int pos); + private static native void nativeSetDataCapacity(int nativePtr, int size); + + private static native boolean nativePushAllowFds(int nativePtr, boolean allowFds); + private static native void nativeRestoreAllowFds(int nativePtr, boolean lastValue); + + private static native void nativeWriteByteArray(int nativePtr, byte[] b, int offset, int len); + private static native void nativeWriteInt(int nativePtr, int val); + private static native void nativeWriteLong(int nativePtr, long val); + private static native void nativeWriteFloat(int nativePtr, float val); + private static native void nativeWriteDouble(int nativePtr, double val); + private static native void nativeWriteString(int nativePtr, String val); + private static native void nativeWriteStrongBinder(int nativePtr, IBinder val); + private static native void nativeWriteFileDescriptor(int nativePtr, FileDescriptor val); + + private static native byte[] nativeCreateByteArray(int nativePtr); + private static native int nativeReadInt(int nativePtr); + private static native long nativeReadLong(int nativePtr); + private static native float nativeReadFloat(int nativePtr); + private static native double nativeReadDouble(int nativePtr); + private static native String nativeReadString(int nativePtr); + private static native IBinder nativeReadStrongBinder(int nativePtr); + private static native FileDescriptor nativeReadFileDescriptor(int nativePtr); + + private static native int nativeCreate(); + private static native void nativeFreeBuffer(int nativePtr); + private static native void nativeDestroy(int nativePtr); + + private static native byte[] nativeMarshall(int nativePtr); + private static native void nativeUnmarshall( + int nativePtr, byte[] data, int offest, int length); + private static native void nativeAppendFrom( + int thisNativePtr, int otherNativePtr, int offset, int length); + private static native boolean nativeHasFileDescriptors(int nativePtr); + private static native void nativeWriteInterfaceToken(int nativePtr, String interfaceName); + private static native void nativeEnforceInterface(int nativePtr, String interfaceName); + public final static Parcelable.Creator<String> STRING_CREATOR = new Parcelable.Creator<String>() { public String createFromParcel(Parcel source) { @@ -262,7 +309,15 @@ public final class Parcel { public final void recycle() { if (DEBUG_RECYCLE) mStack = null; freeBuffer(); - final Parcel[] pool = mOwnObject != 0 ? sOwnedPool : sHolderPool; + + final Parcel[] pool; + if (mOwnsNativeParcelObject) { + pool = sOwnedPool; + } else { + mNativePtr = 0; + pool = sHolderPool; + } + synchronized (pool) { for (int i=0; i<POOL_SIZE; i++) { if (pool[i] == null) { @@ -276,19 +331,25 @@ public final class Parcel { /** * Returns the total amount of data contained in the parcel. */ - public final native int dataSize(); + public final int dataSize() { + return nativeDataSize(mNativePtr); + } /** * Returns the amount of data remaining to be read from the * parcel. That is, {@link #dataSize}-{@link #dataPosition}. */ - public final native int dataAvail(); + public final int dataAvail() { + return nativeDataAvail(mNativePtr); + } /** * Returns the current position in the parcel data. Never * more than {@link #dataSize}. */ - public final native int dataPosition(); + public final int dataPosition() { + return nativeDataPosition(mNativePtr); + } /** * Returns the total amount of space in the parcel. This is always @@ -296,7 +357,9 @@ public final class Parcel { * amount of room left until the parcel needs to re-allocate its * data buffer. */ - public final native int dataCapacity(); + public final int dataCapacity() { + return nativeDataCapacity(mNativePtr); + } /** * Change the amount of data in the parcel. Can be either smaller or @@ -305,14 +368,18 @@ public final class Parcel { * * @param size The new number of bytes in the Parcel. */ - public final native void setDataSize(int size); + public final void setDataSize(int size) { + nativeSetDataSize(mNativePtr, size); + } /** * Move the current read/write position in the parcel. * @param pos New offset in the parcel; must be between 0 and * {@link #dataSize}. */ - public final native void setDataPosition(int pos); + public final void setDataPosition(int pos) { + nativeSetDataPosition(mNativePtr, pos); + } /** * Change the capacity (current available space) of the parcel. @@ -321,13 +388,19 @@ public final class Parcel { * less than {@link #dataSize} -- that is, you can not drop existing data * with this method. */ - public final native void setDataCapacity(int size); + public final void setDataCapacity(int size) { + nativeSetDataCapacity(mNativePtr, size); + } /** @hide */ - public final native boolean pushAllowFds(boolean allowFds); + public final boolean pushAllowFds(boolean allowFds) { + return nativePushAllowFds(mNativePtr, allowFds); + } /** @hide */ - public final native void restoreAllowFds(boolean lastValue); + public final void restoreAllowFds(boolean lastValue) { + nativeRestoreAllowFds(mNativePtr, lastValue); + } /** * Returns the raw bytes of the parcel. @@ -340,27 +413,40 @@ public final class Parcel { * such does not attempt to maintain compatibility with data created * in different versions of the platform. */ - public final native byte[] marshall(); + public final byte[] marshall() { + return nativeMarshall(mNativePtr); + } /** * Set the bytes in data to be the raw bytes of this Parcel. */ - public final native void unmarshall(byte[] data, int offest, int length); + public final void unmarshall(byte[] data, int offest, int length) { + nativeUnmarshall(mNativePtr, data, offest, length); + } - public final native void appendFrom(Parcel parcel, int offset, int length); + public final void appendFrom(Parcel parcel, int offset, int length) { + nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length); + } /** * Report whether the parcel contains any marshalled file descriptors. */ - public final native boolean hasFileDescriptors(); + public final boolean hasFileDescriptors() { + return nativeHasFileDescriptors(mNativePtr); + } /** * Store or read an IBinder interface token in the parcel at the current * {@link #dataPosition}. This is used to validate that the marshalled * transaction is intended for the target interface. */ - public final native void writeInterfaceToken(String interfaceName); - public final native void enforceInterface(String interfaceName); + public final void writeInterfaceToken(String interfaceName) { + nativeWriteInterfaceToken(mNativePtr, interfaceName); + } + + public final void enforceInterface(String interfaceName) { + nativeEnforceInterface(mNativePtr, interfaceName); + } /** * Write a byte array into the parcel at the current {@link #dataPosition}, @@ -384,40 +470,48 @@ public final class Parcel { return; } Arrays.checkOffsetAndCount(b.length, offset, len); - writeNative(b, offset, len); + nativeWriteByteArray(mNativePtr, b, offset, len); } - private native void writeNative(byte[] b, int offset, int len); - /** * Write an integer value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ - public final native void writeInt(int val); + public final void writeInt(int val) { + nativeWriteInt(mNativePtr, val); + } /** * Write a long integer value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ - public final native void writeLong(long val); + public final void writeLong(long val) { + nativeWriteLong(mNativePtr, val); + } /** * Write a floating point value into the parcel at the current * dataPosition(), growing dataCapacity() if needed. */ - public final native void writeFloat(float val); + public final void writeFloat(float val) { + nativeWriteFloat(mNativePtr, val); + } /** * Write a double precision floating point value into the parcel at the * current dataPosition(), growing dataCapacity() if needed. */ - public final native void writeDouble(double val); + public final void writeDouble(double val) { + nativeWriteDouble(mNativePtr, val); + } /** * Write a string value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ - public final native void writeString(String val); + public final void writeString(String val) { + nativeWriteString(mNativePtr, val); + } /** * Write a CharSequence value into the parcel at the current dataPosition(), @@ -432,7 +526,9 @@ public final class Parcel { * Write an object into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ - public final native void writeStrongBinder(IBinder val); + public final void writeStrongBinder(IBinder val) { + nativeWriteStrongBinder(mNativePtr, val); + } /** * Write an object into the parcel at the current dataPosition(), @@ -452,7 +548,9 @@ public final class Parcel { * accepts contextual flags and will close the original file descriptor * if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.</p> */ - public final native void writeFileDescriptor(FileDescriptor val); + public final void writeFileDescriptor(FileDescriptor val) { + nativeWriteFileDescriptor(mNativePtr, val); + } /** * Write an byte value into the parcel at the current dataPosition(), @@ -1341,29 +1439,39 @@ public final class Parcel { /** * Read an integer value from the parcel at the current dataPosition(). */ - public final native int readInt(); + public final int readInt() { + return nativeReadInt(mNativePtr); + } /** * Read a long integer value from the parcel at the current dataPosition(). */ - public final native long readLong(); + public final long readLong() { + return nativeReadLong(mNativePtr); + } /** * Read a floating point value from the parcel at the current * dataPosition(). */ - public final native float readFloat(); + public final float readFloat() { + return nativeReadFloat(mNativePtr); + } /** * Read a double precision floating point value from the parcel at the * current dataPosition(). */ - public final native double readDouble(); + public final double readDouble() { + return nativeReadDouble(mNativePtr); + } /** * Read a string value from the parcel at the current dataPosition(). */ - public final native String readString(); + public final String readString() { + return nativeReadString(mNativePtr); + } /** * Read a CharSequence value from the parcel at the current dataPosition(). @@ -1376,17 +1484,18 @@ public final class Parcel { /** * Read an object from the parcel at the current dataPosition(). */ - public final native IBinder readStrongBinder(); + public final IBinder readStrongBinder() { + return nativeReadStrongBinder(mNativePtr); + } /** * Read a FileDescriptor from the parcel at the current dataPosition(). */ public final ParcelFileDescriptor readFileDescriptor() { - FileDescriptor fd = internalReadFileDescriptor(); + FileDescriptor fd = nativeReadFileDescriptor(mNativePtr); return fd != null ? new ParcelFileDescriptor(fd) : null; } - private native FileDescriptor internalReadFileDescriptor(); /*package*/ static native FileDescriptor openFileDescriptor(String file, int mode) throws FileNotFoundException; /*package*/ static native FileDescriptor dupFileDescriptor(FileDescriptor orig) @@ -1471,7 +1580,9 @@ public final class Parcel { /** * Read and return a byte[] object from the parcel. */ - public final native byte[] createByteArray(); + public final byte[] createByteArray() { + return nativeCreateByteArray(mNativePtr); + } /** * Read a byte[] object from the parcel and copy it into the @@ -2065,12 +2176,37 @@ public final class Parcel { return new Parcel(obj); } - private Parcel(int obj) { + private Parcel(int nativePtr) { if (DEBUG_RECYCLE) { mStack = new RuntimeException(); } //Log.i(TAG, "Initializing obj=0x" + Integer.toHexString(obj), mStack); - init(obj); + init(nativePtr); + } + + private void init(int nativePtr) { + if (nativePtr != 0) { + mNativePtr = nativePtr; + mOwnsNativeParcelObject = false; + } else { + mNativePtr = nativeCreate(); + mOwnsNativeParcelObject = true; + } + } + + private void freeBuffer() { + if (mOwnsNativeParcelObject) { + nativeFreeBuffer(mNativePtr); + } + } + + private void destroy() { + if (mNativePtr != 0) { + if (mOwnsNativeParcelObject) { + nativeDestroy(mNativePtr); + } + mNativePtr = 0; + } } @Override @@ -2083,10 +2219,6 @@ public final class Parcel { destroy(); } - private native void freeBuffer(); - private native void init(int obj); - private native void destroy(); - /* package */ void readMapInternal(Map outVal, int N, ClassLoader loader) { while (N > 0) { diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index f4d7af96192b..10edc0678d05 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -81,8 +81,8 @@ public final class Choreographer { private static final int MSG_DO_ANIMATION = 0; private static final int MSG_DO_DRAW = 1; private static final int MSG_DO_SCHEDULE_VSYNC = 2; - private static final int MSG_POST_DELAYED_ANIMATION = 3; - private static final int MSG_POST_DELAYED_DRAW = 4; + private static final int MSG_DO_SCHEDULE_ANIMATION = 3; + private static final int MSG_DO_SCHEDULE_DRAW = 4; private final Object mLock = new Object(); @@ -152,134 +152,158 @@ public final class Choreographer { } /** + * Subtracts typical frame delay time from a delay interval in milliseconds. + * + * This method can be used to compensate for animation delay times that have baked + * in assumptions about the frame delay. For example, it's quite common for code to + * assume a 60Hz frame time and bake in a 16ms delay. When we call + * {@link #postAnimationCallbackDelayed} we want to know how long to wait before + * posting the animation callback but let the animation timer take care of the remaining + * frame delay time. + * + * This method is somewhat conservative about how much of the frame delay it + * subtracts. It uses the same value returned by {@link #getFrameDelay} which by + * default is 10ms even though many parts of the system assume 16ms. Consequently, + * we might still wait 6ms before posting an animation callback that we want to run + * on the next frame, but this is much better than waiting a whole 16ms and likely + * missing the deadline. + * + * @param delayMillis The original delay time including an assumed frame delay. + * @return The adjusted delay time with the assumed frame delay subtracted out. + */ + public static long subtractFrameDelay(long delayMillis) { + final long frameDelay = sFrameDelay; + return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay; + } + + /** * Posts a callback to run on the next animation cycle. * The callback only runs once and then is automatically removed. * - * @param runnable The callback to run during the next animation cycle. + * @param action The callback action to run during the next animation cycle. + * @param token The callback token, or null if none. * * @see #removeAnimationCallback */ - public void postAnimationCallback(Runnable runnable) { - if (runnable == null) { - throw new IllegalArgumentException("runnable must not be null"); - } - postAnimationCallbackUnchecked(runnable); - } - - private void postAnimationCallbackUnchecked(Runnable runnable) { - synchronized (mLock) { - mAnimationCallbacks = addCallbackLocked(mAnimationCallbacks, runnable); - scheduleAnimationLocked(); - } + public void postAnimationCallback(Runnable action, Object token) { + postAnimationCallbackDelayed(action, token, 0); } /** * Posts a callback to run on the next animation cycle following the specified delay. * The callback only runs once and then is automatically removed. * - * @param runnable The callback to run during the next animation cycle following + * @param action The callback action to run during the next animation cycle after * the specified delay. + * @param token The callback token, or null if none. * @param delayMillis The delay time in milliseconds. * * @see #removeAnimationCallback */ - public void postAnimationCallbackDelayed(Runnable runnable, long delayMillis) { - if (runnable == null) { - throw new IllegalArgumentException("runnable must not be null"); + public void postAnimationCallbackDelayed(Runnable action, Object token, long delayMillis) { + if (action == null) { + throw new IllegalArgumentException("action must not be null"); } - if (delayMillis <= 0) { - postAnimationCallbackUnchecked(runnable); - } else { - Message msg = mHandler.obtainMessage(MSG_POST_DELAYED_ANIMATION, runnable); - mHandler.sendMessageDelayed(msg, delayMillis); + + synchronized (mLock) { + final long now = SystemClock.uptimeMillis(); + final long dueTime = now + delayMillis; + mAnimationCallbacks = addCallbackLocked(mAnimationCallbacks, dueTime, action, token); + + if (dueTime <= now) { + scheduleAnimationLocked(now); + } else { + Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_ANIMATION, action); + mHandler.sendMessageAtTime(msg, dueTime); + } } } /** - * Removes animation callbacks for the specified runnable. - * Does nothing if the specified animation callback has not been posted or has already - * been removed. + * Removes animation callbacks that have the specified action and token. * - * @param runnable The animation callback to remove. + * @param action The action property of the callbacks to remove, or null to remove + * callbacks with any action. + * @param token The token property of the callbacks to remove, or null to remove + * callbacks with any token. * * @see #postAnimationCallback * @see #postAnimationCallbackDelayed */ - public void removeAnimationCallbacks(Runnable runnable) { - if (runnable == null) { - throw new IllegalArgumentException("runnable must not be null"); - } + public void removeAnimationCallbacks(Runnable action, Object token) { synchronized (mLock) { - mAnimationCallbacks = removeCallbacksLocked(mAnimationCallbacks, runnable); + mAnimationCallbacks = removeCallbacksLocked(mAnimationCallbacks, action, token); + if (action != null && token == null) { + mHandler.removeMessages(MSG_DO_SCHEDULE_ANIMATION, action); + } } - mHandler.removeMessages(MSG_POST_DELAYED_ANIMATION, runnable); } /** * Posts a callback to run on the next draw cycle. * The callback only runs once and then is automatically removed. * - * @param runnable The callback to run during the next draw cycle. + * @param action The callback action to run during the next draw cycle. + * @param token The callback token, or null if none. * * @see #removeDrawCallback */ - public void postDrawCallback(Runnable runnable) { - if (runnable == null) { - throw new IllegalArgumentException("runnable must not be null"); - } - postDrawCallbackUnchecked(runnable); - } - - private void postDrawCallbackUnchecked(Runnable runnable) { - synchronized (mLock) { - mDrawCallbacks = addCallbackLocked(mDrawCallbacks, runnable); - scheduleDrawLocked(); - } + public void postDrawCallback(Runnable action, Object token) { + postDrawCallbackDelayed(action, token, 0); } /** * Posts a callback to run on the next draw cycle following the specified delay. * The callback only runs once and then is automatically removed. * - * @param runnable The callback to run during the next draw cycle following + * @param action The callback action to run during the next animation cycle after * the specified delay. + * @param token The callback token, or null if none. * @param delayMillis The delay time in milliseconds. * * @see #removeDrawCallback */ - public void postDrawCallbackDelayed(Runnable runnable, long delayMillis) { - if (runnable == null) { - throw new IllegalArgumentException("runnable must not be null"); + public void postDrawCallbackDelayed(Runnable action, Object token, long delayMillis) { + if (action == null) { + throw new IllegalArgumentException("action must not be null"); } - if (delayMillis <= 0) { - postDrawCallbackUnchecked(runnable); - } else { - Message msg = mHandler.obtainMessage(MSG_POST_DELAYED_DRAW, runnable); - mHandler.sendMessageDelayed(msg, delayMillis); + + synchronized (mLock) { + final long now = SystemClock.uptimeMillis(); + final long dueTime = now + delayMillis; + mDrawCallbacks = addCallbackLocked(mDrawCallbacks, dueTime, action, token); + scheduleDrawLocked(now); + + if (dueTime <= now) { + scheduleDrawLocked(now); + } else { + Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_DRAW, action); + mHandler.sendMessageAtTime(msg, dueTime); + } } } /** - * Removes draw callbacks for the specified runnable. - * Does nothing if the specified draw callback has not been posted or has already - * been removed. + * Removes draw callbacks that have the specified action and token. * - * @param runnable The draw callback to remove. + * @param action The action property of the callbacks to remove, or null to remove + * callbacks with any action. + * @param token The token property of the callbacks to remove, or null to remove + * callbacks with any token. * * @see #postDrawCallback * @see #postDrawCallbackDelayed */ - public void removeDrawCallbacks(Runnable runnable) { - if (runnable == null) { - throw new IllegalArgumentException("runnable must not be null"); - } + public void removeDrawCallbacks(Runnable action, Object token) { synchronized (mLock) { - mDrawCallbacks = removeCallbacksLocked(mDrawCallbacks, runnable); + mDrawCallbacks = removeCallbacksLocked(mDrawCallbacks, action, token); + if (action != null && token == null) { + mHandler.removeMessages(MSG_DO_SCHEDULE_DRAW, action); + } } - mHandler.removeMessages(MSG_POST_DELAYED_DRAW, runnable); } - private void scheduleAnimationLocked() { + private void scheduleAnimationLocked(long now) { if (!mAnimationScheduled) { mAnimationScheduled = true; if (USE_VSYNC) { @@ -291,14 +315,13 @@ public final class Choreographer { // otherwise post a message to schedule the vsync from the UI thread // as soon as possible. if (isRunningOnLooperThreadLocked()) { - doScheduleVsyncLocked(); + scheduleVsyncLocked(); } else { Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); msg.setAsynchronous(true); mHandler.sendMessageAtFrontOfQueue(msg); } } else { - final long now = SystemClock.uptimeMillis(); final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now); if (DEBUG) { Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms."); @@ -310,18 +333,18 @@ public final class Choreographer { } } - private void scheduleDrawLocked() { + private void scheduleDrawLocked(long now) { if (!mDrawScheduled) { mDrawScheduled = true; if (USE_ANIMATION_TIMER_FOR_DRAW) { - scheduleAnimationLocked(); + scheduleAnimationLocked(now); } else { if (DEBUG) { Log.d(TAG, "Scheduling draw immediately."); } Message msg = mHandler.obtainMessage(MSG_DO_DRAW); msg.setAsynchronous(true); - mHandler.sendMessage(msg); + mHandler.sendMessageAtTime(msg, now); } } } @@ -336,7 +359,7 @@ public final class Choreographer { void doAnimationInner() { final long start; - final Callback callbacks; + Callback callbacks; synchronized (mLock) { if (!mAnimationScheduled) { return; // no work to do @@ -351,7 +374,23 @@ public final class Choreographer { mLastAnimationTime = start; callbacks = mAnimationCallbacks; - mAnimationCallbacks = null; + if (callbacks != null) { + if (callbacks.dueTime > start) { + callbacks = null; + } else { + Callback predecessor = callbacks; + Callback successor = predecessor.next; + while (successor != null) { + if (successor.dueTime > start) { + predecessor.next = null; + break; + } + predecessor = successor; + successor = successor.next; + } + mAnimationCallbacks = successor; + } + } } if (callbacks != null) { @@ -368,7 +407,7 @@ public final class Choreographer { void doDraw() { final long start; - final Callback callbacks; + Callback callbacks; synchronized (mLock) { if (!mDrawScheduled) { return; // no work to do @@ -383,7 +422,23 @@ public final class Choreographer { mLastDrawTime = start; callbacks = mDrawCallbacks; - mDrawCallbacks = null; + if (callbacks != null) { + if (callbacks.dueTime > start) { + callbacks = null; + } else { + Callback predecessor = callbacks; + Callback successor = predecessor.next; + while (successor != null) { + if (successor.dueTime > start) { + predecessor.next = null; + break; + } + predecessor = successor; + successor = successor.next; + } + mDrawCallbacks = successor; + } + } } if (callbacks != null) { @@ -400,38 +455,66 @@ public final class Choreographer { void doScheduleVsync() { synchronized (mLock) { - doScheduleVsyncLocked(); + if (mAnimationScheduled) { + scheduleVsyncLocked(); + } } } - private void doScheduleVsyncLocked() { - if (mAnimationScheduled) { - mDisplayEventReceiver.scheduleVsync(); + void doScheduleAnimation() { + synchronized (mLock) { + final long now = SystemClock.uptimeMillis(); + if (mAnimationCallbacks != null && mAnimationCallbacks.dueTime <= now) { + scheduleAnimationLocked(now); + } } } + void doScheduleDraw() { + synchronized (mLock) { + final long now = SystemClock.uptimeMillis(); + if (mDrawCallbacks != null && mDrawCallbacks.dueTime <= now) { + scheduleDrawLocked(now); + } + } + } + + private void scheduleVsyncLocked() { + mDisplayEventReceiver.scheduleVsync(); + } + private boolean isRunningOnLooperThreadLocked() { return Looper.myLooper() == mLooper; } - private Callback addCallbackLocked(Callback head, Runnable runnable) { - Callback callback = obtainCallbackLocked(runnable); + private Callback addCallbackLocked(Callback head, + long dueTime, Runnable action, Object token) { + Callback callback = obtainCallbackLocked(dueTime, action, token); if (head == null) { return callback; } - Callback tail = head; - while (tail.next != null) { - tail = tail.next; + Callback entry = head; + if (dueTime < entry.dueTime) { + callback.next = entry; + return callback; + } + while (entry.next != null) { + if (dueTime < entry.next.dueTime) { + callback.next = entry.next; + break; + } + entry = entry.next; } - tail.next = callback; + entry.next = callback; return head; } - private Callback removeCallbacksLocked(Callback head, Runnable runnable) { + private Callback removeCallbacksLocked(Callback head, Runnable action, Object token) { Callback predecessor = null; for (Callback callback = head; callback != null;) { final Callback next = callback.next; - if (callback.runnable == runnable) { + if ((action == null || callback.action == action) + && (token == null || callback.token == token)) { if (predecessor != null) { predecessor.next = next; } else { @@ -448,7 +531,7 @@ public final class Choreographer { private void runCallbacks(Callback head) { while (head != null) { - head.runnable.run(); + head.action.run(); head = head.next; } } @@ -461,7 +544,7 @@ public final class Choreographer { } } - private Callback obtainCallbackLocked(Runnable runnable) { + private Callback obtainCallbackLocked(long dueTime, Runnable action, Object token) { Callback callback = mCallbackPool; if (callback == null) { callback = new Callback(); @@ -469,12 +552,15 @@ public final class Choreographer { mCallbackPool = callback.next; callback.next = null; } - callback.runnable = runnable; + callback.dueTime = dueTime; + callback.action = action; + callback.token = token; return callback; } private void recycleCallbackLocked(Callback callback) { - callback.runnable = null; + callback.action = null; + callback.token = null; callback.next = mCallbackPool; mCallbackPool = callback; } @@ -496,11 +582,11 @@ public final class Choreographer { case MSG_DO_SCHEDULE_VSYNC: doScheduleVsync(); break; - case MSG_POST_DELAYED_ANIMATION: - postAnimationCallbackUnchecked((Runnable)msg.obj); + case MSG_DO_SCHEDULE_ANIMATION: + doScheduleAnimation(); break; - case MSG_POST_DELAYED_DRAW: - postDrawCallbackUnchecked((Runnable)msg.obj); + case MSG_DO_SCHEDULE_DRAW: + doScheduleDraw(); break; } } @@ -519,6 +605,8 @@ public final class Choreographer { private static final class Callback { public Callback next; - public Runnable runnable; + public long dueTime; + public Runnable action; + public Object token; } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index b38ca5b88061..a651362d82b6 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8793,6 +8793,52 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } /** + * <p>Causes the Runnable to execute on the next animation time step. + * The runnable will be run on the user interface thread.</p> + * + * <p>This method can be invoked from outside of the UI thread + * only when this View is attached to a window.</p> + * + * @param action The Runnable that will be executed. + * + * @hide + */ + public void postOnAnimation(Runnable action) { + final AttachInfo attachInfo = mAttachInfo; + if (attachInfo != null) { + attachInfo.mViewRootImpl.mChoreographer.postAnimationCallback(action, null); + } else { + // Assume that post will succeed later + ViewRootImpl.getRunQueue().post(action); + } + } + + /** + * <p>Causes the Runnable to execute on the next animation time step, + * after the specified amount of time elapses. + * The runnable will be run on the user interface thread.</p> + * + * <p>This method can be invoked from outside of the UI thread + * only when this View is attached to a window.</p> + * + * @param action The Runnable that will be executed. + * @param delayMillis The delay (in milliseconds) until the Runnable + * will be executed. + * + * @hide + */ + public void postOnAnimationDelayed(Runnable action, long delayMillis) { + final AttachInfo attachInfo = mAttachInfo; + if (attachInfo != null) { + attachInfo.mViewRootImpl.mChoreographer.postAnimationCallbackDelayed( + action, null, delayMillis); + } else { + // Assume that post will succeed later + ViewRootImpl.getRunQueue().postDelayed(action, delayMillis); + } + } + + /** * <p>Removes the specified Runnable from the message queue.</p> * * <p>This method can be invoked from outside of the UI thread @@ -8809,6 +8855,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { attachInfo.mHandler.removeCallbacks(action); + attachInfo.mViewRootImpl.mChoreographer.removeAnimationCallbacks(action, null); } else { // Assume that post will succeed later ViewRootImpl.getRunQueue().removeCallbacks(action); @@ -11880,10 +11927,12 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal */ public void scheduleDrawable(Drawable who, Runnable what, long when) { if (verifyDrawable(who) && what != null) { + final long delay = when - SystemClock.uptimeMillis(); if (mAttachInfo != null) { - mAttachInfo.mHandler.postAtTime(what, who, when); + mAttachInfo.mViewRootImpl.mChoreographer.postAnimationCallbackDelayed( + what, who, Choreographer.subtractFrameDelay(delay)); } else { - ViewRootImpl.getRunQueue().postDelayed(what, when - SystemClock.uptimeMillis()); + ViewRootImpl.getRunQueue().postDelayed(what, delay); } } } @@ -11897,7 +11946,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal public void unscheduleDrawable(Drawable who, Runnable what) { if (verifyDrawable(who) && what != null) { if (mAttachInfo != null) { - mAttachInfo.mHandler.removeCallbacks(what, who); + mAttachInfo.mViewRootImpl.mChoreographer.removeAnimationCallbacks(what, who); } else { ViewRootImpl.getRunQueue().removeCallbacks(what); } @@ -11915,7 +11964,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal */ public void unscheduleDrawable(Drawable who) { if (mAttachInfo != null) { - mAttachInfo.mHandler.removeCallbacksAndMessages(who); + mAttachInfo.mViewRootImpl.mChoreographer.removeAnimationCallbacks(null, who); } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 9cde153006c9..72365c795ec8 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -884,7 +884,7 @@ public final class ViewRootImpl implements ViewParent, void scheduleFrame() { if (!mFrameScheduled) { mFrameScheduled = true; - mChoreographer.postDrawCallback(mFrameRunnable); + mChoreographer.postDrawCallback(mFrameRunnable, null); } } @@ -893,7 +893,7 @@ public final class ViewRootImpl implements ViewParent, if (mFrameScheduled) { mFrameScheduled = false; - mChoreographer.removeDrawCallbacks(mFrameRunnable); + mChoreographer.removeDrawCallbacks(mFrameRunnable, null); } } @@ -4051,7 +4051,7 @@ public final class ViewRootImpl implements ViewParent, } if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) { - mChoreographer.removeAnimationCallbacks(this); + mChoreographer.removeAnimationCallbacks(this, null); mPosted = false; } } @@ -4092,7 +4092,7 @@ public final class ViewRootImpl implements ViewParent, private void postIfNeededLocked() { if (!mPosted) { - mChoreographer.postAnimationCallback(this); + mChoreographer.postAnimationCallback(this, null); mPosted = true; } } diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java index 6540613e9609..aef8a34bd356 100644 --- a/core/java/android/widget/Spinner.java +++ b/core/java/android/widget/Spinner.java @@ -26,6 +26,7 @@ import android.database.DataSetObserver; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -202,6 +203,130 @@ public class Spinner extends AbsSpinner implements OnClickListener { } } + /** + * Set the background drawable for the spinner's popup window of choices. + * Only valid in {@link #MODE_DROPDOWN}; this method is a no-op in other modes. + * + * @param background Background drawable + * + * @attr ref android.R.styleable#Spinner_popupBackground + */ + public void setPopupBackgroundDrawable(Drawable background) { + if (!(mPopup instanceof DropdownPopup)) { + Log.e(TAG, "setPopupBackgroundDrawable: incompatible spinner mode; ignoring..."); + return; + } + ((DropdownPopup) mPopup).setBackgroundDrawable(background); + } + + /** + * Set the background drawable for the spinner's popup window of choices. + * Only valid in {@link #MODE_DROPDOWN}; this method is a no-op in other modes. + * + * @param resId Resource ID of a background drawable + * + * @attr ref android.R.styleable#Spinner_popupBackground + */ + public void setPopupBackgroundResource(int resId) { + setPopupBackgroundDrawable(getContext().getResources().getDrawable(resId)); + } + + /** + * Get the background drawable for the spinner's popup window of choices. + * Only valid in {@link #MODE_DROPDOWN}; other modes will return null. + * + * @return background Background drawable + * + * @attr ref android.R.styleable#Spinner_popupBackground + */ + public Drawable getPopupBackground() { + return mPopup.getBackground(); + } + + /** + * Set a vertical offset in pixels for the spinner's popup window of choices. + * Only valid in {@link #MODE_DROPDOWN}; this method is a no-op in other modes. + * + * @param pixels Vertical offset in pixels + * + * @attr ref android.R.styleable#Spinner_dropDownVerticalOffset + */ + public void setDropDownVerticalOffset(int pixels) { + mPopup.setVerticalOffset(pixels); + } + + /** + * Get the configured vertical offset in pixels for the spinner's popup window of choices. + * Only valid in {@link #MODE_DROPDOWN}; other modes will return 0. + * + * @return Vertical offset in pixels + * + * @attr ref android.R.styleable#Spinner_dropDownVerticalOffset + */ + public int getDropDownVerticalOffset() { + return mPopup.getVerticalOffset(); + } + + /** + * Set a horizontal offset in pixels for the spinner's popup window of choices. + * Only valid in {@link #MODE_DROPDOWN}; this method is a no-op in other modes. + * + * @param pixels Horizontal offset in pixels + * + * @attr ref android.R.styleable#Spinner_dropDownHorizontalOffset + */ + public void setDropDownHorizontalOffset(int pixels) { + mPopup.setHorizontalOffset(pixels); + } + + /** + * Get the configured horizontal offset in pixels for the spinner's popup window of choices. + * Only valid in {@link #MODE_DROPDOWN}; other modes will return 0. + * + * @return Horizontal offset in pixels + * + * @attr ref android.R.styleable#Spinner_dropDownHorizontalOffset + */ + public int getDropDownHorizontalOffset() { + return mPopup.getHorizontalOffset(); + } + + /** + * Set the width of the spinner's popup window of choices in pixels. This value + * may also be set to {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} + * to match the width of the Spinner itself, or + * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} to wrap to the measured size + * of contained dropdown list items. + * + * <p>Only valid in {@link #MODE_DROPDOWN}; this method is a no-op in other modes.</p> + * + * @param pixels Width in pixels, WRAP_CONTENT, or MATCH_PARENT + * + * @attr ref android.R.styleable#Spinner_dropDownWidth + */ + public void setDropDownWidth(int pixels) { + if (!(mPopup instanceof DropdownPopup)) { + Log.e(TAG, "Cannot set dropdown width for MODE_DIALOG, ignoring"); + return; + } + mDropDownWidth = pixels; + } + + /** + * Get the configured width of the spinner's popup window of choices in pixels. + * The returned value may also be {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} + * meaning the popup window will match the width of the Spinner itself, or + * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} to wrap to the measured size + * of contained dropdown list items. + * + * @return Width in pixels, WRAP_CONTENT, or MATCH_PARENT + * + * @attr ref android.R.styleable#Spinner_dropDownWidth + */ + public int getDropDownWidth() { + return mDropDownWidth; + } + @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); @@ -231,6 +356,16 @@ public class Spinner extends AbsSpinner implements OnClickListener { } } + /** + * Describes how the selected item view is positioned. The default is determined by the + * current theme. + * + * @return A {@link android.view.Gravity Gravity} value + */ + public int getGravity() { + return mGravity; + } + @Override public void setAdapter(SpinnerAdapter adapter) { super.setAdapter(adapter); @@ -675,6 +810,13 @@ public class Spinner extends AbsSpinner implements OnClickListener { */ public void setPromptText(CharSequence hintText); public CharSequence getHintText(); + + public void setBackgroundDrawable(Drawable bg); + public void setVerticalOffset(int px); + public void setHorizontalOffset(int px); + public Drawable getBackground(); + public int getVerticalOffset(); + public int getHorizontalOffset(); } private class DialogPopup implements SpinnerPopup, DialogInterface.OnClickListener { @@ -719,6 +861,36 @@ public class Spinner extends AbsSpinner implements OnClickListener { } dismiss(); } + + @Override + public void setBackgroundDrawable(Drawable bg) { + Log.e(TAG, "Cannot set popup background for MODE_DIALOG, ignoring"); + } + + @Override + public void setVerticalOffset(int px) { + Log.e(TAG, "Cannot set vertical offset for MODE_DIALOG, ignoring"); + } + + @Override + public void setHorizontalOffset(int px) { + Log.e(TAG, "Cannot set horizontal offset for MODE_DIALOG, ignoring"); + } + + @Override + public Drawable getBackground() { + return null; + } + + @Override + public int getVerticalOffset() { + return 0; + } + + @Override + public int getHorizontalOffset() { + return 0; + } } private class DropdownPopup extends ListPopupWindow implements SpinnerPopup { diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index 334b9c450ef2..92ad88da6414 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -169,6 +169,8 @@ public class Switch extends CompoundButton { /** * Sets the switch text color, size, style, hint color, and highlight color * from the specified TextAppearance resource. + * + * @attr ref android.R.styleable#Switch_switchTextAppearance */ public void setSwitchTextAppearance(Context context, int resid) { TypedArray appearance = @@ -274,7 +276,151 @@ public class Switch extends CompoundButton { } /** + * Set the amount of horizontal padding between the switch and the associated text. + * + * @param pixels Amount of padding in pixels + * + * @attr ref android.R.styleable#Switch_switchPadding + */ + public void setSwitchPadding(int pixels) { + mSwitchPadding = pixels; + requestLayout(); + } + + /** + * Get the amount of horizontal padding between the switch and the associated text. + * + * @return Amount of padding in pixels + * + * @attr ref android.R.styleable#Switch_switchPadding + */ + public int getSwitchPadding() { + return mSwitchPadding; + } + + /** + * Set the minimum width of the switch in pixels. The switch's width will be the maximum + * of this value and its measured width as determined by the switch drawables and text used. + * + * @param pixels Minimum width of the switch in pixels + * + * @attr ref android.R.styleable#Switch_switchMinWidth + */ + public void setSwitchMinWidth(int pixels) { + mSwitchMinWidth = pixels; + requestLayout(); + } + + /** + * Get the minimum width of the switch in pixels. The switch's width will be the maximum + * of this value and its measured width as determined by the switch drawables and text used. + * + * @return Minimum width of the switch in pixels + * + * @attr ref android.R.styleable#Switch_switchMinWidth + */ + public int getSwitchMinWidth() { + return mSwitchMinWidth; + } + + /** + * Set the horizontal padding around the text drawn on the switch itself. + * + * @param pixels Horizontal padding for switch thumb text in pixels + * + * @attr ref android.R.styleable#Switch_thumbTextPadding + */ + public void setThumbTextPadding(int pixels) { + mThumbTextPadding = pixels; + requestLayout(); + } + + /** + * Get the horizontal padding around the text drawn on the switch itself. + * + * @return Horizontal padding for switch thumb text in pixels + * + * @attr ref android.R.styleable#Switch_thumbTextPadding + */ + public int getThumbTextPadding() { + return mThumbTextPadding; + } + + /** + * Set the drawable used for the track that the switch slides within. + * + * @param track Track drawable + * + * @attr ref android.R.styleable#Switch_track + */ + public void setTrackDrawable(Drawable track) { + mTrackDrawable = track; + requestLayout(); + } + + /** + * Set the drawable used for the track that the switch slides within. + * + * @param resId Resource ID of a track drawable + * + * @attr ref android.R.styleable#Switch_track + */ + public void setTrackResource(int resId) { + setTrackDrawable(getContext().getResources().getDrawable(resId)); + } + + /** + * Get the drawable used for the track that the switch slides within. + * + * @return Track drawable + * + * @attr ref android.R.styleable#Switch_track + */ + public Drawable getTrackDrawable() { + return mTrackDrawable; + } + + /** + * Set the drawable used for the switch "thumb" - the piece that the user + * can physically touch and drag along the track. + * + * @param thumb Thumb drawable + * + * @attr ref android.R.styleable#Switch_thumb + */ + public void setThumbDrawable(Drawable thumb) { + mThumbDrawable = thumb; + requestLayout(); + } + + /** + * Set the drawable used for the switch "thumb" - the piece that the user + * can physically touch and drag along the track. + * + * @param resId Resource ID of a thumb drawable + * + * @attr ref android.R.styleable#Switch_thumb + */ + public void setThumbResource(int resId) { + setThumbDrawable(getContext().getResources().getDrawable(resId)); + } + + /** + * Get the drawable used for the switch "thumb" - the piece that the user + * can physically touch and drag along the track. + * + * @return Thumb drawable + * + * @attr ref android.R.styleable#Switch_thumb + */ + public Drawable getThumbDrawable() { + return mThumbDrawable; + } + + /** * Returns the text displayed when the button is in the checked state. + * + * @attr ref android.R.styleable#Switch_textOn */ public CharSequence getTextOn() { return mTextOn; @@ -282,6 +428,8 @@ public class Switch extends CompoundButton { /** * Sets the text displayed when the button is in the checked state. + * + * @attr ref android.R.styleable#Switch_textOn */ public void setTextOn(CharSequence textOn) { mTextOn = textOn; @@ -290,6 +438,8 @@ public class Switch extends CompoundButton { /** * Returns the text displayed when the button is not in the checked state. + * + * @attr ref android.R.styleable#Switch_textOff */ public CharSequence getTextOff() { return mTextOff; @@ -297,6 +447,8 @@ public class Switch extends CompoundButton { /** * Sets the text displayed when the button is not in the checked state. + * + * @attr ref android.R.styleable#Switch_textOff */ public void setTextOff(CharSequence textOff) { mTextOff = textOff; diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 6a99a2bb3473..998c037fc23a 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -348,6 +348,7 @@ public class ZygoteInit { TypedArray ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_drawables); int N = preloadDrawables(runtime, ar); + ar.recycle(); Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis()-startTime) + "ms."); @@ -355,6 +356,7 @@ public class ZygoteInit { ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_color_state_lists); N = preloadColorStateLists(runtime, ar); + ar.recycle(); Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis()-startTime) + "ms."); } diff --git a/core/jni/Android.mk b/core/jni/Android.mk index c389cf7179cb..642988be8840 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -64,6 +64,7 @@ LOCAL_SRC_FILES:= \ android_os_MemoryFile.cpp \ android_os_MessageQueue.cpp \ android_os_ParcelFileDescriptor.cpp \ + android_os_Parcel.cpp \ android_os_Power.cpp \ android_os_StatFs.cpp \ android_os_SystemClock.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 3067e75d71f1..de9fd33d053b 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -130,6 +130,7 @@ extern int register_android_nio_utils(JNIEnv* env); extern int register_android_text_format_Time(JNIEnv* env); extern int register_android_os_Debug(JNIEnv* env); extern int register_android_os_MessageQueue(JNIEnv* env); +extern int register_android_os_Parcel(JNIEnv* env); extern int register_android_os_ParcelFileDescriptor(JNIEnv *env); extern int register_android_os_Power(JNIEnv *env); extern int register_android_os_StatFs(JNIEnv *env); @@ -1094,6 +1095,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_Process), REG_JNI(register_android_os_SystemProperties), REG_JNI(register_android_os_Binder), + REG_JNI(register_android_os_Parcel), REG_JNI(register_android_view_Display), REG_JNI(register_android_view_DisplayEventReceiver), REG_JNI(register_android_nio_utils), diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index d1d3b787c335..5e73a5fc1ea6 100644 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -7,6 +7,7 @@ #include "SkUnPreMultiply.h"
#include <binder/Parcel.h>
+#include "android_os_Parcel.h" #include "android_util_Binder.h"
#include "android_nio_utils.h"
#include "CreateJavaOutputStreamAdaptor.h"
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp index 5c6ebdf0b9c4..866d223c40b8 100644 --- a/core/jni/android/graphics/Region.cpp +++ b/core/jni/android/graphics/Region.cpp @@ -19,6 +19,7 @@ #include "GraphicsJNI.h" #include <binder/Parcel.h> +#include "android_os_Parcel.h" #include "android_util_Binder.h" #include <jni.h> diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp index 579d6ad858ab..ea02f537c0e7 100644 --- a/core/jni/android_database_CursorWindow.cpp +++ b/core/jni/android_database_CursorWindow.cpp @@ -31,6 +31,7 @@ #include <unistd.h> #include <androidfw/CursorWindow.h> +#include "android_os_Parcel.h" #include "android_util_Binder.h" #include "android_database_SQLiteCommon.h" diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp new file mode 100644 index 000000000000..3dfaac39dec4 --- /dev/null +++ b/core/jni/android_os_Parcel.cpp @@ -0,0 +1,676 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Parcel" +//#define LOG_NDEBUG 0 + +#include "android_os_Parcel.h" +#include "android_util_Binder.h" + +#include "JNIHelp.h" + +#include <fcntl.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <utils/Atomic.h> +#include <binder/IInterface.h> +#include <binder/IPCThreadState.h> +#include <utils/Log.h> +#include <utils/SystemClock.h> +#include <utils/List.h> +#include <utils/KeyedVector.h> +#include <cutils/logger.h> +#include <binder/Parcel.h> +#include <binder/ProcessState.h> +#include <binder/IServiceManager.h> +#include <utils/threads.h> +#include <utils/String8.h> + +#include <ScopedUtfChars.h> +#include <ScopedLocalRef.h> + +#include <android_runtime/AndroidRuntime.h> + +//#undef ALOGV +//#define ALOGV(...) fprintf(stderr, __VA_ARGS__) + +#define DEBUG_DEATH 0 +#if DEBUG_DEATH +#define LOGDEATH ALOGD +#else +#define LOGDEATH ALOGV +#endif + +namespace android { + +static struct parcel_offsets_t +{ + jfieldID mNativePtr; +} gParcelOffsets; + +Parcel* parcelForJavaObject(JNIEnv* env, jobject obj) +{ + if (obj) { + Parcel* p = (Parcel*)env->GetIntField(obj, gParcelOffsets.mNativePtr); + if (p != NULL) { + return p; + } + jniThrowException(env, "java/lang/IllegalStateException", "Parcel has been finalized!"); + } + return NULL; +} + +static jint android_os_Parcel_dataSize(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + return parcel ? parcel->dataSize() : 0; +} + +static jint android_os_Parcel_dataAvail(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + return parcel ? parcel->dataAvail() : 0; +} + +static jint android_os_Parcel_dataPosition(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + return parcel ? parcel->dataPosition() : 0; +} + +static jint android_os_Parcel_dataCapacity(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + return parcel ? parcel->dataCapacity() : 0; +} + +static void android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jint nativePtr, jint size) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + const status_t err = parcel->setDataSize(size); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + } + } +} + +static void android_os_Parcel_setDataPosition(JNIEnv* env, jclass clazz, jint nativePtr, jint pos) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + parcel->setDataPosition(pos); + } +} + +static void android_os_Parcel_setDataCapacity(JNIEnv* env, jclass clazz, jint nativePtr, jint size) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + const status_t err = parcel->setDataCapacity(size); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + } + } +} + +static jboolean android_os_Parcel_pushAllowFds(JNIEnv* env, jclass clazz, jint nativePtr, jboolean allowFds) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + jboolean ret = JNI_TRUE; + if (parcel != NULL) { + ret = (jboolean)parcel->pushAllowFds(allowFds); + } + return ret; +} + +static void android_os_Parcel_restoreAllowFds(JNIEnv* env, jclass clazz, jint nativePtr, jboolean lastValue) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + parcel->restoreAllowFds((bool)lastValue); + } +} + +static void android_os_Parcel_writeNative(JNIEnv* env, jclass clazz, jint nativePtr, jobject data, + jint offset, jint length) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel == NULL) { + return; + } + + const status_t err = parcel->writeInt32(length); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + return; + } + + void* dest = parcel->writeInplace(length); + if (dest == NULL) { + signalExceptionForError(env, clazz, NO_MEMORY); + return; + } + + jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)data, 0); + if (ar) { + memcpy(dest, ar + offset, length); + env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0); + } +} + +static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jint nativePtr, jint val) { + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + const status_t err = parcel->writeInt32(val); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + } +} + +static void android_os_Parcel_writeLong(JNIEnv* env, jclass clazz, jint nativePtr, jlong val) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + const status_t err = parcel->writeInt64(val); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + } + } +} + +static void android_os_Parcel_writeFloat(JNIEnv* env, jclass clazz, jint nativePtr, jfloat val) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + const status_t err = parcel->writeFloat(val); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + } + } +} + +static void android_os_Parcel_writeDouble(JNIEnv* env, jclass clazz, jint nativePtr, jdouble val) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + const status_t err = parcel->writeDouble(val); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + } + } +} + +static void android_os_Parcel_writeString(JNIEnv* env, jclass clazz, jint nativePtr, jstring val) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + status_t err = NO_MEMORY; + if (val) { + const jchar* str = env->GetStringCritical(val, 0); + if (str) { + err = parcel->writeString16(str, env->GetStringLength(val)); + env->ReleaseStringCritical(val, str); + } + } else { + err = parcel->writeString16(NULL, 0); + } + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + } + } +} + +static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr, jobject object) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object)); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + } + } +} + +static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jint nativePtr, jobject object) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + const status_t err = + parcel->writeDupFileDescriptor(jniGetFDFromFileDescriptor(env, object)); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + } + } +} + +static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jclass clazz, jint nativePtr) +{ + jbyteArray ret = NULL; + + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + int32_t len = parcel->readInt32(); + + // sanity check the stored length against the true data size + if (len >= 0 && len <= (int32_t)parcel->dataAvail()) { + ret = env->NewByteArray(len); + + if (ret != NULL) { + jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0); + if (a2) { + const void* data = parcel->readInplace(len); + memcpy(a2, data, len); + env->ReleasePrimitiveArrayCritical(ret, a2, 0); + } + } + } + } + + return ret; +} + +static jint android_os_Parcel_readInt(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + return parcel->readInt32(); + } + return 0; +} + +static jlong android_os_Parcel_readLong(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + return parcel->readInt64(); + } + return 0; +} + +static jfloat android_os_Parcel_readFloat(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + return parcel->readFloat(); + } + return 0; +} + +static jdouble android_os_Parcel_readDouble(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + return parcel->readDouble(); + } + return 0; +} + +static jstring android_os_Parcel_readString(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + size_t len; + const char16_t* str = parcel->readString16Inplace(&len); + if (str) { + return env->NewString(str, len); + } + return NULL; + } + return NULL; +} + +static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + return javaObjectForIBinder(env, parcel->readStrongBinder()); + } + return NULL; +} + +static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + int fd = parcel->readFileDescriptor(); + if (fd < 0) return NULL; + fd = dup(fd); + if (fd < 0) return NULL; + return jniCreateFileDescriptor(env, fd); + } + return NULL; +} + +static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jclass clazz, + jstring name, jint mode) +{ + if (name == NULL) { + jniThrowNullPointerException(env, NULL); + return NULL; + } + const jchar* str = env->GetStringCritical(name, 0); + if (str == NULL) { + // Whatever, whatever. + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return NULL; + } + String8 name8(str, env->GetStringLength(name)); + env->ReleaseStringCritical(name, str); + int flags=0; + switch (mode&0x30000000) { + case 0: + case 0x10000000: + flags = O_RDONLY; + break; + case 0x20000000: + flags = O_WRONLY; + break; + case 0x30000000: + flags = O_RDWR; + break; + } + + if (mode&0x08000000) flags |= O_CREAT; + if (mode&0x04000000) flags |= O_TRUNC; + if (mode&0x02000000) flags |= O_APPEND; + + int realMode = S_IRWXU|S_IRWXG; + if (mode&0x00000001) realMode |= S_IROTH; + if (mode&0x00000002) realMode |= S_IWOTH; + + int fd = open(name8.string(), flags, realMode); + if (fd < 0) { + jniThrowException(env, "java/io/FileNotFoundException", strerror(errno)); + return NULL; + } + jobject object = jniCreateFileDescriptor(env, fd); + if (object == NULL) { + close(fd); + } + return object; +} + +static jobject android_os_Parcel_dupFileDescriptor(JNIEnv* env, jclass clazz, jobject orig) +{ + if (orig == NULL) { + jniThrowNullPointerException(env, NULL); + return NULL; + } + int origfd = jniGetFDFromFileDescriptor(env, orig); + if (origfd < 0) { + jniThrowException(env, "java/lang/IllegalArgumentException", "bad FileDescriptor"); + return NULL; + } + + int fd = dup(origfd); + if (fd < 0) { + jniThrowIOException(env, errno); + return NULL; + } + jobject object = jniCreateFileDescriptor(env, fd); + if (object == NULL) { + close(fd); + } + return object; +} + +static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jclass clazz, jobject object) +{ + if (object == NULL) { + jniThrowNullPointerException(env, NULL); + return; + } + int fd = jniGetFDFromFileDescriptor(env, object); + if (fd >= 0) { + jniSetFileDescriptorOfFD(env, object, -1); + //ALOGI("Closing ParcelFileDescriptor %d\n", fd); + close(fd); + } +} + +static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jclass clazz, jobject object) +{ + if (object == NULL) { + jniThrowNullPointerException(env, NULL); + return; + } + int fd = jniGetFDFromFileDescriptor(env, object); + if (fd >= 0) { + jniSetFileDescriptorOfFD(env, object, -1); + } +} + +static jint android_os_Parcel_create(JNIEnv* env, jclass clazz) +{ + Parcel* parcel = new Parcel(); + return reinterpret_cast<jint>(parcel); +} + +static void android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + parcel->freeData(); + } +} + +static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + delete parcel; +} + +static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jint nativePtr) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel == NULL) { + return NULL; + } + + // do not marshall if there are binder objects in the parcel + if (parcel->objectsCount()) + { + jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall a Parcel that contained Binder objects."); + return NULL; + } + + jbyteArray ret = env->NewByteArray(parcel->dataSize()); + + if (ret != NULL) + { + jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0); + if (array != NULL) + { + memcpy(array, parcel->data(), parcel->dataSize()); + env->ReleasePrimitiveArrayCritical(ret, array, 0); + } + } + + return ret; +} + +static void android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jint nativePtr, + jbyteArray data, jint offset, jint length) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel == NULL || length < 0) { + return; + } + + jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0); + if (array) + { + parcel->setDataSize(length); + parcel->setDataPosition(0); + + void* raw = parcel->writeInplace(length); + memcpy(raw, (array + offset), length); + + env->ReleasePrimitiveArrayCritical(data, array, 0); + } +} + +static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jint thisNativePtr, + jint otherNativePtr, jint offset, jint length) +{ + Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr); + if (thisParcel == NULL) { + return; + } + Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr); + if (otherParcel == NULL) { + return; + } + + status_t err = thisParcel->appendFrom(otherParcel, offset, length); + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + } +} + +static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jclass clazz, jint nativePtr) +{ + jboolean ret = JNI_FALSE; + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + if (parcel->hasFileDescriptors()) { + ret = JNI_TRUE; + } + } + return ret; +} + +static void android_os_Parcel_writeInterfaceToken(JNIEnv* env, jclass clazz, jint nativePtr, + jstring name) +{ + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + // In the current implementation, the token is just the serialized interface name that + // the caller expects to be invoking + const jchar* str = env->GetStringCritical(name, 0); + if (str != NULL) { + parcel->writeInterfaceToken(String16(str, env->GetStringLength(name))); + env->ReleaseStringCritical(name, str); + } + } +} + +static void android_os_Parcel_enforceInterface(JNIEnv* env, jclass clazz, jint nativePtr, jstring name) +{ + jboolean ret = JNI_FALSE; + + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); + if (parcel != NULL) { + const jchar* str = env->GetStringCritical(name, 0); + if (str) { + IPCThreadState* threadState = IPCThreadState::self(); + const int32_t oldPolicy = threadState->getStrictModePolicy(); + const bool isValid = parcel->enforceInterface( + String16(str, env->GetStringLength(name)), + threadState); + env->ReleaseStringCritical(name, str); + if (isValid) { + const int32_t newPolicy = threadState->getStrictModePolicy(); + if (oldPolicy != newPolicy) { + // Need to keep the Java-level thread-local strict + // mode policy in sync for the libcore + // enforcements, which involves an upcall back + // into Java. (We can't modify the + // Parcel.enforceInterface signature, as it's + // pseudo-public, and used via AIDL + // auto-generation...) + set_dalvik_blockguard_policy(env, newPolicy); + } + return; // everything was correct -> return silently + } + } + } + + // all error conditions wind up here + jniThrowException(env, "java/lang/SecurityException", + "Binder invocation to an incorrect interface"); +} + +// ---------------------------------------------------------------------------- + +static const JNINativeMethod gParcelMethods[] = { + {"nativeDataSize", "(I)I", (void*)android_os_Parcel_dataSize}, + {"nativeDataAvail", "(I)I", (void*)android_os_Parcel_dataAvail}, + {"nativeDataPosition", "(I)I", (void*)android_os_Parcel_dataPosition}, + {"nativeDataCapacity", "(I)I", (void*)android_os_Parcel_dataCapacity}, + {"nativeSetDataSize", "(II)V", (void*)android_os_Parcel_setDataSize}, + {"nativeSetDataPosition", "(II)V", (void*)android_os_Parcel_setDataPosition}, + {"nativeSetDataCapacity", "(II)V", (void*)android_os_Parcel_setDataCapacity}, + + {"nativePushAllowFds", "(IZ)Z", (void*)android_os_Parcel_pushAllowFds}, + {"nativeRestoreAllowFds", "(IZ)V", (void*)android_os_Parcel_restoreAllowFds}, + + {"nativeWriteByteArray", "(I[BII)V", (void*)android_os_Parcel_writeNative}, + {"nativeWriteInt", "(II)V", (void*)android_os_Parcel_writeInt}, + {"nativeWriteLong", "(IJ)V", (void*)android_os_Parcel_writeLong}, + {"nativeWriteFloat", "(IF)V", (void*)android_os_Parcel_writeFloat}, + {"nativeWriteDouble", "(ID)V", (void*)android_os_Parcel_writeDouble}, + {"nativeWriteString", "(ILjava/lang/String;)V", (void*)android_os_Parcel_writeString}, + {"nativeWriteStrongBinder", "(ILandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder}, + {"nativeWriteFileDescriptor", "(ILjava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor}, + + {"nativeCreateByteArray", "(I)[B", (void*)android_os_Parcel_createByteArray}, + {"nativeReadInt", "(I)I", (void*)android_os_Parcel_readInt}, + {"nativeReadLong", "(I)J", (void*)android_os_Parcel_readLong}, + {"nativeReadFloat", "(I)F", (void*)android_os_Parcel_readFloat}, + {"nativeReadDouble", "(I)D", (void*)android_os_Parcel_readDouble}, + {"nativeReadString", "(I)Ljava/lang/String;", (void*)android_os_Parcel_readString}, + {"nativeReadStrongBinder", "(I)Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder}, + {"nativeReadFileDescriptor", "(I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor}, + + {"openFileDescriptor", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor}, + {"dupFileDescriptor", "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_dupFileDescriptor}, + {"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor}, + {"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor}, + + {"nativeCreate", "()I", (void*)android_os_Parcel_create}, + {"nativeFreeBuffer", "(I)V", (void*)android_os_Parcel_freeBuffer}, + {"nativeDestroy", "(I)V", (void*)android_os_Parcel_destroy}, + + {"nativeMarshall", "(I)[B", (void*)android_os_Parcel_marshall}, + {"nativeUnmarshall", "(I[BII)V", (void*)android_os_Parcel_unmarshall}, + {"nativeAppendFrom", "(IIII)V", (void*)android_os_Parcel_appendFrom}, + {"nativeHasFileDescriptors", "(I)Z", (void*)android_os_Parcel_hasFileDescriptors}, + {"nativeWriteInterfaceToken", "(ILjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken}, + {"nativeEnforceInterface", "(ILjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface}, +}; + +const char* const kParcelPathName = "android/os/Parcel"; + +int register_android_os_Parcel(JNIEnv* env) +{ + jclass clazz; + + clazz = env->FindClass(kParcelPathName); + LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Parcel"); + + gParcelOffsets.mNativePtr + = env->GetFieldID(clazz, "mNativePtr", "I"); + + return AndroidRuntime::registerNativeMethods( + env, kParcelPathName, + gParcelMethods, NELEM(gParcelMethods)); +} + +}; diff --git a/core/jni/android_os_Parcel.h b/core/jni/android_os_Parcel.h new file mode 100644 index 000000000000..65f3819ef867 --- /dev/null +++ b/core/jni/android_os_Parcel.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <binder/IBinder.h> + +#include "jni.h" + +namespace android { + +// Conversion from Java Parcel Object to C++ Parcel instance. +// Note: does not type checking; must guarantee jobject is a Java Parcel +extern Parcel* parcelForJavaObject(JNIEnv* env, jobject obj); + +} diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index e00970a2dbde..0f99fb2af86d 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -17,7 +17,9 @@ #define LOG_TAG "JavaBinder" //#define LOG_NDEBUG 0 +#include "android_os_Parcel.h" #include "android_util_Binder.h" + #include "JNIHelp.h" #include <fcntl.h> @@ -127,12 +129,6 @@ static struct class_offsets_t // ---------------------------------------------------------------------------- -static struct parcel_offsets_t -{ - jfieldID mObject; - jfieldID mOwnObject; -} gParcelOffsets; - static struct log_offsets_t { // Class state. @@ -232,15 +228,6 @@ bail: env->DeleteLocalRef(msgstr); } -static void set_dalvik_blockguard_policy(JNIEnv* env, jint strict_policy) -{ - // Call back into android.os.StrictMode#onBinderStrictModePolicyChange - // to sync our state back to it. See the comments in StrictMode.java. - env->CallStaticVoidMethod(gStrictModeCallbackOffsets.mClass, - gStrictModeCallbackOffsets.mCallback, - strict_policy); -} - class JavaBBinderHolder; class JavaBBinder : public BBinder @@ -634,26 +621,23 @@ sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj) return NULL; } -Parcel* parcelForJavaObject(JNIEnv* env, jobject obj) -{ - if (obj) { - Parcel* p = (Parcel*)env->GetIntField(obj, gParcelOffsets.mObject); - if (p != NULL) { - return p; - } - jniThrowException(env, "java/lang/IllegalStateException", "Parcel has been finalized!"); - } - return NULL; -} - jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc) { return env->NewObject( gParcelFileDescriptorOffsets.mClass, gParcelFileDescriptorOffsets.mConstructor, fileDesc); } -static void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, - bool canThrowRemoteException = false) +void set_dalvik_blockguard_policy(JNIEnv* env, jint strict_policy) +{ + // Call back into android.os.StrictMode#onBinderStrictModePolicyChange + // to sync our state back to it. See the comments in StrictMode.java. + env->CallStaticVoidMethod(gStrictModeCallbackOffsets.mClass, + gStrictModeCallbackOffsets.mCallback, + strict_policy); +} + +void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, + bool canThrowRemoteException) { switch (err) { case UNKNOWN_ERROR: @@ -1273,612 +1257,15 @@ static int int_register_android_os_BinderProxy(JNIEnv* env) // **************************************************************************** // **************************************************************************** -static jint android_os_Parcel_dataSize(JNIEnv* env, jobject clazz) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - return parcel ? parcel->dataSize() : 0; -} - -static jint android_os_Parcel_dataAvail(JNIEnv* env, jobject clazz) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - return parcel ? parcel->dataAvail() : 0; -} - -static jint android_os_Parcel_dataPosition(JNIEnv* env, jobject clazz) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - return parcel ? parcel->dataPosition() : 0; -} - -static jint android_os_Parcel_dataCapacity(JNIEnv* env, jobject clazz) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - return parcel ? parcel->dataCapacity() : 0; -} - -static void android_os_Parcel_setDataSize(JNIEnv* env, jobject clazz, jint size) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - const status_t err = parcel->setDataSize(size); - if (err != NO_ERROR) { - signalExceptionForError(env, clazz, err); - } - } -} - -static void android_os_Parcel_setDataPosition(JNIEnv* env, jobject clazz, jint pos) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - parcel->setDataPosition(pos); - } -} - -static void android_os_Parcel_setDataCapacity(JNIEnv* env, jobject clazz, jint size) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - const status_t err = parcel->setDataCapacity(size); - if (err != NO_ERROR) { - signalExceptionForError(env, clazz, err); - } - } -} - -static jboolean android_os_Parcel_pushAllowFds(JNIEnv* env, jobject clazz, jboolean allowFds) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - jboolean ret = JNI_TRUE; - if (parcel != NULL) { - ret = (jboolean)parcel->pushAllowFds(allowFds); - } - return ret; -} - -static void android_os_Parcel_restoreAllowFds(JNIEnv* env, jobject clazz, jboolean lastValue) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - parcel->restoreAllowFds((bool)lastValue); - } -} - -static void android_os_Parcel_writeNative(JNIEnv* env, jobject clazz, - jobject data, jint offset, - jint length) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel == NULL) { - return; - } - - const status_t err = parcel->writeInt32(length); - if (err != NO_ERROR) { - signalExceptionForError(env, clazz, err); - return; - } - - void* dest = parcel->writeInplace(length); - if (dest == NULL) { - signalExceptionForError(env, clazz, NO_MEMORY); - return; - } - - jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)data, 0); - if (ar) { - memcpy(dest, ar + offset, length); - env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0); - } -} - - -static void android_os_Parcel_writeInt(JNIEnv* env, jobject clazz, jint val) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - const status_t err = parcel->writeInt32(val); - if (err != NO_ERROR) { - signalExceptionForError(env, clazz, err); - } - } -} - -static void android_os_Parcel_writeLong(JNIEnv* env, jobject clazz, jlong val) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - const status_t err = parcel->writeInt64(val); - if (err != NO_ERROR) { - signalExceptionForError(env, clazz, err); - } - } -} - -static void android_os_Parcel_writeFloat(JNIEnv* env, jobject clazz, jfloat val) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - const status_t err = parcel->writeFloat(val); - if (err != NO_ERROR) { - signalExceptionForError(env, clazz, err); - } - } -} - -static void android_os_Parcel_writeDouble(JNIEnv* env, jobject clazz, jdouble val) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - const status_t err = parcel->writeDouble(val); - if (err != NO_ERROR) { - signalExceptionForError(env, clazz, err); - } - } -} - -static void android_os_Parcel_writeString(JNIEnv* env, jobject clazz, jstring val) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - status_t err = NO_MEMORY; - if (val) { - const jchar* str = env->GetStringCritical(val, 0); - if (str) { - err = parcel->writeString16(str, env->GetStringLength(val)); - env->ReleaseStringCritical(val, str); - } - } else { - err = parcel->writeString16(NULL, 0); - } - if (err != NO_ERROR) { - signalExceptionForError(env, clazz, err); - } - } -} - -static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jobject clazz, jobject object) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object)); - if (err != NO_ERROR) { - signalExceptionForError(env, clazz, err); - } - } -} - -static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jobject clazz, jobject object) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - const status_t err = - parcel->writeDupFileDescriptor(jniGetFDFromFileDescriptor(env, object)); - if (err != NO_ERROR) { - signalExceptionForError(env, clazz, err); - } - } -} - -static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jobject clazz) -{ - jbyteArray ret = NULL; - - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - int32_t len = parcel->readInt32(); - - // sanity check the stored length against the true data size - if (len >= 0 && len <= (int32_t)parcel->dataAvail()) { - ret = env->NewByteArray(len); - - if (ret != NULL) { - jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0); - if (a2) { - const void* data = parcel->readInplace(len); - memcpy(a2, data, len); - env->ReleasePrimitiveArrayCritical(ret, a2, 0); - } - } - } - } - - return ret; -} - -static jint android_os_Parcel_readInt(JNIEnv* env, jobject clazz) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - return parcel->readInt32(); - } - return 0; -} - -static jlong android_os_Parcel_readLong(JNIEnv* env, jobject clazz) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - return parcel->readInt64(); - } - return 0; -} - -static jfloat android_os_Parcel_readFloat(JNIEnv* env, jobject clazz) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - return parcel->readFloat(); - } - return 0; -} - -static jdouble android_os_Parcel_readDouble(JNIEnv* env, jobject clazz) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - return parcel->readDouble(); - } - return 0; -} - -static jstring android_os_Parcel_readString(JNIEnv* env, jobject clazz) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - size_t len; - const char16_t* str = parcel->readString16Inplace(&len); - if (str) { - return env->NewString(str, len); - } - return NULL; - } - return NULL; -} - -static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jobject clazz) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - return javaObjectForIBinder(env, parcel->readStrongBinder()); - } - return NULL; -} - -static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jobject clazz) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - int fd = parcel->readFileDescriptor(); - if (fd < 0) return NULL; - fd = dup(fd); - if (fd < 0) return NULL; - return jniCreateFileDescriptor(env, fd); - } - return NULL; -} - -static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jobject clazz, - jstring name, jint mode) -{ - if (name == NULL) { - jniThrowNullPointerException(env, NULL); - return NULL; - } - const jchar* str = env->GetStringCritical(name, 0); - if (str == NULL) { - // Whatever, whatever. - jniThrowException(env, "java/lang/IllegalStateException", NULL); - return NULL; - } - String8 name8(str, env->GetStringLength(name)); - env->ReleaseStringCritical(name, str); - int flags=0; - switch (mode&0x30000000) { - case 0: - case 0x10000000: - flags = O_RDONLY; - break; - case 0x20000000: - flags = O_WRONLY; - break; - case 0x30000000: - flags = O_RDWR; - break; - } - - if (mode&0x08000000) flags |= O_CREAT; - if (mode&0x04000000) flags |= O_TRUNC; - if (mode&0x02000000) flags |= O_APPEND; - - int realMode = S_IRWXU|S_IRWXG; - if (mode&0x00000001) realMode |= S_IROTH; - if (mode&0x00000002) realMode |= S_IWOTH; - - int fd = open(name8.string(), flags, realMode); - if (fd < 0) { - jniThrowException(env, "java/io/FileNotFoundException", strerror(errno)); - return NULL; - } - jobject object = jniCreateFileDescriptor(env, fd); - if (object == NULL) { - close(fd); - } - return object; -} - -static jobject android_os_Parcel_dupFileDescriptor(JNIEnv* env, jobject clazz, jobject orig) -{ - if (orig == NULL) { - jniThrowNullPointerException(env, NULL); - return NULL; - } - int origfd = jniGetFDFromFileDescriptor(env, orig); - if (origfd < 0) { - jniThrowException(env, "java/lang/IllegalArgumentException", "bad FileDescriptor"); - return NULL; - } - - int fd = dup(origfd); - if (fd < 0) { - jniThrowIOException(env, errno); - return NULL; - } - jobject object = jniCreateFileDescriptor(env, fd); - if (object == NULL) { - close(fd); - } - return object; -} - -static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jobject clazz, jobject object) -{ - if (object == NULL) { - jniThrowNullPointerException(env, NULL); - return; - } - int fd = jniGetFDFromFileDescriptor(env, object); - if (fd >= 0) { - jniSetFileDescriptorOfFD(env, object, -1); - //ALOGI("Closing ParcelFileDescriptor %d\n", fd); - close(fd); - } -} - -static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jobject clazz, jobject object) -{ - if (object == NULL) { - jniThrowNullPointerException(env, NULL); - return; - } - int fd = jniGetFDFromFileDescriptor(env, object); - if (fd >= 0) { - jniSetFileDescriptorOfFD(env, object, -1); - } -} - -static void android_os_Parcel_freeBuffer(JNIEnv* env, jobject clazz) -{ - int32_t own = env->GetIntField(clazz, gParcelOffsets.mOwnObject); - if (own) { - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - //ALOGI("Parcel.freeBuffer() called for C++ Parcel %p\n", parcel); - parcel->freeData(); - } - } -} - -static void android_os_Parcel_init(JNIEnv* env, jobject clazz, jint parcelInt) -{ - Parcel* parcel = (Parcel*)parcelInt; - int own = 0; - if (!parcel) { - //ALOGI("Initializing obj %p: creating new Parcel\n", clazz); - own = 1; - parcel = new Parcel; - } else { - //ALOGI("Initializing obj %p: given existing Parcel %p\n", clazz, parcel); - } - if (parcel == NULL) { - jniThrowException(env, "java/lang/OutOfMemoryError", NULL); - return; - } - //ALOGI("Initializing obj %p from C++ Parcel %p, own=%d\n", clazz, parcel, own); - env->SetIntField(clazz, gParcelOffsets.mOwnObject, own); - env->SetIntField(clazz, gParcelOffsets.mObject, (int)parcel); -} - -static void android_os_Parcel_destroy(JNIEnv* env, jobject clazz) -{ - int32_t own = env->GetIntField(clazz, gParcelOffsets.mOwnObject); - if (own) { - Parcel* parcel = parcelForJavaObject(env, clazz); - env->SetIntField(clazz, gParcelOffsets.mObject, 0); - //ALOGI("Destroying obj %p: deleting C++ Parcel %p\n", clazz, parcel); - delete parcel; - } else { - env->SetIntField(clazz, gParcelOffsets.mObject, 0); - //ALOGI("Destroying obj %p: leaving C++ Parcel %p\n", clazz); - } -} - -static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jobject clazz) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel == NULL) { - return NULL; - } - - // do not marshall if there are binder objects in the parcel - if (parcel->objectsCount()) - { - jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall a Parcel that contained Binder objects."); - return NULL; - } - - jbyteArray ret = env->NewByteArray(parcel->dataSize()); - - if (ret != NULL) - { - jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0); - if (array != NULL) - { - memcpy(array, parcel->data(), parcel->dataSize()); - env->ReleasePrimitiveArrayCritical(ret, array, 0); - } - } - - return ret; -} - -static void android_os_Parcel_unmarshall(JNIEnv* env, jobject clazz, jbyteArray data, jint offset, jint length) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel == NULL || length < 0) { - return; - } - - jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0); - if (array) - { - parcel->setDataSize(length); - parcel->setDataPosition(0); - - void* raw = parcel->writeInplace(length); - memcpy(raw, (array + offset), length); - - env->ReleasePrimitiveArrayCritical(data, array, 0); - } -} - -static void android_os_Parcel_appendFrom(JNIEnv* env, jobject clazz, jobject parcel, jint offset, jint length) -{ - Parcel* thisParcel = parcelForJavaObject(env, clazz); - if (thisParcel == NULL) { - return; - } - Parcel* otherParcel = parcelForJavaObject(env, parcel); - if (otherParcel == NULL) { - return; - } - - status_t err = thisParcel->appendFrom(otherParcel, offset, length); - if (err != NO_ERROR) { - signalExceptionForError(env, clazz, err); - } -} - -static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jobject clazz) -{ - jboolean ret = JNI_FALSE; - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - if (parcel->hasFileDescriptors()) { - ret = JNI_TRUE; - } - } - return ret; -} - -static void android_os_Parcel_writeInterfaceToken(JNIEnv* env, jobject clazz, jstring name) -{ - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - // In the current implementation, the token is just the serialized interface name that - // the caller expects to be invoking - const jchar* str = env->GetStringCritical(name, 0); - if (str != NULL) { - parcel->writeInterfaceToken(String16(str, env->GetStringLength(name))); - env->ReleaseStringCritical(name, str); - } - } -} - -static void android_os_Parcel_enforceInterface(JNIEnv* env, jobject clazz, jstring name) +int register_android_os_Binder(JNIEnv* env) { - jboolean ret = JNI_FALSE; - - Parcel* parcel = parcelForJavaObject(env, clazz); - if (parcel != NULL) { - const jchar* str = env->GetStringCritical(name, 0); - if (str) { - IPCThreadState* threadState = IPCThreadState::self(); - const int32_t oldPolicy = threadState->getStrictModePolicy(); - const bool isValid = parcel->enforceInterface( - String16(str, env->GetStringLength(name)), - threadState); - env->ReleaseStringCritical(name, str); - if (isValid) { - const int32_t newPolicy = threadState->getStrictModePolicy(); - if (oldPolicy != newPolicy) { - // Need to keep the Java-level thread-local strict - // mode policy in sync for the libcore - // enforcements, which involves an upcall back - // into Java. (We can't modify the - // Parcel.enforceInterface signature, as it's - // pseudo-public, and used via AIDL - // auto-generation...) - set_dalvik_blockguard_policy(env, newPolicy); - } - return; // everything was correct -> return silently - } - } - } - - // all error conditions wind up here - jniThrowException(env, "java/lang/SecurityException", - "Binder invocation to an incorrect interface"); -} - -// ---------------------------------------------------------------------------- - -static const JNINativeMethod gParcelMethods[] = { - {"dataSize", "()I", (void*)android_os_Parcel_dataSize}, - {"dataAvail", "()I", (void*)android_os_Parcel_dataAvail}, - {"dataPosition", "()I", (void*)android_os_Parcel_dataPosition}, - {"dataCapacity", "()I", (void*)android_os_Parcel_dataCapacity}, - {"setDataSize", "(I)V", (void*)android_os_Parcel_setDataSize}, - {"setDataPosition", "(I)V", (void*)android_os_Parcel_setDataPosition}, - {"setDataCapacity", "(I)V", (void*)android_os_Parcel_setDataCapacity}, - {"pushAllowFds", "(Z)Z", (void*)android_os_Parcel_pushAllowFds}, - {"restoreAllowFds", "(Z)V", (void*)android_os_Parcel_restoreAllowFds}, - {"writeNative", "([BII)V", (void*)android_os_Parcel_writeNative}, - {"writeInt", "(I)V", (void*)android_os_Parcel_writeInt}, - {"writeLong", "(J)V", (void*)android_os_Parcel_writeLong}, - {"writeFloat", "(F)V", (void*)android_os_Parcel_writeFloat}, - {"writeDouble", "(D)V", (void*)android_os_Parcel_writeDouble}, - {"writeString", "(Ljava/lang/String;)V", (void*)android_os_Parcel_writeString}, - {"writeStrongBinder", "(Landroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder}, - {"writeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor}, - {"createByteArray", "()[B", (void*)android_os_Parcel_createByteArray}, - {"readInt", "()I", (void*)android_os_Parcel_readInt}, - {"readLong", "()J", (void*)android_os_Parcel_readLong}, - {"readFloat", "()F", (void*)android_os_Parcel_readFloat}, - {"readDouble", "()D", (void*)android_os_Parcel_readDouble}, - {"readString", "()Ljava/lang/String;", (void*)android_os_Parcel_readString}, - {"readStrongBinder", "()Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder}, - {"internalReadFileDescriptor", "()Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor}, - {"openFileDescriptor", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor}, - {"dupFileDescriptor", "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_dupFileDescriptor}, - {"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor}, - {"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor}, - {"freeBuffer", "()V", (void*)android_os_Parcel_freeBuffer}, - {"init", "(I)V", (void*)android_os_Parcel_init}, - {"destroy", "()V", (void*)android_os_Parcel_destroy}, - {"marshall", "()[B", (void*)android_os_Parcel_marshall}, - {"unmarshall", "([BII)V", (void*)android_os_Parcel_unmarshall}, - {"appendFrom", "(Landroid/os/Parcel;II)V", (void*)android_os_Parcel_appendFrom}, - {"hasFileDescriptors", "()Z", (void*)android_os_Parcel_hasFileDescriptors}, - {"writeInterfaceToken", "(Ljava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken}, - {"enforceInterface", "(Ljava/lang/String;)V", (void*)android_os_Parcel_enforceInterface}, -}; - -const char* const kParcelPathName = "android/os/Parcel"; + if (int_register_android_os_Binder(env) < 0) + return -1; + if (int_register_android_os_BinderInternal(env) < 0) + return -1; + if (int_register_android_os_BinderProxy(env) < 0) + return -1; -static int int_register_android_os_Parcel(JNIEnv* env) -{ jclass clazz; clazz = env->FindClass("android/util/Log"); @@ -1894,14 +1281,6 @@ static int int_register_android_os_Parcel(JNIEnv* env) gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V"); - clazz = env->FindClass(kParcelPathName); - LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Parcel"); - - gParcelOffsets.mObject - = env->GetFieldID(clazz, "mObject", "I"); - gParcelOffsets.mOwnObject - = env->GetFieldID(clazz, "mOwnObject", "I"); - clazz = env->FindClass("android/os/StrictMode"); LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.StrictMode"); gStrictModeCallbackOffsets.mClass = (jclass) env->NewGlobalRef(clazz); @@ -1910,20 +1289,5 @@ static int int_register_android_os_Parcel(JNIEnv* env) LOG_FATAL_IF(gStrictModeCallbackOffsets.mCallback == NULL, "Unable to find strict mode callback."); - return AndroidRuntime::registerNativeMethods( - env, kParcelPathName, - gParcelMethods, NELEM(gParcelMethods)); -} - -int register_android_os_Binder(JNIEnv* env) -{ - if (int_register_android_os_Binder(env) < 0) - return -1; - if (int_register_android_os_BinderInternal(env) < 0) - return -1; - if (int_register_android_os_BinderProxy(env) < 0) - return -1; - if (int_register_android_os_Parcel(env) < 0) - return -1; return 0; } diff --git a/core/jni/android_util_Binder.h b/core/jni/android_util_Binder.h index 0122691b25da..ca320effd69e 100644 --- a/core/jni/android_util_Binder.h +++ b/core/jni/android_util_Binder.h @@ -15,6 +15,9 @@ ** limitations under the License. */ +#ifndef ANDROID_UTIL_BINDER_H +#define ANDROID_UTIL_BINDER_H + #include <binder/IBinder.h> #include "jni.h" @@ -25,10 +28,13 @@ namespace android { extern jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val); extern sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj); -// Conversion from Java Parcel Object to C++ Parcel instance. -// Note: does not type checking; must guarantee jobject is a Java Parcel -extern Parcel* parcelForJavaObject(JNIEnv* env, jobject obj); - extern jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc); +extern void set_dalvik_blockguard_policy(JNIEnv* env, jint strict_policy); + +extern void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, + bool canThrowRemoteException = false); + } + +#endif diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp index 8350e73f91dc..9c44a599a7a8 100644 --- a/core/jni/android_view_InputChannel.cpp +++ b/core/jni/android_view_InputChannel.cpp @@ -23,6 +23,7 @@ #include <utils/Log.h> #include <androidfw/InputTransport.h> #include "android_view_InputChannel.h" +#include "android_os_Parcel.h" #include "android_util_Binder.h" namespace android { diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 0fb1b17a2b8e..e69fb74ecf16 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -21,6 +21,7 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/Log.h> #include <androidfw/Input.h> +#include "android_os_Parcel.h" #include "android_view_MotionEvent.h" #include "android_util_Binder.h" #include "android/graphics/Matrix.h" diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index c38775212042..30d4e20dfd68 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -888,7 +888,7 @@ void nativeClassInit(JNIEnv* env, jclass clazz) no.native_region = env->GetFieldID(region, "mNativeRegion", "I"); jclass parcel = env->FindClass("android/os/Parcel"); - no.native_parcel = env->GetFieldID(parcel, "mObject", "I"); + no.native_parcel = env->GetFieldID(parcel, "mNativePtr", "I"); jclass rect = env->FindClass("android/graphics/Rect"); ro.l = env->GetFieldID(rect, "left", "I"); diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 1a0d47978c0a..8e36948b6a2e 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -671,7 +671,7 @@ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se superó el máximo de intentos permitido para el desbloqueo facial del dispositivo."</string> <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Cargando <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> <string name="lockscreen_charged" msgid="4938930459620989972">"Cargada."</string> - <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string> + <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta tu cargador."</string> <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"No hay tarjeta SIM."</string> <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"No hay tarjeta SIM en el tablet."</string> @@ -768,8 +768,8 @@ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de la API SerialManager."</string> <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"acceder a proveedores externamente"</string> <string name="permdesc_accessContentProvidersExternally" msgid="4544346486697853685">"Permite acceder a los proveedores de contenido desde la interfaz. Las aplicaciones normales nunca deberían necesitarlo."</string> - <string name="permlab_updateLock" msgid="3527558366616680889">"desalentar a las actualizaciones automáticas de dispositivos"</string> - <string name="permdesc_updateLock" msgid="1655625832166778492">"Permite a su titular a ofrecer información al sistema acerca de cuándo sería un buen momento para reiniciar el sistema no interactivo para actualizar el dispositivo."</string> + <string name="permlab_updateLock" msgid="3527558366616680889">"no realizar actualizaciones automáticas"</string> + <string name="permdesc_updateLock" msgid="1655625832166778492">"Permite a su propietario ofrecer información al sistema acerca de cuándo sería adecuado reiniciar el sistema de forma no interactiva y actualizar el dispositivo."</string> <string name="save_password_message" msgid="767344687139195790">"¿Quieres recordar esta contraseña en el navegador?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Ahora no."</string> <string name="save_password_remember" msgid="6491879678996749466">"Recuerda"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 5bb95afec18c..385bebb47219 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -769,7 +769,7 @@ <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"akses pembekal kandungan secara luaran"</string> <string name="permdesc_accessContentProvidersExternally" msgid="4544346486697853685">"Membolehkan pemegang mengakses pembekal kandungan dari luar. Tidak akan sekali-kali diperlukan untuk apl biasa."</string> <string name="permlab_updateLock" msgid="3527558366616680889">"tidak menggalakkan kemas kini peranti automatik"</string> - <string name="permdesc_updateLock" msgid="1655625832166778492">"Membenarkan pemegang untuk menawarkan maklumat kepada sistem tentang bila akan menjadi masa yang baik untuk but semula bukan interaktif untuk menaik taraf peranti."</string> + <string name="permdesc_updateLock" msgid="1655625832166778492">"Membenarkan aplikasi untuk menawarkan maklumat kepada sistem tentang bila akan menjadi masa yang baik untuk but semula bukan interaktif untuk menaik taraf peranti."</string> <string name="save_password_message" msgid="767344687139195790">"Adakah anda mahu penyemak imbas mengingati kata laluan ini?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Bukan sekarang"</string> <string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 6a9f84688386..e70a6649d57d 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -671,7 +671,7 @@ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Du har overskredet grensen for opplåsingsforsøk med Ansiktslås"</string> <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Lader, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> <string name="lockscreen_charged" msgid="4938930459620989972">"Fullt ladet"</string> - <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> + <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string> <string name="lockscreen_low_battery" msgid="1482873981919249740">"Koble til en batterilader."</string> <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Mangler SIM-kort."</string> <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Nettbrettet mangler SIM-kort."</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 286c32c665b1..96dcfa023873 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -768,8 +768,8 @@ <string name="permdesc_serialPort" msgid="2991639985224598193">"Umożliwia posiadaczowi dostęp do portów szeregowych przy użyciu interfejsu API narzędzia SerialManager."</string> <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"Dostęp do dostawców treści z zewnątrz"</string> <string name="permdesc_accessContentProvidersExternally" msgid="4544346486697853685">"Pozwala na dostęp do dostawców treści z powłoki. To uprawnienie nie powinno być potrzebne zwykłym aplikacjom."</string> - <string name="permlab_updateLock" msgid="3527558366616680889">"odradź automatyczne aktualizacje urządzenia"</string> - <string name="permdesc_updateLock" msgid="1655625832166778492">"Umożliwia posiadaczowi poinformowanie systemu, kiedy będzie dobry moment na nieinteraktywne uruchomienie ponowne wymagane do uaktualnienia urządzenia."</string> + <string name="permlab_updateLock" msgid="3527558366616680889">"odradzanie automatycznych aktualizacji urządzenia"</string> + <string name="permdesc_updateLock" msgid="1655625832166778492">"Umożliwia posiadaczowi poinformowanie systemu, kiedy będzie dobry moment na ponowne uruchomienie wymagane do uaktualnienia urządzenia."</string> <string name="save_password_message" msgid="767344687139195790">"Czy chcesz, aby zapamiętać to hasło w przeglądarce?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Nie teraz"</string> <string name="save_password_remember" msgid="6491879678996749466">"Zapamiętaj"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 286e6d66681a..13053ab22667 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -768,8 +768,8 @@ <string name="permdesc_serialPort" msgid="2991639985224598193">"Inaruhusu mmiliki kufikia vituo tambulishi kwa kutumia KisimamiziTambulishi cha API."</string> <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"fikia watoa huduma nje"</string> <string name="permdesc_accessContentProvidersExternally" msgid="4544346486697853685">"Inaruhusu mmiliki kufikia watoa huduma kutoka kwa onyesho. Haifai kuhitajika kamwe kwa programu za kawaida."</string> - <string name="permlab_updateLock" msgid="3527558366616680889">"katisha tamaa usasishaji kifaa kiotomatiki"</string> - <string name="permdesc_updateLock" msgid="1655625832166778492">"Inaruhusu mmiliki kutoa maelezo kwa mfumo kuhusu ni lini itakuwa wakati mzuri wa uwashaji upya usiotagusana ili kuboresha kifaa."</string> + <string name="permlab_updateLock" msgid="3527558366616680889">"pinga usasishaji kifaa kiotomatiki"</string> + <string name="permdesc_updateLock" msgid="1655625832166778492">"Inaruhusu mmiliki kutoa maelezo kwa mfumo kuhusu ni lini itakuwa wakati mzuri wa uwashaji upya usiotagusana ili kupandisha gredi kifaa."</string> <string name="save_password_message" msgid="767344687139195790">"Unataka kuvinjari ili ukumbuke nenosiri hili?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Si Sasa"</string> <string name="save_password_remember" msgid="6491879678996749466">"Kumbuka"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 24b726d3c102..2664ad339558 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -769,7 +769,7 @@ <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"从外部访问内容提供程序"</string> <string name="permdesc_accessContentProvidersExternally" msgid="4544346486697853685">"允许持有者通过界面访问内容提供程序。普通应用绝不需要此权限。"</string> <string name="permlab_updateLock" msgid="3527558366616680889">"阻止自动设备更新"</string> - <string name="permdesc_updateLock" msgid="1655625832166778492">"允许持有人向系统提供相关信息,以确定什么时候适合执行非交互式重新启动来升级设备。"</string> + <string name="permdesc_updateLock" msgid="1655625832166778492">"允许应用向系统提供相关信息,以确定何时适合执行非交互式重启以升级设备。"</string> <string name="save_password_message" msgid="767344687139195790">"是否希望浏览器记住此密码?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"暂不保存"</string> <string name="save_password_remember" msgid="6491879678996749466">"记住"</string> diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index d54ab357e86a..cc0a594d164d 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -185,7 +185,7 @@ public: audio_devices_t device); static uint32_t getStrategyForStream(audio_stream_type_t stream); - static uint32_t getDevicesForStream(audio_stream_type_t stream); + static audio_devices_t getDevicesForStream(audio_stream_type_t stream); static audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc); static status_t registerEffect(effect_descriptor_t *desc, diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h index bdd774748a02..04c927aec3bd 100644 --- a/include/media/IAudioPolicyService.h +++ b/include/media/IAudioPolicyService.h @@ -79,7 +79,7 @@ public: int *index, audio_devices_t device) = 0; virtual uint32_t getStrategyForStream(audio_stream_type_t stream) = 0; - virtual uint32_t getDevicesForStream(audio_stream_type_t stream) = 0; + virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream) = 0; virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc) = 0; virtual status_t registerEffect(effect_descriptor_t *desc, audio_io_handle_t io, diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 6ec5d2073236..f572f71458fc 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -36,6 +36,7 @@ #include "utils/String8.h" #include "android_media_Utils.h" +#include "android_os_Parcel.h" #include "android_util_Binder.h" #include <binder/Parcel.h> #include <gui/ISurfaceTexture.h> diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index e0b186adfde5..a1cbf0f2bd85 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -701,10 +701,10 @@ uint32_t AudioSystem::getStrategyForStream(audio_stream_type_t stream) return aps->getStrategyForStream(stream); } -uint32_t AudioSystem::getDevicesForStream(audio_stream_type_t stream) +audio_devices_t AudioSystem::getDevicesForStream(audio_stream_type_t stream) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); - if (aps == 0) return 0; + if (aps == 0) return (audio_devices_t)0; return aps->getDevicesForStream(stream); } diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 99385aa4f80a..da7c1244e16e 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -267,13 +267,13 @@ public: return reply.readInt32(); } - virtual uint32_t getDevicesForStream(audio_stream_type_t stream) + virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(static_cast <uint32_t>(stream)); remote()->transact(GET_DEVICES_FOR_STREAM, data, &reply); - return (uint32_t) reply.readInt32(); + return (audio_devices_t) reply.readInt32(); } virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc) diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index b21e86a68129..9e00bb349144 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -2108,6 +2108,8 @@ status_t AwesomePlayer::finishSetDataSource_l() { mWVMExtractor = new WVMExtractor(dataSource); mWVMExtractor->setAdaptiveStreamingMode(true); + if (mUIDValid) + mWVMExtractor->setUID(mUID); extractor = mWVMExtractor; } else { extractor = MediaExtractor::Create( diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp index c7ad513baf10..dac8106a6858 100644 --- a/media/libstagefright/WVMExtractor.cpp +++ b/media/libstagefright/WVMExtractor.cpp @@ -123,6 +123,12 @@ void WVMExtractor::setAdaptiveStreamingMode(bool adaptive) { } } +void WVMExtractor::setUID(uid_t uid) { + if (mImpl != NULL) { + mImpl->setUID(uid); + } +} + bool SniffWVM( const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *) { diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h index 9f763f9debef..3c3ca892259a 100644 --- a/media/libstagefright/include/WVMExtractor.h +++ b/media/libstagefright/include/WVMExtractor.h @@ -34,6 +34,7 @@ public: virtual int64_t getCachedDurationUs(status_t *finalStatus) = 0; virtual void setAdaptiveStreamingMode(bool adaptive) = 0; + virtual void setUID(uid_t uid) = 0; }; class WVMExtractor : public MediaExtractor { @@ -60,6 +61,8 @@ public: // is used. void setAdaptiveStreamingMode(bool adaptive); + void setUID(uid_t uid); + static bool getVendorLibHandle(); protected: diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 7c1cd18b8a32..1e826469860e 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -26,7 +26,7 @@ <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Hapus dari daftar"</string> <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Info apl"</string> <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Tidak ada apl terbaru"</string> - <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Singkirkan aplikasi terbaru"</string> + <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Tutup aplikasi terbaru"</string> <plurals name="status_bar_accessibility_recent_apps"> <item quantity="one" msgid="5854176083865845541">"1 apl terbaru"</item> <item quantity="other" msgid="1040784359794890744">"%d apl terbaru"</item> diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp index 7487f4bf94e8..d57326b03dad 100644 --- a/services/audioflinger/AudioPolicyService.cpp +++ b/services/audioflinger/AudioPolicyService.cpp @@ -430,10 +430,12 @@ uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream) return mpAudioPolicy->get_strategy_for_stream(mpAudioPolicy, stream); } -uint32_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stream) +//audio policy: use audio_device_t appropriately + +audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stream) { if (mpAudioPolicy == NULL) { - return 0; + return (audio_devices_t)0; } return mpAudioPolicy->get_devices_for_stream(mpAudioPolicy, stream); } diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h index 106bf6a9c3a2..7119b901d4a6 100644 --- a/services/audioflinger/AudioPolicyService.h +++ b/services/audioflinger/AudioPolicyService.h @@ -95,7 +95,7 @@ public: audio_devices_t device); virtual uint32_t getStrategyForStream(audio_stream_type_t stream); - virtual uint32_t getDevicesForStream(audio_stream_type_t stream); + virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream); virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc); virtual status_t registerEffect(effect_descriptor_t *desc, diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 2538455f8081..fd968e0b7330 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -4934,7 +4934,7 @@ public final class ActivityManagerService extends ActivityManagerNative void grantUriPermissionFromIntentLocked(int callingUid, String targetPkg, Intent intent, UriPermissionOwner owner) { NeededUriGrants needed = checkGrantUriPermissionFromIntentLocked(callingUid, targetPkg, - intent, intent.getFlags(), null); + intent, intent != null ? intent.getFlags() : 0, null); if (needed == null) { return; } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index def22a9bc28b..18b51a7fd411 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -9173,7 +9173,7 @@ public class WindowManagerService extends IWindowManager.Stub void scheduleAnimationLocked() { if (!mAnimationScheduled) { - mChoreographer.postAnimationCallback(mAnimationRunnable); + mChoreographer.postAnimationCallback(mAnimationRunnable, null); mAnimationScheduled = true; } } |