summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java126
-rw-r--r--core/java/android/app/UiAutomation.java25
-rw-r--r--core/java/android/content/ContentProvider.java10
-rw-r--r--core/java/android/provider/MediaStore.java13
-rw-r--r--core/proto/android/server/jobscheduler.proto2
-rw-r--r--media/java/android/media/MediaScannerConnection.java198
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java12
-rw-r--r--services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java1
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java28
-rw-r--r--services/core/java/com/android/server/content/ContentService.java12
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java42
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java2
-rw-r--r--tools/aapt2/optimize/ResourceDeduper.cpp9
-rw-r--r--tools/aapt2/optimize/ResourceDeduper_test.cpp47
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 = {};