diff options
14 files changed, 375 insertions, 152 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java index 4c11947212f9..1bb9e967c025 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java @@ -18,13 +18,20 @@ package com.android.server.job.controllers; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlarmManager; import android.app.AlarmManager.OnAlarmListener; +import android.content.ContentResolver; import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; import android.os.Process; import android.os.UserHandle; import android.os.WorkSource; +import android.provider.Settings; +import android.util.KeyValueListParser; import android.util.Log; import android.util.Slog; import android.util.TimeUtils; @@ -32,6 +39,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.job.ConstantsProto; import com.android.server.job.JobSchedulerService; import com.android.server.job.StateControllerProto; @@ -55,6 +63,9 @@ public final class TimeController extends StateController { /** Delay alarm tag for logging purposes */ private final String DELAY_TAG = "*job.delay*"; + private final Handler mHandler; + private final TcConstants mTcConstants; + private long mNextJobExpiredElapsedMillis; private long mNextDelayExpiredElapsedMillis; @@ -70,6 +81,14 @@ public final class TimeController extends StateController { mNextJobExpiredElapsedMillis = Long.MAX_VALUE; mNextDelayExpiredElapsedMillis = Long.MAX_VALUE; mChainedAttributionEnabled = mService.isChainedAttributionEnabled(); + + mHandler = new Handler(mContext.getMainLooper()); + mTcConstants = new TcConstants(mHandler); + } + + @Override + public void onSystemServicesReady() { + mTcConstants.start(mContext.getContentResolver()); } /** @@ -294,8 +313,7 @@ public final class TimeController extends StateController { } else { if (!wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) { if (DEBUG) { - Slog.i(TAG, - "Skipping " + job + " because delay won't make it ready."); + Slog.i(TAG, "Skipping " + job + " because delay won't make it ready."); } continue; } @@ -354,7 +372,8 @@ public final class TimeController extends StateController { /** * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's * delay will expire. - * This alarm <b>will</b> wake up the phone. + * This alarm <b>will not</b> wake up the phone if + * {@link TcConstants#USE_NON_WAKEUP_ALARM_FOR_DELAY} is true. */ private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) { alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis); @@ -362,8 +381,11 @@ public final class TimeController extends StateController { return; } mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis; - updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener, - mNextDelayExpiredElapsedMillis, ws); + final int alarmType = + mTcConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY + ? AlarmManager.ELAPSED_REALTIME : AlarmManager.ELAPSED_REALTIME_WAKEUP; + updateAlarmWithListenerLocked(DELAY_TAG, alarmType, + mNextDelayExpiredListener, mNextDelayExpiredElapsedMillis, ws); } /** @@ -377,16 +399,16 @@ public final class TimeController extends StateController { return; } mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis; - updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener, - mNextJobExpiredElapsedMillis, ws); + updateAlarmWithListenerLocked(DEADLINE_TAG, AlarmManager.ELAPSED_REALTIME_WAKEUP, + mDeadlineExpiredListener, mNextJobExpiredElapsedMillis, ws); } private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) { return Math.max(proposedAlarmTimeElapsedMillis, sElapsedRealtimeClock.millis()); } - private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener, - long alarmTimeElapsed, WorkSource ws) { + private void updateAlarmWithListenerLocked(String tag, @AlarmManager.AlarmType int alarmType, + OnAlarmListener listener, long alarmTimeElapsed, WorkSource ws) { ensureAlarmServiceLocked(); if (alarmTimeElapsed == Long.MAX_VALUE) { mAlarmService.cancel(listener); @@ -394,7 +416,7 @@ public final class TimeController extends StateController { if (DEBUG) { Slog.d(TAG, "Setting " + tag + " for: " + alarmTimeElapsed); } - mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsed, + mAlarmService.set(alarmType, alarmTimeElapsed, AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, ws); } } @@ -422,9 +444,77 @@ public final class TimeController extends StateController { }; @VisibleForTesting - void recheckAlarmsLocked() { - checkExpiredDeadlinesAndResetAlarm(); - checkExpiredDelaysAndResetAlarm(); + class TcConstants extends ContentObserver { + private ContentResolver mResolver; + private final KeyValueListParser mParser = new KeyValueListParser(','); + + private static final String KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY = + "use_non_wakeup_delay_alarm"; + + private static final boolean DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY = true; + + /** + * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't + * ready now. + */ + public boolean USE_NON_WAKEUP_ALARM_FOR_DELAY = DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY; + + /** + * Creates a content observer. + * + * @param handler The handler to run {@link #onChange} on, or null if none. + */ + TcConstants(Handler handler) { + super(handler); + } + + private void start(ContentResolver resolver) { + mResolver = resolver; + mResolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS), false, this); + onChange(true, null); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + final String constants = Settings.Global.getString( + mResolver, Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS); + + try { + mParser.setString(constants); + } catch (Exception e) { + // Failed to parse the settings string, log this and move on with defaults. + Slog.e(TAG, "Bad jobscheduler time controller settings", e); + } + + USE_NON_WAKEUP_ALARM_FOR_DELAY = mParser.getBoolean( + KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY, DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY); + // Intentionally not calling checkExpiredDelaysAndResetAlarm() here. There's no need to + // iterate through the entire list again for this constant change. The next delay alarm + // that is set will make use of the new constant value. + } + + private void dump(IndentingPrintWriter pw) { + pw.println(); + pw.println("TimeController:"); + pw.increaseIndent(); + pw.printPair(KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY, + USE_NON_WAKEUP_ALARM_FOR_DELAY).println(); + pw.decreaseIndent(); + } + + private void dump(ProtoOutputStream proto) { + final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER); + proto.write(ConstantsProto.TimeController.USE_NON_WAKEUP_ALARM_FOR_DELAY, + USE_NON_WAKEUP_ALARM_FOR_DELAY); + proto.end(tcToken); + } + } + + @VisibleForTesting + @NonNull + TcConstants getTcConstants() { + return mTcConstants; } @Override @@ -501,4 +591,14 @@ public final class TimeController extends StateController { proto.end(mToken); proto.end(token); } + + @Override + public void dumpConstants(IndentingPrintWriter pw) { + mTcConstants.dump(pw); + } + + @Override + public void dumpConstants(ProtoOutputStream proto) { + mTcConstants.dump(proto); + } } diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index ed2b99187b95..f9b96c50e0b8 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -242,7 +242,7 @@ public final class UiAutomation { mUiAutomationConnection.connect(mClient, flags); mFlags = flags; } catch (RemoteException re) { - throw new RuntimeException("Error while connecting UiAutomation", re); + throw new RuntimeException("Error while connecting " + this, re); } synchronized (mLock) { @@ -255,7 +255,7 @@ public final class UiAutomation { final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; final long remainingTimeMillis = CONNECT_TIMEOUT_MILLIS - elapsedTimeMillis; if (remainingTimeMillis <= 0) { - throw new RuntimeException("Error while connecting UiAutomation"); + throw new RuntimeException("Error while connecting " + this); } try { mLock.wait(remainingTimeMillis); @@ -290,7 +290,7 @@ public final class UiAutomation { synchronized (mLock) { if (mIsConnecting) { throw new IllegalStateException( - "Cannot call disconnect() while connecting!"); + "Cannot call disconnect() while connecting " + this); } throwIfNotConnectedLocked(); mConnectionId = CONNECTION_ID_UNDEFINED; @@ -299,7 +299,7 @@ public final class UiAutomation { // Calling out without a lock held. mUiAutomationConnection.disconnect(); } catch (RemoteException re) { - throw new RuntimeException("Error while disconnecting UiAutomation", re); + throw new RuntimeException("Error while disconnecting " + this, re); } finally { mRemoteCallbackThread.quit(); mRemoteCallbackThread = null; @@ -1184,19 +1184,29 @@ public final class UiAutomation { return result; } + @Override + public String toString() { + final StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("UiAutomation@").append(Integer.toHexString(hashCode())); + stringBuilder.append("[id=").append(mConnectionId); + stringBuilder.append(", flags=").append(mFlags); + stringBuilder.append("]"); + return stringBuilder.toString(); + } + private boolean isConnectedLocked() { return mConnectionId != CONNECTION_ID_UNDEFINED; } private void throwIfConnectedLocked() { if (mConnectionId != CONNECTION_ID_UNDEFINED) { - throw new IllegalStateException("UiAutomation not connected!"); + throw new IllegalStateException("UiAutomation not connected, " + this); } } private void throwIfNotConnectedLocked() { if (!isConnectedLocked()) { - throw new IllegalStateException("UiAutomation not connected!"); + throw new IllegalStateException("UiAutomation not connected, " + this); } } @@ -1220,6 +1230,9 @@ public final class UiAutomation { mConnectionId = connectionId; mLock.notifyAll(); } + if (Build.IS_DEBUGGABLE) { + Log.v(LOG_TAG, "Init " + UiAutomation.this); + } } @Override diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 65c11d7c8ca2..f297c0631a30 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -1033,10 +1033,12 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall /** @hide */ public final void setTransportLoggingEnabled(boolean enabled) { - if (enabled) { - mTransport.mInterface = new LoggingContentInterface(getClass().getSimpleName(), this); - } else { - mTransport.mInterface = this; + if (mTransport != null) { + if (enabled) { + mTransport.mInterface = new LoggingContentInterface(getClass().getSimpleName(), this); + } else { + mTransport.mInterface = this; + } } } diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 2299aad6f79a..a959913f6fb0 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -3592,10 +3592,23 @@ public final class MediaStore { } /** @hide */ + public static Uri scanFile(ContentProviderClient client, File file) { + return scan(client, SCAN_FILE_CALL, file, false); + } + + /** @hide */ private static Uri scan(Context context, String method, File file, boolean originatedFromShell) { final ContentResolver resolver = context.getContentResolver(); try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY)) { + return scan(client, method, file, originatedFromShell); + } + } + + /** @hide */ + private static Uri scan(ContentProviderClient client, String method, File file, + boolean originatedFromShell) { + try { final Bundle in = new Bundle(); in.putParcelable(Intent.EXTRA_STREAM, Uri.fromFile(file)); in.putBoolean(EXTRA_ORIGINATED_FROM_SHELL, originatedFromShell); diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index aac144c4d732..79167ab476c1 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -308,6 +308,8 @@ message ConstantsProto { // Whether or not TimeController should skip setting wakeup alarms for jobs that aren't // ready now. reserved 1; // skip_not_ready_jobs + // Whether or not TimeController will use a non-wakeup alarm for delay constraints. + optional bool use_non_wakeup_alarm_for_delay = 2; } optional TimeController time_controller = 25; diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java index 471fa2c4bad9..7eec8d9f6cc3 100644 --- a/media/java/android/media/MediaScannerConnection.java +++ b/media/java/android/media/MediaScannerConnection.java @@ -16,17 +16,20 @@ package android.media; +import android.annotation.UnsupportedAppUsage; import android.content.ComponentName; +import android.content.ContentProviderClient; import android.content.Context; -import android.content.Intent; import android.content.ServiceConnection; -import android.media.IMediaScannerListener; -import android.media.IMediaScannerService; import android.net.Uri; +import android.os.Build; import android.os.IBinder; -import android.os.RemoteException; +import android.provider.MediaStore; import android.util.Log; +import com.android.internal.os.BackgroundThread; + +import java.io.File; /** * MediaScannerConnection provides a way for applications to pass a @@ -38,20 +41,24 @@ import android.util.Log; * to the client of the MediaScannerConnection class. */ public class MediaScannerConnection implements ServiceConnection { - private static final String TAG = "MediaScannerConnection"; - private Context mContext; - private MediaScannerConnectionClient mClient; - private IMediaScannerService mService; - private boolean mConnected; // true if connect() has been called since last disconnect() + private final Context mContext; + private final MediaScannerConnectionClient mClient; + private ContentProviderClient mProvider; + + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) + private IMediaScannerService mService; + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) + private boolean mConnected; + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) private final IMediaScannerListener.Stub mListener = new IMediaScannerListener.Stub() { + @Override public void scanCompleted(String path, Uri uri) { - MediaScannerConnectionClient client = mClient; - if (client != null) { - client.onScanCompleted(path, uri); - } } }; @@ -81,15 +88,6 @@ public class MediaScannerConnection implements ServiceConnection { * MediaScanner service has been established. */ public void onMediaScannerConnected(); - - /** - * Called to notify the client when the media scanner has finished - * scanning a file. - * @param path the path to the file that has been scanned. - * @param uri the Uri for the file if the scanning operation succeeded - * and the file was added to the media database, or null if scanning failed. - */ - public void onScanCompleted(String path, Uri uri); } /** @@ -111,13 +109,12 @@ public class MediaScannerConnection implements ServiceConnection { */ public void connect() { synchronized (this) { - if (!mConnected) { - Intent intent = new Intent(IMediaScannerService.class.getName()); - intent.setComponent( - new ComponentName("com.android.providers.media", - "com.android.providers.media.MediaScannerService")); - mContext.bindService(intent, this, Context.BIND_AUTO_CREATE); - mConnected = true; + if (mProvider == null) { + mProvider = mContext.getContentResolver() + .acquireContentProviderClient(MediaStore.AUTHORITY); + if (mClient != null) { + mClient.onMediaScannerConnected(); + } } } } @@ -127,22 +124,9 @@ public class MediaScannerConnection implements ServiceConnection { */ public void disconnect() { synchronized (this) { - if (mConnected) { - if (false) { - Log.v(TAG, "Disconnecting from Media Scanner"); - } - try { - mContext.unbindService(this); - if (mClient instanceof ClientProxy) { - mClient = null; - } - mService = null; - } catch (IllegalArgumentException ex) { - if (false) { - Log.v(TAG, "disconnect failed: " + ex); - } - } - mConnected = false; + if (mProvider != null) { + mProvider.close(); + mProvider = null; } } } @@ -152,7 +136,7 @@ public class MediaScannerConnection implements ServiceConnection { * @return true if we are connected, false otherwise */ public synchronized boolean isConnected() { - return (mService != null && mConnected); + return (mProvider != null); } /** @@ -166,107 +150,107 @@ public class MediaScannerConnection implements ServiceConnection { */ public void scanFile(String path, String mimeType) { synchronized (this) { - if (mService == null || !mConnected) { + if (mProvider == null) { throw new IllegalStateException("not connected to MediaScannerService"); } - try { - if (false) { - Log.v(TAG, "Scanning file " + path); + BackgroundThread.getExecutor().execute(() -> { + final Uri uri = scanFileQuietly(mProvider, new File(path)); + if (mClient != null) { + mClient.onScanCompleted(path, uri); } - mService.requestScanFile(path, mimeType, mListener); - } catch (RemoteException e) { - if (false) { - Log.d(TAG, "Failed to scan file " + path); + }); + } + } + + /** + * Convenience for constructing a {@link MediaScannerConnection}, calling + * {@link #connect} on it, and calling {@link #scanFile} with the given + * <var>path</var> and <var>mimeType</var> when the connection is + * established. + * @param context The caller's Context, required for establishing a connection to + * the media scanner service. + * Success or failure of the scanning operation cannot be determined until + * {@link MediaScannerConnectionClient#onScanCompleted(String, Uri)} is called. + * @param paths Array of paths to be scanned. + * @param mimeTypes Optional array of MIME types for each path. + * If mimeType is null, then the mimeType will be inferred from the file extension. + * @param callback Optional callback through which you can receive the + * scanned URI and MIME type; If null, the file will be scanned but + * you will not get a result back. + * @see #scanFile(String, String) + */ + public static void scanFile(Context context, String[] paths, String[] mimeTypes, + OnScanCompletedListener callback) { + BackgroundThread.getExecutor().execute(() -> { + try (ContentProviderClient client = context.getContentResolver() + .acquireContentProviderClient(MediaStore.AUTHORITY)) { + for (String path : paths) { + final Uri uri = scanFileQuietly(client, new File(path)); + if (callback != null) { + callback.onScanCompleted(path, uri); + } } } + }); + } + + private static Uri scanFileQuietly(ContentProviderClient client, File file) { + Uri uri = null; + try { + uri = MediaStore.scanFile(client, file); + Log.d(TAG, "Scanned " + file + " to " + uri); + } catch (Exception e) { + Log.w(TAG, "Failed to scan " + file + ": " + e); } + return uri; } + @Deprecated static class ClientProxy implements MediaScannerConnectionClient { + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) final String[] mPaths; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) final String[] mMimeTypes; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) final OnScanCompletedListener mClient; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) MediaScannerConnection mConnection; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) int mNextPath; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) ClientProxy(String[] paths, String[] mimeTypes, OnScanCompletedListener client) { mPaths = paths; mMimeTypes = mimeTypes; mClient = client; } + @Override public void onMediaScannerConnected() { - scanNextPath(); } + @Override public void onScanCompleted(String path, Uri uri) { - if (mClient != null) { - mClient.onScanCompleted(path, uri); - } - scanNextPath(); } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O) void scanNextPath() { - if (mNextPath >= mPaths.length) { - mConnection.disconnect(); - mConnection = null; - return; - } - String mimeType = mMimeTypes != null ? mMimeTypes[mNextPath] : null; - mConnection.scanFile(mPaths[mNextPath], mimeType); - mNextPath++; } } /** - * Convenience for constructing a {@link MediaScannerConnection}, calling - * {@link #connect} on it, and calling {@link #scanFile} with the given - * <var>path</var> and <var>mimeType</var> when the connection is - * established. - * @param context The caller's Context, required for establishing a connection to - * the media scanner service. - * Success or failure of the scanning operation cannot be determined until - * {@link MediaScannerConnectionClient#onScanCompleted(String, Uri)} is called. - * @param paths Array of paths to be scanned. - * @param mimeTypes Optional array of MIME types for each path. - * If mimeType is null, then the mimeType will be inferred from the file extension. - * @param callback Optional callback through which you can receive the - * scanned URI and MIME type; If null, the file will be scanned but - * you will not get a result back. - * @see #scanFile(String, String) - */ - public static void scanFile(Context context, String[] paths, String[] mimeTypes, - OnScanCompletedListener callback) { - ClientProxy client = new ClientProxy(paths, mimeTypes, callback); - MediaScannerConnection connection = new MediaScannerConnection(context, client); - client.mConnection = connection; - connection.connect(); - } - - /** * Part of the ServiceConnection interface. Do not call. */ + @Override public void onServiceConnected(ComponentName className, IBinder service) { - if (false) { - Log.v(TAG, "Connected to Media Scanner"); - } - synchronized (this) { - mService = IMediaScannerService.Stub.asInterface(service); - if (mService != null && mClient != null) { - mClient.onMediaScannerConnected(); - } - } + // No longer needed } /** * Part of the ServiceConnection interface. Do not call. */ + @Override public void onServiceDisconnected(ComponentName className) { - if (false) { - Log.v(TAG, "Disconnected from Media Scanner"); - } - synchronized (this) { - mService = null; - } + // No longer needed } } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 68b1ffe94b18..7ea83f56557a 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -841,7 +841,11 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt } } - private void attachBottomNavBarWindow() { + /** + * Attaches the bottom nav bar window. Can be extended to modify the specific behavior of + * attaching the bottom nav bar. + */ + protected void attachBottomNavBarWindow() { if (!mShowBottom) { return; } @@ -864,7 +868,11 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mWindowManager.addView(mNavigationBarWindow, lp); } - private void detachBottomNavBarWindow() { + /** + * Detaches the bottom nav bar window. Can be extended to modify the specific behavior of + * detaching the bottom nav bar. + */ + protected void detachBottomNavBarWindow() { if (!mShowBottom) { return; } diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java index 2698b72fdb36..b2e0492a761d 100644 --- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java +++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java @@ -66,6 +66,7 @@ class UiAutomationManager { mUiAutomationServiceOwner.unlinkToDeath(this, 0); mUiAutomationServiceOwner = null; destroyUiAutomationService(); + Slog.v(LOG_TAG, "UiAutomation service owner died"); } }; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 22928890e75a..7ef6032365d2 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -12532,6 +12532,13 @@ public class ActivityManagerService extends IActivityManager.Stub if (!brief && !opts.oomOnly && (procs.size() == 1 || opts.isCheckinRequest || opts.packages)) { opts.dumpDetails = true; } + final int numProcs = procs.size(); + final boolean collectNative = !opts.isCheckinRequest && numProcs > 1 && !opts.packages; + if (collectNative) { + // If we are showing aggregations, also look for native processes to + // include so that our aggregations are more accurate. + updateCpuStatsNow(); + } dumpApplicationMemoryUsageHeader(pw, uptime, realtime, opts.isCheckinRequest, opts.isCompact); @@ -12570,7 +12577,7 @@ public class ActivityManagerService extends IActivityManager.Stub boolean hasSwapPss = false; Debug.MemoryInfo mi = null; - for (int i = procs.size() - 1 ; i >= 0 ; i--) { + for (int i = numProcs - 1; i >= 0; i--) { final ProcessRecord r = procs.get(i); final IApplicationThread thread; final int pid; @@ -12724,10 +12731,7 @@ public class ActivityManagerService extends IActivityManager.Stub long nativeProcTotalPss = 0; - if (!opts.isCheckinRequest && procs.size() > 1 && !opts.packages) { - // If we are showing aggregations, also look for native processes to - // include so that our aggregations are more accurate. - updateCpuStatsNow(); + if (collectNative) { mi = null; synchronized (mProcessCpuTracker) { final int N = mProcessCpuTracker.countStats(); @@ -13095,6 +13099,13 @@ public class ActivityManagerService extends IActivityManager.Stub if (!brief && !opts.oomOnly && (procs.size() == 1 || opts.isCheckinRequest || opts.packages)) { opts.dumpDetails = true; } + final int numProcs = procs.size(); + final boolean collectNative = numProcs > 1 && !opts.packages; + if (collectNative) { + // If we are showing aggregations, also look for native processes to + // include so that our aggregations are more accurate. + updateCpuStatsNow(); + } ProtoOutputStream proto = new ProtoOutputStream(fd); @@ -13136,7 +13147,7 @@ public class ActivityManagerService extends IActivityManager.Stub boolean hasSwapPss = false; Debug.MemoryInfo mi = null; - for (int i = procs.size() - 1 ; i >= 0 ; i--) { + for (int i = numProcs - 1; i >= 0; i--) { final ProcessRecord r = procs.get(i); final IApplicationThread thread; final int pid; @@ -13283,10 +13294,7 @@ public class ActivityManagerService extends IActivityManager.Stub long nativeProcTotalPss = 0; - if (procs.size() > 1 && !opts.packages) { - // If we are showing aggregations, also look for native processes to - // include so that our aggregations are more accurate. - updateCpuStatsNow(); + if (collectNative) { mi = null; synchronized (mProcessCpuTracker) { final int N = mProcessCpuTracker.countStats(); diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 3e1817bd14ff..36e872a109dd 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -461,7 +461,7 @@ public final class ContentService extends IContentService.Stub { } synchronized (mCache) { - final String providerPackageName = getProviderPackageName(uri); + final String providerPackageName = getProviderPackageName(uri, userHandle); invalidateCacheLocked(userHandle, providerPackageName, uri); } } finally { @@ -1145,9 +1145,9 @@ public final class ContentService extends IContentService.Stub { } } - private @Nullable String getProviderPackageName(Uri uri) { - final ProviderInfo pi = mContext.getPackageManager() - .resolveContentProvider(uri.getAuthority(), 0); + private @Nullable String getProviderPackageName(Uri uri, int userId) { + final ProviderInfo pi = mContext.getPackageManager().resolveContentProviderAsUser( + uri.getAuthority(), 0, userId); return (pi != null) ? pi.packageName : null; } @@ -1200,7 +1200,7 @@ public final class ContentService extends IContentService.Stub { mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), packageName); - final String providerPackageName = getProviderPackageName(key); + final String providerPackageName = getProviderPackageName(key, userId); final Pair<String, Uri> fullKey = Pair.create(packageName, key); synchronized (mCache) { @@ -1222,7 +1222,7 @@ public final class ContentService extends IContentService.Stub { mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), packageName); - final String providerPackageName = getProviderPackageName(key); + final String providerPackageName = getProviderPackageName(key, userId); final Pair<String, Uri> fullKey = Pair.create(packageName, key); synchronized (mCache) { diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java index 3614763fecab..5d041b7c5757 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java @@ -71,6 +71,7 @@ public class TimeControllerTest { private static final String SOURCE_PACKAGE = "com.android.frameworks.mockingservicestests"; private static final int SOURCE_USER_ID = 0; + private TimeController.TcConstants mConstants; private TimeController mTimeController; private MockitoSession mMockingSession; @@ -110,6 +111,7 @@ public class TimeControllerTest { // Initialize real objects. mTimeController = new TimeController(mJobSchedulerService); + mConstants = mTimeController.getTcConstants(); spyOn(mTimeController); } @@ -528,6 +530,46 @@ public class TimeControllerTest { } @Test + public void testJobDelayWakeupAlarmToggling() { + final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); + + JobStatus job = createJobStatus( + "testMaybeStartTrackingJobLocked_DeadlineReverseOrder", + createJob().setMinimumLatency(HOUR_IN_MILLIS)); + + doReturn(true).when(mTimeController) + .wouldBeReadyWithConstraintLocked(eq(job), anyInt()); + + // Starting off with using a wakeup alarm. + mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = false; + InOrder inOrder = inOrder(mAlarmManager); + + mTimeController.maybeStartTrackingJobLocked(job, null); + inOrder.verify(mAlarmManager, times(1)) + .set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(now + HOUR_IN_MILLIS), anyLong(), + anyLong(), + eq(TAG_DELAY), any(), any(), any()); + + // Use a non wakeup alarm. + mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = true; + + mTimeController.maybeStartTrackingJobLocked(job, null); + inOrder.verify(mAlarmManager, times(1)) + .set(eq(AlarmManager.ELAPSED_REALTIME), eq(now + HOUR_IN_MILLIS), anyLong(), + anyLong(), eq(TAG_DELAY), + any(), any(), any()); + + // Back off, use a wakeup alarm. + mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = false; + + mTimeController.maybeStartTrackingJobLocked(job, null); + inOrder.verify(mAlarmManager, times(1)) + .set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(now + HOUR_IN_MILLIS), anyLong(), + anyLong(), + eq(TAG_DELAY), any(), any(), any()); + } + + @Test public void testCheckExpiredDeadlinesAndResetAlarm_AllReady() { doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 35b435d8dfb7..553bff26f78f 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -11047,6 +11047,8 @@ public class TelephonyManager { * The {@link #EXTRA_NETWORK_COUNTRY} extra indicates the country code of the current * network returned by {@link #getNetworkCountryIso()}. * + * <p>There may be a delay of several minutes before reporting that no country is detected. + * * @see #EXTRA_NETWORK_COUNTRY * @see #getNetworkCountryIso() */ diff --git a/tools/aapt2/optimize/ResourceDeduper.cpp b/tools/aapt2/optimize/ResourceDeduper.cpp index 78ebcb97b811..0278b439cfae 100644 --- a/tools/aapt2/optimize/ResourceDeduper.cpp +++ b/tools/aapt2/optimize/ResourceDeduper.cpp @@ -63,13 +63,14 @@ class DominatedKeyValueRemover : public DominatorTree::BottomUpVisitor { // Compare compatible configs for this entry and ensure the values are // equivalent. const ConfigDescription& node_configuration = node_value->config; - for (const auto& sibling : entry_->values) { - if (!sibling->value) { + for (const auto& sibling : parent->children()) { + ResourceConfigValue* sibling_value = sibling->value(); + if (!sibling_value->value) { // Sibling was already removed. continue; } - if (node_configuration.IsCompatibleWith(sibling->config) && - !node_value->value->Equals(sibling->value.get())) { + if (node_configuration.IsCompatibleWith(sibling_value->config) && + !node_value->value->Equals(sibling_value->value.get())) { // The configurations are compatible, but the value is // different, so we can't remove this value. return; diff --git a/tools/aapt2/optimize/ResourceDeduper_test.cpp b/tools/aapt2/optimize/ResourceDeduper_test.cpp index 2e098aec4f8d..048e318d2802 100644 --- a/tools/aapt2/optimize/ResourceDeduper_test.cpp +++ b/tools/aapt2/optimize/ResourceDeduper_test.cpp @@ -80,11 +80,58 @@ TEST(ResourceDeduperTest, DifferentValuesAreKept) { .Build(); ASSERT_TRUE(ResourceDeduper().Consume(context.get(), table.get())); + EXPECT_THAT(table, HasValue("android:string/keep", default_config)); EXPECT_THAT(table, HasValue("android:string/keep", ldrtl_config)); EXPECT_THAT(table, HasValue("android:string/keep", ldrtl_v21_config)); EXPECT_THAT(table, HasValue("android:string/keep", land_config)); } +TEST(ResourceDeduperTest, SameValuesAreDedupedIncompatibleSiblings) { + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + const ConfigDescription default_config = {}; + const ConfigDescription ldrtl_config = test::ParseConfigOrDie("ldrtl"); + const ConfigDescription ldrtl_night_config = test::ParseConfigOrDie("ldrtl-night"); + // Chosen because this configuration is not compatible with ldrtl-night. + const ConfigDescription ldrtl_notnight_config = test::ParseConfigOrDie("ldrtl-notnight"); + + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .AddString("android:string/keep", ResourceId{}, default_config, "keep") + .AddString("android:string/keep", ResourceId{}, ldrtl_config, "dedupe") + .AddString("android:string/keep", ResourceId{}, ldrtl_night_config, "dedupe") + .AddString("android:string/keep", ResourceId{}, ldrtl_notnight_config, "keep2") + .Build(); + + ASSERT_TRUE(ResourceDeduper().Consume(context.get(), table.get())); + EXPECT_THAT(table, HasValue("android:string/keep", default_config)); + EXPECT_THAT(table, HasValue("android:string/keep", ldrtl_config)); + EXPECT_THAT(table, Not(HasValue("android:string/keep", ldrtl_night_config))); + EXPECT_THAT(table, HasValue("android:string/keep", ldrtl_notnight_config)); +} + +TEST(ResourceDeduperTest, SameValuesAreDedupedCompatibleNonSiblings) { + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + const ConfigDescription default_config = {}; + const ConfigDescription ldrtl_config = test::ParseConfigOrDie("ldrtl"); + const ConfigDescription ldrtl_night_config = test::ParseConfigOrDie("ldrtl-night"); + // Chosen because this configuration is compatible with ldrtl. + const ConfigDescription land_config = test::ParseConfigOrDie("land"); + + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .AddString("android:string/keep", ResourceId{}, default_config, "keep") + .AddString("android:string/keep", ResourceId{}, ldrtl_config, "dedupe") + .AddString("android:string/keep", ResourceId{}, ldrtl_night_config, "dedupe") + .AddString("android:string/keep", ResourceId{}, land_config, "keep2") + .Build(); + + ASSERT_TRUE(ResourceDeduper().Consume(context.get(), table.get())); + EXPECT_THAT(table, HasValue("android:string/keep", default_config)); + EXPECT_THAT(table, HasValue("android:string/keep", ldrtl_config)); + EXPECT_THAT(table, Not(HasValue("android:string/keep", ldrtl_night_config))); + EXPECT_THAT(table, HasValue("android:string/keep", land_config)); +} + TEST(ResourceDeduperTest, LocalesValuesAreKept) { std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); const ConfigDescription default_config = {}; |