Merge "Fixed check for null Anchor."
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index c28172c..f1c2f34 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -150,7 +150,7 @@
public void addPrimaryClipChangedListener(OnPrimaryClipChangedListener what) {
synchronized (mPrimaryClipChangedListeners) {
- if (mPrimaryClipChangedListeners.size() == 0) {
+ if (mPrimaryClipChangedListeners.isEmpty()) {
try {
mService.addPrimaryClipChangedListener(
mPrimaryClipChangedServiceListener, mContext.getOpPackageName());
@@ -165,7 +165,7 @@
public void removePrimaryClipChangedListener(OnPrimaryClipChangedListener what) {
synchronized (mPrimaryClipChangedListeners) {
mPrimaryClipChangedListeners.remove(what);
- if (mPrimaryClipChangedListeners.size() == 0) {
+ if (mPrimaryClipChangedListeners.isEmpty()) {
try {
mService.removePrimaryClipChangedListener(
mPrimaryClipChangedServiceListener);
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index fd1e24a..8f3a317 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -508,14 +508,14 @@
/** Create a ContentProviderOperation from this {@link Builder}. */
public ContentProviderOperation build() {
if (mType == TYPE_UPDATE) {
- if ((mValues == null || mValues.size() == 0)
- && (mValuesBackReferences == null || mValuesBackReferences.size() == 0)) {
+ if ((mValues == null || mValues.isEmpty())
+ && (mValuesBackReferences == null || mValuesBackReferences.isEmpty())) {
throw new IllegalArgumentException("Empty values");
}
}
if (mType == TYPE_ASSERT) {
- if ((mValues == null || mValues.size() == 0)
- && (mValuesBackReferences == null || mValuesBackReferences.size() == 0)
+ if ((mValues == null || mValues.isEmpty())
+ && (mValuesBackReferences == null || mValuesBackReferences.isEmpty())
&& (mExpectedCount == null)) {
throw new IllegalArgumentException("Empty values");
}
diff --git a/core/java/android/content/ContentValues.java b/core/java/android/content/ContentValues.java
index 3a87cb3..6f93798 100644
--- a/core/java/android/content/ContentValues.java
+++ b/core/java/android/content/ContentValues.java
@@ -204,6 +204,17 @@
}
/**
+ * Indicates whether this collection is empty.
+ *
+ * @return true iff size == 0
+ * {@hide}
+ * TODO: consider exposing this new method publicly
+ */
+ public boolean isEmpty() {
+ return mValues.isEmpty();
+ }
+
+ /**
* Remove a single value.
*
* @param key the name of the value to remove
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 8e17832..fe849b8 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1449,7 +1449,7 @@
sql.append('(');
Object[] bindArgs = null;
- int size = (initialValues != null && initialValues.size() > 0)
+ int size = (initialValues != null && !initialValues.isEmpty())
? initialValues.size() : 0;
if (size > 0) {
bindArgs = new Object[size];
@@ -1541,7 +1541,7 @@
*/
public int updateWithOnConflict(String table, ContentValues values,
String whereClause, String[] whereArgs, int conflictAlgorithm) {
- if (values == null || values.size() == 0) {
+ if (values == null || values.isEmpty()) {
throw new IllegalArgumentException("Empty values");
}
diff --git a/core/tests/coretests/README b/core/tests/coretests/README
index 4a69843..aced441 100644
--- a/core/tests/coretests/README
+++ b/core/tests/coretests/README
@@ -45,6 +45,10 @@
-e debug true
+To uninstall the package:
+
+ adb shell pm uninstall -k com.android.frameworks.coretests
+
For more arguments, see the guide to command=line testing:
https://developer.android.com/studio/test/command-line.html
diff --git a/core/tests/coretests/src/android/content/ContentTests.java b/core/tests/coretests/src/android/content/ContentTests.java
index a1299e3..567b79a 100644
--- a/core/tests/coretests/src/android/content/ContentTests.java
+++ b/core/tests/coretests/src/android/content/ContentTests.java
@@ -23,6 +23,7 @@
TestSuite suite = new TestSuite(ContentTests.class.getName());
suite.addTestSuite(AssetTest.class);
+ suite.addTestSuite(ContentValuesTest.class);
return suite;
}
}
diff --git a/core/tests/coretests/src/android/content/ContentValuesTest.java b/core/tests/coretests/src/android/content/ContentValuesTest.java
new file mode 100644
index 0000000..7b39939
--- /dev/null
+++ b/core/tests/coretests/src/android/content/ContentValuesTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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.content;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+
+/*
+ runtest -c android.content.ContentValuesTest frameworks-core
+
+ or
+
+ make -j256 FrameworksCoreTests && \
+ adb shell pm uninstall -k com.android.frameworks.coretests && \
+ adb install out/target/product/bullhead/testcases/FrameworksCoreTests/FrameworksCoreTests.apk && \
+ adb shell am instrument -w -e package android.content \
+ com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+*/
+public class ContentValuesTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testIsEmpty() throws Exception {
+ ContentValues cv = new ContentValues();
+ assertTrue(cv.isEmpty());
+ assertEquals(0, cv.size());
+
+ cv.put("key", "value");
+ assertFalse(cv.isEmpty());
+ assertEquals(1, cv.size());
+ }
+}
diff --git a/services/core/Android.mk b/services/core/Android.mk
index e35a171..099f557 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -22,7 +22,8 @@
services.net \
android.hardware.light@2.0-java \
android.hardware.power@1.0-java \
- android.hardware.tv.cec@1.0-java
+ android.hardware.tv.cec@1.0-java \
+ android.hidl.manager@1.0-java
LOCAL_STATIC_JAVA_LIBRARIES := \
tzdata_shared2 \
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index ce4ca02..80f89fc 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.hidl.manager.V1_0.IServiceManager;
import android.os.Debug;
import android.os.Handler;
import android.os.IPowerManager;
@@ -42,6 +43,9 @@
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
/** This class calls its monitor every minute. Killing this process if they don't return **/
public class Watchdog extends Thread {
@@ -75,6 +79,14 @@
"com.android.bluetooth", // Bluetooth service
};
+ public static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList(
+ "android.hardware.audio@2.0::IDevicesFactory",
+ "android.hardware.bluetooth@1.0::IBluetoothHci",
+ "android.hardware.camera.provider@2.4::ICameraProvider",
+ "android.hardware.vr@1.0::IVr",
+ "android.hardware.media.omx@1.0::IOmx"
+ );
+
static Watchdog sWatchdog;
/* This handler will be used to post message back onto the main thread */
@@ -344,6 +356,43 @@
return builder.toString();
}
+ private ArrayList<Integer> getInterestingHalPids() {
+ try {
+ IServiceManager serviceManager = IServiceManager.getService();
+ ArrayList<IServiceManager.InstanceDebugInfo> dump =
+ serviceManager.debugDump();
+ HashSet<Integer> pids = new HashSet<>();
+ for (IServiceManager.InstanceDebugInfo info : dump) {
+ if (info.pid == IServiceManager.PidConstant.NO_PID) {
+ continue;
+ }
+
+ if (!HAL_INTERFACES_OF_INTEREST.contains(info.interfaceName)) {
+ continue;
+ }
+
+ pids.add(info.pid);
+ }
+ return new ArrayList<Integer>(pids);
+ } catch (RemoteException e) {
+ return new ArrayList<Integer>();
+ }
+ }
+
+ private ArrayList<Integer> getInterestingNativePids() {
+ ArrayList<Integer> pids = getInterestingHalPids();
+
+ int[] nativePids = Process.getPidsForCommands(NATIVE_STACKS_OF_INTEREST);
+ if (nativePids != null) {
+ pids.ensureCapacity(pids.size() + nativePids.length);
+ for (int i : nativePids) {
+ pids.add(i);
+ }
+ }
+
+ return pids;
+ }
+
@Override
public void run() {
boolean waitedHalf = false;
@@ -400,7 +449,7 @@
ArrayList<Integer> pids = new ArrayList<Integer>();
pids.add(Process.myPid());
ActivityManagerService.dumpStackTraces(true, pids, null, null,
- NATIVE_STACKS_OF_INTEREST);
+ getInterestingNativePids());
waitedHalf = true;
}
continue;
@@ -417,13 +466,13 @@
// Then kill this process so that the system will restart.
EventLog.writeEvent(EventLogTags.WATCHDOG, subject);
- ArrayList<Integer> pids = new ArrayList<Integer>();
+ ArrayList<Integer> pids = new ArrayList<>();
pids.add(Process.myPid());
if (mPhonePid > 0) pids.add(mPhonePid);
// Pass !waitedHalf so that just in case we somehow wind up here without having
// dumped the halfway stacks, we properly re-initialize the trace file.
final File stack = ActivityManagerService.dumpStackTraces(
- !waitedHalf, pids, null, null, NATIVE_STACKS_OF_INTEREST);
+ !waitedHalf, pids, null, null, getInterestingNativePids());
// Give some extra time to make sure the stack traces get written.
// The system's been hanging for a minute, another second or two won't hurt much.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3eb236e..272fbf8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5468,11 +5468,12 @@
* appended to any existing file content.
* @param firstPids of dalvik VM processes to dump stack traces for first
* @param lastPids of dalvik VM processes to dump stack traces for last
- * @param nativeProcs optional list of native process names to dump stack crawls
+ * @param nativePids optional list of native pids to dump stack crawls
* @return file containing stack traces, or null if no dump file is configured
*/
public static File dumpStackTraces(boolean clearTraces, ArrayList<Integer> firstPids,
- ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids, String[] nativeProcs) {
+ ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids,
+ ArrayList<Integer> nativePids) {
String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
if (tracesPath == null || tracesPath.length() == 0) {
return null;
@@ -5488,7 +5489,7 @@
return null;
}
- dumpStackTraces(tracesPath, firstPids, processCpuTracker, lastPids, nativeProcs);
+ dumpStackTraces(tracesPath, firstPids, processCpuTracker, lastPids, nativePids);
return tracesFile;
}
@@ -5530,7 +5531,8 @@
}
private static void dumpStackTraces(String tracesPath, ArrayList<Integer> firstPids,
- ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids, String[] nativeProcs) {
+ ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids,
+ ArrayList<Integer> nativePids) {
// Use a FileObserver to detect when traces finish writing.
// The order of traces is considered important to maintain for legibility.
DumpStackFileObserver observer = new DumpStackFileObserver(tracesPath);
@@ -5551,18 +5553,15 @@
}
// Next collect the stacks of the native pids
- if (nativeProcs != null) {
- int[] pids = Process.getPidsForCommands(nativeProcs);
- if (pids != null) {
- for (int pid : pids) {
- if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
- final long sime = SystemClock.elapsedRealtime();
+ if (nativePids != null) {
+ for (int pid : nativePids) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
+ final long sime = SystemClock.elapsedRealtime();
- Debug.dumpNativeBacktraceToFileTimeout(
- pid, tracesPath, DumpStackFileObserver.TRACE_DUMP_TIMEOUT_SECONDS);
- if (DEBUG_ANR) Slog.d(TAG, "Done with native pid " + pid
- + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
- }
+ Debug.dumpNativeBacktraceToFileTimeout(
+ pid, tracesPath, DumpStackFileObserver.TRACE_DUMP_TIMEOUT_SECONDS);
+ if (DEBUG_ANR) Slog.d(TAG, "Done with native pid " + pid
+ + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9a4f804..28a4e1a 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -759,6 +759,12 @@
}
}
+ final void removeActivitiesFromLRUListLocked(TaskRecord task) {
+ for (ActivityRecord r : task.mActivities) {
+ mLRUActivities.remove(r);
+ }
+ }
+
final boolean updateLRUListLocked(ActivityRecord r) {
final boolean hadit = mLRUActivities.remove(r);
mLRUActivities.add(r);
@@ -4947,6 +4953,7 @@
}
}
mTaskHistory.remove(task);
+ removeActivitiesFromLRUListLocked(task);
updateTaskMovement(task, true);
if (mode == REMOVE_TASK_MODE_DESTROYING && task.mActivities.isEmpty()) {
@@ -5114,6 +5121,7 @@
// Apps may depend on onResume()/onPause() being called in pairs.
if (setResume) {
mResumedActivity = r;
+ updateLRUListLocked(r);
}
// If the activity was previously pausing, then ensure we transfer that as well
if (setPause) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 27b8e91..8559dca 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3555,8 +3555,16 @@
stackHeader.append(" mFullscreen=" + stack.mFullscreen);
stackHeader.append("\n");
stackHeader.append(" mBounds=" + stack.mBounds);
- printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
- needSep, stackHeader.toString());
+
+ final boolean printedStackHeader = stack.dumpActivitiesLocked(fd, pw, dumpAll,
+ dumpClient, dumpPackage, needSep, stackHeader.toString());
+ printed |= printedStackHeader;
+ if (!printedStackHeader) {
+ // Ensure we always dump the stack header even if there are no activities
+ pw.println();
+ pw.println(stackHeader);
+ }
+
printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false,
!dumpAll, false, dumpPackage, true,
" Running activities (most recent first):", null);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 1b7b225..4bd06b7 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1790,21 +1790,7 @@
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
- if (mLaunchBounds != null) {
- mInTask.updateOverrideConfiguration(mLaunchBounds);
- int stackId = mInTask.getLaunchStackId();
- if (stackId != mInTask.getStackId()) {
- mInTask.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE,
- DEFER_RESUME, "inTaskToFront");
- stackId = mInTask.getStackId();
- }
- if (StackId.resizeStackWithLaunchBounds(stackId)) {
- mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
- }
- }
mTargetStack = mInTask.getStack();
- mTargetStack.moveTaskToFrontLocked(
- mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront");
// Check whether we should actually launch the new activity in to the task,
// or just reuse the current activity on top.
@@ -1813,6 +1799,8 @@
&& top.userId == mStartActivity.userId) {
if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| mLaunchSingleTop || mLaunchSingleTask) {
+ mTargetStack.moveTaskToFrontLocked(mInTask, mNoAnimation, mOptions,
+ mStartActivity.appTimeTracker, "inTaskToFront");
ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and the client said not to do
@@ -1826,12 +1814,31 @@
}
if (!mAddingToTask) {
+ mTargetStack.moveTaskToFrontLocked(mInTask, mNoAnimation, mOptions,
+ mStartActivity.appTimeTracker, "inTaskToFront");
// We don't actually want to have this activity added to the task, so just
// stop here but still tell the caller that we consumed the intent.
ActivityOptions.abort(mOptions);
return START_TASK_TO_FRONT;
}
+ if (mLaunchBounds != null) {
+ mInTask.updateOverrideConfiguration(mLaunchBounds);
+ int stackId = mInTask.getLaunchStackId();
+ if (stackId != mInTask.getStackId()) {
+ mInTask.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE,
+ DEFER_RESUME, "inTaskToFront");
+ stackId = mInTask.getStackId();
+ mTargetStack = mInTask.getStack();
+ }
+ if (StackId.resizeStackWithLaunchBounds(stackId)) {
+ mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
+ }
+ }
+
+ mTargetStack.moveTaskToFrontLocked(
+ mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront");
+
addOrReparentStartingActivity(mInTask, "setTaskFromInTask");
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ " in explicit task " + mStartActivity.task);
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index f927cce..7b1af38 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -870,12 +870,22 @@
nativeProcs = NATIVE_STACKS_OF_INTEREST;
}
+ int[] pids = Process.getPidsForCommands(nativeProcs);
+ ArrayList<Integer> nativePids = null;
+
+ if (pids != null) {
+ nativePids = new ArrayList<Integer>(pids.length);
+ for (int i : pids) {
+ nativePids.add(i);
+ }
+ }
+
// For background ANRs, don't pass the ProcessCpuTracker to
// avoid spending 1/2 second collecting stats to rank lastPids.
File tracesFile = mService.dumpStackTraces(true, firstPids,
(isSilentANR) ? null : processCpuTracker,
(isSilentANR) ? null : lastPids,
- nativeProcs);
+ nativePids);
String cpuInfo = null;
if (ActivityManagerService.MONITOR_CPU_USAGE) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 1b28db7..e55e073 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -20,6 +20,7 @@
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.os.Build;
+import android.os.SystemProperties;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.TimeUtils;
@@ -56,6 +57,9 @@
private static final boolean DEBUG = UsageStatsService.DEBUG;
private static final String BAK_SUFFIX = ".bak";
private static final String CHECKED_IN_SUFFIX = UsageStatsXml.CHECKED_IN_SUFFIX;
+ private static final String RETENTION_LEN_KEY = "ro.usagestats.chooser.retention";
+ private static final int SELECTION_LOG_RETENTION_LEN =
+ SystemProperties.getInt(RETENTION_LEN_KEY, 14);
private final Object mLock = new Object();
private final File[] mIntervalDirs;
@@ -504,7 +508,7 @@
mCal.getTimeInMillis());
mCal.setTimeInMillis(currentTimeMillis);
- mCal.addDays(-14);
+ mCal.addDays(-SELECTION_LOG_RETENTION_LEN);
for (int i = 0; i < mIntervalDirs.length; ++i) {
pruneChooserCountsOlderThan(mIntervalDirs[i], mCal.getTimeInMillis());
}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/font_test.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/font_test.png
index 957831d..736b287 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/font_test.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/font_test.png
Binary files differ