diff options
16 files changed, 150 insertions, 63 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index f765620a2eb9..0fb85d25cf1a 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1342,6 +1342,7 @@ public class Activity extends ContextThemeWrapper 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 @@ public class Activity extends ContextThemeWrapper 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 adc592af03b1..6564a30c9893 100644 --- a/core/java/android/app/UiModeManager.java +++ b/core/java/android/app/UiModeManager.java @@ -232,7 +232,7 @@ public class UiModeManager { * 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 5bf3a7c43640..06c069c583b5 100644 --- a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java +++ b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java @@ -41,6 +41,7 @@ public class SQLiteCompatibilityWalFlags { 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 @@ public class SQLiteCompatibilityWalFlags { 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 @@ public class SQLiteCompatibilityWalFlags { 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 101fb821f4ce..9c639a5a9867 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -32,6 +32,7 @@ import android.util.Printer; 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 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } else { setSyncMode(SQLiteGlobal.getWALSyncMode()); } + maybeTruncateWalFile(); } else { setJournalMode(mConfiguration.journalMode == null ? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode); @@ -312,6 +314,40 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } } + /** + * 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 e6b6acf7b8ee..67e5f65d5a1f 100644 --- a/core/java/android/database/sqlite/SQLiteGlobal.java +++ b/core/java/android/database/sqlite/SQLiteGlobal.java @@ -164,4 +164,21 @@ public final class SQLiteGlobal { 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 fbe6f3ee7dff..e00ff205c082 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -12777,6 +12777,7 @@ public final class Settings { * 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 d21cb3e64b8c..8b3ce42b076b 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -44,6 +44,7 @@ import android.service.autofill.UserData; 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 @@ public final class AutofillManager { // 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 c503ef215ea1..8ebf303136ef 100644 --- a/core/java/android/widget/DigitalClock.java +++ b/core/java/android/widget/DigitalClock.java @@ -27,7 +27,7 @@ import android.util.AttributeSet; 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 396deb4d7a0a..c233ea8e78b7 100644 --- a/core/java/com/android/internal/os/KernelCpuProcReader.java +++ b/core/java/com/android/internal/os/KernelCpuProcReader.java @@ -24,13 +24,14 @@ import com.android.internal.annotations.VisibleForTesting; 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 @@ public class KernelCpuProcReader { 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 @@ public class KernelCpuProcReader { 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 @@ public class KernelCpuProcReader { 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 @@ public class KernelCpuProcReader { 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 a9d69c1bcbbe..a10c1975339d 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 a3ed1b0526d0..95af9a602577 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 230655de8a00..551a58ed7cb5 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 @@ public class SQLiteCompatibilityWalFlagsTest { 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 c3b984172802..e8f255f4dfc1 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.Intent; 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 @@ public class SliceManagerService extends ISliceManager.Stub { 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 2941e93d12dc..22ac65df4337 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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo 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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo 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 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo 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 1ae680f793ca..087bd6a80c73 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; 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } 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 a05e04dd6c7c..c56c3035e127 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 @@ class WindowStateAnimator { 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 @@ class WindowStateAnimator { 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); } |