Merge "Fix malformed Javadoc." into pi-dev
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f765620..0fb85d2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1342,6 +1342,7 @@
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
getApplication().dispatchActivityResumed(this);
mActivityTransitionState.onResume(this, isTopOfTask());
+ enableAutofillCompatibilityIfNeeded();
if (mAutoFillResetNeeded) {
if (!mAutoFillIgnoreFirstResumePause) {
View focus = getCurrentFocus();
@@ -7108,7 +7109,6 @@
mWindow.setColorMode(info.colorMode);
setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
- enableAutofillCompatibilityIfNeeded();
}
private void enableAutofillCompatibilityIfNeeded() {
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index adc592a..6564a30 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -232,7 +232,7 @@
* Changes to night mode take effect globally and will result in a configuration change
* (and potentially an Activity lifecycle event) being applied to all running apps.
* Developers interested in an app-local implementation of night mode should consider using
- * {@link androidx.appcompat.app.AppCompatDelegate#setDefaultNightMode(int)} to manage the
+ * {@link android.support.v7.app.AppCompatDelegate#setDefaultNightMode(int)} to manage the
* -night qualifier locally.
*
* @param mode the night mode to set
diff --git a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java
index 5bf3a7c..06c069c 100644
--- a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java
+++ b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java
@@ -41,6 +41,7 @@
private static volatile boolean sFlagsSet;
private static volatile boolean sCompatibilityWalSupported;
private static volatile String sWALSyncMode;
+ private static volatile long sTruncateSize = -1;
// This flag is used to avoid recursive initialization due to circular dependency on Settings
private static volatile boolean sCallingGlobalSettings;
@@ -71,6 +72,19 @@
return sWALSyncMode;
}
+ /**
+ * Override {@link com.android.internal.R.integer#db_wal_truncate_size}.
+ *
+ * @return the value set in the global setting, or -1 if a value is not set.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public static long getTruncateSize() {
+ initIfNeeded();
+ return sTruncateSize;
+ }
+
private static void initIfNeeded() {
if (sInitialized || sCallingGlobalSettings) {
return;
@@ -115,6 +129,7 @@
sCompatibilityWalSupported = parser.getBoolean("compatibility_wal_supported",
SQLiteGlobal.isCompatibilityWalSupported());
sWALSyncMode = parser.getString("wal_syncmode", SQLiteGlobal.getWALSyncMode());
+ sTruncateSize = parser.getInt("truncate_size", -1);
Log.i(TAG, "Read compatibility WAL flags: compatibility_wal_supported="
+ sCompatibilityWalSupported + ", wal_syncmode=" + sWALSyncMode);
sFlagsSet = true;
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 101fb82..9c639a5 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -32,6 +32,7 @@
import dalvik.system.BlockGuard;
import dalvik.system.CloseGuard;
+import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
@@ -303,6 +304,7 @@
} else {
setSyncMode(SQLiteGlobal.getWALSyncMode());
}
+ maybeTruncateWalFile();
} else {
setJournalMode(mConfiguration.journalMode == null
? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode);
@@ -312,6 +314,40 @@
}
}
+ /**
+ * If the WAL file exists and larger than a threshold, truncate it by executing
+ * PRAGMA wal_checkpoint.
+ */
+ private void maybeTruncateWalFile() {
+ final long threshold = SQLiteGlobal.getWALTruncateSize();
+ if (DEBUG) {
+ Log.d(TAG, "Truncate threshold=" + threshold);
+ }
+ if (threshold == 0) {
+ return;
+ }
+
+ final File walFile = new File(mConfiguration.path + "-wal");
+ if (!walFile.isFile()) {
+ return;
+ }
+ final long size = walFile.length();
+ if (size < threshold) {
+ if (DEBUG) {
+ Log.d(TAG, walFile.getAbsolutePath() + " " + size + " bytes: No need to truncate");
+ }
+ return;
+ }
+
+ Log.i(TAG, walFile.getAbsolutePath() + " " + size + " bytes: Bigger than "
+ + threshold + "; truncating");
+ try {
+ executeForString("PRAGMA wal_checkpoint(TRUNCATE)", null, null);
+ } catch (SQLiteException e) {
+ Log.w(TAG, "Failed to truncate the -wal file", e);
+ }
+ }
+
private void setSyncMode(String newValue) {
String value = executeForString("PRAGMA synchronous", null, null);
if (!canonicalizeSyncMode(value).equalsIgnoreCase(
diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java
index e6b6acf..67e5f65 100644
--- a/core/java/android/database/sqlite/SQLiteGlobal.java
+++ b/core/java/android/database/sqlite/SQLiteGlobal.java
@@ -164,4 +164,21 @@
com.android.internal.R.integer.db_default_idle_connection_timeout));
}
+ /**
+ * When opening a database, if the WAL file is larger than this size, we'll truncate it.
+ *
+ * (If it's 0, we do not truncate.)
+ *
+ * @hide
+ */
+ public static long getWALTruncateSize() {
+ final long setting = SQLiteCompatibilityWalFlags.getTruncateSize();
+ if (setting >= 0) {
+ return setting;
+ }
+ return SystemProperties.getInt("debug.sqlite.wal.truncatesize",
+ Resources.getSystem().getInteger(
+ com.android.internal.R.integer.db_wal_truncate_size));
+ }
+
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fbe6f3e..e00ff20 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12777,6 +12777,7 @@
* Supported keys:
* compatibility_wal_supported (boolean)
* wal_syncmode (String)
+ * truncate_size (int)
*
* @hide
*/
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index d21cb3e..8b3ce42 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -44,6 +44,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.Choreographer;
import android.view.KeyEvent;
@@ -548,6 +549,9 @@
// different bridge based on which activity is currently focused
// in the current process. Since compat would be rarely used, just
// create and register a new instance every time.
+ if (sDebug) {
+ Slog.d(TAG, "creating CompatibilityBridge for " + mContext);
+ }
mCompatibilityBridge = new CompatibilityBridge();
}
}
diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java
index c503ef2..8ebf303 100644
--- a/core/java/android/widget/DigitalClock.java
+++ b/core/java/android/widget/DigitalClock.java
@@ -27,7 +27,7 @@
import java.util.Calendar;
/**
- * Like AnalogClock, but digital. Shows seconds.
+ * Like AnalogClock, but digital.
*
* @deprecated It is recommended you use {@link TextClock} instead.
*/
diff --git a/core/java/com/android/internal/os/KernelCpuProcReader.java b/core/java/com/android/internal/os/KernelCpuProcReader.java
index 396deb4..c233ea8 100644
--- a/core/java/com/android/internal/os/KernelCpuProcReader.java
+++ b/core/java/com/android/internal/os/KernelCpuProcReader.java
@@ -24,13 +24,14 @@
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
+import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
+import java.util.Arrays;
/**
* Reads cpu time proc files with throttling (adjustable interval).
@@ -55,7 +56,6 @@
private static final int ERROR_THRESHOLD = 5;
// Throttle interval in milliseconds
private static final long DEFAULT_THROTTLE_INTERVAL = 3000L;
- private static final int INITIAL_BUFFER_SIZE = 8 * 1024;
private static final int MAX_BUFFER_SIZE = 1024 * 1024;
private static final String PROC_UID_FREQ_TIME = "/proc/uid_cpupower/time_in_state";
private static final String PROC_UID_ACTIVE_TIME = "/proc/uid_cpupower/concurrent_active_time";
@@ -84,13 +84,12 @@
private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL;
private long mLastReadTime = Long.MIN_VALUE;
private final Path mProc;
- private ByteBuffer mBuffer;
+ private byte[] mBuffer = new byte[8 * 1024];
+ private int mContentSize;
@VisibleForTesting
public KernelCpuProcReader(String procFile) {
mProc = Paths.get(procFile);
- mBuffer = ByteBuffer.allocateDirect(INITIAL_BUFFER_SIZE);
- mBuffer.clear();
}
/**
@@ -108,38 +107,45 @@
return null;
}
if (SystemClock.elapsedRealtime() < mLastReadTime + mThrottleInterval) {
- if (mBuffer.limit() > 0 && mBuffer.limit() < mBuffer.capacity()) {
- // mBuffer has data.
- return mBuffer.asReadOnlyBuffer().order(ByteOrder.nativeOrder());
+ if (mContentSize > 0) {
+ return ByteBuffer.wrap(mBuffer, 0, mContentSize).asReadOnlyBuffer()
+ .order(ByteOrder.nativeOrder());
}
return null;
}
mLastReadTime = SystemClock.elapsedRealtime();
- mBuffer.clear();
+ mContentSize = 0;
final int oldMask = StrictMode.allowThreadDiskReadsMask();
- try (FileChannel fc = FileChannel.open(mProc, StandardOpenOption.READ)) {
- while (fc.read(mBuffer) == mBuffer.capacity()) {
- if (!resize()) {
- mErrors++;
- Slog.e(TAG, "Proc file is too large: " + mProc);
- return null;
+ try (InputStream in = Files.newInputStream(mProc)) {
+ int numBytes = 0;
+ int curr;
+ while ((curr = in.read(mBuffer, numBytes, mBuffer.length - numBytes)) >= 0) {
+ numBytes += curr;
+ if (numBytes == mBuffer.length) {
+ // Hit the limit. Resize mBuffer.
+ if (mBuffer.length == MAX_BUFFER_SIZE) {
+ mErrors++;
+ Slog.e(TAG, "Proc file is too large: " + mProc);
+ return null;
+ }
+ mBuffer = Arrays.copyOf(mBuffer,
+ Math.min(mBuffer.length << 1, MAX_BUFFER_SIZE));
}
- fc.position(0);
}
+ mContentSize = numBytes;
+ return ByteBuffer.wrap(mBuffer, 0, mContentSize).asReadOnlyBuffer()
+ .order(ByteOrder.nativeOrder());
} catch (NoSuchFileException | FileNotFoundException e) {
// Happens when the kernel does not provide this file. Not a big issue. Just log it.
mErrors++;
Slog.w(TAG, "File not exist: " + mProc);
- return null;
} catch (IOException e) {
mErrors++;
Slog.e(TAG, "Error reading: " + mProc, e);
- return null;
} finally {
StrictMode.setThreadPolicyMask(oldMask);
}
- mBuffer.flip();
- return mBuffer.asReadOnlyBuffer().order(ByteOrder.nativeOrder());
+ return null;
}
/**
@@ -153,14 +159,4 @@
mThrottleInterval = throttleInterval;
}
}
-
- private boolean resize() {
- if (mBuffer.capacity() >= MAX_BUFFER_SIZE) {
- return false;
- }
- int newSize = Math.min(mBuffer.capacity() << 1, MAX_BUFFER_SIZE);
- // Slog.i(TAG, "Resize buffer " + mBuffer.capacity() + " => " + newSize);
- mBuffer = ByteBuffer.allocateDirect(newSize);
- return true;
- }
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a9d69c1..a10c197 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1873,6 +1873,10 @@
truncate it after committing the transaction. -->
<integer name="db_journal_size_limit">524288</integer>
+ <!-- When opening a database with WAL enabled and if the wal file already exists and larger
+ than this size in bytes, we'll truncate it. -->
+ <integer name="db_wal_truncate_size">1048576</integer>
+
<!-- The database synchronization mode when using the default journal mode.
FULL is safest and preserves durability at the cost of extra fsyncs.
NORMAL also preserves durability in non-WAL modes and uses checksums to ensure
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a3ed1b0..95af9a6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3415,4 +3415,6 @@
<java-symbol type="string" name="config_misprovisionedDeviceModel" />
<java-symbol type="string" name="config_misprovisionedBrandValue" />
+
+ <java-symbol type="integer" name="db_wal_truncate_size" />
</resources>
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
index 230655d..551a58e 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
@@ -62,18 +62,24 @@
assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet());
assertFalse(SQLiteCompatibilityWalFlags.isCompatibilityWalSupported());
assertEquals("OFF", SQLiteCompatibilityWalFlags.getWALSyncMode());
+ assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize());
SQLiteCompatibilityWalFlags.init("wal_syncmode=VALUE");
assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet());
assertEquals(SQLiteGlobal.isCompatibilityWalSupported(),
SQLiteCompatibilityWalFlags.isCompatibilityWalSupported());
assertEquals("VALUE", SQLiteCompatibilityWalFlags.getWALSyncMode());
+ assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize());
SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true");
assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet());
assertEquals(SQLiteGlobal.getWALSyncMode(),
SQLiteCompatibilityWalFlags.getWALSyncMode());
assertTrue(SQLiteCompatibilityWalFlags.isCompatibilityWalSupported());
+ assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize());
+
+ SQLiteCompatibilityWalFlags.init("truncate_size=1024");
+ assertEquals(1024, SQLiteCompatibilityWalFlags.getTruncateSize());
SQLiteCompatibilityWalFlags.reset();
SQLiteCompatibilityWalFlags.init("Invalid value");
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index c3b9841..e8f255f 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -42,6 +42,7 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Binder;
@@ -395,30 +396,11 @@
private String getProviderPkg(Uri uri, int user) {
long ident = Binder.clearCallingIdentity();
try {
- IBinder token = new Binder();
- IActivityManager activityManager = ActivityManager.getService();
- ContentProviderHolder holder = null;
String providerName = getUriWithoutUserId(uri).getAuthority();
- try {
- try {
- holder = activityManager.getContentProviderExternal(
- providerName, getUserIdFromUri(uri, user), token);
- if (holder != null && holder.info != null) {
- return holder.info.packageName;
- } else {
- return null;
- }
- } finally {
- if (holder != null && holder.provider != null) {
- activityManager.removeContentProviderExternal(providerName, token);
- }
- }
- } catch (RemoteException e) {
- // Can't happen.
- throw e.rethrowAsRuntimeException();
- }
+ ProviderInfo provider = mContext.getPackageManager().resolveContentProviderAsUser(
+ providerName, 0, getUserIdFromUri(uri, user));
+ return provider.packageName;
} finally {
- // I know, the double finally seems ugly, but seems safest for the identity.
Binder.restoreCallingIdentity(ident);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2941e93..22ac65d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -400,6 +400,9 @@
private MagnificationSpec mMagnificationSpec;
+ /** Caches the value whether told display manager that we have content. */
+ private boolean mLastHasContent;
+
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
final AppWindowToken atoken = w.mAppToken;
@@ -2916,8 +2919,9 @@
forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
prepareSurfaces();
+ mLastHasContent = mTmpApplySurfaceChangesTransactionState.displayHasContent;
mService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
- mTmpApplySurfaceChangesTransactionState.displayHasContent,
+ mLastHasContent,
mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferredModeId,
true /* inTraversal, must call performTraversalInTrans... below */);
@@ -4052,4 +4056,11 @@
private boolean canUpdateImeTarget() {
return mDeferUpdateImeTargetCount == 0;
}
+
+ /**
+ * @return Cached value whether we told display manager that we have content.
+ */
+ boolean getLastHasContent() {
+ return mLastHasContent;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1ae680f..087bd6a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -85,6 +85,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
@@ -4248,10 +4249,15 @@
}
if (!mWinAnimator.mLastHidden || wasDeferred) {
mWinAnimator.hide(reason);
+ getDisplayContent().mWallpaperController.mDeferredHideWallpaper = null;
dispatchWallpaperVisibility(false);
final DisplayContent displayContent = getDisplayContent();
if (displayContent != null) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ if (DEBUG_LAYOUT_REPEATS) {
+ mService.mWindowPlacerLocked.debugLayoutRepeats("hideWallpaperWindow " + this,
+ displayContent.pendingLayoutChanges);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index a05e04d..c56c303 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1126,7 +1126,7 @@
setSurfaceBoundariesLocked(recoveringMemory);
- if (mIsWallpaper && !mWin.mWallpaperVisible) {
+ if (mIsWallpaper && !w.mWallpaperVisible) {
// Wallpaper is no longer visible and there is no wp target => hide it.
hide("prepareSurfaceLocked");
} else if (w.isParentWindowHidden() || !w.isOnScreen()) {
@@ -1185,11 +1185,18 @@
if (mIsWallpaper) {
w.dispatchWallpaperVisibility(true);
}
- // This draw means the difference between unique content and mirroring.
- // Run another pass through performLayout to set mHasContent in the
- // LogicalDisplay.
- mAnimator.setPendingLayoutChanges(w.getDisplayId(),
- FINISH_LAYOUT_REDO_ANIM);
+ if (!w.getDisplayContent().getLastHasContent()) {
+ // This draw means the difference between unique content and mirroring.
+ // Run another pass through performLayout to set mHasContent in the
+ // LogicalDisplay.
+ mAnimator.setPendingLayoutChanges(w.getDisplayId(),
+ FINISH_LAYOUT_REDO_ANIM);
+ if (DEBUG_LAYOUT_REPEATS) {
+ mService.mWindowPlacerLocked.debugLayoutRepeats(
+ "showSurfaceRobustlyLocked " + w,
+ mAnimator.getPendingLayoutChanges(w.getDisplayId()));
+ }
+ }
} else {
w.setOrientationChanging(false);
}