Merge "Fix unused local variale warning from clang/llvm."
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index bc0c451..29ba1d7 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -117,6 +117,8 @@
" am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" +
" am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
" am clear-debug-app\n" +
+ " am set-watch-heap <PROCESS> <MEM-LIMIT>\n" +
+ " am clear-watch-heap\n" +
" am monitor [--gdb <port>]\n" +
" am hang [--allow-restart]\n" +
" am restart\n" +
@@ -211,6 +213,11 @@
"\n" +
"am clear-debug-app: clear the previously set-debug-app.\n" +
"\n" +
+ "am set-watch-heap: start monitoring pss size of <PROCESS>, if it is at or\n" +
+ " above <HEAP-LIMIT> then a heap dump is collected for the user to report\n" +
+ "\n" +
+ "am clear-watch-heap: clear the previously set-watch-heap.\n" +
+ "\n" +
"am bug-report: request bug report generation; will launch UI\n" +
" when done to select where it should be delivered.\n" +
"\n" +
@@ -342,6 +349,10 @@
runSetDebugApp();
} else if (op.equals("clear-debug-app")) {
runClearDebugApp();
+ } else if (op.equals("set-watch-heap")) {
+ runSetWatchHeap();
+ } else if (op.equals("clear-watch-heap")) {
+ runClearWatchHeap();
} else if (op.equals("bug-report")) {
runBugReport();
} else if (op.equals("monitor")) {
@@ -1172,6 +1183,17 @@
mAm.setDebugApp(null, false, true);
}
+ private void runSetWatchHeap() throws Exception {
+ String proc = nextArgRequired();
+ String limit = nextArgRequired();
+ mAm.setDumpHeapDebugLimit(proc, Long.parseLong(limit));
+ }
+
+ private void runClearWatchHeap() throws Exception {
+ String proc = nextArgRequired();
+ mAm.setDumpHeapDebugLimit(proc, -1);
+ }
+
private void runBugReport() throws Exception {
mAm.requestBugReport();
System.out.println("Your lovely bug report is being created; please be patient.");
diff --git a/core/java/android/annotation/CallSuper.java b/core/java/android/annotation/CallSuper.java
new file mode 100644
index 0000000..82e2723
--- /dev/null
+++ b/core/java/android/annotation/CallSuper.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that any overriding methods should invoke this method as well.
+ * <p>
+ * Example:
+ * <pre>{@code
+ * @CallSuper
+ * public abstract void onFocusLost();
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD})
+public @interface CallSuper {
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/CheckResult.java b/core/java/android/annotation/CheckResult.java
new file mode 100644
index 0000000..787514e
--- /dev/null
+++ b/core/java/android/annotation/CheckResult.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated method returns a result that it typically is
+ * an error to ignore. This is usually used for methods that have no side effect,
+ * so calling it without actually looking at the result usually means the developer
+ * has misunderstood what the method does.
+ * <p>
+ * Example:
+ * <pre>{@code
+ * public @CheckResult String trim(String s) { return s.trim(); }
+ * ...
+ * s.trim(); // this is probably an error
+ * s = s.trim(); // ok
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD})
+public @interface CheckResult {
+ /** Defines the name of the suggested method to use instead, if applicable (using
+ * the same signature format as javadoc.) If there is more than one possibility,
+ * list them all separated by commas.
+ * <p>
+ * For example, ProcessBuilder has a method named {@code redirectErrorStream()}
+ * which sounds like it might redirect the error stream. It does not. It's just
+ * a getter which returns whether the process builder will redirect the error stream,
+ * and to actually set it, you must call {@code redirectErrorStream(boolean)}.
+ * In that case, the method should be defined like this:
+ * <pre>
+ * @CheckResult(suggest="#redirectErrorStream(boolean)")
+ * public boolean redirectErrorStream() { ... }
+ * </pre>
+ */
+ String suggest() default "";
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/ColorInt.java b/core/java/android/annotation/ColorInt.java
new file mode 100644
index 0000000..c4c93ee
--- /dev/null
+++ b/core/java/android/annotation/ColorInt.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element represents a packed color
+ * int, {@code AARRGGBB}. If applied to an int array, every element
+ * in the array represents a color integer.
+ * <p>
+ * public abstract void setTextColor(@ColorInt int color);
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({PARAMETER,METHOD,LOCAL_VARIABLE,FIELD})
+public @interface ColorInt {
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/FloatRange.java b/core/java/android/annotation/FloatRange.java
new file mode 100644
index 0000000..3a7c150
--- /dev/null
+++ b/core/java/android/annotation/FloatRange.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element should be a float or double in the given range
+ * <p>
+ * Example:
+ * <pre>{@code
+ * @FloatRange(from=0.0,to=1.0)
+ * public float getAlpha() {
+ * ...
+ * }
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE})
+public @interface FloatRange {
+ /** Smallest value. Whether it is inclusive or not is determined
+ * by {@link #fromInclusive} */
+ double from() default Double.NEGATIVE_INFINITY;
+ /** Largest value. Whether it is inclusive or not is determined
+ * by {@link #toInclusive} */
+ double to() default Double.POSITIVE_INFINITY;
+
+ /** Whether the from value is included in the range */
+ boolean fromInclusive() default true;
+
+ /** Whether the to value is included in the range */
+ boolean toInclusive() default true;
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/IntRange.java b/core/java/android/annotation/IntRange.java
new file mode 100644
index 0000000..1e3c072
--- /dev/null
+++ b/core/java/android/annotation/IntRange.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element should be an int or long in the given range
+ * <p>
+ * Example:
+ * <pre>{@code
+ * @IntRange(from=0,to=255)
+ * public int getAlpha() {
+ * ...
+ * }
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE})
+public @interface IntRange {
+ /** Smallest value, inclusive */
+ long from() default Long.MIN_VALUE;
+ /** Largest value, inclusive */
+ long to() default Long.MAX_VALUE;
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/Size.java b/core/java/android/annotation/Size.java
new file mode 100644
index 0000000..389b819
--- /dev/null
+++ b/core/java/android/annotation/Size.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element should have a given size or length.
+ * Note that "-1" means "unset". Typically used with a parameter or
+ * return value of type array or collection.
+ * <p>
+ * Example:
+ * <pre>{@code
+ * public void getLocationInWindow(@Size(2) int[] location) {
+ * ...
+ * }
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({PARAMETER,LOCAL_VARIABLE,METHOD,FIELD})
+public @interface Size {
+ /** An exact size (or -1 if not specified) */
+ long value() default -1;
+ /** A minimum size, inclusive */
+ long min() default Long.MIN_VALUE;
+ /** A maximum size, inclusive */
+ long max() default Long.MAX_VALUE;
+ /** The size must be a multiple of this factor */
+ long multiple() default 1;
+}
\ No newline at end of file
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 3197461..997f69d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2423,6 +2423,23 @@
reply.writeNoException();
return true;
}
+
+ case SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String procName = data.readString();
+ long maxMemSize = data.readLong();
+ setDumpHeapDebugLimit(procName, maxMemSize);
+ reply.writeNoException();
+ return true;
+ }
+
+ case DUMP_HEAP_FINISHED_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String path = data.readString();
+ dumpHeapFinished(path);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -5616,5 +5633,30 @@
reply.recycle();
}
+ @Override
+ public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(processName);
+ data.writeLong(maxMemSize);
+ mRemote.transact(SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ @Override
+ public void dumpHeapFinished(String path) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(path);
+ mRemote.transact(DUMP_HEAP_FINISHED_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 653b951..c93cf22 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4247,6 +4247,10 @@
} else {
Debug.dumpNativeHeap(dhd.fd.getFileDescriptor());
}
+ try {
+ ActivityManagerNative.getDefault().dumpHeapFinished(dhd.path);
+ } catch (RemoteException e) {
+ }
}
final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 1277cfa..3dcbdd2 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -482,6 +482,9 @@
public void systemBackupRestored() throws RemoteException;
public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException;
+ public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException;
+ public void dumpHeapFinished(String path) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -512,7 +515,7 @@
dest.writeStrongBinder(null);
}
dest.writeStrongBinder(connection);
- dest.writeInt(noReleaseNeeded ? 1:0);
+ dest.writeInt(noReleaseNeeded ? 1 : 0);
}
public static final Parcelable.Creator<ContentProviderHolder> CREATOR
@@ -531,7 +534,7 @@
private ContentProviderHolder(Parcel source) {
info = ProviderInfo.CREATOR.createFromParcel(source);
provider = ContentProviderNative.asInterface(
- source.readStrongBinder());
+ source.readStrongBinder());
connection = source.readStrongBinder();
noReleaseNeeded = source.readInt() != 0;
}
@@ -813,4 +816,6 @@
int REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+284;
int RESIZE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+285;
int GET_LOCK_TASK_MODE_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+286;
+ int SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+287;
+ int DUMP_HEAP_FINISHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+288;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9c00e1c..85a6aff 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.SdkConstant;
@@ -338,6 +339,7 @@
* @see #FLAG_SHOW_LIGHTS
* @see #flags
*/
+ @ColorInt
public int ledARGB;
/**
@@ -415,7 +417,6 @@
* Bit to be bitwise-ored into the {@link #flags} field that should be
* set if the notification should be canceled when it is clicked by the
* user.
-
*/
public static final int FLAG_AUTO_CANCEL = 0x00000010;
@@ -520,12 +521,14 @@
* {@link #icon} image (stenciled in white) atop a field of this color. Alpha components are
* ignored.
*/
+ @ColorInt
public int color = COLOR_DEFAULT;
/**
* Special value of {@link #color} telling the system not to decorate this notification with
* any special color but instead use default colors when presenting this notification.
*/
+ @ColorInt
public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT
/**
@@ -2388,7 +2391,7 @@
* @see Notification#ledOnMS
* @see Notification#ledOffMS
*/
- public Builder setLights(int argb, int onMs, int offMs) {
+ public Builder setLights(@ColorInt int argb, int onMs, int offMs) {
mLedArgb = argb;
mLedOnMs = onMs;
mLedOffMs = offMs;
@@ -2712,7 +2715,7 @@
*
* @return The same Builder.
*/
- public Builder setColor(int argb) {
+ public Builder setColor(@ColorInt int argb) {
mColor = argb;
return this;
}
@@ -5160,7 +5163,7 @@
* automotive setting. This method can be used to override the color provided in the
* notification in such a situation.
*/
- public CarExtender setColor(int color) {
+ public CarExtender setColor(@ColorInt int color) {
mColor = color;
return this;
}
@@ -5170,6 +5173,7 @@
*
* @see setColor
*/
+ @ColorInt
public int getColor() {
return mColor;
}
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index ace402a..841b09d 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -16,6 +16,7 @@
package android.content.res;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Resources.Theme;
@@ -91,7 +92,7 @@
* Creates a ColorStateList that returns the specified mapping from
* states to colors.
*/
- public ColorStateList(int[][] states, int[] colors) {
+ public ColorStateList(int[][] states, @ColorInt int[] colors) {
mStateSpecs = states;
mColors = colors;
@@ -102,7 +103,7 @@
* @return A ColorStateList containing a single color.
*/
@NonNull
- public static ColorStateList valueOf(int color) {
+ public static ColorStateList valueOf(@ColorInt int color) {
synchronized (sCache) {
final int index = sCache.indexOfKey(color);
if (index >= 0) {
@@ -436,6 +437,7 @@
*
* @return the default color in this {@link ColorStateList}.
*/
+ @ColorInt
public int getDefaultColor() {
return mDefaultColor;
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 584f3f6..5dc9ef9 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -16,6 +16,7 @@
package android.content.res;
+import android.annotation.ColorInt;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -925,6 +926,7 @@
* @return A single color value in the form 0xAARRGGBB.
* @deprecated Use {@link #getColor(int, Theme)} instead.
*/
+ @ColorInt
public int getColor(@ColorRes int id) throws NotFoundException {
return getColor(id, null);
}
@@ -945,6 +947,7 @@
*
* @return A single color value in the form 0xAARRGGBB.
*/
+ @ColorInt
public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException {
TypedValue value;
synchronized (mAccessLock) {
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 3e07f0c..410849a 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -17,6 +17,7 @@
package android.content.res;
import android.annotation.AnyRes;
+import android.annotation.ColorInt;
import android.annotation.Nullable;
import android.graphics.drawable.Drawable;
import android.os.StrictMode;
@@ -420,7 +421,8 @@
* @throws UnsupportedOperationException if the attribute is defined but is
* not an integer color or color state list.
*/
- public int getColor(int index, int defValue) {
+ @ColorInt
+ public int getColor(int index, @ColorInt int defValue) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java
index e1a2a25..e0d454c 100644
--- a/core/java/android/gesture/GestureOverlayView.java
+++ b/core/java/android/gesture/GestureOverlayView.java
@@ -16,6 +16,7 @@
package android.gesture;
+import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -204,18 +205,20 @@
mOrientation = orientation;
}
- public void setGestureColor(int color) {
+ public void setGestureColor(@ColorInt int color) {
mCertainGestureColor = color;
}
- public void setUncertainGestureColor(int color) {
+ public void setUncertainGestureColor(@ColorInt int color) {
mUncertainGestureColor = color;
}
+ @ColorInt
public int getUncertainGestureColor() {
return mUncertainGestureColor;
}
+ @ColorInt
public int getGestureColor() {
return mCertainGestureColor;
}
diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java
index 0447117..4f8cff0 100644
--- a/core/java/android/text/TextPaint.java
+++ b/core/java/android/text/TextPaint.java
@@ -16,6 +16,7 @@
package android.text;
+import android.annotation.ColorInt;
import android.graphics.Paint;
/**
@@ -25,8 +26,10 @@
public class TextPaint extends Paint {
// Special value 0 means no background paint
+ @ColorInt
public int bgColor;
public int baselineShift;
+ @ColorInt
public int linkColor;
public int[] drawableState;
public float density = 1.0f;
@@ -34,6 +37,7 @@
* Special value 0 means no custom underline
* @hide
*/
+ @ColorInt
public int underlineColor = 0;
/**
* Defined as a multiplier of the default underline thickness. Use 1.0f for default thickness.
diff --git a/core/java/android/text/style/ForegroundColorSpan.java b/core/java/android/text/style/ForegroundColorSpan.java
index c9e09bd..f167aab 100644
--- a/core/java/android/text/style/ForegroundColorSpan.java
+++ b/core/java/android/text/style/ForegroundColorSpan.java
@@ -16,6 +16,7 @@
package android.text.style;
+import android.annotation.ColorInt;
import android.os.Parcel;
import android.text.ParcelableSpan;
import android.text.TextPaint;
@@ -26,7 +27,7 @@
private final int mColor;
- public ForegroundColorSpan(int color) {
+ public ForegroundColorSpan(@ColorInt int color) {
mColor = color;
}
@@ -46,6 +47,7 @@
dest.writeInt(mColor);
}
+ @ColorInt
public int getForegroundColor() {
return mColor;
}
diff --git a/core/java/android/text/style/QuoteSpan.java b/core/java/android/text/style/QuoteSpan.java
index 29dd273..17748ca 100644
--- a/core/java/android/text/style/QuoteSpan.java
+++ b/core/java/android/text/style/QuoteSpan.java
@@ -16,6 +16,7 @@
package android.text.style;
+import android.annotation.ColorInt;
import android.graphics.Paint;
import android.graphics.Canvas;
import android.os.Parcel;
@@ -34,7 +35,7 @@
mColor = 0xff0000ff;
}
- public QuoteSpan(int color) {
+ public QuoteSpan(@ColorInt int color) {
super();
mColor = color;
}
@@ -55,6 +56,7 @@
dest.writeInt(mColor);
}
+ @ColorInt
public int getColor() {
return mColor;
}
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index f607207..84d9ce8 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -16,6 +16,7 @@
package android.util;
+import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.util.Locale;
@@ -123,4 +124,83 @@
}
}
+ /** @hide */
+ public static void printSizeValue(PrintWriter pw, long number) {
+ float result = number;
+ String suffix = "";
+ if (result > 900) {
+ suffix = "KB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "MB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "GB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "TB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "PB";
+ result = result / 1024;
+ }
+ String value;
+ if (result < 1) {
+ value = String.format("%.2f", result);
+ } else if (result < 10) {
+ value = String.format("%.1f", result);
+ } else if (result < 100) {
+ value = String.format("%.0f", result);
+ } else {
+ value = String.format("%.0f", result);
+ }
+ pw.print(value);
+ pw.print(suffix);
+ }
+
+ /** @hide */
+ public static String sizeValueToString(long number, StringBuilder outBuilder) {
+ if (outBuilder == null) {
+ outBuilder = new StringBuilder(32);
+ }
+ float result = number;
+ String suffix = "";
+ if (result > 900) {
+ suffix = "KB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "MB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "GB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "TB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "PB";
+ result = result / 1024;
+ }
+ String value;
+ if (result < 1) {
+ value = String.format("%.2f", result);
+ } else if (result < 10) {
+ value = String.format("%.1f", result);
+ } else if (result < 100) {
+ value = String.format("%.0f", result);
+ } else {
+ value = String.format("%.0f", result);
+ }
+ outBuilder.append(value);
+ outBuilder.append(suffix);
+ return outBuilder.toString();
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4b3765a..ed1197c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -18,6 +18,7 @@
import android.animation.AnimatorInflater;
import android.animation.StateListAnimator;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.IntDef;
@@ -14311,7 +14312,7 @@
* @see #buildDrawingCache()
* @see #getDrawingCache()
*/
- public void setDrawingCacheBackgroundColor(int color) {
+ public void setDrawingCacheBackgroundColor(@ColorInt int color) {
if (color != mDrawingCacheBackgroundColor) {
mDrawingCacheBackgroundColor = color;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
@@ -14323,6 +14324,7 @@
*
* @return The background color to used for the drawing cache's bitmap
*/
+ @ColorInt
public int getDrawingCacheBackgroundColor() {
return mDrawingCacheBackgroundColor;
}
@@ -15536,6 +15538,7 @@
* @return The known solid color background for this view, or 0 if the color may vary
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @ColorInt
public int getSolidColor() {
return 0;
}
@@ -16222,7 +16225,7 @@
* @param color the color of the background
*/
@RemotableViewMethod
- public void setBackgroundColor(int color) {
+ public void setBackgroundColor(@ColorInt int color) {
if (mBackground instanceof ColorDrawable) {
((ColorDrawable) mBackground.mutate()).setColor(color);
computeOpaqueFlags();
@@ -16238,6 +16241,7 @@
*
* @return The color of the ColorDrawable background, if set, otherwise 0.
*/
+ @ColorInt
public int getBackgroundColor() {
if (mBackground instanceof ColorDrawable) {
return ((ColorDrawable) mBackground).getColor();
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index e332135..744f665 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
@@ -1069,7 +1070,7 @@
public abstract void setTitle(CharSequence title);
@Deprecated
- public abstract void setTitleColor(int textColor);
+ public abstract void setTitleColor(@ColorInt int textColor);
public abstract void openPanel(int featureId, KeyEvent event);
@@ -1835,6 +1836,7 @@
/**
* @return the color of the status bar.
*/
+ @ColorInt
public abstract int getStatusBarColor();
/**
@@ -1852,11 +1854,12 @@
* The transitionName for the view background will be "android:status:background".
* </p>
*/
- public abstract void setStatusBarColor(int color);
+ public abstract void setStatusBarColor(@ColorInt int color);
/**
* @return the color of the navigation bar.
*/
+ @ColorInt
public abstract int getNavigationBarColor();
/**
@@ -1874,7 +1877,7 @@
* The transitionName for the view background will be "android:navigation:background".
* </p>
*/
- public abstract void setNavigationBarColor(int color);
+ public abstract void setNavigationBarColor(@ColorInt int color);
}
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 85d77cb..a5524d8 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -16,6 +16,7 @@
package android.view.animation;
+import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.RectF;
@@ -622,7 +623,7 @@
* @param bg The background color. If 0, no background. Currently must
* be black, with any desired alpha level.
*/
- public void setBackgroundColor(int bg) {
+ public void setBackgroundColor(@ColorInt int bg) {
mBackgroundColor = bg;
}
@@ -753,6 +754,7 @@
/**
* Returns the background color behind the animation.
*/
+ @ColorInt
public int getBackgroundColor() {
return mBackgroundColor;
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index a6e2952..168066a 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.content.Context;
import android.content.Intent;
@@ -5982,7 +5983,7 @@
*
* @param color The background color
*/
- public void setCacheColorHint(int color) {
+ public void setCacheColorHint(@ColorInt int color) {
if (color != mCacheColorHint) {
mCacheColorHint = color;
int count = getChildCount();
@@ -6000,6 +6001,7 @@
* @return The cache color hint
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @ColorInt
public int getCacheColorHint() {
return mCacheColorHint;
}
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index fd1c4b8..5bc16cb 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.Widget;
import android.content.Context;
@@ -140,7 +141,7 @@
*
* @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor
*/
- public void setSelectedWeekBackgroundColor(int color) {
+ public void setSelectedWeekBackgroundColor(@ColorInt int color) {
mDelegate.setSelectedWeekBackgroundColor(color);
}
@@ -151,6 +152,7 @@
*
* @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor
*/
+ @ColorInt
public int getSelectedWeekBackgroundColor() {
return mDelegate.getSelectedWeekBackgroundColor();
}
@@ -162,7 +164,7 @@
*
* @attr ref android.R.styleable#CalendarView_focusedMonthDateColor
*/
- public void setFocusedMonthDateColor(int color) {
+ public void setFocusedMonthDateColor(@ColorInt int color) {
mDelegate.setFocusedMonthDateColor(color);
}
@@ -173,6 +175,7 @@
*
* @attr ref android.R.styleable#CalendarView_focusedMonthDateColor
*/
+ @ColorInt
public int getFocusedMonthDateColor() {
return mDelegate.getFocusedMonthDateColor();
}
@@ -184,7 +187,7 @@
*
* @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor
*/
- public void setUnfocusedMonthDateColor(int color) {
+ public void setUnfocusedMonthDateColor(@ColorInt int color) {
mDelegate.setUnfocusedMonthDateColor(color);
}
@@ -195,6 +198,7 @@
*
* @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor
*/
+ @ColorInt
public int getUnfocusedMonthDateColor() {
return mDelegate.getUnfocusedMonthDateColor();
}
@@ -206,7 +210,7 @@
*
* @attr ref android.R.styleable#CalendarView_weekNumberColor
*/
- public void setWeekNumberColor(int color) {
+ public void setWeekNumberColor(@ColorInt int color) {
mDelegate.setWeekNumberColor(color);
}
@@ -217,6 +221,7 @@
*
* @attr ref android.R.styleable#CalendarView_weekNumberColor
*/
+ @ColorInt
public int getWeekNumberColor() {
return mDelegate.getWeekNumberColor();
}
@@ -228,7 +233,7 @@
*
* @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor
*/
- public void setWeekSeparatorLineColor(int color) {
+ public void setWeekSeparatorLineColor(@ColorInt int color) {
mDelegate.setWeekSeparatorLineColor(color);
}
@@ -239,6 +244,7 @@
*
* @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor
*/
+ @ColorInt
public int getWeekSeparatorLineColor() {
return mDelegate.getWeekSeparatorLineColor();
}
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 391347e..9019f31 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.graphics.PorterDuff;
@@ -292,7 +293,7 @@
*
* @param color Color in argb
*/
- public void setColor(int color) {
+ public void setColor(@ColorInt int color) {
mPaint.setColor(color);
}
@@ -300,6 +301,7 @@
* Return the color of this edge effect in argb.
* @return The color of this edge effect in argb
*/
+ @ColorInt
public int getColor() {
return mPaint.getColor();
}
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index c748e00..6cc4bda 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -1012,8 +1012,6 @@
LayoutParams lp = getLayoutParams(c);
if (firstPass) {
measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
- mHorizontalAxis.recordOriginalMeasurement(i);
- mVerticalAxis.recordOriginalMeasurement(i);
} else {
boolean horizontal = (mOrientation == HORIZONTAL);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
@@ -1231,7 +1229,6 @@
public boolean hasWeights;
public boolean hasWeightsValid = false;
- public int[] originalMeasurements;
public int[] deltas;
boolean orderPreserved = DEFAULT_ORDER_PRESERVED;
@@ -1310,9 +1307,8 @@
// we must include views that are GONE here, see introductory javadoc
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
- int size = (spec.weight == 0) ?
- getMeasurementIncludingMargin(c, horizontal) :
- getOriginalMeasurements()[i] + getDeltas()[i];
+ int size = getMeasurementIncludingMargin(c, horizontal) +
+ ((spec.weight == 0) ? 0 : getDeltas()[i]);
groupBounds.getValue(i).include(GridLayout.this, c, spec, this, size);
}
}
@@ -1721,19 +1717,6 @@
return hasWeights;
}
- public int[] getOriginalMeasurements() {
- if (originalMeasurements == null) {
- originalMeasurements = new int[getChildCount()];
- }
- return originalMeasurements;
- }
-
- private void recordOriginalMeasurement(int i) {
- if (hasWeights()) {
- getOriginalMeasurements()[i] = getMeasurementIncludingMargin(getChildAt(i), horizontal);
- }
- }
-
public int[] getDeltas() {
if (deltas == null) {
deltas = new int[getChildCount()];
@@ -1898,7 +1881,6 @@
locations = null;
- originalMeasurements = null;
deltas = null;
hasWeightsValid = false;
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index dd7fa18..a10be11 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.Application;
@@ -2263,7 +2264,7 @@
* @param color Sets the text color for all the states (normal, selected,
* focused) to be this color.
*/
- public void setTextColor(int viewId, int color) {
+ public void setTextColor(int viewId, @ColorInt int color) {
setInt(viewId, "setTextColor", color);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index dfe68fd..faf1c40 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,6 +17,7 @@
package android.widget;
import android.R;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -2997,7 +2998,7 @@
* @attr ref android.R.styleable#TextView_textColor
*/
@android.view.RemotableViewMethod
- public void setTextColor(int color) {
+ public void setTextColor(@ColorInt int color) {
mTextColor = ColorStateList.valueOf(color);
updateTextColors();
}
@@ -3038,6 +3039,7 @@
*
* @return Returns the current text color.
*/
+ @ColorInt
public final int getCurrentTextColor() {
return mCurTextColor;
}
@@ -3048,7 +3050,7 @@
* @attr ref android.R.styleable#TextView_textColorHighlight
*/
@android.view.RemotableViewMethod
- public void setHighlightColor(int color) {
+ public void setHighlightColor(@ColorInt int color) {
if (mHighlightColor != color) {
mHighlightColor = color;
invalidate();
@@ -3062,6 +3064,7 @@
*
* @attr ref android.R.styleable#TextView_textColorHighlight
*/
+ @ColorInt
public int getHighlightColor() {
return mHighlightColor;
}
@@ -3156,6 +3159,7 @@
*
* @attr ref android.R.styleable#TextView_shadowColor
*/
+ @ColorInt
public int getShadowColor() {
return mShadowColor;
}
@@ -3231,7 +3235,7 @@
* @attr ref android.R.styleable#TextView_textColorHint
*/
@android.view.RemotableViewMethod
- public final void setHintTextColor(int color) {
+ public final void setHintTextColor(@ColorInt int color) {
mHintTextColor = ColorStateList.valueOf(color);
updateTextColors();
}
@@ -3270,6 +3274,7 @@
*
* @return Returns the current hint text color.
*/
+ @ColorInt
public final int getCurrentHintTextColor() {
return mHintTextColor != null ? mCurHintTextColor : mCurTextColor;
}
@@ -3283,7 +3288,7 @@
* @attr ref android.R.styleable#TextView_textColorLink
*/
@android.view.RemotableViewMethod
- public final void setLinkTextColor(int color) {
+ public final void setLinkTextColor(@ColorInt int color) {
mLinkTextColor = ColorStateList.valueOf(color);
updateTextColors();
}
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 9bc2aab..d2430bc 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActionBar;
@@ -685,7 +686,7 @@
*
* @param color The new text color in 0xAARRGGBB format
*/
- public void setTitleTextColor(int color) {
+ public void setTitleTextColor(@ColorInt int color) {
mTitleTextColor = color;
if (mTitleTextView != null) {
mTitleTextView.setTextColor(color);
@@ -697,7 +698,7 @@
*
* @param color The new text color in 0xAARRGGBB format
*/
- public void setSubtitleTextColor(int color) {
+ public void setSubtitleTextColor(@ColorInt int color) {
mSubtitleTextColor = color;
if (mSubtitleTextView != null) {
mSubtitleTextView.setTextColor(color);
diff --git a/core/java/com/android/internal/app/DumpHeapActivity.java b/core/java/com/android/internal/app/DumpHeapActivity.java
new file mode 100644
index 0000000..7e70b0c
--- /dev/null
+++ b/core/java/com/android/internal/app/DumpHeapActivity.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.internal.app;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ClipData;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.DebugUtils;
+
+/**
+ * This activity is displayed when the system has collected a heap dump from
+ * a large process and the user has selected to share it.
+ */
+public class DumpHeapActivity extends Activity {
+ /** The process we are reporting */
+ public static final String KEY_PROCESS = "process";
+ /** The size limit the process reached */
+ public static final String KEY_SIZE = "size";
+
+ // Broadcast action to determine when to delete the current dump heap data.
+ public static final String ACTION_DELETE_DUMPHEAP = "com.android.server.am.DELETE_DUMPHEAP";
+
+ // Extra for above: delay delete of data, since the user is in the process of sharing it.
+ public static final String EXTRA_DELAY_DELETE = "delay_delete";
+
+ static final public Uri JAVA_URI = Uri.parse("content://com.android.server.heapdump/java");
+
+ String mProcess;
+ long mSize;
+ AlertDialog mDialog;
+ boolean mHandled = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mProcess = getIntent().getStringExtra(KEY_PROCESS);
+ mSize = getIntent().getLongExtra(KEY_SIZE, 0);
+ AlertDialog.Builder b = new AlertDialog.Builder(this,
+ android.R.style.Theme_Material_Light_Dialog_Alert);
+ b.setTitle(com.android.internal.R.string.dump_heap_title);
+ b.setMessage(getString(com.android.internal.R.string.dump_heap_text,
+ mProcess, DebugUtils.sizeValueToString(mSize, null)));
+ b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mHandled = true;
+ sendBroadcast(new Intent(ACTION_DELETE_DUMPHEAP));
+ finish();
+ }
+ });
+ b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mHandled = true;
+ Intent broadcast = new Intent(ACTION_DELETE_DUMPHEAP);
+ broadcast.putExtra(EXTRA_DELAY_DELETE, true);
+ sendBroadcast(broadcast);
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI);
+ intent.setClipData(clip);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.setType(clip.getDescription().getMimeType(0));
+ intent.putExtra(Intent.EXTRA_STREAM, JAVA_URI);
+ startActivity(Intent.createChooser(intent,
+ getText(com.android.internal.R.string.dump_heap_title)));
+ finish();
+ }
+ });
+ mDialog = b.show();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ if (!isChangingConfigurations()) {
+ if (!mHandled) {
+ sendBroadcast(new Intent(ACTION_DELETE_DUMPHEAP));
+ }
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mDialog.dismiss();
+ }
+}
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 70fb510..75beee9 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -24,6 +24,7 @@
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.DebugUtils;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -897,17 +898,17 @@
pw.print(STATE_NAMES[procStates[ip]]); pw.print(": ");
pw.print(count);
pw.print(" samples ");
- printSizeValue(pw, proc.getPssMinimum(bucket) * 1024);
+ DebugUtils.printSizeValue(pw, proc.getPssMinimum(bucket) * 1024);
pw.print(" ");
- printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
+ DebugUtils.printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
pw.print(" ");
- printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
+ DebugUtils.printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
pw.print(" / ");
- printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
+ DebugUtils.printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
pw.print(" ");
- printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
+ DebugUtils.printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
pw.print(" ");
- printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
+ DebugUtils.printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
pw.println();
}
}
@@ -924,9 +925,9 @@
if (proc.mNumCachedKill != 0) {
pw.print(prefix); pw.print("Killed from cached state: ");
pw.print(proc.mNumCachedKill); pw.print(" times from pss ");
- printSizeValue(pw, proc.mMinCachedKillPss * 1024); pw.print("-");
- printSizeValue(pw, proc.mAvgCachedKillPss * 1024); pw.print("-");
- printSizeValue(pw, proc.mMaxCachedKillPss * 1024); pw.println();
+ DebugUtils.printSizeValue(pw, proc.mMinCachedKillPss * 1024); pw.print("-");
+ DebugUtils.printSizeValue(pw, proc.mAvgCachedKillPss * 1024); pw.print("-");
+ DebugUtils.printSizeValue(pw, proc.mMaxCachedKillPss * 1024); pw.println();
}
}
@@ -939,11 +940,11 @@
int bucket, int index) {
pw.print(prefix); pw.print(label);
pw.print(": ");
- printSizeValue(pw, getSysMemUsageValue(bucket, index) * 1024);
+ DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index) * 1024);
pw.print(" min, ");
- printSizeValue(pw, getSysMemUsageValue(bucket, index + 1) * 1024);
+ DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index + 1) * 1024);
pw.print(" avg, ");
- printSizeValue(pw, getSysMemUsageValue(bucket, index+2) * 1024);
+ DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index+2) * 1024);
pw.println(" max");
}
@@ -1150,43 +1151,6 @@
pw.print("%");
}
- static void printSizeValue(PrintWriter pw, long number) {
- float result = number;
- String suffix = "";
- if (result > 900) {
- suffix = "KB";
- result = result / 1024;
- }
- if (result > 900) {
- suffix = "MB";
- result = result / 1024;
- }
- if (result > 900) {
- suffix = "GB";
- result = result / 1024;
- }
- if (result > 900) {
- suffix = "TB";
- result = result / 1024;
- }
- if (result > 900) {
- suffix = "PB";
- result = result / 1024;
- }
- String value;
- if (result < 1) {
- value = String.format("%.2f", result);
- } else if (result < 10) {
- value = String.format("%.1f", result);
- } else if (result < 100) {
- value = String.format("%.0f", result);
- } else {
- value = String.format("%.0f", result);
- }
- pw.print(value);
- pw.print(suffix);
- }
-
public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
boolean sepProcStates, int[] procStates, long now) {
@@ -2437,7 +2401,7 @@
pw.print(prefix);
pw.print(label);
pw.print(": ");
- printSizeValue(pw, mem);
+ DebugUtils.printSizeValue(pw, mem);
pw.print(" (");
pw.print(samples);
pw.print(" samples)");
@@ -2475,7 +2439,7 @@
totalPss = printMemoryCategory(pw, " ", "Z-Ram ", totalMem.sysMemZRamWeight,
totalMem.totalTime, totalPss, totalMem.sysMemSamples);
pw.print(" TOTAL : ");
- printSizeValue(pw, totalPss);
+ DebugUtils.printSizeValue(pw, totalPss);
pw.println();
printMemoryCategory(pw, " ", STATE_NAMES[STATE_SERVICE_RESTARTING],
totalMem.processStateWeight[STATE_SERVICE_RESTARTING], totalMem.totalTime, totalPss,
@@ -3781,17 +3745,17 @@
printPercent(pw, (double) totalTime / (double) overallTime);
if (numPss > 0) {
pw.print(" (");
- printSizeValue(pw, minPss * 1024);
+ DebugUtils.printSizeValue(pw, minPss * 1024);
pw.print("-");
- printSizeValue(pw, avgPss * 1024);
+ DebugUtils.printSizeValue(pw, avgPss * 1024);
pw.print("-");
- printSizeValue(pw, maxPss * 1024);
+ DebugUtils.printSizeValue(pw, maxPss * 1024);
pw.print("/");
- printSizeValue(pw, minUss * 1024);
+ DebugUtils.printSizeValue(pw, minUss * 1024);
pw.print("-");
- printSizeValue(pw, avgUss * 1024);
+ DebugUtils.printSizeValue(pw, avgUss * 1024);
pw.print("-");
- printSizeValue(pw, maxUss * 1024);
+ DebugUtils.printSizeValue(pw, maxUss * 1024);
if (full) {
pw.print(" over ");
pw.print(numPss);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2ce5bb3..ed4776b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3033,6 +3033,19 @@
android:excludeFromRecents="true"
android:process=":ui">
</activity>
+ <activity android:name="com.android.internal.app.DumpHeapActivity"
+ android:theme="@style/Theme.Translucent.NoTitleBar"
+ android:label="@string/dump_heap_title"
+ android:finishOnCloseSystemDialogs="true"
+ android:noHistory="true"
+ android:excludeFromRecents="true"
+ android:process=":ui">
+ </activity>
+ <provider android:name="com.android.server.am.DumpHeapProvider"
+ android:authorities="com.android.server.heapdump"
+ android:grantUriPermissions="true"
+ android:multiprocess="false"
+ android:singleUser="true" />
<activity android:name="android.accounts.ChooseAccountActivity"
android:excludeFromRecents="true"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 67ce159..bf370f4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3715,6 +3715,23 @@
<string name="new_app_action">Start <xliff:g id="old_app">%1$s</xliff:g></string>
<string name="new_app_description">Stop the old app without saving.</string>
+ <!-- Notification text to tell the user that a process has exceeded its memory limit. -->
+ <string name="dump_heap_notification"><xliff:g id="proc">%1$s</xliff:g> exceeded memory
+ limit</string>
+
+ <!-- Notification details to tell the user that a process has exceeded its memory limit. -->
+ <string name="dump_heap_notification_detail">Heap dump has been collected;
+ touch to share</string>
+
+ <!-- Title of dialog prompting the user to share a heap dump. -->
+ <string name="dump_heap_title">Share heap dump?</string>
+
+ <!-- Text of dialog prompting the user to share a heap dump. -->
+ <string name="dump_heap_text">The process <xliff:g id="proc">%1$s</xliff:g> has exceeded
+ its process memory limit of <xliff:g id="size">%2$s</xliff:g>. A heap dump is available
+ for you to share with its developer. Be careful: this heap dump can contain any
+ of your personal information that the application has access to.</string>
+
<!-- Displayed in the title of the chooser for things to do with text that
is to be sent to another application. For example, I can send
text through SMS or IM. A dialog with those choices would be shown,
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 078c12f..b204a0b 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1723,6 +1723,10 @@
<java-symbol type="string" name="data_usage_wifi_limit_title" />
<java-symbol type="string" name="default_wallpaper_component" />
<java-symbol type="string" name="dlg_ok" />
+ <java-symbol type="string" name="dump_heap_notification" />
+ <java-symbol type="string" name="dump_heap_notification_detail" />
+ <java-symbol type="string" name="dump_heap_text" />
+ <java-symbol type="string" name="dump_heap_title" />
<java-symbol type="string" name="factorytest_failed" />
<java-symbol type="string" name="factorytest_no_action" />
<java-symbol type="string" name="factorytest_not_system" />
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 5b20d48..aae11cd 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -16,6 +16,7 @@
package android.graphics;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
@@ -1278,7 +1279,7 @@
*
* @throws IllegalStateException if the bitmap is not mutable.
*/
- public void eraseColor(int c) {
+ public void eraseColor(@ColorInt int c) {
checkRecycled("Can't erase a recycled bitmap");
if (!isMutable()) {
throw new IllegalStateException("cannot erase immutable bitmaps");
@@ -1296,6 +1297,7 @@
* @return The argb {@link Color} at the specified coordinate
* @throws IllegalArgumentException if x, y exceed the bitmap's bounds
*/
+ @ColorInt
public int getPixel(int x, int y) {
checkRecycled("Can't call getPixel() on a recycled bitmap");
checkPixelAccess(x, y);
@@ -1325,7 +1327,7 @@
* @throws ArrayIndexOutOfBoundsException if the pixels array is too small
* to receive the specified number of pixels.
*/
- public void getPixels(int[] pixels, int offset, int stride,
+ public void getPixels(@ColorInt int[] pixels, int offset, int stride,
int x, int y, int width, int height) {
checkRecycled("Can't call getPixels() on a recycled bitmap");
if (width == 0 || height == 0) {
@@ -1407,7 +1409,7 @@
* @throws IllegalArgumentException if x, y are outside of the bitmap's
* bounds.
*/
- public void setPixel(int x, int y, int color) {
+ public void setPixel(int x, int y, @ColorInt int color) {
checkRecycled("Can't call setPixel() on a recycled bitmap");
if (!isMutable()) {
throw new IllegalStateException();
@@ -1439,7 +1441,7 @@
* @throws ArrayIndexOutOfBoundsException if the pixels array is too small
* to receive the specified number of pixels.
*/
- public void setPixels(int[] pixels, int offset, int stride,
+ public void setPixels(@ColorInt int[] pixels, int offset, int stride,
int x, int y, int width, int height) {
checkRecycled("Can't call setPixels() on a recycled bitmap");
if (!isMutable()) {
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 85fa3cb..55b7277 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -16,6 +16,7 @@
package android.graphics;
+import android.annotation.ColorInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1012,7 +1013,7 @@
*
* @param color the color to draw onto the canvas
*/
- public void drawColor(int color) {
+ public void drawColor(@ColorInt int color) {
native_drawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt);
}
@@ -1023,7 +1024,7 @@
* @param color the color to draw with
* @param mode the porter-duff mode to apply to the color
*/
- public void drawColor(int color, @NonNull PorterDuff.Mode mode) {
+ public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
native_drawColor(mNativeCanvasWrapper, color, mode.nativeInt);
}
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 3fe5672..df0ebee 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -16,6 +16,7 @@
package android.graphics;
+import android.annotation.ColorInt;
import android.util.MathUtils;
import com.android.internal.util.XmlUtils;
@@ -35,23 +36,24 @@
* 0xFFFFFFFF
*/
public class Color {
- public static final int BLACK = 0xFF000000;
- public static final int DKGRAY = 0xFF444444;
- public static final int GRAY = 0xFF888888;
- public static final int LTGRAY = 0xFFCCCCCC;
- public static final int WHITE = 0xFFFFFFFF;
- public static final int RED = 0xFFFF0000;
- public static final int GREEN = 0xFF00FF00;
- public static final int BLUE = 0xFF0000FF;
- public static final int YELLOW = 0xFFFFFF00;
- public static final int CYAN = 0xFF00FFFF;
- public static final int MAGENTA = 0xFFFF00FF;
- public static final int TRANSPARENT = 0;
+ @ColorInt public static final int BLACK = 0xFF000000;
+ @ColorInt public static final int DKGRAY = 0xFF444444;
+ @ColorInt public static final int GRAY = 0xFF888888;
+ @ColorInt public static final int LTGRAY = 0xFFCCCCCC;
+ @ColorInt public static final int WHITE = 0xFFFFFFFF;
+ @ColorInt public static final int RED = 0xFFFF0000;
+ @ColorInt public static final int GREEN = 0xFF00FF00;
+ @ColorInt public static final int BLUE = 0xFF0000FF;
+ @ColorInt public static final int YELLOW = 0xFFFFFF00;
+ @ColorInt public static final int CYAN = 0xFF00FFFF;
+ @ColorInt public static final int MAGENTA = 0xFFFF00FF;
+ @ColorInt public static final int TRANSPARENT = 0;
/**
* Return the alpha component of a color int. This is the same as saying
* color >>> 24
*/
+ @ColorInt
public static int alpha(int color) {
return color >>> 24;
}
@@ -60,6 +62,7 @@
* Return the red component of a color int. This is the same as saying
* (color >> 16) & 0xFF
*/
+ @ColorInt
public static int red(int color) {
return (color >> 16) & 0xFF;
}
@@ -68,6 +71,7 @@
* Return the green component of a color int. This is the same as saying
* (color >> 8) & 0xFF
*/
+ @ColorInt
public static int green(int color) {
return (color >> 8) & 0xFF;
}
@@ -76,6 +80,7 @@
* Return the blue component of a color int. This is the same as saying
* color & 0xFF
*/
+ @ColorInt
public static int blue(int color) {
return color & 0xFF;
}
@@ -90,6 +95,7 @@
* @param green Green component [0..255] of the color
* @param blue Blue component [0..255] of the color
*/
+ @ColorInt
public static int rgb(int red, int green, int blue) {
return (0xFF << 24) | (red << 16) | (green << 8) | blue;
}
@@ -104,6 +110,7 @@
* @param green Green component [0..255] of the color
* @param blue Blue component [0..255] of the color
*/
+ @ColorInt
public static int argb(int alpha, int red, int green, int blue) {
return (alpha << 24) | (red << 16) | (green << 8) | blue;
}
@@ -115,7 +122,7 @@
*
* @hide Pending API council
*/
- public static float hue(int color) {
+ public static float hue(@ColorInt int color) {
int r = (color >> 16) & 0xFF;
int g = (color >> 8) & 0xFF;
int b = color & 0xFF;
@@ -157,7 +164,7 @@
*
* @hide Pending API council
*/
- public static float saturation(int color) {
+ public static float saturation(@ColorInt int color) {
int r = (color >> 16) & 0xFF;
int g = (color >> 8) & 0xFF;
int b = color & 0xFF;
@@ -184,7 +191,7 @@
*
* @hide Pending API council
*/
- public static float brightness(int color) {
+ public static float brightness(@ColorInt int color) {
int r = (color >> 16) & 0xFF;
int g = (color >> 8) & 0xFF;
int b = color & 0xFF;
@@ -206,6 +213,7 @@
* 'aqua', 'fuchsia', 'lime', 'maroon', 'navy', 'olive', 'purple',
* 'silver', 'teal'.
*/
+ @ColorInt
public static int parseColor(String colorString) {
if (colorString.charAt(0) == '#') {
// Use a long to avoid rollovers on #ffXXXXXX
@@ -237,6 +245,7 @@
*
* @hide Pending API council
*/
+ @ColorInt
public static int HSBtoColor(float[] hsb) {
return HSBtoColor(hsb[0], hsb[1], hsb[2]);
}
@@ -254,6 +263,7 @@
*
* @hide Pending API council
*/
+ @ColorInt
public static int HSBtoColor(float h, float s, float b) {
h = MathUtils.constrain(h, 0.0f, 1.0f);
s = MathUtils.constrain(s, 0.0f, 1.0f);
@@ -332,7 +342,7 @@
* @param color the argb color to convert. The alpha component is ignored.
* @param hsv 3 element array which holds the resulting HSV components.
*/
- public static void colorToHSV(int color, float hsv[]) {
+ public static void colorToHSV(@ColorInt int color, float hsv[]) {
RGBToHSV((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, hsv);
}
@@ -379,6 +389,7 @@
*
* @hide
*/
+ @ColorInt
public static int getHtmlColor(String color) {
Integer i = sColorNameMap.get(color.toLowerCase(Locale.ROOT));
if (i != null) {
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 681bc62..0656b2e 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -16,6 +16,7 @@
package android.graphics;
+import android.annotation.ColorInt;
import android.text.GraphicsOperations;
import android.text.SpannableString;
import android.text.SpannedString;
@@ -777,6 +778,7 @@
*
* @return the paint's color (and alpha).
*/
+ @ColorInt
public native int getColor();
/**
@@ -787,7 +789,7 @@
*
* @param color The new color (including alpha) to set in the paint.
*/
- public native void setColor(int color);
+ public native void setColor(@ColorInt int color);
/**
* Helper to getColor() that just returns the color's alpha value. This is
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 85e02b7..f75ab36 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -16,6 +16,7 @@
package android.graphics.drawable;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.graphics.*;
import android.graphics.PorterDuff.Mode;
@@ -62,7 +63,7 @@
*
* @param color The color to draw.
*/
- public ColorDrawable(int color) {
+ public ColorDrawable(@ColorInt int color) {
mColorState = new ColorState();
setColor(color);
@@ -117,6 +118,7 @@
*
* @return int The color to draw.
*/
+ @ColorInt
public int getColor() {
return mColorState.mUseColor;
}
@@ -128,7 +130,7 @@
*
* @param color The color to draw.
*/
- public void setColor(int color) {
+ public void setColor(@ColorInt int color) {
if (mColorState.mBaseColor != color || mColorState.mUseColor != color) {
mColorState.mBaseColor = mColorState.mUseColor = color;
invalidateSelf();
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 2cc192c..16760c7 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -16,6 +16,7 @@
package android.graphics.drawable;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.ColorStateList;
@@ -544,7 +545,7 @@
* @see #setTintList(ColorStateList)
* @see #setTintMode(PorterDuff.Mode)
*/
- public void setTint(int tintColor) {
+ public void setTint(@ColorInt int tintColor) {
setTintList(ColorStateList.valueOf(tintColor));
}
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 6ea23d4..eff152c 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -16,6 +16,7 @@
package android.graphics.drawable;
+import android.annotation.ColorInt;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -181,7 +182,7 @@
* Create a new gradient drawable given an orientation and an array
* of colors for the gradient.
*/
- public GradientDrawable(Orientation orientation, int[] colors) {
+ public GradientDrawable(Orientation orientation, @ColorInt int[] colors) {
this(new GradientState(orientation, colors), null);
}
@@ -250,7 +251,7 @@
* @see #mutate()
* @see #setStroke(int, int, float, float)
*/
- public void setStroke(int width, int color) {
+ public void setStroke(int width, @ColorInt int color) {
setStroke(width, color, 0, 0);
}
@@ -286,7 +287,7 @@
* @see #mutate()
* @see #setStroke(int, int)
*/
- public void setStroke(int width, int color, float dashWidth, float dashGap) {
+ public void setStroke(int width, @ColorInt int color, float dashWidth, float dashGap) {
mGradientState.setStroke(width, ColorStateList.valueOf(color), dashWidth, dashGap);
setStrokeInternal(width, color, dashWidth, dashGap);
}
@@ -501,7 +502,7 @@
* @see #mutate()
* @see #setColor(int)
*/
- public void setColors(int[] colors) {
+ public void setColors(@ColorInt int[] colors) {
mGradientState.setColors(colors);
mGradientIsDirty = true;
invalidateSelf();
@@ -713,7 +714,7 @@
* @see #mutate()
* @see #setColors(int[])
*/
- public void setColor(int argb) {
+ public void setColor(@ColorInt int argb) {
mGradientState.setColorStateList(ColorStateList.valueOf(argb));
mFillPaint.setColor(argb);
invalidateSelf();
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index d0ea3a6..46b0945 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -15,6 +15,7 @@
*/
#include "JankTracker.h"
+#include <algorithm>
#include <cstdio>
#include <inttypes.h>
@@ -95,7 +96,12 @@
// Fast-path for jank-free frames
int64_t totalDuration =
frame[FrameInfoIndex::kFrameCompleted] - frame[FrameInfoIndex::kIntendedVsync];
+ uint32_t framebucket = std::min(
+ static_cast<typeof sizeof(mFrameCounts)>(ns2ms(totalDuration)),
+ sizeof(mFrameCounts) / sizeof(mFrameCounts[0]));
+ // Keep the fast path as fast as possible.
if (CC_LIKELY(totalDuration < mFrameInterval)) {
+ mFrameCounts[framebucket]++;
return;
}
@@ -103,6 +109,7 @@
return;
}
+ mFrameCounts[framebucket]++;
mJankFrameCount++;
for (int i = 0; i < NUM_BUCKETS; i++) {
@@ -119,6 +126,9 @@
fprintf(file, "\n Total frames rendered: %u", mTotalFrameCount);
fprintf(file, "\n Janky frames: %u (%.2f%%)", mJankFrameCount,
(float) mJankFrameCount / (float) mTotalFrameCount * 100.0f);
+ fprintf(file, "\n 90th percentile: %ums", findPercentile(90));
+ fprintf(file, "\n 95th percentile: %ums", findPercentile(95));
+ fprintf(file, "\n 99th percentile: %ums", findPercentile(99));
for (int i = 0; i < NUM_BUCKETS; i++) {
fprintf(file, "\n Number %s: %u", JANK_TYPE_NAMES[i], mBuckets[i].count);
}
@@ -127,10 +137,23 @@
}
void JankTracker::reset() {
- memset(mBuckets, 0, sizeof(JankBucket) * NUM_BUCKETS);
+ memset(mBuckets, 0, sizeof(mBuckets));
+ memset(mFrameCounts, 0, sizeof(mFrameCounts));
mTotalFrameCount = 0;
mJankFrameCount = 0;
}
+uint32_t JankTracker::findPercentile(int percentile) {
+ int pos = percentile * mTotalFrameCount / 100;
+ int remaining = mTotalFrameCount - pos;
+ for (int i = sizeof(mFrameCounts) / sizeof(mFrameCounts[0]) - 1; i >= 0; i--) {
+ remaining -= mFrameCounts[i];
+ if (remaining <= 0) {
+ return i;
+ }
+ }
+ return 0;
+}
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index aa554cd..3d4929b 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -54,8 +54,11 @@
void reset();
private:
+ uint32_t findPercentile(int p);
+
JankBucket mBuckets[NUM_BUCKETS];
int64_t mThresholds[NUM_BUCKETS];
+ uint32_t mFrameCounts[128];
int64_t mFrameInterval;
uint32_t mTotalFrameCount;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1247105..d8a9d3e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -56,11 +56,13 @@
import android.service.voice.IVoiceInteractionSession;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.DebugUtils;
import android.util.SparseIntArray;
import android.view.Display;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.DumpHeapActivity;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ProcessMap;
@@ -1126,6 +1128,11 @@
boolean mAutoStopProfiler = false;
int mProfileType = 0;
String mOpenGlTraceApp = null;
+ final ArrayMap<String, Long> mMemWatchProcesses = new ArrayMap<>();
+ String mMemWatchDumpProcName;
+ String mMemWatchDumpFile;
+ int mMemWatchDumpPid;
+ int mMemWatchDumpUid;
final long[] mTmpLong = new long[1];
@@ -1268,6 +1275,8 @@
static final int DISMISS_DIALOG_MSG = 48;
static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 49;
static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 50;
+ static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 51;
+ static final int DELETE_DUMPHEAP_MSG = 52;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1822,6 +1831,78 @@
}
break;
}
+ case POST_DUMP_HEAP_NOTIFICATION_MSG: {
+ final String procName;
+ final int uid;
+ final long memLimit;
+ synchronized (ActivityManagerService.this) {
+ procName = mMemWatchDumpProcName;
+ uid = mMemWatchDumpUid;
+ Long limit = mMemWatchProcesses.get(procName);
+ memLimit = limit != null ? limit : 0;
+ }
+ if (procName == null) {
+ return;
+ }
+
+ if (DEBUG_PSS) Slog.d(TAG, "Showing dump heap notification from "
+ + procName + "/" + uid);
+
+ INotificationManager inm = NotificationManager.getService();
+ if (inm == null) {
+ return;
+ }
+
+ String text = mContext.getString(R.string.dump_heap_notification, procName);
+ Notification notification = new Notification();
+ notification.icon = com.android.internal.R.drawable.stat_sys_adb;
+ notification.when = 0;
+ notification.flags = Notification.FLAG_ONGOING_EVENT|Notification.FLAG_AUTO_CANCEL;
+ notification.tickerText = text;
+ notification.defaults = 0; // please be quiet
+ notification.sound = null;
+ notification.vibrate = null;
+ notification.color = mContext.getResources().getColor(
+ com.android.internal.R.color.system_notification_accent_color);
+ Intent deleteIntent = new Intent();
+ deleteIntent.setAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP);
+ notification.deleteIntent = PendingIntent.getBroadcastAsUser(mContext, 0,
+ deleteIntent, 0, UserHandle.OWNER);
+ Intent intent = new Intent();
+ intent.setClassName("android", DumpHeapActivity.class.getName());
+ intent.putExtra(DumpHeapActivity.KEY_PROCESS, procName);
+ intent.putExtra(DumpHeapActivity.KEY_SIZE, memLimit);
+ int userId = UserHandle.getUserId(uid);
+ notification.setLatestEventInfo(mContext, text,
+ mContext.getText(R.string.dump_heap_notification_detail),
+ PendingIntent.getActivityAsUser(mContext, 0, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT, null,
+ new UserHandle(userId)));
+
+ try {
+ int[] outId = new int[1];
+ inm.enqueueNotificationWithTag("android", "android", null,
+ R.string.dump_heap_notification,
+ notification, outId, userId);
+ } catch (RuntimeException e) {
+ Slog.w(ActivityManagerService.TAG,
+ "Error showing notification for dump heap", e);
+ } catch (RemoteException e) {
+ }
+ } break;
+ case DELETE_DUMPHEAP_MSG: {
+ revokeUriPermission(ActivityThread.currentActivityThread().getApplicationThread(),
+ DumpHeapActivity.JAVA_URI,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+ UserHandle.myUserId());
+ synchronized (ActivityManagerService.this) {
+ mMemWatchDumpFile = null;
+ mMemWatchDumpProcName = null;
+ mMemWatchDumpPid = -1;
+ mMemWatchDumpUid = -1;
+ }
+ } break;
}
}
};
@@ -1908,7 +1989,7 @@
if (pss != 0 && proc.thread != null && proc.setProcState == procState
&& proc.pid == pid && proc.lastPssTime == lastPssTime) {
num++;
- recordPssSample(proc, procState, pss, tmp[0],
+ recordPssSampleLocked(proc, procState, pss, tmp[0],
SystemClock.uptimeMillis());
}
}
@@ -5706,7 +5787,7 @@
for (String pkg : pkgs) {
synchronized (ActivityManagerService.this) {
if (forceStopPackageLocked(pkg, -1, false, false, false, false, false,
- 0, "finished booting")) {
+ 0, "query restart")) {
setResultCode(Activity.RESULT_OK);
return;
}
@@ -5716,6 +5797,19 @@
}
}, pkgFilter);
+ IntentFilter dumpheapFilter = new IntentFilter();
+ dumpheapFilter.addAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getBooleanExtra(DumpHeapActivity.EXTRA_DELAY_DELETE, false)) {
+ mHandler.sendEmptyMessageDelayed(POST_DUMP_HEAP_NOTIFICATION_MSG, 5*60*1000);
+ } else {
+ mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+ }
+ }
+ }, dumpheapFilter);
+
// Let system services know.
mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);
@@ -12741,6 +12835,22 @@
+ " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
}
}
+ if (mMemWatchProcesses.size() > 0) {
+ pw.println(" Mem watch processes:");
+ for (int i=0; i<mMemWatchProcesses.size(); i++) {
+ if (needSep) {
+ pw.println();
+ needSep = false;
+ }
+ pw.print(" "); pw.print(mMemWatchProcesses.keyAt(i));
+ pw.print(": "); DebugUtils.printSizeValue(pw, mMemWatchProcesses.valueAt(i));
+ pw.println();
+ }
+ pw.print(" mMemWatchDumpProcName="); pw.println(mMemWatchDumpProcName);
+ pw.print(" mMemWatchDumpFile="); pw.println(mMemWatchDumpFile);
+ pw.print(" mMemWatchDumpPid="); pw.print(mMemWatchDumpPid);
+ pw.print(" mMemWatchDumpUid="); pw.println(mMemWatchDumpUid);
+ }
if (mOpenGlTraceApp != null) {
if (dumpPackage == null || dumpPackage.equals(mOpenGlTraceApp)) {
if (needSep) {
@@ -13423,8 +13533,9 @@
pw.print(" ");
pw.print("state: cur="); pw.print(ProcessList.makeProcStateString(r.curProcState));
pw.print(" set="); pw.print(ProcessList.makeProcStateString(r.setProcState));
- pw.print(" lastPss="); pw.print(r.lastPss);
- pw.print(" lastCachedPss="); pw.println(r.lastCachedPss);
+ pw.print(" lastPss="); DebugUtils.printSizeValue(pw, r.lastPss*1024);
+ pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, r.lastCachedPss*1024);
+ pw.println();
pw.print(prefix);
pw.print(" ");
pw.print("cached="); pw.print(r.cached);
@@ -17232,7 +17343,7 @@
/**
* Record new PSS sample for a process.
*/
- void recordPssSample(ProcessRecord proc, int procState, long pss, long uss, long now) {
+ void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss, long now) {
EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss*1024, uss*1024);
proc.lastPssTime = now;
proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList);
@@ -17246,6 +17357,67 @@
if (procState >= ActivityManager.PROCESS_STATE_HOME) {
proc.lastCachedPss = pss;
}
+
+ Long check = mMemWatchProcesses.get(proc.processName);
+ if (check != null) {
+ if ((pss*1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) {
+ boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+ if (!isDebuggable) {
+ if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ isDebuggable = true;
+ }
+ }
+ if (isDebuggable) {
+ Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check + "; reporting");
+ final ProcessRecord myProc = proc;
+ final File heapdumpFile = DumpHeapProvider.getJavaFile();
+ mMemWatchDumpProcName = proc.processName;
+ mMemWatchDumpFile = heapdumpFile.toString();
+ mMemWatchDumpPid = proc.pid;
+ mMemWatchDumpUid = proc.uid;
+ BackgroundThread.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ revokeUriPermission(ActivityThread.currentActivityThread()
+ .getApplicationThread(),
+ DumpHeapActivity.JAVA_URI,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+ UserHandle.myUserId());
+ ParcelFileDescriptor fd = null;
+ try {
+ heapdumpFile.delete();
+ fd = ParcelFileDescriptor.open(heapdumpFile,
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE |
+ ParcelFileDescriptor.MODE_READ_WRITE);
+ IApplicationThread thread = myProc.thread;
+ if (thread != null) {
+ try {
+ if (DEBUG_PSS) Slog.d(TAG, "Requesting dump heap from "
+ + myProc + " to " + heapdumpFile);
+ thread.dumpHeap(true, heapdumpFile.toString(), fd);
+ } catch (RemoteException e) {
+ }
+ }
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } finally {
+ if (fd != null) {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+ });
+ } else {
+ Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check
+ + ", but debugging not enabled");
+ }
+ }
+ }
}
/**
@@ -17604,7 +17776,7 @@
// states, which well tend to give noisy data.
long start = SystemClock.uptimeMillis();
long pss = Debug.getPss(app.pid, mTmpLong, null);
- recordPssSample(app, app.curProcState, pss, mTmpLong[0], now);
+ recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], now);
mPendingPssProcesses.remove(app);
Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
+ " to " + app.curProcState + ": "
@@ -18424,6 +18596,38 @@
}
}
+ @Override
+ public void setDumpHeapDebugLimit(String processName, long maxMemSize) {
+ enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
+ "setDumpHeapDebugLimit()");
+ synchronized (this) {
+ if (maxMemSize > 0) {
+ mMemWatchProcesses.put(processName, maxMemSize);
+ mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+ } else {
+ mMemWatchProcesses.remove(processName);
+ }
+ }
+ }
+
+ @Override
+ public void dumpHeapFinished(String path) {
+ synchronized (this) {
+ if (Binder.getCallingPid() != mMemWatchDumpPid) {
+ Slog.w(TAG, "dumpHeapFinished: Calling pid " + Binder.getCallingPid()
+ + " does not match last pid " + mMemWatchDumpPid);
+ return;
+ }
+ if (mMemWatchDumpFile == null || !mMemWatchDumpFile.equals(path)) {
+ Slog.w(TAG, "dumpHeapFinished: Calling path " + path
+ + " does not match last path " + mMemWatchDumpFile);
+ return;
+ }
+ if (DEBUG_PSS) Slog.d(TAG, "Dump heap finished for " + path);
+ mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+ }
+ }
+
/** In this method we try to acquire our lock to make sure that we have not deadlocked */
public void monitor() {
synchronized (this) { }
diff --git a/services/core/java/com/android/server/am/DumpHeapProvider.java b/services/core/java/com/android/server/am/DumpHeapProvider.java
new file mode 100644
index 0000000..a8b639e
--- /dev/null
+++ b/services/core/java/com/android/server/am/DumpHeapProvider.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.server.am;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+public class DumpHeapProvider extends ContentProvider {
+ static final Object sLock = new Object();
+ static File sHeapDumpJavaFile;
+
+ static public File getJavaFile() {
+ synchronized (sLock) {
+ return sHeapDumpJavaFile;
+ }
+ }
+
+ @Override
+ public boolean onCreate() {
+ synchronized (sLock) {
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ File heapdumpDir = new File(systemDir, "heapdump");
+ heapdumpDir.mkdir();
+ sHeapDumpJavaFile = new File(heapdumpDir, "javaheap.bin");
+ }
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return "application/octet-stream";
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+ synchronized (sLock) {
+ String path = uri.getEncodedPath();
+ final String tag = Uri.decode(path);
+ if (tag.equals("/java")) {
+ return ParcelFileDescriptor.open(sHeapDumpJavaFile,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ } else {
+ throw new FileNotFoundException("Invalid path for " + uri);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index a6c616a..f374c86 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import android.util.ArraySet;
+import android.util.DebugUtils;
import android.util.EventLog;
import android.util.Slog;
import com.android.internal.app.ProcessStats;
@@ -248,8 +249,9 @@
pw.println();
pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
pw.print(" lruSeq="); pw.print(lruSeq);
- pw.print(" lastPss="); pw.print(lastPss);
- pw.print(" lastCachedPss="); pw.println(lastCachedPss);
+ pw.print(" lastPss="); DebugUtils.printSizeValue(pw, lastPss*1024);
+ pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, lastCachedPss*1024);
+ pw.println();
pw.print(prefix); pw.print("cached="); pw.print(cached);
pw.print(" empty="); pw.println(empty);
if (serviceb) {