diff options
Diffstat (limited to 'services/core/java/com')
33 files changed, 1024 insertions, 385 deletions
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 9931651081d..9bcded3e1e1 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -74,11 +74,14 @@ import com.android.server.pm.UserRestrictionsUtils; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -261,6 +264,47 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } }; + public boolean onFactoryReset() { + // Wait for stable state if bluetooth is temporary state. + int state = getState(); + if (state == BluetoothAdapter.STATE_BLE_TURNING_ON + || state == BluetoothAdapter.STATE_TURNING_ON + || state == BluetoothAdapter.STATE_TURNING_OFF) { + if (!waitForState(new HashSet<Integer>(Arrays.asList(BluetoothAdapter.STATE_BLE_ON, + BluetoothAdapter.STATE_ON)))) { + return false; + } + } + + // Clear registered LE apps to force shut-off Bluetooth + clearBleApps(); + state = getState(); + try { + mBluetoothLock.readLock().lock(); + if (mBluetooth == null) { + return false; + } + if (state == BluetoothAdapter.STATE_BLE_ON) { + addActiveLog( + BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET, + mContext.getPackageName(), false); + mBluetooth.onBrEdrDown(); + return true; + } else if (state == BluetoothAdapter.STATE_ON) { + addActiveLog( + BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET, + mContext.getPackageName(), false); + mBluetooth.disable(); + return true; + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to shutdown Bluetooth", e); + } finally { + mBluetoothLock.readLock().unlock(); + } + return false; + } + public void onAirplaneModeChanged() { synchronized (this) { if (isBluetoothPersistedStateOn()) { @@ -1644,7 +1688,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { // the previous Bluetooth process has exited. The // waiting period has three components: // (a) Wait until the local state is STATE_OFF. This - // is accomplished by "waitForOnOff(false, true)". + // is accomplished by + // "waitForState(new HashSet<Integer>( + // Arrays.asList(BluetoothAdapter.STATE_OFF)))". // (b) Wait until the STATE_OFF state is updated to // all components. // (c) Wait until the Bluetooth process exits, and @@ -1654,7 +1700,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { // message. The delay time is backed off if Bluetooth // continuously failed to turn on itself. // - waitForOnOff(false, true); + waitForState(new HashSet<Integer>(Arrays.asList( + BluetoothAdapter.STATE_OFF))); Message restartMsg = mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs()); @@ -1667,10 +1714,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE); if (mEnable && mBluetooth != null) { - waitForOnOff(true, false); + waitForState(new HashSet<Integer>(Arrays.asList( + BluetoothAdapter.STATE_ON))); mEnable = false; handleDisable(); - waitForOnOff(false, false); + waitForState(new HashSet<Integer>(Arrays.asList(BluetoothAdapter.STATE_OFF, + BluetoothAdapter.STATE_TURNING_ON, + BluetoothAdapter.STATE_TURNING_OFF, + BluetoothAdapter.STATE_BLE_TURNING_ON, + BluetoothAdapter.STATE_BLE_ON, + BluetoothAdapter.STATE_BLE_TURNING_OFF))); } else { mEnable = false; handleDisable(); @@ -1799,9 +1852,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } if (!mEnable) { - waitForOnOff(true, false); + waitForState(new HashSet<Integer>(Arrays.asList( + BluetoothAdapter.STATE_ON))); handleDisable(); - waitForOnOff(false, false); + waitForState(new HashSet<Integer>(Arrays.asList(BluetoothAdapter.STATE_OFF, + BluetoothAdapter.STATE_TURNING_ON, + BluetoothAdapter.STATE_TURNING_OFF, + BluetoothAdapter.STATE_BLE_TURNING_ON, + BluetoothAdapter.STATE_BLE_ON, + BluetoothAdapter.STATE_BLE_TURNING_OFF))); } break; } @@ -1833,7 +1892,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { == BluetoothAdapter.STATE_OFF)) { if (mEnable) { Slog.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting."); - waitForOnOff(false, true); + waitForState(new HashSet<Integer>(Arrays.asList( + BluetoothAdapter.STATE_OFF))); Message restartMsg = mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE); mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs()); @@ -1962,7 +2022,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mState = BluetoothAdapter.STATE_TURNING_ON; } - waitForOnOff(true, false); + waitForState(new HashSet<Integer>(Arrays.asList( + BluetoothAdapter.STATE_ON))); if (mState == BluetoothAdapter.STATE_TURNING_ON) { bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON); @@ -1977,7 +2038,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON, BluetoothAdapter.STATE_TURNING_OFF); - boolean didDisableTimeout = !waitForOnOff(false, true); + boolean didDisableTimeout = + !waitForState(new HashSet<Integer>(Arrays.asList( + BluetoothAdapter.STATE_OFF))); bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF, BluetoothAdapter.STATE_OFF); @@ -2229,12 +2292,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } } - /** - * if on is true, wait for state become ON - * if off is true, wait for state become OFF - * if both on and off are false, wait for state not ON - */ - private boolean waitForOnOff(boolean on, boolean off) { + private boolean waitForState(Set<Integer> states) { int i = 0; while (i < 10) { try { @@ -2242,18 +2300,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { if (mBluetooth == null) { break; } - if (on) { - if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) { - return true; - } - } else if (off) { - if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) { - return true; - } - } else { - if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) { - return true; - } + if (states.contains(mBluetooth.getState())) { + return true; } } catch (RemoteException e) { Slog.e(TAG, "getState()", e); @@ -2261,14 +2309,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } finally { mBluetoothLock.readLock().unlock(); } - if (on || off) { - SystemClock.sleep(300); - } else { - SystemClock.sleep(50); - } + SystemClock.sleep(300); i++; } - Slog.e(TAG, "waitForOnOff time out"); + Slog.e(TAG, "waitForState " + states + " time out"); return false; } @@ -2329,7 +2373,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mContext.getPackageName(), false); handleDisable(); - waitForOnOff(false, true); + waitForState(new HashSet<Integer>(Arrays.asList(BluetoothAdapter.STATE_OFF))); sendBluetoothServiceDownCallback(); @@ -2491,6 +2535,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return "USER_SWITCH"; case BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING: return "RESTORE_USER_SETTING"; + case BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET: + return "FACTORY_RESET"; case BluetoothProtoEnums.ENABLE_DISABLE_REASON_UNSPECIFIED: default: return "UNKNOWN[" + reason + "]"; } diff --git a/services/core/java/com/android/server/CountryDetectorService.java b/services/core/java/com/android/server/CountryDetectorService.java index d8a2fe35c7e..b0132d35fa3 100644 --- a/services/core/java/com/android/server/CountryDetectorService.java +++ b/services/core/java/com/android/server/CountryDetectorService.java @@ -16,14 +16,6 @@ package com.android.server; -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.HashMap; - -import com.android.internal.os.BackgroundThread; -import com.android.internal.util.DumpUtils; -import com.android.server.location.ComprehensiveCountryDetector; - import android.content.Context; import android.location.Country; import android.location.CountryListener; @@ -32,21 +24,37 @@ import android.location.ICountryListener; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; +import android.text.TextUtils; import android.util.PrintWriterPrinter; import android.util.Printer; import android.util.Slog; +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.BackgroundThread; +import com.android.internal.util.DumpUtils; +import com.android.server.location.ComprehensiveCountryDetector; +import com.android.server.location.CountryDetectorBase; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; + /** - * This class detects the country that the user is in through - * {@link ComprehensiveCountryDetector}. + * This class detects the country that the user is in. The default country detection is made through + * {@link com.android.server.location.ComprehensiveCountryDetector}. It is possible to overlay the + * detection algorithm by overlaying the attribute R.string.config_customCountryDetector with the + * custom class name to use instead. The custom class must extend + * {@link com.android.server.location.CountryDetectorBase} * * @hide */ -public class CountryDetectorService extends ICountryDetector.Stub implements Runnable { +public class CountryDetectorService extends ICountryDetector.Stub { /** - * The class represents the remote listener, it will also removes itself - * from listener list when the remote process was died. + * The class represents the remote listener, it will also removes itself from listener list when + * the remote process was died. */ private final class Receiver implements IBinder.DeathRecipient { private final ICountryListener mListener; @@ -79,28 +87,36 @@ public class CountryDetectorService extends ICountryDetector.Stub implements Run } } - private final static String TAG = "CountryDetector"; + private static final String TAG = "CountryDetector"; - /** Whether to dump the state of the country detector service to bugreports */ + /** + * Whether to dump the state of the country detector service to bugreports + */ private static final boolean DEBUG = false; private final HashMap<IBinder, Receiver> mReceivers; private final Context mContext; - private ComprehensiveCountryDetector mCountryDetector; + private CountryDetectorBase mCountryDetector; private boolean mSystemReady; private Handler mHandler; private CountryListener mLocationBasedDetectorListener; public CountryDetectorService(Context context) { + this(context, BackgroundThread.getHandler()); + } + + @VisibleForTesting + CountryDetectorService(Context context, Handler handler) { super(); - mReceivers = new HashMap<IBinder, Receiver>(); + mReceivers = new HashMap<>(); mContext = context; + mHandler = handler; } @Override public Country detectCountry() { if (!mSystemReady) { - return null; // server not yet active + return null; // server not yet active } else { return mCountryDetector.detectCountry(); } @@ -154,9 +170,8 @@ public class CountryDetectorService extends ICountryDetector.Stub implements Run } } - protected void notifyReceivers(Country country) { - synchronized(mReceivers) { + synchronized (mReceivers) { for (Receiver receiver : mReceivers.values()) { try { receiver.getListener().onCountryDetected(country); @@ -170,42 +185,58 @@ public class CountryDetectorService extends ICountryDetector.Stub implements Run void systemRunning() { // Shall we wait for the initialization finish. - BackgroundThread.getHandler().post(this); - } - - private void initialize() { - mCountryDetector = new ComprehensiveCountryDetector(mContext); - mLocationBasedDetectorListener = new CountryListener() { - public void onCountryDetected(final Country country) { - mHandler.post(new Runnable() { - public void run() { - notifyReceivers(country); - } + mHandler.post( + () -> { + initialize(); + mSystemReady = true; }); - } - }; } - public void run() { - mHandler = new Handler(); - initialize(); - mSystemReady = true; + @VisibleForTesting + void initialize() { + final String customCountryClass = mContext.getString(R.string.config_customCountryDetector); + if (!TextUtils.isEmpty(customCountryClass)) { + mCountryDetector = loadCustomCountryDetectorIfAvailable(customCountryClass); + } + + if (mCountryDetector == null) { + Slog.d(TAG, "Using default country detector"); + mCountryDetector = new ComprehensiveCountryDetector(mContext); + } + mLocationBasedDetectorListener = country -> mHandler.post(() -> notifyReceivers(country)); } protected void setCountryListener(final CountryListener listener) { - mHandler.post(new Runnable() { - @Override - public void run() { - mCountryDetector.setCountryListener(listener); - } - }); + mHandler.post(() -> mCountryDetector.setCountryListener(listener)); + } + + @VisibleForTesting + CountryDetectorBase getCountryDetector() { + return mCountryDetector; } - // For testing + @VisibleForTesting boolean isSystemReady() { return mSystemReady; } + private CountryDetectorBase loadCustomCountryDetectorIfAvailable( + final String customCountryClass) { + CountryDetectorBase customCountryDetector = null; + + Slog.d(TAG, "Using custom country detector class: " + customCountryClass); + try { + customCountryDetector = Class.forName(customCountryClass).asSubclass( + CountryDetectorBase.class).getConstructor(Context.class).newInstance( + mContext); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException + | NoSuchMethodException | InvocationTargetException e) { + Slog.e(TAG, "Could not instantiate the custom country detector class"); + } + + return customCountryDetector; + } + @SuppressWarnings("unused") @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { @@ -214,9 +245,10 @@ public class CountryDetectorService extends ICountryDetector.Stub implements Run try { final Printer p = new PrintWriterPrinter(fout); p.println("CountryDetectorService state:"); + p.println("Country detector class=" + mCountryDetector.getClass().getName()); p.println(" Number of listeners=" + mReceivers.keySet().size()); if (mCountryDetector == null) { - p.println(" ComprehensiveCountryDetector not initialized"); + p.println(" CountryDetector not initialized"); } else { p.println(" " + mCountryDetector.toString()); } diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 3dee9f06eaf..417992cc888 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -59,6 +59,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkPolicyManager; import android.net.NetworkRequest; +import android.net.NetworkStack; import android.net.NetworkStats; import android.net.NetworkUtils; import android.net.RouteInfo; @@ -986,6 +987,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public void setIPv6AddrGenMode(String iface, int mode) throws ServiceSpecificException { + NetworkStack.checkNetworkStackPermission(mContext); try { mNetdService.setIPv6AddrGenMode(iface, mode); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java index c5b4966ddcf..3df585e4b86 100644 --- a/services/core/java/com/android/server/SystemServiceManager.java +++ b/services/core/java/com/android/server/SystemServiceManager.java @@ -22,6 +22,7 @@ import android.os.Environment; import android.os.SystemClock; import android.os.Trace; import android.util.Slog; +import android.util.TimingsTraceLog; import java.io.File; import java.lang.reflect.Constructor; @@ -178,12 +179,13 @@ public class SystemServiceManager { } public void startUser(final int userHandle) { + final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceBegin("ssm.startUser-" + userHandle); Slog.i(TAG, "Calling onStartUser u" + userHandle); final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { final SystemService service = mServices.get(i); - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onStartUser " - + service.getClass().getName()); + t.traceBegin("onStartUser-" + userHandle + " " + service.getClass().getName()); long time = SystemClock.elapsedRealtime(); try { service.onStartUser(userHandle); @@ -192,17 +194,19 @@ public class SystemServiceManager { + " to service " + service.getClass().getName(), ex); } warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStartUser "); - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceEnd(); } + t.traceEnd(); } public void unlockUser(final int userHandle) { + final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceBegin("ssm.unlockUser-" + userHandle); Slog.i(TAG, "Calling onUnlockUser u" + userHandle); final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { final SystemService service = mServices.get(i); - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onUnlockUser " - + service.getClass().getName()); + t.traceBegin("onUnlockUser-" + userHandle + " " + service.getClass().getName()); long time = SystemClock.elapsedRealtime(); try { service.onUnlockUser(userHandle); @@ -211,17 +215,19 @@ public class SystemServiceManager { + " to service " + service.getClass().getName(), ex); } warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onUnlockUser "); - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceEnd(); } + t.traceEnd(); } public void switchUser(final int userHandle) { + final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceBegin("ssm.switchUser-" + userHandle); Slog.i(TAG, "Calling switchUser u" + userHandle); final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { final SystemService service = mServices.get(i); - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onSwitchUser " - + service.getClass().getName()); + t.traceBegin("onSwitchUser-" + userHandle + " " + service.getClass().getName()); long time = SystemClock.elapsedRealtime(); try { service.onSwitchUser(userHandle); @@ -230,17 +236,19 @@ public class SystemServiceManager { + " to service " + service.getClass().getName(), ex); } warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onSwitchUser"); - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceEnd(); } + t.traceEnd(); } public void stopUser(final int userHandle) { + final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceBegin("ssm.stopUser-" + userHandle); Slog.i(TAG, "Calling onStopUser u" + userHandle); final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { final SystemService service = mServices.get(i); - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onStopUser " - + service.getClass().getName()); + t.traceBegin("onStopUser-" + userHandle + " " + service.getClass().getName()); long time = SystemClock.elapsedRealtime(); try { service.onStopUser(userHandle); @@ -249,17 +257,19 @@ public class SystemServiceManager { + " to service " + service.getClass().getName(), ex); } warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStopUser"); - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceEnd(); } + t.traceEnd(); } public void cleanupUser(final int userHandle) { + final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceBegin("ssm.cleanupUser-" + userHandle); Slog.i(TAG, "Calling onCleanupUser u" + userHandle); final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { final SystemService service = mServices.get(i); - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onCleanupUser " - + service.getClass().getName()); + t.traceBegin("onCleanupUser-" + userHandle + " " + service.getClass().getName()); long time = SystemClock.elapsedRealtime(); try { service.onCleanupUser(userHandle); @@ -268,8 +278,9 @@ public class SystemServiceManager { + " to service " + service.getClass().getName(), ex); } warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onCleanupUser"); - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceEnd(); } + t.traceEnd(); } /** Sets the safe mode flag for services to query. */ diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index f7e825eecc1..84c43591dcd 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -31,6 +31,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; +import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.telephony.CallAttributes; @@ -469,7 +470,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { synchronized (mRecords) { // register IBinder b = callback.asBinder(); - Record r = add(b); + Record r = add(b, Binder.getCallingPid(), false); if (r == null) { return; @@ -522,7 +523,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { synchronized (mRecords) { // register IBinder b = callback.asBinder(); - Record r = add(b); + Record r = add(b, Binder.getCallingPid(), false); if (r == null) { return; @@ -643,7 +644,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { synchronized (mRecords) { // register IBinder b = callback.asBinder(); - Record r = add(b); + boolean shouldEnforceListenerLimit = + Binder.getCallingUid() != Process.SYSTEM_UID + && Binder.getCallingUid() != Process.PHONE_UID + && Binder.getCallingUid() != Process.myUid(); + Record r = add(b, Binder.getCallingPid(), shouldEnforceListenerLimit); if (r == null) { return; @@ -893,18 +898,35 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return record.canReadCallLog() ? mCallIncomingNumber[phoneId] : ""; } - private Record add(IBinder binder) { + private Record add(IBinder binder, int callingPid, boolean enforceLimit) { Record r; synchronized (mRecords) { final int N = mRecords.size(); + // While iterating through the records, keep track of how many we have from this pid. + int numRecordsForPid = 0; for (int i = 0; i < N; i++) { r = mRecords.get(i); if (binder == r.binder) { // Already existed. return r; } + if (r.callerPid == callingPid) { + numRecordsForPid++; + } + } + // If we've exceeded the limit for registrations, log a warning and quit. + if (enforceLimit && numRecordsForPid >= PhoneStateListener.PER_PID_REGISTRATION_LIMIT) { + String errorMsg = "Pid " + callingPid + " has exceeded the number of permissible" + + "registered listeners. Ignoring request to add."; + loge(errorMsg); + throw new IllegalStateException(errorMsg); + } else if (enforceLimit + && numRecordsForPid >= PhoneStateListener.PER_PID_REGISTRATION_LIMIT / 2) { + Rlog.w(TAG, "Pid " + callingPid + " has exceeded half the number of permissible" + + "registered listeners. Now at " + numRecordsForPid); } + r = new Record(); r.binder = binder; r.deathRecipient = new TelephonyRegistryDeathRecipient(binder); diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index 978cc577f1e..17742b7f634 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -16,6 +16,7 @@ package com.android.server; +import android.annotation.IntRange; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; @@ -41,6 +42,7 @@ import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager.ServiceType; import android.os.PowerManagerInternal; +import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; @@ -67,6 +69,10 @@ import com.android.server.wm.WindowManagerInternal; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.Map; + +import static android.app.UiModeManager.MODE_NIGHT_AUTO; +import static android.app.UiModeManager.MODE_NIGHT_YES; final class UiModeManagerService extends SystemService { private static final String TAG = UiModeManager.class.getSimpleName(); @@ -124,6 +130,7 @@ final class UiModeManagerService extends SystemService { private NotificationManager mNotificationManager; private StatusBarManager mStatusBarManager; private WindowManagerInternal mWindowManager; + private PowerManager mPowerManager; private PowerManager.WakeLock mWakeLock; @@ -136,11 +143,12 @@ final class UiModeManagerService extends SystemService { @VisibleForTesting protected UiModeManagerService(Context context, WindowManagerInternal wm, PowerManager.WakeLock wl, TwilightManager tm, - boolean setupWizardComplete) { + PowerManager pm, boolean setupWizardComplete) { super(context); mWindowManager = wm; mWakeLock = wl; mTwilightManager = tm; + mPowerManager = pm; mSetupWizardComplete = setupWizardComplete; } @@ -261,14 +269,19 @@ final class UiModeManagerService extends SystemService { private final ContentObserver mDarkThemeObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange, Uri uri) { - int mode = Secure.getIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE, - mNightMode, 0); - mode = mode == UiModeManager.MODE_NIGHT_AUTO - ? UiModeManager.MODE_NIGHT_YES : mode; - SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode)); + updateSystemProperties(); } }; + private void updateSystemProperties() { + int mode = Secure.getIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE, + mNightMode, 0); + if (mode == MODE_NIGHT_AUTO) { + mode = MODE_NIGHT_YES; + } + SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode)); + } + @Override public void onSwitchUser(int userHandle) { super.onSwitchUser(userHandle); @@ -280,9 +293,9 @@ final class UiModeManagerService extends SystemService { public void onStart() { final Context context = getContext(); - final PowerManager powerManager = + mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); + mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); mWindowManager = LocalServices.getService(WindowManagerInternal.class); // If setup isn't complete for this user listen for completion so we can unblock @@ -349,6 +362,7 @@ final class UiModeManagerService extends SystemService { context.getContentResolver().registerContentObserver(Secure.getUriFor(Secure.UI_NIGHT_MODE), false, mDarkThemeObserver, 0); + mHandler.post(() -> updateSystemProperties()); } @VisibleForTesting @@ -406,6 +420,7 @@ final class UiModeManagerService extends SystemService { } private void registerScreenOffEvent() { + if (mPowerSave) return; mWaitForScreenOff = true; final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); @@ -510,7 +525,9 @@ final class UiModeManagerService extends SystemService { persistNightMode(user); } // on screen off will update configuration instead - if (mNightMode != UiModeManager.MODE_NIGHT_AUTO || mCar) { + if ((mNightMode != MODE_NIGHT_AUTO) + || shouldApplyAutomaticChangesImmediately()) { + unregisterScreenOffEvent(); updateLocked(0, 0); } else { registerScreenOffEvent(); @@ -587,19 +604,20 @@ final class UiModeManagerService extends SystemService { synchronized (mLock) { pw.println("Current UI Mode Service state:"); pw.print(" mDockState="); pw.print(mDockState); - pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); + pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); pw.print(" mNightMode="); pw.print(mNightMode); pw.print(" ("); - pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") "); - pw.print(" mNightModeLocked="); pw.print(mNightModeLocked); - pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled); - pw.print(" mComputedNightMode="); pw.print(mComputedNightMode); - pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags); - pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch); + pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") "); + pw.print(" mNightModeLocked="); pw.print(mNightModeLocked); + pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled); + pw.print(" mComputedNightMode="); pw.print(mComputedNightMode); + pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags); + pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch); pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode)); - pw.print(" mUiModeLocked="); pw.print(mUiModeLocked); - pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode)); + pw.print(" mUiModeLocked="); pw.print(mUiModeLocked); + pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode)); pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration); - pw.print(" mSystemReady="); pw.println(mSystemReady); + pw.print(" mSystemReady="); pw.println(mSystemReady); + if (mTwilightManager != null) { // We may not have a TwilightManager. pw.print(" mTwilightService.getLastTwilightState()="); @@ -615,7 +633,6 @@ final class UiModeManagerService extends SystemService { mTwilightManager = getLocalService(TwilightManager.class); mSystemReady = true; mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; - updateComputedNightModeLocked(); registerVrStateListener(); updateLocked(0, 0); } @@ -683,40 +700,56 @@ final class UiModeManagerService extends SystemService { uiMode = Configuration.UI_MODE_TYPE_VR_HEADSET; } - if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + if (mNightMode == MODE_NIGHT_YES || mNightMode == UiModeManager.MODE_NIGHT_NO) { + mComputedNightMode = mNightMode == MODE_NIGHT_YES; + } + + if (mNightMode == MODE_NIGHT_AUTO) { + boolean activateNightMode = mComputedNightMode; if (mTwilightManager != null) { mTwilightManager.registerListener(mTwilightListener, mHandler); + final TwilightState lastState = mTwilightManager.getLastTwilightState(); + activateNightMode = lastState == null ? mComputedNightMode : lastState.isNight(); } - updateComputedNightModeLocked(); - uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES - : Configuration.UI_MODE_NIGHT_NO; + + updateComputedNightModeLocked(activateNightMode); } else { if (mTwilightManager != null) { mTwilightManager.unregisterListener(mTwilightListener); } - uiMode |= mNightMode << 4; } // Override night mode in power save mode if not in car mode if (mPowerSave && !mCarModeEnabled) { uiMode &= ~Configuration.UI_MODE_NIGHT_NO; uiMode |= Configuration.UI_MODE_NIGHT_YES; + } else { + uiMode = getComputedUiModeConfiguration(uiMode); } if (LOG) { Slog.d(TAG, - "updateConfigurationLocked: mDockState=" + mDockState + "updateConfigurationLocked: mDockState=" + mDockState + "; mCarMode=" + mCarModeEnabled + "; mNightMode=" + mNightMode + "; uiMode=" + uiMode); } mCurUiMode = uiMode; - if (!mHoldingConfiguration || !mWaitForScreenOff) { + if (!mHoldingConfiguration && (!mWaitForScreenOff || mPowerSave)) { mConfiguration.uiMode = uiMode; } } + @UiModeManager.NightMode + private int getComputedUiModeConfiguration(@UiModeManager.NightMode int uiMode) { + uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES + : Configuration.UI_MODE_NIGHT_NO; + uiMode &= mComputedNightMode ? ~Configuration.UI_MODE_NIGHT_NO + : ~Configuration.UI_MODE_NIGHT_YES; + return uiMode; + } + private void applyConfigurationExternallyLocked() { if (mSetUiMode != mConfiguration.uiMode) { mSetUiMode = mConfiguration.uiMode; @@ -724,10 +757,16 @@ final class UiModeManagerService extends SystemService { ActivityTaskManager.getService().updateConfiguration(mConfiguration); } catch (RemoteException e) { Slog.w(TAG, "Failure communicating with activity manager", e); + } catch (SecurityException e) { + Slog.e(TAG, "Activity does not have the ", e); } } } + private boolean shouldApplyAutomaticChangesImmediately() { + return mCar || !mPowerManager.isInteractive(); + } + void updateLocked(int enableFlags, int disableFlags) { String action = null; String oldAction = null; @@ -958,26 +997,21 @@ final class UiModeManagerService extends SystemService { } } - private void updateComputedNightModeLocked() { - if (mTwilightManager != null) { - TwilightState state = mTwilightManager.getLastTwilightState(); - if (state != null) { - mComputedNightMode = state.isNight(); - } - if (mNightModeOverride == UiModeManager.MODE_NIGHT_YES && !mComputedNightMode) { - mComputedNightMode = true; - return; - } - if (mNightModeOverride == UiModeManager.MODE_NIGHT_NO && mComputedNightMode) { - mComputedNightMode = false; - return; - } - - mNightModeOverride = mNightMode; - final int user = UserHandle.getCallingUserId(); - Secure.putIntForUser(getContext().getContentResolver(), - OVERRIDE_NIGHT_MODE, mNightModeOverride, user); + private void updateComputedNightModeLocked(boolean activate) { + mComputedNightMode = activate; + if (mNightModeOverride == UiModeManager.MODE_NIGHT_YES && !mComputedNightMode) { + mComputedNightMode = true; + return; + } + if (mNightModeOverride == UiModeManager.MODE_NIGHT_NO && mComputedNightMode) { + mComputedNightMode = false; + return; } + + mNightModeOverride = mNightMode; + final int user = UserHandle.getCallingUserId(); + Secure.putIntForUser(getContext().getContentResolver(), + OVERRIDE_NIGHT_MODE, mNightModeOverride, user); } private void registerVrStateListener() { @@ -1098,7 +1132,7 @@ final class UiModeManagerService extends SystemService { final boolean isIt = (mConfiguration.uiMode & Configuration.UI_MODE_NIGHT_YES) != 0; if (LOG) { Slog.d(TAG, - "LocalService.isNightMode(): mNightMode=" + mNightMode + "LocalService.isNightMode(): mNightMode=" + mNightMode + "; mComputedNightMode=" + mComputedNightMode + "; uiMode=" + mConfiguration.uiMode + "; isIt=" + isIt); diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 0d2882216f0..c732521bb7c 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -4404,7 +4404,6 @@ public class AccountManagerService return true; } - @Override public boolean renameSharedAccountAsUser(Account account, String newName, int userId) { userId = handleIncomingUser(userId); UserAccounts accounts = getUserAccounts(userId); @@ -4420,7 +4419,6 @@ public class AccountManagerService return r > 0; } - @Override public boolean removeSharedAccountAsUser(Account account, int userId) { return removeSharedAccountAsUser(account, userId, getCallingUid()); } @@ -4438,7 +4436,6 @@ public class AccountManagerService return deleted; } - @Override public Account[] getSharedAccountsAsUser(int userId) { userId = handleIncomingUser(userId); UserAccounts accounts = getUserAccounts(userId); diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java index 4b48ef91774..143474bd5c9 100644 --- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java +++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java @@ -413,6 +413,11 @@ public class AdbDebuggingManager { case MESSAGE_ADB_CLEAR: { Slog.d(TAG, "Received a request to clear the adb authorizations"); mConnectedKeys.clear(); + // If the key store has not yet been instantiated then do so now; this avoids + // the unnecessary creation of the key store when adb is not enabled. + if (mAdbKeyStore == null) { + mAdbKeyStore = new AdbKeyStore(); + } mAdbKeyStore.deleteKeyStore(); cancelJobToUpdateAdbKeyStore(); break; diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 8373994b4c4..1a01a4b0dd4 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -3174,8 +3174,11 @@ public final class ActiveServices { } } - // If unbound while waiting to start, remove the pending service - mPendingServices.remove(s); + // If unbound while waiting to start and there is no connection left in this service, + // remove the pending service + if (s.getConnections().isEmpty()) { + mPendingServices.remove(s); + } if ((c.flags&Context.BIND_AUTO_CREATE) != 0) { boolean hasAutoCreate = s.hasAutoCreateConnections(); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 20253be76c6..0d9b907cddf 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -271,8 +271,8 @@ import android.os.WorkSource; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.provider.DeviceConfig; -import android.provider.Settings; import android.provider.DeviceConfig.Properties; +import android.provider.Settings; import android.server.ServerProtoEnums; import android.sysprop.VoldProperties; import android.text.TextUtils; @@ -352,7 +352,6 @@ import com.android.server.contentcapture.ContentCaptureManagerInternal; import com.android.server.firewall.IntentFirewall; import com.android.server.job.JobSchedulerInternal; import com.android.server.pm.Installer; -import com.android.server.pm.Installer.InstallerException; import com.android.server.uri.GrantUri; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.utils.PriorityDump; @@ -364,8 +363,6 @@ import com.android.server.wm.ActivityTaskManagerService; import com.android.server.wm.WindowManagerService; import com.android.server.wm.WindowProcessController; -import dalvik.system.VMRuntime; - import libcore.util.EmptyArray; import java.io.File; @@ -5205,26 +5202,6 @@ public class ActivityManagerService extends IActivityManager.Stub mCallFinishBooting = false; } - ArraySet<String> completedIsas = new ArraySet<String>(); - for (String abi : Build.SUPPORTED_ABIS) { - ZYGOTE_PROCESS.establishZygoteConnectionForAbi(abi); - final String instructionSet = VMRuntime.getInstructionSet(abi); - if (!completedIsas.contains(instructionSet)) { - try { - mInstaller.markBootComplete(VMRuntime.getInstructionSet(abi)); - } catch (InstallerException e) { - if (!VMRuntime.didPruneDalvikCache()) { - // This is technically not the right filter, as different zygotes may - // have made different pruning decisions. But the log is best effort, - // anyways. - Slog.w(TAG, "Unable to mark boot complete for abi: " + abi + " (" + - e.getMessage() +")"); - } - } - completedIsas.add(instructionSet); - } - } - IntentFilter pkgFilter = new IntentFilter(); pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); pkgFilter.addDataScheme("package"); @@ -8263,6 +8240,21 @@ public class ActivityManagerService extends IActivityManager.Stub } } + private boolean isActiveInstrumentation(int uid) { + synchronized (ActivityManagerService.this) { + for (int i = mActiveInstrumentation.size() - 1; i >= 0; i--) { + final ActiveInstrumentation instrumentation = mActiveInstrumentation.get(i); + for (int j = instrumentation.mRunningProcesses.size() - 1; j >= 0; j--) { + final ProcessRecord process = instrumentation.mRunningProcesses.get(j); + if (process.uid == uid) { + return true; + } + } + } + } + return false; + } + @Override public int getUidProcessState(int uid, String callingPackage) { if (!hasUsageStatsPermission(callingPackage)) { @@ -18507,6 +18499,11 @@ public class ActivityManagerService extends IActivityManager.Stub public void unregisterProcessObserver(IProcessObserver processObserver) { ActivityManagerService.this.unregisterProcessObserver(processObserver); } + + @Override + public boolean isActiveInstrumentation(int uid) { + return ActivityManagerService.this.isActiveInstrumentation(uid); + } } long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { diff --git a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java index ebfc2a011e8..a6811e3070b 100644 --- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java +++ b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java @@ -30,9 +30,9 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.UserManager; +import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; @@ -56,8 +56,6 @@ final class CarUserSwitchingDialog extends UserSwitchingDialog { String switchingToSystemUserMessage) { super(service, context, oldUser, newUser, aboveSystem, switchingFromSystemUserMessage, switchingToSystemUserMessage); - - getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); } @Override @@ -81,8 +79,19 @@ final class CarUserSwitchingDialog extends UserSwitchingDialog { .setImageDrawable(drawable); } - ((TextView) view.findViewById(R.id.user_loading)) - .setText(res.getString(R.string.car_loading_profile)); + TextView msgView = view.findViewById(R.id.user_loading); + + // TODO(b/145132885): use constant from CarSettings + boolean showInfo = "true".equals(Settings.Global.getString( + getContext().getContentResolver(), + "android.car.ENABLE_USER_SWITCH_DEVELOPER_MESSAGE")); + + if (showInfo) { + msgView.setText(res.getString(R.string.car_loading_profile) + " user\n(from " + + mOldUser.id + " to " + mNewUser.id + ")"); + } else { + msgView.setText(res.getString(R.string.car_loading_profile)); + } setView(view); } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index fe29a36ec45..278163b9dfe 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -422,9 +422,7 @@ public final class ProcessList { @GuardedBy("ProcessList.this.mService") void freeIsolatedUidLocked(int uid) { - // Strip out userId - final int appId = UserHandle.getAppId(uid); - mUidUsed.delete(appId); + mUidUsed.delete(uid); } }; diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index f6b49bc9a25..07b5c5fccca 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -129,6 +129,10 @@ class UserController implements Handler.Callback { // giving up on them and unfreezing the screen. static final int USER_SWITCH_TIMEOUT_MS = 3 * 1000; + // Amount of time we wait for observers to handle a user switch before we log a warning. + // Must be smaller than USER_SWITCH_TIMEOUT_MS. + private static final int USER_SWITCH_WARNING_TIMEOUT_MS = 500; + // ActivityManager thread message constants static final int REPORT_USER_SWITCH_MSG = 10; static final int CONTINUE_USER_SWITCH_MSG = 20; @@ -408,6 +412,7 @@ class UserController implements Handler.Callback { */ private boolean finishUserUnlocking(final UserState uss) { final int userId = uss.mHandle.getIdentifier(); + Slog.d(TAG, "UserController event: finishUserUnlocking(" + userId + ")"); // Only keep marching forward if user is actually unlocked if (!StorageManager.isUserKeyUnlocked(userId)) return false; synchronized (mLock) { @@ -452,6 +457,7 @@ class UserController implements Handler.Callback { */ void finishUserUnlocked(final UserState uss) { final int userId = uss.mHandle.getIdentifier(); + Slog.d(TAG, "UserController event: finishUserUnlocked(" + userId + ")"); // Only keep marching forward if user is actually unlocked if (!StorageManager.isUserKeyUnlocked(userId)) return; synchronized (mLock) { @@ -522,6 +528,7 @@ class UserController implements Handler.Callback { private void finishUserUnlockedCompleted(UserState uss) { final int userId = uss.mHandle.getIdentifier(); + Slog.d(TAG, "UserController event: finishUserUnlockedCompleted(" + userId + ")"); synchronized (mLock) { // Bail if we ended up with a stale user if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return; @@ -739,6 +746,7 @@ class UserController implements Handler.Callback { } void finishUserStopping(final int userId, final UserState uss) { + Slog.d(TAG, "UserController event: finishUserStopping(" + userId + ")"); // On to the next. final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN); // This is the result receiver for the final shutdown broadcast. @@ -778,6 +786,7 @@ class UserController implements Handler.Callback { void finishUserStopped(UserState uss) { final int userId = uss.mHandle.getIdentifier(); + Slog.d(TAG, "UserController event: finishUserStopped(" + userId + ")"); final boolean stopped; boolean lockUser = true; final ArrayList<IStopUserCallback> stopCallbacks; @@ -1259,7 +1268,7 @@ class UserController implements Handler.Callback { Slog.w(TAG, msg); throw new SecurityException(msg); } - + Slog.i(TAG, "unlocking user " + userId); final long binderToken = Binder.clearCallingIdentity(); try { return unlockUserCleared(userId, token, secret, listener); @@ -1344,6 +1353,7 @@ class UserController implements Handler.Callback { boolean switchUser(final int targetUserId) { enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId); + Slog.i(TAG, "switching to user " + targetUserId); int currentUserId = getCurrentUserId(); UserInfo targetUserInfo = getUserInfo(targetUserId); if (targetUserId == currentUserId) { @@ -1486,9 +1496,13 @@ class UserController implements Handler.Callback { synchronized (mLock) { long delay = SystemClock.elapsedRealtime() - dispatchStartedTime; if (delay > USER_SWITCH_TIMEOUT_MS) { - Slog.e(TAG, "User switch timeout: observer " + name + Slog.e(TAG, "User switch timeout: observer " + name + " sent result after " + delay + " ms"); + } else if (delay > USER_SWITCH_WARNING_TIMEOUT_MS) { + Slog.w(TAG, "User switch slowed down by observer " + name + + ": result sent after " + delay + " ms"); } + curWaitingUserSwitchCallbacks.remove(name); // Continue switching if all callbacks have been notified and // user switching session is still valid diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 314e04c8da3..687ca192788 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -31,10 +31,13 @@ import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION; import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED; import static android.app.AppOpsManager.UID_STATE_PERSISTENT; import static android.app.AppOpsManager.UID_STATE_TOP; +import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES; import static android.app.AppOpsManager.modeToName; import static android.app.AppOpsManager.opToName; import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState; +import static java.lang.Long.max; + import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -938,6 +941,19 @@ public class AppOpsService extends IAppOpsService.Stub { } } + /** + * Update the pending state for the uid + * + * @param currentTime The current elapsed real time + * @param uid The uid that has a pending state + */ + private void updatePendingState(long currentTime, int uid) { + synchronized (this) { + mLastRealtime = max(currentTime, mLastRealtime); + updatePendingStateIfNeededLocked(mUidStates.get(uid)); + } + } + public void updateUidProcState(int uid, int procState) { synchronized (this) { final UidState uidState = getUidStateLocked(uid, true); @@ -963,7 +979,12 @@ public class AppOpsService extends IAppOpsService.Stub { } else { settleTime = mConstants.BG_STATE_SETTLE_TIME; } - uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime; + final long commitTime = SystemClock.elapsedRealtime() + settleTime; + uidState.pendingStateCommitTime = commitTime; + + mHandler.sendMessageDelayed( + PooledLambda.obtainMessage(AppOpsService::updatePendingState, this, + commitTime + 1, uid), settleTime + 1); } if (uidState.startNesting != 0) { // There is some actively running operation... need to find it @@ -1110,8 +1131,8 @@ public class AppOpsService extends IAppOpsService.Stub { return Collections.emptyList(); } synchronized (this) { - Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */, - false /* uidMismatchExpected */); + Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* isPrivileged */, + false /* edit */); if (pkgOps == null) { return null; } @@ -1208,8 +1229,7 @@ public class AppOpsService extends IAppOpsService.Stub { private void pruneOp(Op op, int uid, String packageName) { if (!op.hasAnyTime()) { - Ops ops = getOpsRawLocked(uid, packageName, false /* edit */, - false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(uid, packageName, false /* isPrivileged */, false /* edit */); if (ops != null) { ops.remove(op.op); if (ops.size() <= 0) { @@ -1294,6 +1314,18 @@ public class AppOpsService extends IAppOpsService.Stub { uidState.evalForegroundOps(mOpModeWatchers); } + notifyOpChangedForAllPkgsInUid(code, uid, false); + notifyOpChangedSync(code, uid, null, mode); + } + + /** + * Notify that an op changed for all packages in an uid. + * + * @param code The op that changed + * @param uid The uid the op was changed for + * @param onlyForeground Only notify watchers that watch for foreground changes + */ + private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground) { String[] uidPackageNames = getPackagesForUid(uid); ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null; @@ -1303,6 +1335,10 @@ public class AppOpsService extends IAppOpsService.Stub { final int callbackCount = callbacks.size(); for (int i = 0; i < callbackCount; i++) { ModeCallback callback = callbacks.valueAt(i); + if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) { + continue; + } + ArraySet<String> changedPackages = new ArraySet<>(); Collections.addAll(changedPackages, uidPackageNames); if (callbackSpecs == null) { @@ -1321,6 +1357,10 @@ public class AppOpsService extends IAppOpsService.Stub { final int callbackCount = callbacks.size(); for (int i = 0; i < callbackCount; i++) { ModeCallback callback = callbacks.valueAt(i); + if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) { + continue; + } + ArraySet<String> changedPackages = callbackSpecs.get(callback); if (changedPackages == null) { changedPackages = new ArraySet<>(); @@ -1333,7 +1373,6 @@ public class AppOpsService extends IAppOpsService.Stub { } if (callbackSpecs == null) { - notifyOpChangedSync(code, uid, null, mode); return; } @@ -1355,8 +1394,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } } - - notifyOpChangedSync(code, uid, null, mode); } private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) { @@ -1409,11 +1446,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } - @Override - public void setMode(int code, int uid, String packageName, int mode) { - setMode(code, uid, packageName, mode, true, false); - } - /** * Sets the mode for a certain op and uid. * @@ -1421,19 +1453,25 @@ public class AppOpsService extends IAppOpsService.Stub { * @param uid The UID for which to set * @param packageName The package for which to set * @param mode The new mode to set - * @param verifyUid Iff {@code true}, check that the package name belongs to the uid - * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid == - * false}) */ - private void setMode(int code, int uid, @NonNull String packageName, int mode, - boolean verifyUid, boolean isPrivileged) { + @Override + public void setMode(int code, int uid, @NonNull String packageName, int mode) { enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid); verifyIncomingOp(code); ArraySet<ModeCallback> repCbs = null; code = AppOpsManager.opToSwitch(code); + + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "Cannot setMode", e); + return; + } + synchronized (this) { UidState uidState = getUidStateLocked(uid, false); - Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged); + Op op = getOpLocked(code, uid, packageName, isPrivileged, true); if (op != null) { if (op.mode != mode) { op.mode = mode; @@ -1799,34 +1837,32 @@ public class AppOpsService extends IAppOpsService.Stub { } /** - * @see #checkOperationUnchecked(int, int, String, boolean, boolean) - */ - private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, - boolean raw) { - return checkOperationUnchecked(code, uid, packageName, raw, true); - } - - /** * Get the mode of an app-op. * * @param code The code of the op * @param uid The uid of the package the op belongs to * @param packageName The package the op belongs to * @param raw If the raw state of eval-ed state should be checked. - * @param verify If the code should check the package belongs to the uid * * @return The mode of the op */ private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, - boolean raw, boolean verify) { + boolean raw) { if (isOpRestrictedDueToSuspend(code, packageName, uid)) { return AppOpsManager.MODE_IGNORED; } + + boolean isPrivileged; + + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "checkOperation", e); + return AppOpsManager.opToDefaultMode(code); + } + synchronized (this) { - if (verify) { - checkPackage(uid, packageName); - } - if (isOpRestrictedLocked(uid, code, packageName)) { + if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) { return AppOpsManager.MODE_IGNORED; } code = AppOpsManager.opToSwitch(code); @@ -1836,7 +1872,7 @@ public class AppOpsService extends IAppOpsService.Stub { final int rawMode = uidState.opModes.get(code); return raw ? rawMode : uidState.evalMode(code, rawMode); } - Op op = getOpLocked(code, uid, packageName, false, verify, false); + Op op = getOpLocked(code, uid, packageName, false, false); if (op == null) { return AppOpsManager.opToDefaultMode(code); } @@ -1941,14 +1977,12 @@ public class AppOpsService extends IAppOpsService.Stub { @Override public int checkPackage(int uid, String packageName) { Preconditions.checkNotNull(packageName); - synchronized (this) { - Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - true /* uidMismatchExpected */); - if (ops != null) { - return AppOpsManager.MODE_ALLOWED; - } else { - return AppOpsManager.MODE_ERRORED; - } + try { + verifyAndGetIsPrivileged(uid, packageName); + + return AppOpsManager.MODE_ALLOWED; + } catch (SecurityException ignored) { + return AppOpsManager.MODE_ERRORED; } } @@ -2011,9 +2045,16 @@ public class AppOpsService extends IAppOpsService.Stub { private int noteOperationUnchecked(int code, int uid, String packageName, int proxyUid, String proxyPackageName, @OpFlags int flags) { + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "noteOperation", e); + return AppOpsManager.MODE_ERRORED; + } + synchronized (this) { - final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - false /* uidMismatchExpected */); + final Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, true /* edit */); if (ops == null) { scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED); @@ -2022,7 +2063,7 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.MODE_ERRORED; } final Op op = getOpLocked(ops, code, true); - if (isOpRestrictedLocked(uid, code, packageName)) { + if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) { scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED); return AppOpsManager.MODE_IGNORED; @@ -2181,16 +2222,25 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.MODE_IGNORED; } ClientState client = (ClientState)token; + + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "startOperation", e); + return AppOpsManager.MODE_ERRORED; + } + synchronized (this) { - final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */, - false /* uidMismatchExpected */); + final Ops ops = getOpsRawLocked(uid, resolvedPackageName, isPrivileged, + true /* edit */); if (ops == null) { if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid + " package " + resolvedPackageName); return AppOpsManager.MODE_ERRORED; } final Op op = getOpLocked(ops, code, true); - if (isOpRestrictedLocked(uid, code, resolvedPackageName)) { + if (isOpRestrictedLocked(uid, code, resolvedPackageName, isPrivileged)) { return AppOpsManager.MODE_IGNORED; } final int switchCode = AppOpsManager.opToSwitch(code); @@ -2262,8 +2312,17 @@ public class AppOpsService extends IAppOpsService.Stub { return; } ClientState client = (ClientState) token; + + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "Cannot finishOperation", e); + return; + } + synchronized (this) { - Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false); + Op op = getOpLocked(code, uid, resolvedPackageName, isPrivileged, true); if (op == null) { return; } @@ -2451,6 +2510,18 @@ public class AppOpsService extends IAppOpsService.Stub { uidState = new UidState(uid); mUidStates.put(uid, uidState); } else { + updatePendingStateIfNeededLocked(uidState); + } + return uidState; + } + + /** + * Check if the pending state should be updated and do so if needed + * + * @param uidState The uidState that might have a pending state + */ + private void updatePendingStateIfNeededLocked(@NonNull UidState uidState) { + if (uidState != null) { if (uidState.pendingStateCommitTime != 0) { if (uidState.pendingStateCommitTime < mLastRealtime) { commitUidPendingStateLocked(uidState); @@ -2462,7 +2533,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } } - return uidState; } private void commitUidPendingStateLocked(UidState uidState) { @@ -2480,24 +2550,28 @@ public class AppOpsService extends IAppOpsService.Stub { if (resolvedLastFg == resolvedNowFg) { continue; } - final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code); - if (callbacks != null) { - for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) { - final ModeCallback callback = callbacks.valueAt(cbi); - if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0 - || !callback.isWatchingUid(uidState.uid)) { - continue; - } - boolean doAllPackages = uidState.opModes != null - && uidState.opModes.indexOfKey(code) >= 0 - && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND; - if (uidState.pkgOps != null) { + + if (uidState.opModes != null + && uidState.opModes.indexOfKey(code) >= 0 + && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND) { + mHandler.sendMessage(PooledLambda.obtainMessage( + AppOpsService::notifyOpChangedForAllPkgsInUid, + this, code, uidState.uid, true)); + } else { + final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code); + if (callbacks != null) { + for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) { + final ModeCallback callback = callbacks.valueAt(cbi); + if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0 + || !callback.isWatchingUid(uidState.uid)) { + continue; + } for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) { final Op op = uidState.pkgOps.valueAt(pkgi).get(code); if (op == null) { continue; } - if (doAllPackages || op.mode == AppOpsManager.MODE_FOREGROUND) { + if (op.mode == AppOpsManager.MODE_FOREGROUND) { mHandler.sendMessage(PooledLambda.obtainMessage( AppOpsService::notifyOpChanged, this, callback, code, uidState.uid, @@ -2513,8 +2587,76 @@ public class AppOpsService extends IAppOpsService.Stub { uidState.pendingStateCommitTime = 0; } - private Ops getOpsRawLocked(int uid, String packageName, boolean edit, - boolean uidMismatchExpected) { + /** + * Verify that package belongs to uid and return whether the package is privileged. + * + * @param uid The uid the package belongs to + * @param packageName The package the might belong to the uid + * + * @return {@code true} iff the package is privileged + */ + private boolean verifyAndGetIsPrivileged(int uid, String packageName) { + if (uid == Process.ROOT_UID) { + // For backwards compatibility, don't check package name for root UID. + return false; + } + + // Do not check if uid/packageName is already known + synchronized (this) { + UidState uidState = mUidStates.get(uid); + if (uidState != null && uidState.pkgOps != null) { + Ops ops = uidState.pkgOps.get(packageName); + + if (ops != null) { + return ops.isPrivileged; + } + } + } + + boolean isPrivileged = false; + final long ident = Binder.clearCallingIdentity(); + try { + int pkgUid; + + ApplicationInfo appInfo = LocalServices.getService(PackageManagerInternal.class) + .getApplicationInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE + | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS + | PackageManager.MATCH_UNINSTALLED_PACKAGES + | PackageManager.MATCH_INSTANT, + Process.SYSTEM_UID, UserHandle.getUserId(uid)); + if (appInfo != null) { + pkgUid = appInfo.uid; + isPrivileged = (appInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; + } else { + pkgUid = resolveUid(packageName); + if (pkgUid >= 0) { + isPrivileged = false; + } + } + if (pkgUid != uid) { + throw new SecurityException("Specified package " + packageName + " under uid " + uid + + " but it is really " + pkgUid); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + + return isPrivileged; + } + + /** + * Get (and potentially create) ops. + * + * @param uid The uid the package belongs to + * @param packageName The name of the package + * @param isPrivileged If the package is privilidged (ignored if {@code edit} is false) + * @param edit If an ops does not exist, create the ops? + + * @return + */ + private Ops getOpsRawLocked(int uid, String packageName, boolean isPrivileged, boolean edit) { UidState uidState = getUidStateLocked(uid, edit); if (uidState == null) { return null; @@ -2532,47 +2674,6 @@ public class AppOpsService extends IAppOpsService.Stub { if (!edit) { return null; } - boolean isPrivileged = false; - // This is the first time we have seen this package name under this uid, - // so let's make sure it is valid. - if (uid != 0) { - final long ident = Binder.clearCallingIdentity(); - try { - int pkgUid = -1; - try { - ApplicationInfo appInfo = ActivityThread.getPackageManager() - .getApplicationInfo(packageName, - PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - UserHandle.getUserId(uid)); - if (appInfo != null) { - pkgUid = appInfo.uid; - isPrivileged = (appInfo.privateFlags - & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; - } else { - pkgUid = resolveUid(packageName); - if (pkgUid >= 0) { - isPrivileged = false; - } - } - } catch (RemoteException e) { - Slog.w(TAG, "Could not contact PackageManager", e); - } - if (pkgUid != uid) { - // Oops! The package name is not valid for the uid they are calling - // under. Abort. - if (!uidMismatchExpected) { - RuntimeException ex = new RuntimeException("here"); - ex.fillInStackTrace(); - Slog.w(TAG, "Bad call: specified package " + packageName - + " under uid " + uid + " but it is really " + pkgUid, ex); - } - return null; - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } ops = new Ops(packageName, uidState, isPrivileged); uidState.pkgOps.put(packageName, ops); } @@ -2580,7 +2681,7 @@ public class AppOpsService extends IAppOpsService.Stub { } /** - * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>. + * Get the state of all ops for a package. * * <p>Usually callers should use {@link #getOpLocked} and not call this directly. * @@ -2638,23 +2739,15 @@ public class AppOpsService extends IAppOpsService.Stub { * @param code The code of the op * @param uid The uid the of the package * @param packageName The package name for which to get the state for + * @param isPrivileged Whether the package is privileged or not (only used if {@code edit + * == true}) * @param edit Iff {@code true} create the {@link Op} object if not yet created - * @param verifyUid Iff {@code true} check that the package belongs to the uid - * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid - * == false}) * * @return The {@link Op state} of the op */ - private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit, - boolean verifyUid, boolean isPrivileged) { - Ops ops; - - if (verifyUid) { - ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */); - } else { - ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged); - } - + private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, + boolean isPrivileged, boolean edit) { + Ops ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged); if (ops == null) { return null; } @@ -2684,7 +2777,8 @@ public class AppOpsService extends IAppOpsService.Stub { return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid)); } - private boolean isOpRestrictedLocked(int uid, int code, String packageName) { + private boolean isOpRestrictedLocked(int uid, int code, String packageName, + boolean isPrivileged) { int userHandle = UserHandle.getUserId(uid); final int restrictionSetCount = mOpUserRestrictions.size(); @@ -2696,8 +2790,8 @@ public class AppOpsService extends IAppOpsService.Stub { if (AppOpsManager.opAllowSystemBypassRestriction(code)) { // If we are the system, bypass user restrictions for certain codes synchronized (this) { - Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, + true /* edit */); if ((ops != null) && ops.isPrivileged) { return false; } @@ -3068,7 +3162,7 @@ public class AppOpsService extends IAppOpsService.Stub { out.attribute(null, "n", Integer.toString(pkg.getUid())); synchronized (this) { Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), - false /* edit */, false /* uidMismatchExpected */); + false /* isPrivileged */, false /* edit */); // Should always be present as the list of PackageOps is generated // from Ops. if (ops != null) { @@ -4647,18 +4741,8 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override - public void setUidMode(int code, int uid, int mode) { - AppOpsService.this.setUidMode(code, uid, mode); - } - - @Override public void setAllPkgModesToDefault(int code, int uid) { AppOpsService.this.setAllPkgModesToDefault(code, uid); } - - @Override - public @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName) { - return AppOpsService.this.checkOperationUnchecked(code, uid, packageName, true, false); - } } } diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING index a53797dfa9e..1a5dac50346 100644 --- a/services/core/java/com/android/server/appop/TEST_MAPPING +++ b/services/core/java/com/android/server/appop/TEST_MAPPING @@ -10,6 +10,14 @@ "include-filter": "com.android.server.appop" } ] + }, + { + "name": "FrameworksMockingServicesTests", + "options": [ + { + "include-filter": "com.android.server.appop" + } + ] } ] } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 8274b8fac30..eaf51ab2954 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1057,6 +1057,27 @@ public class AudioService extends IAudioService.Stub } } + // Restore capture policies + synchronized (mPlaybackMonitor) { + HashMap<Integer, Integer> allowedCapturePolicies = + mPlaybackMonitor.getAllAllowedCapturePolicies(); + for (HashMap.Entry<Integer, Integer> entry : allowedCapturePolicies.entrySet()) { + int result = AudioSystem.setAllowedCapturePolicy( + entry.getKey(), + AudioAttributes.capturePolicyToFlags(entry.getValue(), 0x0)); + if (result != AudioSystem.AUDIO_STATUS_OK) { + Log.e(TAG, "Failed to restore capture policy, uid: " + + entry.getKey() + ", capture policy: " + entry.getValue() + + ", result: " + result); + // When restoring capture policy failed, set the capture policy as + // ALLOW_CAPTURE_BY_ALL, which will result in removing the cached + // capture policy in PlaybackActivityMonitor. + mPlaybackMonitor.setAllowedCapturePolicy( + entry.getKey(), AudioAttributes.ALLOW_CAPTURE_BY_ALL); + } + } + } + onIndicateSystemReady(); // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); @@ -2804,10 +2825,6 @@ public class AudioService extends IAudioService.Stub setSystemAudioMute(mute); AudioSystem.setMasterMute(mute); sendMasterMuteUpdate(mute, flags); - - Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION); - intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute); - sendBroadcastToAll(intent); } } } @@ -7304,6 +7321,43 @@ public class AudioService extends IAudioService.Stub mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid()); } + /** + * Specifies whether the audio played by this app may or may not be captured by other apps or + * the system. + * + * @param capturePolicy one of + * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, + * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}, + * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}. + * @return AudioSystem.AUDIO_STATUS_OK if set allowed capture policy succeed. + * @throws IllegalArgumentException if the argument is not a valid value. + */ + public int setAllowedCapturePolicy(int capturePolicy) { + int callingUid = Binder.getCallingUid(); + int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0); + final long identity = Binder.clearCallingIdentity(); + synchronized (mPlaybackMonitor) { + int result = AudioSystem.setAllowedCapturePolicy(callingUid, flags); + if (result == AudioSystem.AUDIO_STATUS_OK) { + mPlaybackMonitor.setAllowedCapturePolicy(callingUid, capturePolicy); + } + Binder.restoreCallingIdentity(identity); + return result; + } + } + + /** + * Return the capture policy. + * @return the cached capture policy for the calling uid. + */ + public int getAllowedCapturePolicy() { + int callingUid = Binder.getCallingUid(); + final long identity = Binder.clearCallingIdentity(); + int capturePolicy = mPlaybackMonitor.getAllowedCapturePolicy(callingUid); + Binder.restoreCallingIdentity(identity); + return capturePolicy; + } + //====================== // Audio device management //====================== diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java index db55138e446..7578948adb1 100644 --- a/services/core/java/com/android/server/audio/FocusRequester.java +++ b/services/core/java/com/android/server/audio/FocusRequester.java @@ -416,7 +416,8 @@ public class FocusRequester { } int dispatchFocusChange(int focusChange) { - if (mFocusDispatcher == null) { + final IAudioFocusDispatcher fd = mFocusDispatcher; + if (fd == null) { if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusChange: no focus dispatcher"); } return AudioManager.AUDIOFOCUS_REQUEST_FAILED; } @@ -436,7 +437,7 @@ public class FocusRequester { mFocusLossReceived = focusChange; } try { - mFocusDispatcher.dispatchAudioFocusChange(focusChange, mClientId); + fd.dispatchAudioFocusChange(focusChange, mClientId); } catch (android.os.RemoteException e) { Log.e(TAG, "dispatchFocusChange: error talking to focus listener " + mClientId, e); return AudioManager.AUDIOFOCUS_REQUEST_FAILED; @@ -445,16 +446,18 @@ public class FocusRequester { } void dispatchFocusResultFromExtPolicy(int requestResult) { - if (mFocusDispatcher == null) { + final IAudioFocusDispatcher fd = mFocusDispatcher; + if (fd == null) { if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusResultFromExtPolicy: no focus dispatcher"); } + return; } if (DEBUG) { Log.v(TAG, "dispatching result" + requestResult + " to " + mClientId); } try { - mFocusDispatcher.dispatchFocusResultFromExtPolicy(requestResult, mClientId); + fd.dispatchFocusResultFromExtPolicy(requestResult, mClientId); } catch (android.os.RemoteException e) { Log.e(TAG, "dispatchFocusResultFromExtPolicy: error talking to focus listener" + mClientId, e); diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index 3a25d980e97..93ffe835338 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -160,6 +160,12 @@ public final class PlaybackActivityMonitor new AudioPlaybackConfiguration(pic, newPiid, Binder.getCallingUid(), Binder.getCallingPid()); apc.init(); + synchronized (mAllowedCapturePolicies) { + int uid = apc.getClientUid(); + if (mAllowedCapturePolicies.containsKey(uid)) { + updateAllowedCapturePolicy(apc, mAllowedCapturePolicies.get(uid)); + } + } sEventLogger.log(new NewPlayerEvent(apc)); synchronized(mPlayerLock) { mPlayers.put(newPiid, apc); @@ -169,6 +175,13 @@ public final class PlaybackActivityMonitor public void playerAttributes(int piid, @NonNull AudioAttributes attr, int binderUid) { final boolean change; + synchronized (mAllowedCapturePolicies) { + if (mAllowedCapturePolicies.containsKey(binderUid) + && attr.getAllowedCapturePolicy() < mAllowedCapturePolicies.get(binderUid)) { + attr = new AudioAttributes.Builder(attr) + .setAllowedCapturePolicy(mAllowedCapturePolicies.get(binderUid)).build(); + } + } synchronized(mPlayerLock) { final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid)); if (checkConfigurationCaller(piid, apc, binderUid)) { @@ -284,6 +297,69 @@ public final class PlaybackActivityMonitor } } + /** + * A map of uid to capture policy. + */ + private final HashMap<Integer, Integer> mAllowedCapturePolicies = + new HashMap<Integer, Integer>(); + + /** + * Cache allowed capture policy, which specifies whether the audio played by the app may or may + * not be captured by other apps or the system. + * + * @param uid the uid of requested app + * @param capturePolicy one of + * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, + * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}, + * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}. + */ + public void setAllowedCapturePolicy(int uid, int capturePolicy) { + synchronized (mAllowedCapturePolicies) { + if (capturePolicy == AudioAttributes.ALLOW_CAPTURE_BY_ALL) { + // When the capture policy is ALLOW_CAPTURE_BY_ALL, it is okay to + // remove it from cached capture policy as it is the default value. + mAllowedCapturePolicies.remove(uid); + return; + } else { + mAllowedCapturePolicies.put(uid, capturePolicy); + } + } + synchronized (mPlayerLock) { + for (AudioPlaybackConfiguration apc : mPlayers.values()) { + if (apc.getClientUid() == uid) { + updateAllowedCapturePolicy(apc, capturePolicy); + } + } + } + } + + /** + * Return the capture policy for given uid. + * @param uid the uid to query its cached capture policy. + * @return cached capture policy for given uid or AudioAttributes.ALLOW_CAPTURE_BY_ALL + * if there is not cached capture policy. + */ + public int getAllowedCapturePolicy(int uid) { + return mAllowedCapturePolicies.getOrDefault(uid, AudioAttributes.ALLOW_CAPTURE_BY_ALL); + } + + /** + * Return all cached capture policies. + */ + public HashMap<Integer, Integer> getAllAllowedCapturePolicies() { + return mAllowedCapturePolicies; + } + + private void updateAllowedCapturePolicy(AudioPlaybackConfiguration apc, int capturePolicy) { + AudioAttributes attr = apc.getAudioAttributes(); + if (attr.getAllowedCapturePolicy() >= capturePolicy) { + return; + } + apc.handleAudioAttributesEvent( + new AudioAttributes.Builder(apc.getAudioAttributes()) + .setAllowedCapturePolicy(capturePolicy).build()); + } + // Implementation of AudioPlaybackConfiguration.PlayerDeathMonitor @Override public void playerDeath(int piid) { @@ -331,6 +407,12 @@ public final class PlaybackActivityMonitor // log sEventLogger.dump(pw); } + synchronized (mAllowedCapturePolicies) { + pw.println("\n allowed capture policies:"); + for (HashMap.Entry<Integer, Integer> entry : mAllowedCapturePolicies.entrySet()) { + pw.println(" uid: " + entry.getKey() + " policy: " + entry.getValue()); + } + } } /** diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java index 9730c9a1a38..ab5bef8b80a 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java @@ -275,8 +275,18 @@ class Convert { return hwSel; } - static @NonNull ProgramSelector programSelectorFromHal( + private static boolean isEmpty( @NonNull android.hardware.broadcastradio.V2_0.ProgramSelector sel) { + if (sel.primaryId.type != 0) return false; + if (sel.primaryId.value != 0) return false; + if (sel.secondaryIds.size() != 0) return false; + return true; + } + + static @Nullable ProgramSelector programSelectorFromHal( + @NonNull android.hardware.broadcastradio.V2_0.ProgramSelector sel) { + if (isEmpty(sel)) return null; + ProgramSelector.Identifier[] secondaryIds = sel.secondaryIds.stream(). map(Convert::programIdentifierFromHal).map(Objects::requireNonNull). toArray(ProgramSelector.Identifier[]::new); @@ -364,7 +374,7 @@ class Convert { collect(Collectors.toList()); return new RadioManager.ProgramInfo( - programSelectorFromHal(info.selector), + Objects.requireNonNull(programSelectorFromHal(info.selector)), programIdentifierFromHal(info.logicallyTunedTo), programIdentifierFromHal(info.physicallyTunedTo), relatedContent, @@ -402,7 +412,7 @@ class Convert { public static @NonNull android.hardware.radio.Announcement announcementFromHal( @NonNull Announcement hwAnnouncement) { return new android.hardware.radio.Announcement( - programSelectorFromHal(hwAnnouncement.selector), + Objects.requireNonNull(programSelectorFromHal(hwAnnouncement.selector)), hwAnnouncement.type, vendorInfoFromHal(hwAnnouncement.vendorInfo) ); diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 722a696c172..fc01a1e2993 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -59,6 +59,7 @@ import android.os.MessageQueue; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; +import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.text.TextUtils; @@ -128,6 +129,9 @@ public class InputManagerService extends IInputManager.Stub private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml"; private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml"; + // Feature flag name for the deep press feature + private static final String DEEP_PRESS_ENABLED = "deep_press_enabled"; + private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1; private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2; private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3; @@ -244,6 +248,7 @@ public class InputManagerService extends IInputManager.Stub private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon); private static native void nativeSetPointerCapture(long ptr, boolean detached); private static native boolean nativeCanDispatchToDisplay(long ptr, int deviceId, int displayId); + private static native void nativeSetMotionClassifierEnabled(long ptr, boolean enabled); // Input event injection constants defined in InputDispatcher.h. private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0; @@ -349,6 +354,7 @@ public class InputManagerService extends IInputManager.Stub registerPointerSpeedSettingObserver(); registerShowTouchesSettingObserver(); registerAccessibilityLargePointerSettingObserver(); + registerLongPressTimeoutObserver(); registerVolumeKeysRotationSettingObserver(); mContext.registerReceiver(new BroadcastReceiver() { @@ -357,6 +363,7 @@ public class InputManagerService extends IInputManager.Stub updatePointerSpeedFromSettings(); updateShowTouchesFromSettings(); updateAccessibilityLargePointerFromSettings(); + updateDeepPressStatusFromSettings("user switched"); updateVolumeKeysRotationFromSettings(); } }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler); @@ -364,6 +371,7 @@ public class InputManagerService extends IInputManager.Stub updatePointerSpeedFromSettings(); updateShowTouchesFromSettings(); updateAccessibilityLargePointerFromSettings(); + updateDeepPressStatusFromSettings("just booted"); updateVolumeKeysRotationFromSettings(); } @@ -1578,7 +1586,7 @@ public class InputManagerService extends IInputManager.Stub setPointerSpeedUnchecked(speed); } - public void updatePointerSpeedFromSettings() { + private void updatePointerSpeedFromSettings() { int speed = getPointerSpeedSetting(); setPointerSpeedUnchecked(speed); } @@ -1610,7 +1618,7 @@ public class InputManagerService extends IInputManager.Stub return speed; } - public void updateShowTouchesFromSettings() { + private void updateShowTouchesFromSettings() { int setting = getShowTouchesSetting(0); nativeSetShowTouches(mPtr, setting != 0); } @@ -1626,7 +1634,7 @@ public class InputManagerService extends IInputManager.Stub }, UserHandle.USER_ALL); } - public void updateAccessibilityLargePointerFromSettings() { + private void updateAccessibilityLargePointerFromSettings() { final int accessibilityConfig = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, 0, UserHandle.USER_CURRENT); @@ -1645,6 +1653,34 @@ public class InputManagerService extends IInputManager.Stub }, UserHandle.USER_ALL); } + private void updateDeepPressStatusFromSettings(String reason) { + // Not using ViewConfiguration.getLongPressTimeout here because it may return a stale value + final int timeout = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.LONG_PRESS_TIMEOUT, ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT, + UserHandle.USER_CURRENT); + final boolean featureEnabledFlag = + DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT, + DEEP_PRESS_ENABLED, true /* default */); + final boolean enabled = + featureEnabledFlag && timeout <= ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT; + Log.i(TAG, + (enabled ? "Enabling" : "Disabling") + " motion classifier because " + reason + + ": feature " + (featureEnabledFlag ? "enabled" : "disabled") + + ", long press timeout = " + timeout); + nativeSetMotionClassifierEnabled(mPtr, enabled); + } + + private void registerLongPressTimeoutObserver() { + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.LONG_PRESS_TIMEOUT), true, + new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange) { + updateDeepPressStatusFromSettings("timeout changed"); + } + }, UserHandle.USER_ALL); + } + private int getShowTouchesSetting(int defaultValue) { int result = defaultValue; try { diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 19b62685dfa..01d8a303719 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -388,6 +388,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_SUBSCRIPTION_OVERRIDE = 16; private static final int MSG_METERED_RESTRICTED_PACKAGES_CHANGED = 17; private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18; + private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19; private static final int UID_MSG_STATE_CHANGED = 100; private static final int UID_MSG_GONE = 101; @@ -3067,6 +3068,34 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mContext.enforceCallingOrSelfPermission(MANAGE_SUBSCRIPTION_PLANS, TAG); } + private void enforceSubscriptionPlanValidity(SubscriptionPlan[] plans) { + // nothing to check if no plans + if (plans.length == 0) { + return; + } + + long applicableNetworkTypes = 0; + boolean allNetworks = false; + for (SubscriptionPlan plan : plans) { + if (plan.getNetworkTypes() == null) { + allNetworks = true; + } else { + if ((applicableNetworkTypes & plan.getNetworkTypesBitMask()) != 0) { + throw new IllegalArgumentException( + "Multiple subscription plans defined for a single network type."); + } else { + applicableNetworkTypes |= plan.getNetworkTypesBitMask(); + } + } + } + + // ensure at least one plan applies for every network type + if (!allNetworks) { + throw new IllegalArgumentException( + "No generic subscription plan that applies to all network types."); + } + } + @Override public SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage) { enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage); @@ -3231,9 +3260,26 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public void setSubscriptionPlans(int subId, SubscriptionPlan[] plans, String callingPackage) { enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage); + enforceSubscriptionPlanValidity(plans); + int count5GPlans = 0; + SubscriptionPlan plan5G = null; for (SubscriptionPlan plan : plans) { Preconditions.checkNotNull(plan); + // temporary workaround to allow 5G unmetered for March QPR + // TODO: remove once SubscriptionPlan.Builder#setNetworkTypes(int[]) is public in R + if (plan.getTitle() != null && plan.getTitle().toString().contains("NR 5G unmetered") + && plan.getDataLimitBytes() == SubscriptionPlan.BYTES_UNLIMITED + && (plan.getDataLimitBehavior() == SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN + || plan.getDataLimitBehavior() == SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)) { + count5GPlans++; + plan5G = plan; + } + } + + // TODO: remove once SubscriptionPlan.Builder#setNetworkTypes(int[]) is public in R + if (count5GPlans == 1 && plans.length > 1) { + plan5G.setNetworkTypes(new int[] {TelephonyManager.NETWORK_TYPE_NR}); } final long token = Binder.clearCallingIdentity(); @@ -3259,6 +3305,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); mContext.sendBroadcast(intent, android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS); + mHandler.sendMessage( + mHandler.obtainMessage(MSG_SUBSCRIPTION_PLANS_CHANGED, subId, 0, plans)); } finally { Binder.restoreCallingIdentity(token); } @@ -4463,6 +4511,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + private void dispatchSubscriptionPlansChanged(INetworkPolicyListener listener, int subId, + SubscriptionPlan[] plans) { + if (listener != null) { + try { + listener.onSubscriptionPlansChanged(subId, plans); + } catch (RemoteException ignored) { + } + } + } + private final Handler.Callback mHandlerCallback = new Handler.Callback() { @Override public boolean handleMessage(Message msg) { @@ -4581,6 +4639,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { setNetworkTemplateEnabledInner(template, enabled); return true; } + case MSG_SUBSCRIPTION_PLANS_CHANGED: { + final SubscriptionPlan[] plans = (SubscriptionPlan[]) msg.obj; + final int subId = msg.arg1; + final int length = mListeners.beginBroadcast(); + for (int i = 0; i < length; i++) { + final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); + dispatchSubscriptionPlansChanged(listener, subId, plans); + } + mListeners.finishBroadcast(); + return true; + } default: { return false; } diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index b3b0029326d..56910ddbbb7 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -434,16 +434,6 @@ public class Installer extends SystemService { } } - public void markBootComplete(String instructionSet) throws InstallerException { - assertValidInstructionSet(instructionSet); - if (!checkBeforeRemote()) return; - try { - mInstalld.markBootComplete(instructionSet); - } catch (Exception e) { - throw InstallerException.from(e); - } - } - public void freeCache(String uuid, long targetFreeBytes, long cacheReservedBytes, int flags) throws InstallerException { if (!checkBeforeRemote()) return; diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index fd8db4b99be..d17365db77d 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -258,12 +258,15 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } // Don't hold mSessions lock when calling restoreSession, since it might trigger an APK // atomic install which needs to query sessions, which requires lock on mSessions. + boolean isDeviceUpgrading = mPm.isDeviceUpgrading(); for (PackageInstallerSession session : stagedSessionsToRestore) { - if (mPm.isDeviceUpgrading() && !session.isStagedAndInTerminalState()) { + if (!session.isStagedAndInTerminalState() && session.hasParentSessionId() + && getSession(session.getParentSessionId()) == null) { session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, - "Build fingerprint has changed"); + "An orphan staged session " + session.sessionId + " is found, " + + "parent " + session.getParentSessionId() + " is missing"); } - mStagingManager.restoreSession(session); + mStagingManager.restoreSession(session, isDeviceUpgrading); } // Broadcasts are not sent while we restore sessions on boot, since no processes would be // ready to listen to them. From now on, we greedily assume that broadcasts requests are diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c153a452cbe..179abe958b1 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -209,6 +209,7 @@ import android.os.AsyncTask; import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.ConditionVariable; import android.os.Debug; import android.os.Environment; import android.os.FileUtils; @@ -980,6 +981,8 @@ public class PackageManagerService extends IPackageManager.Stub private Future<?> mPrepareAppDataFuture; + private final ConditionVariable mBlockDeleteOnUserRemoveForTest = new ConditionVariable(true); + private static class IFVerificationParams { PackageParser.Package pkg; boolean replacing; @@ -2321,33 +2324,59 @@ public class PackageManagerService extends IPackageManager.Stub return m; } + private boolean isSystemUserPackagesBlacklistSupported() { + return Resources.getSystem().getBoolean( + R.bool.config_systemUserPackagesBlacklistSupported); + } + private void enableSystemUserPackages() { - if (!UserManager.isSplitSystemUser()) { + if (!isSystemUserPackagesBlacklistSupported()) { + Log.i(TAG, "Skipping system user blacklist since " + + "config_systemUserPackagesBlacklistSupported is false"); return; } - // For system user, enable apps based on the following conditions: - // - app is whitelisted or belong to one of these groups: - // -- system app which has no launcher icons - // -- system app which has INTERACT_ACROSS_USERS permission - // -- system IME app - // - app is not in the blacklist - AppsQueryHelper queryHelper = new AppsQueryHelper(this); + + boolean isHeadlessSystemUserMode = UserManager.isHeadlessSystemUserMode(); + if (!isHeadlessSystemUserMode && !UserManager.isSplitSystemUser()) { + Log.i(TAG, "Skipping system user blacklist on 'regular' device type"); + return; + } + + Log.i(TAG, "blacklisting packages for system user"); + Set<String> enableApps = new ArraySet<>(); - enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS - | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM - | AppsQueryHelper.GET_IMES, /* systemAppsOnly */ true, UserHandle.SYSTEM)); - ArraySet<String> wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps(); - enableApps.addAll(wlApps); - enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_REQUIRED_FOR_SYSTEM_USER, - /* systemAppsOnly */ false, UserHandle.SYSTEM)); - ArraySet<String> blApps = SystemConfig.getInstance().getSystemUserBlacklistedApps(); - enableApps.removeAll(blApps); - Log.i(TAG, "Applications installed for system user: " + enableApps); + AppsQueryHelper queryHelper = new AppsQueryHelper(this); List<String> allAps = queryHelper.queryApps(0, /* systemAppsOnly */ false, UserHandle.SYSTEM); + + if (isHeadlessSystemUserMode) { + enableApps.addAll(allAps); + } else { + // For split system user, select apps based on the following conditions: + // -- system app which has no launcher icons + // -- system app which has INTERACT_ACROSS_USERS permission + // -- system IME app + enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS + | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM + | AppsQueryHelper.GET_IMES, /* systemAppsOnly */ true, UserHandle.SYSTEM)); + enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_REQUIRED_FOR_SYSTEM_USER, + /* systemAppsOnly */ false, UserHandle.SYSTEM)); + + // Apply whitelist for split system user + ArraySet<String> whitelistedSystemUserApps = SystemConfig.getInstance() + .getSystemUserWhitelistedApps(); + enableApps.addAll(whitelistedSystemUserApps); + Log.i(TAG, "Whitelisted packages: " + whitelistedSystemUserApps); + } + // Apply blacklist for split system user/headless system user + ArraySet<String> blacklistedSystemUserApps = SystemConfig.getInstance() + .getSystemUserBlacklistedApps(); + enableApps.removeAll(blacklistedSystemUserApps); + Log.i(TAG, "Blacklisted packages: " + blacklistedSystemUserApps); + final int allAppsSize = allAps.size(); synchronized (mPackages) { - for (int i = 0; i < allAppsSize; i++) { + for (int i = 0; i < allAppsSize; i++) { String pName = allAps.get(i); PackageSetting pkgSetting = mSettings.mPackages.get(pName); // Should not happen, but we shouldn't be failing if it does @@ -18209,7 +18238,9 @@ public class PackageManagerService extends IPackageManager.Stub final int verificationId = mIntentFilterVerificationToken++; for (PackageParser.Activity a : pkg.activities) { for (ActivityIntentInfo filter : a.intents) { - if (filter.handlesWebUris(true) && needsNetworkVerificationLPr(filter)) { + // Run verification against hosts mentioned in any web-nav intent filter, + // even if the filter matches non-web schemes as well + if (filter.handlesWebUris(false) && needsNetworkVerificationLPr(filter)) { if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Verification needed for IntentFilter:" + filter.toString()); mIntentFilterVerifier.addOneIntentFilterVerification( @@ -22365,6 +22396,18 @@ public class PackageManagerService extends IPackageManager.Stub if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) { mSettings.dumpPackagesLPr(pw, packageName, permissionNames, dumpState, checkin); + + boolean systemUserPackagesBlacklistSupported = + isSystemUserPackagesBlacklistSupported(); + pw.println("isSystemUserPackagesBlacklistSupported: " + + systemUserPackagesBlacklistSupported); + if (systemUserPackagesBlacklistSupported) { + SystemConfig sysconfig = SystemConfig.getInstance(); + dumpPackagesList(pw, " ", "whitelist", + sysconfig.getSystemUserWhitelistedApps()); + dumpPackagesList(pw, " ", "blacklist", + sysconfig.getSystemUserBlacklistedApps()); + } } if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) { @@ -22474,6 +22517,21 @@ public class PackageManagerService extends IPackageManager.Stub } } + private void dumpPackagesList(PrintWriter pw, String prefix, String name, + ArraySet<String> list) { + pw.print(prefix); pw.print(name); pw.print(": "); + int size = list.size(); + if (size == 0) { + pw.println("empty"); + return; + } + pw.print(size); pw.println(" packages"); + String prefix2 = prefix + " "; + for (int i = 0; i < size; i++) { + pw.print(prefix2); pw.println(list.valueAt(i)); + } + } + //TODO: b/111402650 private void disableSkuSpecificApps() { String apkList[] = mContext.getResources().getStringArray( @@ -23816,8 +23874,13 @@ public class PackageManagerService extends IPackageManager.Stub Slog.i(TAG, " Removing package " + packageName); } //end run - mHandler.post(() -> deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST, - userHandle, 0)); + mHandler.post(() -> { + if (!mBlockDeleteOnUserRemoveForTest.block(30000 /* 30 seconds*/)) { + mBlockDeleteOnUserRemoveForTest.open(); + } + deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST, + userHandle, 0); + }); } } } @@ -25179,6 +25242,16 @@ public class PackageManagerService extends IPackageManager.Stub Slog.wtf(TAG, e); } } + + @Override + public void notifyingOnNextUserRemovalForTest() { + mBlockDeleteOnUserRemoveForTest.close(); + } + + @Override + public void userRemovedForTest() { + mBlockDeleteOnUserRemoveForTest.open(); + } } @GuardedBy("mPackages") diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 9c87c748f86..895d2c5d00b 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -40,6 +40,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.ParcelableException; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; @@ -403,29 +404,28 @@ public class StagingManager { } else { params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION; } - int apkSessionId = mPi.createSession( - params, originalSession.getInstallerPackageName(), - 0 /* UserHandle.SYSTEM */); - PackageInstallerSession apkSession = mPi.getSession(apkSessionId); - try { + int apkSessionId = mPi.createSession( + params, originalSession.getInstallerPackageName(), + 0 /* UserHandle.SYSTEM */); + PackageInstallerSession apkSession = mPi.getSession(apkSessionId); apkSession.open(); for (String apkFilePath : apkFilePaths) { File apkFile = new File(apkFilePath); ParcelFileDescriptor pfd = ParcelFileDescriptor.open(apkFile, ParcelFileDescriptor.MODE_READ_ONLY); - long sizeBytes = pfd.getStatSize(); + long sizeBytes = (pfd == null) ? -1 : pfd.getStatSize(); if (sizeBytes < 0) { Slog.e(TAG, "Unable to get size of: " + apkFilePath); return null; } apkSession.write(apkFile.getName(), 0, sizeBytes, pfd); } - } catch (IOException e) { + return apkSession; + } catch (IOException | ParcelableException e) { Slog.e(TAG, "Failure to install APK staged session " + originalSession.sessionId, e); return null; } - return apkSession; } private boolean commitApkSession(@NonNull PackageInstallerSession apkSession, @@ -619,7 +619,7 @@ public class StagingManager { return false; } - void restoreSession(@NonNull PackageInstallerSession session) { + void restoreSession(@NonNull PackageInstallerSession session, boolean isDeviceUpgrading) { PackageInstallerSession sessionToResume = session; synchronized (mStagedSessions) { mStagedSessions.append(session.sessionId, session); @@ -636,6 +636,13 @@ public class StagingManager { } } } + // The preconditions used during pre-reboot verification might have changed when device + // is upgrading. Updated staged sessions to activation failed before we resume the session. + if (isDeviceUpgrading && !sessionToResume.isStagedAndInTerminalState()) { + sessionToResume.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, + "Build fingerprint has changed"); + return; + } checkStateAndResume(sessionToResume); } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 6fcb4b6e47f..82bc41fcdcd 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import static android.Manifest.permission.INJECT_EVENTS; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; @@ -39,6 +40,7 @@ import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PackageManagerInternal; import android.content.pm.ShortcutServiceInternal; import android.content.pm.UserInfo; import android.content.pm.UserInfo.UserInfoFlag; @@ -127,6 +129,7 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; /** * Service for {@link UserManager}. @@ -250,6 +253,7 @@ public class UserManagerService extends IUserManager.Stub { private final File mUserListFile; private static final IBinder mUserRestriconToken = new Binder(); + private final AtomicBoolean mNotifyPackageManagerOnUserRemoval = new AtomicBoolean(false); /** * Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps. @@ -3352,6 +3356,11 @@ public class UserManagerService extends IUserManager.Stub { mRemovingUserIds.delete(userHandle); } } + if (mNotifyPackageManagerOnUserRemoval.getAndSet(false)) { + final PackageManagerInternal pmInternal = + LocalServices.getService(PackageManagerInternal.class); + pmInternal.userRemovedForTest(); + } } private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) { @@ -4493,4 +4502,20 @@ public class UserManagerService extends IUserManager.Stub { + " does not match the calling uid " + callingUid); } } + + @Override + public void notifyOnNextUserRemoveForTest() { + mContext.enforceCallingOrSelfPermission(INJECT_EVENTS, "notifyOnNextUserRemoveForTest"); + final ActivityManagerInternal amInternal = + LocalServices.getService(ActivityManagerInternal.class); + if (!amInternal.isActiveInstrumentation(Binder.getCallingUid())) { + return; + } + + this.mNotifyPackageManagerOnUserRemoval.set(true); + + final PackageManagerInternal pmInternal = + LocalServices.getService(PackageManagerInternal.class); + pmInternal.notifyingOnNextUserRemovalForTest(); + } } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index cff13229c93..6066cdf7fec 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -446,6 +446,8 @@ public final class PowerManagerService extends SystemService // True if doze should not be started until after the screen off transition. private boolean mDozeAfterScreenOff; + private boolean mEnableAutoSuspendConfig; + // The minimum screen off timeout, in milliseconds. private long mMinimumScreenOffTimeoutConfig; @@ -1023,6 +1025,8 @@ public final class PowerManagerService extends SystemService com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay); mDecoupleHalInteractiveModeFromDisplayConfig = resources.getBoolean( com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay); + mEnableAutoSuspendConfig = resources.getBoolean( + com.android.internal.R.bool.config_enableAutoSuspend); mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean( com.android.internal.R.bool.config_unplugTurnsOnScreen); mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig = resources.getBoolean( @@ -2770,7 +2774,8 @@ public final class PowerManagerService extends SystemService if (!mDecoupleHalInteractiveModeFromDisplayConfig) { setHalInteractiveModeLocked(false); } - if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) { + if (mEnableAutoSuspendConfig + && !mDecoupleHalAutoSuspendModeFromDisplayConfig) { setHalAutoSuspendModeLocked(true); } } else { @@ -2815,7 +2820,7 @@ public final class PowerManagerService extends SystemService private void updateSuspendBlockerLocked() { final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0); final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked(); - final boolean autoSuspend = !needDisplaySuspendBlocker; + final boolean autoSuspend = mEnableAutoSuspendConfig && !needDisplaySuspendBlocker; final boolean interactive = mDisplayPowerRequest.isBrightOrDim(); // Disable auto-suspend if needed. diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 08c1bb53621..1f75294de8e 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -58,6 +58,7 @@ import android.util.SparseLongArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.Watchdog; @@ -1479,6 +1480,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; + IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); synchronized (mLock) { for (RollbackData data : mRollbacks) { diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 5f5cd3c4611..2394bafc09d 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -1437,7 +1437,8 @@ public class TrustManagerService extends SystemService { if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) { refreshAgentList(getSendingUserId()); updateDevicePolicyFeatures(); - } else if (Intent.ACTION_USER_ADDED.equals(action)) { + } else if (Intent.ACTION_USER_ADDED.equals(action) || Intent.ACTION_USER_STARTED.equals( + action)) { int userId = getUserId(intent); if (userId > 0) { maybeEnableFactoryTrustAgents(mLockPatternUtils, userId); @@ -1478,6 +1479,7 @@ public class TrustManagerService extends SystemService { filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); filter.addAction(Intent.ACTION_USER_ADDED); filter.addAction(Intent.ACTION_USER_REMOVED); + filter.addAction(Intent.ACTION_USER_STARTED); context.registerReceiverAsUser(this, UserHandle.ALL, filter, diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 4e136af0fdc..0e2f0ce991c 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1180,6 +1180,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } }; + private Runnable mTryToRebindRunnable = () -> { + tryToRebind(); + }; + WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper, int clientUid) { mInfo = info; mWallpaper = wallpaper; @@ -1286,7 +1290,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub saveSettingsLocked(mWallpaper.userId); } FgThread.getHandler().removeCallbacks(mResetRunnable); - mContext.getMainThreadHandler().removeCallbacks(this::tryToRebind); + mContext.getMainThreadHandler().removeCallbacks(mTryToRebindRunnable); } } } @@ -1344,7 +1348,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub < WALLPAPER_RECONNECT_TIMEOUT_MS) { // Bind fail without timeout, schedule rebind Slog.w(TAG, "Rebind fail! Try again later"); - mContext.getMainThreadHandler().postDelayed(this::tryToRebind, 1000); + mContext.getMainThreadHandler().postDelayed(mTryToRebindRunnable, 1000); } else { // Timeout Slog.w(TAG, "Reverting to built-in wallpaper!"); diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java index 90bb494232c..338df39a162 100644 --- a/services/core/java/com/android/server/wm/BarController.java +++ b/services/core/java/com/android/server/wm/BarController.java @@ -164,7 +164,8 @@ public class BarController { } boolean isTransparentAllowed(WindowState win) { - return win == null || !win.isLetterboxedOverlappingWith(mContentFrame); + return win == null || mState == StatusBarManager.WINDOW_STATE_HIDING + || !win.isLetterboxedOverlappingWith(mContentFrame); } boolean setBarShowingLw(final boolean show) { diff --git a/services/core/java/com/android/server/wm/PolicyControl.java b/services/core/java/com/android/server/wm/PolicyControl.java index 4c8ce9ebb72..87c34908d04 100644 --- a/services/core/java/com/android/server/wm/PolicyControl.java +++ b/services/core/java/com/android/server/wm/PolicyControl.java @@ -67,15 +67,19 @@ class PolicyControl { : (attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility); if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) { vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + | View.SYSTEM_UI_FLAG_FULLSCREEN; + if (attrs.isFullscreen()) { + vis |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + } vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.STATUS_BAR_TRANSLUCENT); } if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) { vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; + if (attrs.isFullscreen()) { + vis |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; + } vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.NAVIGATION_BAR_TRANSLUCENT); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 2e0f263b593..7cf245e0bd0 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -5710,6 +5710,12 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setForceShowSystemBars(boolean show) { + boolean isAutomotive = mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_AUTOMOTIVE); + if (!isAutomotive) { + throw new UnsupportedOperationException("Force showing system bars is only supported" + + "for Automotive use cases."); + } if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Caller does not hold permission " |