summaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java14
-rw-r--r--services/backup/java/com/android/server/backup/Trampoline.java32
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerFiles.java5
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java67
-rw-r--r--services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java2
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java34
-rw-r--r--services/backup/java/com/android/server/backup/utils/FileUtils.java40
-rw-r--r--services/backup/java/com/android/server/backup/utils/RandomAccessFileUtils.java52
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java94
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java93
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java9
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java121
-rw-r--r--services/core/java/com/android/server/ExtconUEventObserver.java18
-rw-r--r--services/core/java/com/android/server/FgThread.java12
-rw-r--r--services/core/java/com/android/server/IoThread.java12
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java206
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java38
-rw-r--r--services/core/java/com/android/server/RescueParty.java16
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java144
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java44
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java20
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java95
-rw-r--r--services/core/java/com/android/server/am/AppCompactor.java9
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java4
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java24
-rw-r--r--services/core/java/com/android/server/am/BroadcastDispatcher.java76
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java24
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java1
-rw-r--r--services/core/java/com/android/server/am/EventLogTags.logtags2
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java3
-rw-r--r--services/core/java/com/android/server/am/PendingIntentRecord.java6
-rw-r--r--services/core/java/com/android/server/am/PreBootBroadcaster.java3
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java42
-rw-r--r--services/core/java/com/android/server/am/UserController.java49
-rw-r--r--services/core/java/com/android/server/appbinding/AppBindingService.java38
-rw-r--r--services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java35
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java50
-rw-r--r--services/core/java/com/android/server/attention/AttentionManagerService.java96
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java4
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java46
-rw-r--r--services/core/java/com/android/server/audio/FocusRequester.java27
-rw-r--r--services/core/java/com/android/server/audio/MediaFocusControl.java33
-rw-r--r--services/core/java/com/android/server/biometrics/AuthenticationClient.java41
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java50
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricServiceBase.java369
-rw-r--r--services/core/java/com/android/server/biometrics/EnumerateClient.java8
-rw-r--r--services/core/java/com/android/server/biometrics/RemovalClient.java8
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java245
-rw-r--r--services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java359
-rw-r--r--services/core/java/com/android/server/biometrics/iris/IrisService.java30
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java2
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java78
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java4
-rw-r--r--services/core/java/com/android/server/display/ColorDisplayService.java479
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java9
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceInfo.java3
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java2
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java2
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayAdapter.java2
-rw-r--r--services/core/java/com/android/server/display/WifiDisplayAdapter.java11
-rw-r--r--services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java47
-rw-r--r--services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java10
-rw-r--r--services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceThrottler.java2
-rw-r--r--services/core/java/com/android/server/gpu/GpuService.java101
-rw-r--r--services/core/java/com/android/server/input/InputForwarder.java45
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java24
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java12
-rw-r--r--services/core/java/com/android/server/location/GnssVisibilityControl.java95
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java22
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java19
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java28
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java16
-rw-r--r--services/core/java/com/android/server/net/LockdownVpnTracker.java8
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyLogger.java10
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java10
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java7
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java36
-rw-r--r--services/core/java/com/android/server/pm/DynamicCodeLoggingService.java27
-rw-r--r--services/core/java/com/android/server/pm/OWNERS7
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java264
-rw-r--r--services/core/java/com/android/server/pm/Settings.java246
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java20
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java28
-rw-r--r--services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java (renamed from services/core/java/com/android/server/pm/dex/DexLogger.java)18
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java9
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java331
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java (renamed from services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java)11
-rw-r--r--services/core/java/com/android/server/pm/permission/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/policy/DisplayFoldController.java53
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java18
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java15
-rw-r--r--services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java66
-rw-r--r--services/core/java/com/android/server/power/AttentionDetector.java5
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java101
-rw-r--r--services/core/java/com/android/server/role/RoleManagerService.java35
-rw-r--r--services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java47
-rw-r--r--services/core/java/com/android/server/rollback/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java45
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarShellCommand.java56
-rw-r--r--services/core/java/com/android/server/telecom/TelecomLoaderService.java4
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java23
-rw-r--r--services/core/java/com/android/server/utils/FlagNamespaceUtils.java133
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java63
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java14
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java35
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java25
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java3
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java10
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java22
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java9
-rw-r--r--services/core/java/com/android/server/wm/RootActivityContainer.java7
-rw-r--r--services/core/java/com/android/server/wm/TaskRecord.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java109
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerShellCommand.java38
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowTraceBuffer.java157
-rw-r--r--services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java105
-rw-r--r--services/core/java/com/android/server/wm/WindowTraceRingBuffer.java70
-rw-r--r--services/core/java/com/android/server/wm/WindowTracing.java281
-rw-r--r--services/core/jni/com_android_server_am_BatteryStatsService.cpp119
-rw-r--r--services/core/jni/com_android_server_power_PowerManagerService.cpp8
-rw-r--r--services/devicepolicy/TEST_MAPPING7
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java4
-rw-r--r--services/java/com/android/server/SystemServer.java5
-rw-r--r--services/net/Android.bp4
-rw-r--r--services/net/java/android/net/NetworkStackClient.java289
-rw-r--r--services/net/java/android/net/dhcp/DhcpServerCallbacks.java33
-rw-r--r--services/net/java/android/net/ip/IpClientCallbacks.java119
-rw-r--r--services/net/java/android/net/ip/IpClientUtil.java24
-rw-r--r--services/net/java/android/net/ip/IpServer.java9
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java (renamed from services/robotests/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java)0
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java (renamed from services/robotests/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java)0
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java (renamed from services/robotests/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java)0
-rw-r--r--services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-refresh-intervals.xml46
-rw-r--r--services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file-no-refresh-interval.xml (renamed from services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-refresh-interval.xml)0
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UserControllerTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java39
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/utils/FileUtilsTest.java80
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/utils/RandomAccessFileUtilsTest.java114
-rw-r--r--services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java118
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java33
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DynamicCodeLoggerTests.java (renamed from services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java)49
-rw-r--r--services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java87
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java32
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java27
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/KeyguardDisableHandlerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java36
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java35
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java146
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/utils/CoordinateTransformsTest.java2
-rw-r--r--services/usage/java/com/android/server/usage/IntervalStats.java22
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java116
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java44
172 files changed, 5143 insertions, 3085 deletions
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 9b863a9f2d26..61f63d3bbc3d 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -47,7 +47,7 @@ final class RemoteAugmentedAutofillService
private static final String TAG = RemoteAugmentedAutofillService.class.getSimpleName();
- private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
+ private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
RemoteAugmentedAutofillService(Context context, ComponentName serviceName,
int userId, RemoteAugmentedAutofillServiceCallbacks callbacks,
@@ -106,6 +106,12 @@ final class RemoteAugmentedAutofillService
activityComponent, focusedId, focusedValue));
}
+ @Override
+ public String toString() {
+ return "RemoteAugmentedAutofillService["
+ + ComponentName.flattenToShortString(getComponentName()) + "]";
+ }
+
/**
* Called by {@link Session} when it's time to destroy all augmented autofill requests.
*/
@@ -181,11 +187,13 @@ final class RemoteAugmentedAutofillService
@Override
protected void onTimeout(RemoteAugmentedAutofillService remoteService) {
- Slog.wtf(TAG, "timed out: " + this);
+ // TODO(b/122858578): must update the logged AUTOFILL_AUGMENTED_REQUEST with the
+ // timeout
+ Slog.w(TAG, "PendingAutofillRequest timed out (" + TIMEOUT_REMOTE_REQUEST_MILLIS
+ + "ms) for " + remoteService);
// NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks
finish();
}
-
}
public interface RemoteAugmentedAutofillServiceCallbacks
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 17e9b350d368..00cb6d3a0a26 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -47,6 +47,8 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
+import com.android.server.backup.utils.FileUtils;
+import com.android.server.backup.utils.RandomAccessFileUtils;
import java.io.File;
import java.io.FileDescriptor;
@@ -89,6 +91,12 @@ public class Trampoline extends IBackupManager.Stub {
*/
private static final String BACKUP_ACTIVATED_FILENAME = "backup-activated";
+ /**
+ * Name of file for non-system users that remembers whether backup was explicitly activated or
+ * deactivated with a call to setBackupServiceActive.
+ */
+ private static final String REMEMBER_ACTIVATED_FILENAME_PREFIX = "backup-remember-activated";
+
// Product-level suppression of backup/restore.
private static final String BACKUP_DISABLE_PROPERTY = "ro.backup.disable";
@@ -134,11 +142,17 @@ public class Trampoline extends IBackupManager.Stub {
}
/** Stored in the system user's directory and the file is indexed by the user it refers to. */
+ protected File getRememberActivatedFileForNonSystemUser(int userId) {
+ return FileUtils.createNewFile(UserBackupManagerFiles.getStateFileInSystemDir(
+ REMEMBER_ACTIVATED_FILENAME_PREFIX, userId));
+ }
+
+ /** Stored in the system user's directory and the file is indexed by the user it refers to. */
protected File getActivatedFileForNonSystemUser(int userId) {
- return new File(UserBackupManagerFiles.getBaseStateDir(UserHandle.USER_SYSTEM),
- BACKUP_ACTIVATED_FILENAME + "-" + userId);
+ return UserBackupManagerFiles.getStateFileInSystemDir(BACKUP_ACTIVATED_FILENAME, userId);
}
+ // TODO (b/124359804) move to util method in FileUtils
private void createFile(File file) throws IOException {
if (file.exists()) {
return;
@@ -150,6 +164,7 @@ public class Trampoline extends IBackupManager.Stub {
}
}
+ // TODO (b/124359804) move to util method in FileUtils
private void deleteFile(File file) {
if (!file.exists()) {
return;
@@ -312,6 +327,19 @@ public class Trampoline extends IBackupManager.Stub {
public void setBackupServiceActive(int userId, boolean makeActive) {
enforcePermissionsOnUser(userId);
+ // In Q, backup is OFF by default for non-system users. In the future, we will change that
+ // to ON unless backup was explicitly deactivated with a (permissioned) call to
+ // setBackupServiceActive.
+ // Therefore, remember this for use in the future. Basically the default in the future will
+ // be: rememberFile.exists() ? rememberFile.value() : ON
+ // Note that this has to be done right after the permission checks and before any other
+ // action since we need to remember that a permissioned call was made irrespective of
+ // whether the call changes the state or not.
+ if (userId != UserHandle.USER_SYSTEM) {
+ RandomAccessFileUtils.writeBoolean(getRememberActivatedFileForNonSystemUser(userId),
+ makeActive);
+ }
+
if (mGlobalDisable) {
Slog.i(TAG, "Backup service not supported");
return;
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java b/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java
index aabd41a611a1..4638ac63de4a 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java
@@ -48,4 +48,9 @@ final class UserBackupManagerFiles {
// is a staging dir, we dont need to copy below dir to new system user dir
return new File(Environment.getDownloadCacheDirectory(), BACKUP_STAGING_DIR);
}
+
+ /** Stored in the system user's directory and the file is indexed by the user it refers to. */
+ static File getStateFileInSystemDir(String prefix, int userId) {
+ return new File(getBaseStateDir(UserHandle.USER_SYSTEM), prefix + "-" + userId);
+ }
}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index b2afbc3ec5f9..32e2cacbb37b 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -70,6 +70,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -130,6 +131,7 @@ import com.android.server.backup.transport.TransportNotRegisteredException;
import com.android.server.backup.utils.AppBackupUtils;
import com.android.server.backup.utils.BackupManagerMonitorUtils;
import com.android.server.backup.utils.BackupObserverUtils;
+import com.android.server.backup.utils.FileUtils;
import com.android.server.backup.utils.SparseArrayUtils;
import com.google.android.collect.Sets;
@@ -1483,19 +1485,50 @@ public class UserBackupManagerService {
}
/**
- * Clear an application's data, blocking until the operation completes or times out. If {@code
- * keepSystemState} is {@code true}, we intentionally do not clear system state that would
- * ordinarily also be cleared, because we aren't actually wiping the app back to empty; we're
- * bringing it into the actual expected state related to the already-restored notification state
- * etc.
+ * Clear an application's data after a failed restore, blocking until the operation completes or
+ * times out.
*/
- public void clearApplicationDataSynchronous(String packageName, boolean keepSystemState) {
- // Don't wipe packages marked allowClearUserData=false
+ public void clearApplicationDataAfterRestoreFailure(String packageName) {
+ clearApplicationDataSynchronous(packageName, true, false);
+ }
+
+ /**
+ * Clear an application's data before restore, blocking until the operation completes or times
+ * out.
+ */
+ public void clearApplicationDataBeforeRestore(String packageName) {
+ clearApplicationDataSynchronous(packageName, false, true);
+ }
+
+ /**
+ * Clear an application's data, blocking until the operation completes or times out.
+ *
+ * @param checkFlagAllowClearUserDataOnFailedRestore if {@code true} uses
+ * {@link ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE} to decide if
+ * clearing data is allowed after a failed restore.
+ *
+ * @param keepSystemState if {@code true}, we don't clear system state such as already restored
+ * notification settings, permission grants, etc.
+ */
+ private void clearApplicationDataSynchronous(String packageName,
+ boolean checkFlagAllowClearUserDataOnFailedRestore, boolean keepSystemState) {
try {
- PackageInfo info = mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId);
- if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
+ ApplicationInfo applicationInfo = mPackageManager.getPackageInfoAsUser(
+ packageName, 0, mUserId).applicationInfo;
+
+ boolean shouldClearData;
+ if (checkFlagAllowClearUserDataOnFailedRestore
+ && applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
+ shouldClearData = (applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE) != 0;
+ } else {
+ shouldClearData =
+ (applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) != 0;
+ }
+
+ if (!shouldClearData) {
if (MORE_DEBUG) {
- Slog.i(TAG, "allowClearUserData=false so not wiping "
+ Slog.i(TAG, "Clearing app data is not allowed so not wiping "
+ packageName);
}
return;
@@ -1510,8 +1543,8 @@ public class UserBackupManagerService {
synchronized (mClearDataLock) {
mClearingData = true;
try {
- mActivityManager.clearApplicationUserData(
- packageName, keepSystemState, observer, mUserId);
+ mActivityManager.clearApplicationUserData(packageName, keepSystemState, observer,
+ mUserId);
} catch (RemoteException e) {
// can't happen because the activity manager is in this process
}
@@ -2319,6 +2352,7 @@ public class UserBackupManagerService {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
"setAncestralSerialNumber");
Slog.v(TAG, "Setting ancestral work profile id to " + ancestralSerialNumber);
+ // TODO (b/124359804)
try (RandomAccessFile af = getAncestralSerialNumberFile()) {
af.writeLong(ancestralSerialNumber);
} catch (IOException e) {
@@ -2331,6 +2365,7 @@ public class UserBackupManagerService {
* {@link #setAncestralSerialNumber(long)}. Will return {@code -1} if not set.
*/
public long getAncestralSerialNumber() {
+ // TODO (b/124359804)
try (RandomAccessFile af = getAncestralSerialNumberFile()) {
return af.readLong();
} catch (IOException e) {
@@ -2344,13 +2379,7 @@ public class UserBackupManagerService {
mAncestralSerialNumberFile = new File(
UserBackupManagerFiles.getBaseStateDir(getUserId()),
SERIAL_ID_FILE);
- if (!mAncestralSerialNumberFile.exists()) {
- try {
- mAncestralSerialNumberFile.createNewFile();
- } catch (IOException e) {
- Slog.w(TAG, "serial number mapping file creation failed", e);
- }
- }
+ FileUtils.createNewFile(mAncestralSerialNumberFile);
}
return new RandomAccessFile(mAncestralSerialNumberFile, "rwd");
}
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index c5389fa5f878..836a5e883c62 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -352,7 +352,7 @@ public class FullRestoreEngine extends RestoreEngine {
Slog.d(TAG,
"Clearing app data preparatory to full restore");
}
- mBackupManagerService.clearApplicationDataSynchronous(pkg, true);
+ mBackupManagerService.clearApplicationDataBeforeRestore(pkg);
} else {
if (MORE_DEBUG) {
Slog.d(TAG, "backup agent ("
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 324c2d974010..6714b0aea261 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -660,7 +660,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
++mCount;
} catch (Exception e) {
Slog.e(TAG, "Error when attempting restore: " + e.toString());
- keyValueAgentErrorCleanup();
+ keyValueAgentErrorCleanup(false);
executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
}
}
@@ -686,6 +686,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
boolean staging = !packageName.equals("android");
ParcelFileDescriptor stage;
File downloadFile = (staging) ? mStageName : mBackupDataName;
+ boolean startedAgentRestore = false;
try {
IBackupTransport transport =
@@ -766,13 +767,15 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
backupManagerService.prepareOperationTimeout(
mEphemeralOpToken, restoreAgentTimeoutMillis, this, OP_TYPE_RESTORE_WAIT);
+ startedAgentRestore = true;
mAgent.doRestore(mBackupData, appVersionCode, mNewState,
mEphemeralOpToken, backupManagerService.getBackupManagerBinder());
} catch (Exception e) {
Slog.e(TAG, "Unable to call app for restore: " + packageName, e);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
packageName, e.toString());
- keyValueAgentErrorCleanup(); // clears any pending timeout messages as well
+ // Clears any pending timeout messages as well.
+ keyValueAgentErrorCleanup(startedAgentRestore);
// After a restore failure we go back to running the queue. If there
// are no more packages to be restored that will be handled by the
@@ -832,7 +835,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
Slog.e(TAG, "Unable to finalize restore of " + packageName);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
packageName, e.toString());
- keyValueAgentErrorCleanup();
+ keyValueAgentErrorCleanup(true);
executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
}
}
@@ -988,8 +991,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// We also need to wipe the current target's data, as it's probably
// in an incoherent state.
- backupManagerService.clearApplicationDataSynchronous(
- mCurrentPackage.packageName, false);
+ backupManagerService.clearApplicationDataAfterRestoreFailure(
+ mCurrentPackage.packageName);
// Schedule the next state based on the nature of our failure
if (status == BackupTransport.TRANSPORT_ERROR) {
@@ -1110,11 +1113,18 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
mListener.onFinished(callerLogString);
}
- void keyValueAgentErrorCleanup() {
- // If the agent fails restore, it might have put the app's data
- // into an incoherent state. For consistency we wipe its data
- // again in this case before continuing with normal teardown
- backupManagerService.clearApplicationDataSynchronous(mCurrentPackage.packageName, false);
+ /**
+ * @param clearAppData - set to {@code true} if the backup agent had already been invoked when
+ * restore faied. So the app data may be in corrupted state and has to be cleared.
+ */
+ void keyValueAgentErrorCleanup(boolean clearAppData) {
+ if (clearAppData) {
+ // If the agent fails restore, it might have put the app's data
+ // into an incoherent state. For consistency we wipe its data
+ // again in this case before continuing with normal teardown
+ backupManagerService.clearApplicationDataAfterRestoreFailure(
+ mCurrentPackage.packageName);
+ }
keyValueAgentCleanup();
}
@@ -1251,7 +1261,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// Some kind of horrible semantic error; we're in an unexpected state.
// Back off hard and wind up.
Slog.e(TAG, "Unexpected restore callback into state " + mState);
- keyValueAgentErrorCleanup();
+ keyValueAgentErrorCleanup(true);
nextState = UnifiedRestoreState.FINAL;
break;
}
@@ -1271,7 +1281,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
mCurrentPackage.packageName, "restore timeout");
// Handle like an agent that threw on invocation: wipe it and go on to the next
- keyValueAgentErrorCleanup();
+ keyValueAgentErrorCleanup(true);
executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
}
diff --git a/services/backup/java/com/android/server/backup/utils/FileUtils.java b/services/backup/java/com/android/server/backup/utils/FileUtils.java
new file mode 100644
index 000000000000..00686cba4777
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/utils/FileUtils.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.utils;
+
+import static com.android.server.backup.BackupManagerService.TAG;
+
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+
+/** Utility methods useful for working with backup related files. */
+public final class FileUtils {
+ /**
+ * Ensure that the file exists in the file system. If an IOException is thrown, it is ignored.
+ * This method is useful to avoid code duplication of the "try-catch-ignore exception" block.
+ */
+ public static File createNewFile(File file) {
+ try {
+ file.createNewFile();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to create file:" + file.getAbsolutePath(), e);
+ }
+ return file;
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/utils/RandomAccessFileUtils.java b/services/backup/java/com/android/server/backup/utils/RandomAccessFileUtils.java
new file mode 100644
index 000000000000..abf906aee5dd
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/utils/RandomAccessFileUtils.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.utils;
+
+import static com.android.server.backup.BackupManagerService.TAG;
+
+import android.util.Slog;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/** Utility methods useful for working with backup related RandomAccessFiles. */
+public final class RandomAccessFileUtils {
+ private static RandomAccessFile getRandomAccessFile(File file) throws FileNotFoundException {
+ return new RandomAccessFile(file, "rwd");
+ }
+
+ /** Write a boolean to a File by wrapping it using a RandomAccessFile. */
+ public static void writeBoolean(File file, boolean b) {
+ try (RandomAccessFile af = getRandomAccessFile(file)) {
+ af.writeBoolean(b);
+ } catch (IOException e) {
+ Slog.w(TAG, "Error writing file:" + file.getAbsolutePath(), e);
+ }
+ }
+
+ /** Read a boolean from a File by wrapping it using a RandomAccessFile. */
+ public static boolean readBoolean(File file, boolean def) {
+ try (RandomAccessFile af = getRandomAccessFile(file)) {
+ return af.readBoolean();
+ } catch (IOException e) {
+ Slog.w(TAG, "Error reading file:" + file.getAbsolutePath(), e);
+ }
+ return def;
+ }
+}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 4afbc641ea6c..45ceeda689f7 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -45,6 +45,7 @@ import android.provider.Settings;
import android.util.LocalLog;
import android.util.Slog;
import android.util.SparseBooleanArray;
+import android.view.contentcapture.ContentCaptureHelper;
import android.view.contentcapture.ContentCaptureManager;
import android.view.contentcapture.IContentCaptureManager;
import android.view.contentcapture.UserDataRemovalRequest;
@@ -79,7 +80,8 @@ public final class ContentCaptureManagerService extends
private final LocalService mLocalService = new LocalService();
- private final LocalLog mRequestsHistory = new LocalLog(20);
+ @Nullable
+ final LocalLog mRequestsHistory;
@GuardedBy("mLock")
private ActivityManagerInternal mAm;
@@ -105,15 +107,19 @@ public final class ContentCaptureManagerService extends
UserManager.DISALLOW_CONTENT_CAPTURE);
DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
ActivityThread.currentApplication().getMainExecutor(),
- (namespace, key, value) -> {
- if (!ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED
- .equals(key)) {
- Slog.i(mTag, "Ignoring change on " + key);
- return;
- }
- setDisabledByDeviceConfig(value);
- });
- setDisabledByDeviceConfig();
+ (namespace, key, value) -> onDeviceConfigChange(key, value));
+ setLoggingLevelFromDeviceConfig();
+ setDisabledFromDeviceConfig();
+
+ final int loggingSize = ContentCaptureHelper.getIntDeviceConfigProperty(
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE, 20);
+ if (loggingSize > 0) {
+ if (debug) Slog.d(mTag, "log history size: " + loggingSize);
+ mRequestsHistory = new LocalLog(loggingSize);
+ } else {
+ if (debug) Slog.d(mTag, "disabled log history because size is " + loggingSize);
+ mRequestsHistory = null;
+ }
// Sets which services are disabled
final UserManager um = getContext().getSystemService(UserManager.class);
@@ -213,7 +219,33 @@ public final class ContentCaptureManagerService extends
return false;
}
- private void setDisabledByDeviceConfig() {
+ private void onDeviceConfigChange(@NonNull String key, @Nullable String value) {
+ switch (key) {
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED:
+ setDisabledByDeviceConfig(value);
+ return;
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL:
+ setLoggingLevelFromDeviceConfig();
+ return;
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE:
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY:
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE:
+ case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY:
+ // TODO(b/123096662): implement it
+ Slog.d(mTag, "changes on " + key + " not supported yet");
+ return;
+ default:
+ Slog.i(mTag, "Ignoring change on " + key);
+ }
+ }
+
+ private void setLoggingLevelFromDeviceConfig() {
+ ContentCaptureHelper.setLoggingLevel();
+ verbose = ContentCaptureHelper.sVerbose;
+ debug = ContentCaptureHelper.sDebug;
+ }
+
+ private void setDisabledFromDeviceConfig() {
final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
setDisabledByDeviceConfig(value);
@@ -327,13 +359,6 @@ public final class ContentCaptureManagerService extends
}
}
- /**
- * Logs a request so it's dumped later...
- */
- void logRequestLocked(@NonNull String historyItem) {
- mRequestsHistory.log(historyItem);
- }
-
private ActivityManagerInternal getAmInternal() {
synchronized (mLock) {
if (mAm == null) {
@@ -480,31 +505,6 @@ public final class ContentCaptureManagerService extends
}
@Override
- public void setContentCaptureFeatureEnabled(boolean enabled,
- @NonNull IResultReceiver result) {
- final int userId = UserHandle.getCallingUserId();
- final boolean isService;
- synchronized (mLock) {
- isService = assertCalledByServiceLocked("setContentCaptureFeatureEnabled()", userId,
- Binder.getCallingUid(), result);
- }
- if (!isService) return;
-
- final long token = Binder.clearCallingIdentity();
- try {
- Settings.Secure.putStringForUser(getContext().getContentResolver(),
- Settings.Secure.CONTENT_CAPTURE_ENABLED, Boolean.toString(enabled), userId);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- try {
- result.send(ContentCaptureManager.RESULT_CODE_TRUE, /* resultData= */null);
- } catch (RemoteException e) {
- Slog.w(mTag, "Unable to send setContentCaptureFeatureEnabled(): " + e);
- }
- }
-
- @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), mTag, pw)) return;
@@ -527,9 +527,13 @@ public final class ContentCaptureManagerService extends
synchronized (mLock) {
dumpLocked("", pw);
}
- if (showHistory) {
- pw.println(); pw.println("Requests history:"); pw.println();
+ pw.print("Requests history: ");
+ if (mRequestsHistory == null) {
+ pw.println("disabled by device config");
+ } else if (showHistory) {
+ pw.println();
mRequestsHistory.reverseDump(fd, pw, args);
+ pw.println();
}
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 7102b82d5e18..9e159600e42c 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -21,6 +21,7 @@ import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
import static android.view.contentcapture.ContentCaptureSession.STATE_DUPLICATED_ID;
import static android.view.contentcapture.ContentCaptureSession.STATE_INTERNAL_ERROR;
import static android.view.contentcapture.ContentCaptureSession.STATE_NO_SERVICE;
+import static android.view.contentcapture.ContentCaptureSession.STATE_PACKAGE_NOT_WHITELISTED;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
@@ -43,11 +44,12 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.provider.Settings;
import android.service.contentcapture.ContentCaptureService;
import android.service.contentcapture.IContentCaptureServiceCallback;
import android.service.contentcapture.SnapshotData;
import android.util.ArrayMap;
-import android.util.Log;
+import android.util.ArraySet;
import android.util.Slog;
import android.view.contentcapture.UserDataRemovalRequest;
@@ -87,6 +89,12 @@ final class ContentCapturePerUserService
private final ContentCaptureServiceRemoteCallback mRemoteServiceCallback =
new ContentCaptureServiceRemoteCallback();
+ /**
+ * List of packages that are whitelisted to be content captured.
+ */
+ @GuardedBy("mLock")
+ private final ArraySet<String> mWhitelistedPackages = new ArraySet<>();
+
// TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's
ContentCapturePerUserService(@NonNull ContentCaptureManagerService master,
@@ -185,15 +193,19 @@ final class ContentCapturePerUserService
final int taskId = activityPresentationInfo.taskId;
final int displayId = activityPresentationInfo.displayId;
final ComponentName componentName = activityPresentationInfo.componentName;
+ final boolean whitelisted = isWhitelistedLocked(componentName);
final ComponentName serviceComponentName = getServiceComponentName();
final boolean enabled = isEnabledLocked();
- final String historyItem =
- "id=" + sessionId + " uid=" + uid
- + " a=" + ComponentName.flattenToShortString(componentName)
- + " t=" + taskId + " d=" + displayId
- + " s=" + ComponentName.flattenToShortString(serviceComponentName)
- + " u=" + mUserId + " f=" + flags + (enabled ? "" : " (disabled)");
- mMaster.logRequestLocked(historyItem);
+ if (mMaster.mRequestsHistory != null) {
+ final String historyItem =
+ "id=" + sessionId + " uid=" + uid
+ + " a=" + ComponentName.flattenToShortString(componentName)
+ + " t=" + taskId + " d=" + displayId
+ + " s=" + ComponentName.flattenToShortString(serviceComponentName)
+ + " u=" + mUserId + " f=" + flags + (enabled ? "" : " (disabled)")
+ + " w=" + whitelisted;
+ mMaster.mRequestsHistory.log(historyItem);
+ }
if (!enabled) {
// TODO: it would be better to split in differet reasons, like
@@ -212,6 +224,16 @@ final class ContentCapturePerUserService
return;
}
+ if (!whitelisted) {
+ if (mMaster.debug) {
+ Slog.d(TAG, "startSession(" + componentName + "): not whitelisted");
+ }
+ // TODO(b/122595322): need to return STATE_ACTIVITY_NOT_WHITELISTED as well
+ setClientState(clientReceiver, STATE_DISABLED | STATE_PACKAGE_NOT_WHITELISTED,
+ /* binder= */ null);
+ return;
+ }
+
final ContentCaptureServerSession existingSession = mSessions.get(sessionId);
if (existingSession != null) {
Slog.w(TAG, "startSession(id=" + existingSession + ", token=" + activityToken
@@ -245,6 +267,26 @@ final class ContentCapturePerUserService
newSession.notifySessionStartedLocked(clientReceiver);
}
+ @GuardedBy("mLock")
+ private boolean isWhitelistedLocked(@NonNull ComponentName componentName) {
+ // TODO(b/122595322): need to check whitelisted activities as well.
+ final String packageName = componentName.getPackageName();
+ return mWhitelistedPackages.contains(packageName);
+ }
+
+ private void whitelistPackages(@NonNull List<String> packages) {
+ // TODO(b/122595322): add CTS test for when it's null
+ synchronized (mLock) {
+ if (packages == null) {
+ if (mMaster.verbose) Slog.v(TAG, "clearing all whitelisted packages");
+ mWhitelistedPackages.clear();
+ } else {
+ if (mMaster.verbose) Slog.v(TAG, "whitelisting packages: " + packages);
+ mWhitelistedPackages.addAll(packages);
+ }
+ }
+ }
+
// TODO(b/119613670): log metrics
@GuardedBy("mLock")
public void finishSessionLocked(@NonNull String sessionId) {
@@ -376,15 +418,23 @@ final class ContentCapturePerUserService
mRemoteService.dump(prefix2, pw);
}
+ final int whitelistSize = mWhitelistedPackages.size();
+ pw.print(prefix); pw.print("Whitelisted packages: "); pw.println(whitelistSize);
+ for (int i = 0; i < whitelistSize; i++) {
+ final String whitelistedPkg = mWhitelistedPackages.valueAt(i);
+ pw.print(prefix2); pw.print(i + 1); pw.print(": "); pw.println(whitelistedPkg);
+ }
+
if (mSessions.isEmpty()) {
pw.print(prefix); pw.println("no sessions");
} else {
- final int size = mSessions.size();
- pw.print(prefix); pw.print("number sessions: "); pw.println(size);
- for (int i = 0; i < size; i++) {
- pw.print(prefix); pw.print("session@"); pw.println(i);
+ final int sessionsSize = mSessions.size();
+ pw.print(prefix); pw.print("number sessions: "); pw.println(sessionsSize);
+ for (int i = 0; i < sessionsSize; i++) {
+ pw.print(prefix); pw.print("#"); pw.println(i);
final ContentCaptureServerSession session = mSessions.valueAt(i);
session.dumpLocked(prefix2, pw);
+ pw.println();
}
}
}
@@ -410,11 +460,26 @@ final class ContentCapturePerUserService
public void setContentCaptureWhitelist(List<String> packages,
List<ComponentName> activities) {
if (mMaster.verbose) {
- Log.v(TAG, "setContentCaptureWhitelist(packages=" + packages + ", activities="
+ Slog.v(TAG, "setContentCaptureWhitelist(packages=" + packages + ", activities="
+ activities + ")");
}
- // TODO(b/122595322): implement
+ whitelistPackages(packages);
+
+ // TODO(b/122595322): whitelist activities as well
// TODO(b/119613670): log metrics
}
+
+ @Override
+ public void disableSelf() {
+ if (mMaster.verbose) Slog.v(TAG, "disableSelf()");
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putStringForUser(getContext().getContentResolver(),
+ Settings.Secure.CONTENT_CAPTURE_ENABLED, "false", mUserId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
}
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index 3c52e17ce1e8..40948432751d 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -20,6 +20,7 @@ import android.content.ComponentName;
import android.os.IBinder;
import android.service.contentcapture.ContentCaptureService;
import android.service.contentcapture.SnapshotData;
+import android.util.LocalLog;
import android.util.Slog;
import android.view.contentcapture.ContentCaptureContext;
import android.view.contentcapture.ContentCaptureSessionId;
@@ -37,6 +38,9 @@ final class ContentCaptureServerSession {
final IBinder mActivityToken;
private final ContentCapturePerUserService mService;
private final RemoteContentCaptureService mRemoteService;
+
+ // NOTE: this is the "internal" context (like package and taskId), not the explicit content
+ // set by apps - those are only send to the ContentCaptureService.
private final ContentCaptureContext mContentCaptureContext;
/**
@@ -83,7 +87,10 @@ final class ContentCaptureServerSession {
*/
@GuardedBy("mLock")
public void sendActivitySnapshotLocked(@NonNull SnapshotData snapshotData) {
- mService.getMaster().logRequestLocked("snapshot: id=" + mId);
+ final LocalLog logHistory = mService.getMaster().mRequestsHistory;
+ if (logHistory != null) {
+ logHistory.log("snapshot: id=" + mId);
+ }
mRemoteService.onActivitySnapshotRequest(mId, snapshotData);
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d1cd072ee215..915c131ff0fb 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -57,8 +57,10 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.database.ContentObserver;
+import android.net.CaptivePortal;
import android.net.ConnectionInfo;
import android.net.ConnectivityManager;
+import android.net.ICaptivePortal;
import android.net.IConnectivityManager;
import android.net.IIpConnectivityMetrics;
import android.net.INetd;
@@ -86,6 +88,7 @@ import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
+import android.net.NetworkStackClient;
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.NetworkWatchlistManager;
@@ -917,7 +920,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
mPermissionMonitor = new PermissionMonitor(mContext, mNMS);
- //set up the listener for user state for creating user VPNs
+ // Set up the listener for user state for creating user VPNs.
+ // Should run on mHandler to avoid any races.
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_STARTED);
intentFilter.addAction(Intent.ACTION_USER_STOPPED);
@@ -925,7 +929,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiverAsUser(
- mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
+ mIntentReceiver,
+ UserHandle.ALL,
+ intentFilter,
+ null /* broadcastPermission */,
+ mHandler);
mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM,
new IntentFilter(Intent.ACTION_USER_PRESENT), null, null);
@@ -936,7 +944,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
mContext.registerReceiverAsUser(
- mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
+ mIntentReceiver,
+ UserHandle.ALL,
+ intentFilter,
+ null /* broadcastPermission */,
+ mHandler);
try {
mNMS.registerObserver(mTethering);
@@ -2690,11 +2702,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE,
mNai.network.netId));
}
-
- @Override
- public void logCaptivePortalLoginEvent(int eventId, String packageName) {
- new MetricsLogger().action(eventId, packageName);
- }
}
private boolean networkRequiresValidation(NetworkAgentInfo nai) {
@@ -2842,6 +2849,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (DBG) {
log(nai.name() + " got DISCONNECTED, was satisfying " + nai.numNetworkRequests());
}
+ // Clear all notifications of this network.
+ mNotifier.clearNotification(nai.network.netId);
// A network agent has disconnected.
// TODO - if we move the logic to the network agent (have them disconnect
// because they lost all their requests or because their score isn't good)
@@ -3247,22 +3256,63 @@ public class ConnectivityService extends IConnectivityManager.Stub
/**
* NetworkStack endpoint to start the captive portal app. The NetworkStack needs to use this
* endpoint as it does not have INTERACT_ACROSS_USERS_FULL itself.
+ * @param network Network on which the captive portal was detected.
* @param appExtras Bundle to use as intent extras for the captive portal application.
* Must be treated as opaque to avoid preventing the captive portal app to
* update its arguments.
*/
@Override
- public void startCaptivePortalAppInternal(Bundle appExtras) {
+ public void startCaptivePortalAppInternal(Network network, Bundle appExtras) {
mContext.checkCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
final Intent appIntent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
appIntent.putExtras(appExtras);
+ appIntent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL,
+ new CaptivePortal(new CaptivePortalImpl(network).asBinder()));
appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
Binder.withCleanCallingIdentity(() ->
mContext.startActivityAsUser(appIntent, UserHandle.CURRENT));
}
+ private class CaptivePortalImpl extends ICaptivePortal.Stub {
+ private final Network mNetwork;
+
+ private CaptivePortalImpl(Network network) {
+ mNetwork = network;
+ }
+
+ @Override
+ public void appResponse(final int response) throws RemoteException {
+ if (response == CaptivePortal.APP_RETURN_WANTED_AS_IS) {
+ enforceSettingsPermission();
+ }
+
+ // getNetworkAgentInfoForNetwork is thread-safe
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(mNetwork);
+ if (nai == null) return;
+
+ // nai.networkMonitor() is thread-safe
+ final INetworkMonitor nm = nai.networkMonitor();
+ if (nm == null) return;
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ nm.notifyCaptivePortalAppFinished(response);
+ } finally {
+ // Not using Binder.withCleanCallingIdentity() to keep the checked RemoteException
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void logEvent(int eventId, String packageName) {
+ enforceSettingsPermission();
+
+ new MetricsLogger().action(eventId, packageName);
+ }
+ }
+
public boolean avoidBadWifi() {
return mMultinetworkPolicyTracker.getAvoidBadWifi();
}
@@ -4097,17 +4147,27 @@ public class ConnectivityService extends IConnectivityManager.Stub
* handler thread through their agent, this is asynchronous. When the capabilities objects
* are computed they will be up-to-date as they are computed synchronously from here and
* this is running on the ConnectivityService thread.
- * TODO : Fix this and call updateCapabilities inline to remove out-of-order events.
*/
private void updateAllVpnsCapabilities() {
+ Network defaultNetwork = getNetwork(getDefaultNetwork());
synchronized (mVpns) {
for (int i = 0; i < mVpns.size(); i++) {
final Vpn vpn = mVpns.valueAt(i);
- vpn.updateCapabilities();
+ NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
+ updateVpnCapabilities(vpn, nc);
}
}
}
+ private void updateVpnCapabilities(Vpn vpn, @Nullable NetworkCapabilities nc) {
+ ensureRunningOnConnectivityServiceThread();
+ NetworkAgentInfo vpnNai = getNetworkAgentInfoForNetId(vpn.getNetId());
+ if (vpnNai == null || nc == null) {
+ return;
+ }
+ updateCapabilities(vpnNai.getCurrentScore(), vpnNai, nc);
+ }
+
@Override
public boolean updateLockdownVpn() {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
@@ -4448,22 +4508,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void onUserAdded(int userId) {
mPermissionMonitor.onUserAdded(userId);
+ Network defaultNetwork = getNetwork(getDefaultNetwork());
synchronized (mVpns) {
final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) {
Vpn vpn = mVpns.valueAt(i);
vpn.onUserAdded(userId);
+ NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
+ updateVpnCapabilities(vpn, nc);
}
}
}
private void onUserRemoved(int userId) {
mPermissionMonitor.onUserRemoved(userId);
+ Network defaultNetwork = getNetwork(getDefaultNetwork());
synchronized (mVpns) {
final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) {
Vpn vpn = mVpns.valueAt(i);
vpn.onUserRemoved(userId);
+ NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
+ updateVpnCapabilities(vpn, nc);
}
}
}
@@ -4532,6 +4598,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ ensureRunningOnConnectivityServiceThread();
final String action = intent.getAction();
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
@@ -5041,6 +5108,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
return getNetworkForRequest(mDefaultRequest.requestId);
}
+ @Nullable
+ private Network getNetwork(@Nullable NetworkAgentInfo nai) {
+ return nai != null ? nai.network : null;
+ }
+
+ private void ensureRunningOnConnectivityServiceThread() {
+ if (mHandler.getLooper().getThread() != Thread.currentThread()) {
+ throw new IllegalStateException(
+ "Not running on ConnectivityService thread: "
+ + Thread.currentThread().getName());
+ }
+ }
+
private boolean isDefaultNetwork(NetworkAgentInfo nai) {
return nai == getDefaultNetwork();
}
@@ -5097,7 +5177,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (DBG) log("registerNetworkAgent " + nai);
final long token = Binder.clearCallingIdentity();
try {
- mContext.getSystemService(NetworkStack.class).makeNetworkMonitor(
+ getNetworkStack().makeNetworkMonitor(
toStableParcelable(nai.network), name, new NetworkMonitorCallbacks(nai));
} finally {
Binder.restoreCallingIdentity(token);
@@ -5109,6 +5189,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
return nai.network.netId;
}
+ @VisibleForTesting
+ protected NetworkStackClient getNetworkStack() {
+ return NetworkStackClient.getInstance();
+ }
+
private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) {
nai.onNetworkMonitorCreated(networkMonitor);
if (VDBG) log("Got NetworkAgent Messenger");
@@ -5667,6 +5752,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
updateTcpBufferSizes(newNetwork.linkProperties.getTcpBufferSizes());
mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
notifyIfacesChangedForNetworkStats();
+ // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks.
+ updateAllVpnsCapabilities();
}
private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
@@ -6106,6 +6193,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
// doing.
updateSignalStrengthThresholds(networkAgent, "CONNECT", null);
+ if (networkAgent.isVPN()) {
+ updateAllVpnsCapabilities();
+ }
+
// Consider network even though it is not yet validated.
final long now = SystemClock.elapsedRealtime();
rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now);
@@ -6367,7 +6458,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
success = mVpns.get(user).setUnderlyingNetworks(networks);
}
if (success) {
- mHandler.post(() -> notifyIfacesChangedForNetworkStats());
+ mHandler.post(() -> {
+ // Update VPN's capabilities based on updated underlying network set.
+ updateAllVpnsCapabilities();
+ notifyIfacesChangedForNetworkStats();
+ });
}
return success;
}
diff --git a/services/core/java/com/android/server/ExtconUEventObserver.java b/services/core/java/com/android/server/ExtconUEventObserver.java
index ebd4c5584fe1..775e4c8cf4ed 100644
--- a/services/core/java/com/android/server/ExtconUEventObserver.java
+++ b/services/core/java/com/android/server/ExtconUEventObserver.java
@@ -49,7 +49,7 @@ public abstract class ExtconUEventObserver extends UEventObserver {
private static final String TAG = "ExtconUEventObserver";
private static final boolean LOG = false;
private static final String SELINUX_POLICIES_NEED_TO_BE_CHANGED =
- "This probably mean the selinux policies need to be changed.";
+ "This probably means the selinux policies need to be changed.";
private final Map<String, ExtconInfo> mExtconInfos = new ArrayMap<>();
@@ -68,7 +68,7 @@ public abstract class ExtconUEventObserver extends UEventObserver {
* Subclasses of ExtconUEventObserver should override this method to handle UEvents.
*
* @param extconInfo that matches the {@code DEVPATH} of {@code event}
- * @param event the event
+ * @param event the event
*/
protected abstract void onUEvent(ExtconInfo extconInfo, UEvent event);
@@ -91,6 +91,9 @@ public abstract class ExtconUEventObserver extends UEventObserver {
/** Returns a new list of all external connections whose name matches {@code regex}. */
public static List<ExtconInfo> getExtconInfos(@Nullable String regex) {
+ if (!extconExists()) {
+ return new ArrayList<>(0); // Always return a new list.
+ }
Pattern p = regex == null ? null : Pattern.compile(regex);
File file = new File("/sys/class/extcon");
File[] files = file.listFiles();
@@ -159,6 +162,15 @@ public abstract class ExtconUEventObserver extends UEventObserver {
/** Does the {@link /sys/class/extcon} directory exist */
public static boolean extconExists() {
File extconDir = new File("/sys/class/extcon");
- return extconDir.exists() && extconDir.isDirectory();
+ boolean retVal = extconDir.exists() && extconDir.isDirectory();
+ // TODO(b/124364409): return the correct value after selinux policy is updated.
+ if (retVal) {
+ Slog.w(TAG, extconDir + " exists " + extconDir.exists() + " isDir "
+ + extconDir.isDirectory()
+ + " but reporting it does not exist until selinux policies are updated."
+ + " see b/124364409"
+ );
+ }
+ return false;
}
}
diff --git a/services/core/java/com/android/server/FgThread.java b/services/core/java/com/android/server/FgThread.java
index fe30057fc820..5d0e308f6649 100644
--- a/services/core/java/com/android/server/FgThread.java
+++ b/services/core/java/com/android/server/FgThread.java
@@ -17,9 +17,12 @@
package com.android.server;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Trace;
+import java.util.concurrent.Executor;
+
/**
* Shared singleton foreground thread for the system. This is a thread for regular
* foreground service operations, which shouldn't be blocked by anything running in
@@ -34,6 +37,7 @@ public final class FgThread extends ServiceThread {
private static FgThread sInstance;
private static Handler sHandler;
+ private static HandlerExecutor sHandlerExecutor;
private FgThread() {
super("android.fg", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
@@ -48,6 +52,7 @@ public final class FgThread extends ServiceThread {
looper.setSlowLogThresholdMs(
SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
sHandler = new Handler(sInstance.getLooper());
+ sHandlerExecutor = new HandlerExecutor(sHandler);
}
}
@@ -64,4 +69,11 @@ public final class FgThread extends ServiceThread {
return sHandler;
}
}
+
+ public static Executor getExecutor() {
+ synchronized (FgThread.class) {
+ ensureThreadLocked();
+ return sHandlerExecutor;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/IoThread.java b/services/core/java/com/android/server/IoThread.java
index bfe825a3a89e..21fd29c3bbef 100644
--- a/services/core/java/com/android/server/IoThread.java
+++ b/services/core/java/com/android/server/IoThread.java
@@ -17,8 +17,11 @@
package com.android.server;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Trace;
+import java.util.concurrent.Executor;
+
/**
* Shared singleton I/O thread for the system. This is a thread for non-background
* service operations that can potential block briefly on network IO operations
@@ -27,6 +30,7 @@ import android.os.Trace;
public final class IoThread extends ServiceThread {
private static IoThread sInstance;
private static Handler sHandler;
+ private static HandlerExecutor sHandlerExecutor;
private IoThread() {
super("android.io", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
@@ -38,6 +42,7 @@ public final class IoThread extends ServiceThread {
sInstance.start();
sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
sHandler = new Handler(sInstance.getLooper());
+ sHandlerExecutor = new HandlerExecutor(sHandler);
}
}
@@ -54,4 +59,11 @@ public final class IoThread extends ServiceThread {
return sHandler;
}
}
+
+ public static Executor getExecutor() {
+ synchronized (IoThread.class) {
+ ensureThreadLocked();
+ return sHandlerExecutor;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 3479e18b97c5..5989a46c5a0a 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1645,36 +1645,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private abstract static class LinkedListenerBase implements IBinder.DeathRecipient {
- protected final CallerIdentity mCallerIdentity;
- protected final String mListenerName;
-
- private LinkedListenerBase(@NonNull CallerIdentity callerIdentity,
- @NonNull String listenerName) {
- mCallerIdentity = callerIdentity;
- mListenerName = listenerName;
- }
- }
-
- private static class LinkedListener<TListener> extends LinkedListenerBase {
- private final TListener mListener;
- private final Consumer<TListener> mBinderDeathCallback;
-
- private LinkedListener(@NonNull TListener listener, String listenerName,
- @NonNull CallerIdentity callerIdentity,
- @NonNull Consumer<TListener> binderDeathCallback) {
- super(callerIdentity, listenerName);
- mListener = listener;
- mBinderDeathCallback = binderDeathCallback;
- }
-
- @Override
- public void binderDied() {
- if (D) Log.d(TAG, "Remote " + mListenerName + " died.");
- mBinderDeathCallback.accept(mListener);
- }
- }
-
@Override
public void removeGnssBatchingCallback() {
synchronized (mLock) {
@@ -2069,7 +2039,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
if (!provider.isUseableLocked()) {
if (isSettingsExemptLocked(record)) {
- providerRequest.forceLocation = true;
+ providerRequest.locationSettingsIgnored = true;
providerRequest.lowPowerMode = false;
} else {
continue;
@@ -2079,8 +2049,9 @@ public class LocationManagerService extends ILocationManager.Stub {
LocationRequest locationRequest = record.mRealRequest;
long interval = locationRequest.getInterval();
+
// if we're forcing location, don't apply any throttling
- if (!providerRequest.forceLocation && !isThrottlingExemptLocked(
+ if (!providerRequest.locationSettingsIgnored && !isThrottlingExemptLocked(
record.mReceiver.mCallerIdentity)) {
if (!record.mIsForegroundUid) {
interval = Math.max(interval, backgroundThrottleInterval);
@@ -2165,6 +2136,13 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
+ @Override
+ public String[] getIgnoreSettingsWhitelist() {
+ synchronized (mLock) {
+ return mIgnoreSettingsPackageWhitelist.toArray(new String[0]);
+ }
+ }
+
@GuardedBy("mLock")
private boolean isThrottlingExemptLocked(CallerIdentity callerIdentity) {
if (callerIdentity.mUid == Process.SYSTEM_UID) {
@@ -2710,77 +2688,85 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName) {
- if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
- return false;
- }
+ return addGnssDataListener(listener, packageName, "GnssStatusListener",
+ mGnssStatusProvider, mGnssStatusListeners,
+ this::unregisterGnssStatusCallback);
+ }
- CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
- Binder.getCallingPid(), packageName);
- LinkedListener<IGnssStatusListener> linkedListener = new LinkedListener<>(listener,
- "GnssStatusListener", callerIdentity, this::unregisterGnssStatusCallback);
- IBinder binder = listener.asBinder();
- synchronized (mLock) {
- if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) {
- return false;
- }
+ @Override
+ public void unregisterGnssStatusCallback(IGnssStatusListener listener) {
+ removeGnssDataListener(listener, mGnssStatusProvider, mGnssStatusListeners);
+ }
- mGnssStatusListeners.put(binder, linkedListener);
- long identity = Binder.clearCallingIdentity();
- try {
- if (isThrottlingExemptLocked(callerIdentity)
- || isImportanceForeground(
- mActivityManager.getPackageImportance(packageName))) {
- mGnssStatusProvider.addListener(listener, callerIdentity);
- }
- return true;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
+ @Override
+ public boolean addGnssMeasurementsListener(
+ IGnssMeasurementsListener listener, String packageName) {
+ return addGnssDataListener(listener, packageName, "GnssMeasurementsListener",
+ mGnssMeasurementsProvider, mGnssMeasurementsListeners,
+ this::removeGnssMeasurementsListener);
}
@Override
- public void unregisterGnssStatusCallback(IGnssStatusListener listener) {
- if (mGnssStatusProvider == null) {
- return;
+ public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
+ removeGnssDataListener(listener, mGnssMeasurementsProvider, mGnssMeasurementsListeners);
+ }
+
+ private abstract static class LinkedListenerBase implements IBinder.DeathRecipient {
+ protected final CallerIdentity mCallerIdentity;
+ protected final String mListenerName;
+
+ private LinkedListenerBase(@NonNull CallerIdentity callerIdentity,
+ @NonNull String listenerName) {
+ mCallerIdentity = callerIdentity;
+ mListenerName = listenerName;
}
+ }
- IBinder binder = listener.asBinder();
- synchronized (mLock) {
- LinkedListener<IGnssStatusListener> linkedListener =
- mGnssStatusListeners.remove(binder);
- if (linkedListener == null) {
- return;
- }
- unlinkFromListenerDeathNotificationLocked(binder, linkedListener);
- mGnssStatusProvider.removeListener(listener);
+ private static class LinkedListener<TListener> extends LinkedListenerBase {
+ private final TListener mListener;
+ private final Consumer<TListener> mBinderDeathCallback;
+
+ private LinkedListener(@NonNull TListener listener, String listenerName,
+ @NonNull CallerIdentity callerIdentity,
+ @NonNull Consumer<TListener> binderDeathCallback) {
+ super(callerIdentity, listenerName);
+ mListener = listener;
+ mBinderDeathCallback = binderDeathCallback;
+ }
+
+ @Override
+ public void binderDied() {
+ if (D) Log.d(TAG, "Remote " + mListenerName + " died.");
+ mBinderDeathCallback.accept(mListener);
}
}
- @Override
- public boolean addGnssMeasurementsListener(
- IGnssMeasurementsListener listener, String packageName) {
- if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
+ private <TListener extends IInterface> boolean addGnssDataListener(
+ TListener listener, String packageName, String listenerName,
+ RemoteListenerHelper<TListener> gnssDataProvider,
+ ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners,
+ Consumer<TListener> binderDeathCallback) {
+ if (!hasGnssPermissions(packageName) || gnssDataProvider == null) {
return false;
}
CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
Binder.getCallingPid(), packageName);
- LinkedListener<IGnssMeasurementsListener> linkedListener = new LinkedListener<>(listener,
- "GnssMeasurementsListener", callerIdentity, this::removeGnssMeasurementsListener);
+ LinkedListener<TListener> linkedListener = new LinkedListener<>(listener,
+ listenerName, callerIdentity, binderDeathCallback);
IBinder binder = listener.asBinder();
synchronized (mLock) {
if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) {
return false;
}
- mGnssMeasurementsListeners.put(binder, linkedListener);
+ gnssDataListeners.put(binder, linkedListener);
long identity = Binder.clearCallingIdentity();
try {
if (isThrottlingExemptLocked(callerIdentity)
|| isImportanceForeground(
mActivityManager.getPackageImportance(packageName))) {
- mGnssMeasurementsProvider.addListener(listener, callerIdentity);
+ gnssDataProvider.addListener(listener, callerIdentity);
}
return true;
} finally {
@@ -2789,25 +2775,24 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- @Override
- public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
- if (mGnssMeasurementsProvider == null) {
+ private <TListener extends IInterface> void removeGnssDataListener(
+ TListener listener, RemoteListenerHelper<TListener> gnssDataProvider,
+ ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners) {
+ if (gnssDataProvider == null) {
return;
}
IBinder binder = listener.asBinder();
synchronized (mLock) {
- LinkedListener<IGnssMeasurementsListener> linkedListener =
- mGnssMeasurementsListeners.remove(binder);
+ LinkedListener<TListener> linkedListener = gnssDataListeners.remove(binder);
if (linkedListener == null) {
return;
}
unlinkFromListenerDeathNotificationLocked(binder, linkedListener);
- mGnssMeasurementsProvider.removeListener(listener);
+ gnssDataProvider.removeListener(listener);
}
}
-
private boolean linkToListenerDeathNotificationLocked(IBinder binder,
LinkedListenerBase linkedListener) {
try {
@@ -2816,8 +2801,7 @@ public class LocationManagerService extends ILocationManager.Stub {
} catch (RemoteException e) {
// if the remote process registering the listener is already dead, just swallow the
// exception and return
- Log.w(TAG, "Could not link " + linkedListener.mListenerName + " death callback.",
- e);
+ Log.w(TAG, "Could not link " + linkedListener.mListenerName + " death callback.", e);
return false;
}
}
@@ -2830,8 +2814,7 @@ public class LocationManagerService extends ILocationManager.Stub {
} catch (NoSuchElementException e) {
// if the death callback isn't connected (it should be...), log error,
// swallow the exception and return
- Log.w(TAG, "Could not unlink " + linkedListener.mListenerName + " death callback.",
- e);
+ Log.w(TAG, "Could not unlink " + linkedListener.mListenerName + " death callback.", e);
return false;
}
}
@@ -2863,52 +2846,15 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public boolean addGnssNavigationMessageListener(
IGnssNavigationMessageListener listener, String packageName) {
- if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
- return false;
- }
-
- CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
- Binder.getCallingPid(), packageName);
- LinkedListener<IGnssNavigationMessageListener> linkedListener =
- new LinkedListener<>(listener, "GnssNavigationMessageListener", callerIdentity,
- this::removeGnssNavigationMessageListener);
- IBinder binder = listener.asBinder();
- synchronized (mLock) {
- if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) {
- return false;
- }
-
- mGnssNavigationMessageListeners.put(binder, linkedListener);
- long identity = Binder.clearCallingIdentity();
- try {
- if (isThrottlingExemptLocked(callerIdentity)
- || isImportanceForeground(
- mActivityManager.getPackageImportance(packageName))) {
- mGnssNavigationMessageProvider.addListener(listener, callerIdentity);
- }
- return true;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
+ return addGnssDataListener(listener, packageName, "GnssNavigationMessageListener",
+ mGnssNavigationMessageProvider, mGnssNavigationMessageListeners,
+ this::removeGnssNavigationMessageListener);
}
@Override
public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
- if (mGnssNavigationMessageProvider == null) {
- return;
- }
-
- IBinder binder = listener.asBinder();
- synchronized (mLock) {
- LinkedListener<IGnssNavigationMessageListener> linkedListener =
- mGnssNavigationMessageListeners.remove(binder);
- if (linkedListener == null) {
- return;
- }
- unlinkFromListenerDeathNotificationLocked(binder, linkedListener);
- mGnssNavigationMessageProvider.removeListener(listener);
- }
+ removeGnssDataListener(listener, mGnssNavigationMessageProvider,
+ mGnssNavigationMessageListeners);
}
@Override
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index f505b76178a4..dc394d0ad482 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -20,18 +20,18 @@ import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.SHUTDOWN;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_BLACKLIST;
+import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_CHAIN_NONE;
+import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
+import static android.net.INetd.FIREWALL_RULE_ALLOW;
+import static android.net.INetd.FIREWALL_RULE_DENY;
+import static android.net.INetd.FIREWALL_WHITELIST;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
-import static android.net.NetworkPolicyManager.FIREWALL_TYPE_BLACKLIST;
-import static android.net.NetworkPolicyManager.FIREWALL_TYPE_WHITELIST;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.STATS_PER_UID;
import static android.net.NetworkStats.TAG_ALL;
@@ -1946,7 +1946,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
int numUids = 0;
if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName);
- if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
+ if (getFirewallType(chain) == FIREWALL_WHITELIST) {
// Close all sockets on all non-system UIDs...
ranges = new UidRange[] {
// TODO: is there a better way of finding all existing users? If so, we could
@@ -1958,7 +1958,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
final SparseIntArray rules = getUidFirewallRulesLR(chain);
exemptUids = new int[rules.size()];
for (int i = 0; i < exemptUids.length; i++) {
- if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
+ if (rules.valueAt(i) == FIREWALL_RULE_ALLOW) {
exemptUids[numUids] = rules.keyAt(i);
numUids++;
}
@@ -1980,7 +1980,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
final SparseIntArray rules = getUidFirewallRulesLR(chain);
ranges = new UidRange[rules.size()];
for (int i = 0; i < ranges.length; i++) {
- if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_DENY) {
+ if (rules.valueAt(i) == FIREWALL_RULE_DENY) {
int uid = rules.keyAt(i);
ranges[numUids] = new UidRange(uid, uid);
numUids++;
@@ -2052,13 +2052,13 @@ public class NetworkManagementService extends INetworkManagementService.Stub
private int getFirewallType(int chain) {
switch (chain) {
case FIREWALL_CHAIN_STANDBY:
- return FIREWALL_TYPE_BLACKLIST;
+ return FIREWALL_BLACKLIST;
case FIREWALL_CHAIN_DOZABLE:
- return FIREWALL_TYPE_WHITELIST;
+ return FIREWALL_WHITELIST;
case FIREWALL_CHAIN_POWERSAVE:
- return FIREWALL_TYPE_WHITELIST;
+ return FIREWALL_WHITELIST;
default:
- return isFirewallEnabled() ? FIREWALL_TYPE_WHITELIST : FIREWALL_TYPE_BLACKLIST;
+ return isFirewallEnabled() ? FIREWALL_WHITELIST : FIREWALL_BLACKLIST;
}
}
@@ -2160,14 +2160,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub
private @NonNull String getFirewallRuleName(int chain, int rule) {
String ruleName;
- if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
- if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
+ if (getFirewallType(chain) == FIREWALL_WHITELIST) {
+ if (rule == FIREWALL_RULE_ALLOW) {
ruleName = "allow";
} else {
ruleName = "deny";
}
} else { // Blacklist mode
- if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) {
+ if (rule == FIREWALL_RULE_DENY) {
ruleName = "deny";
} else {
ruleName = "allow";
@@ -2194,7 +2194,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
private int getFirewallRuleType(int chain, int rule) {
if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
- return getFirewallType(chain) == FIREWALL_TYPE_WHITELIST
+ return getFirewallType(chain) == FIREWALL_WHITELIST
? INetd.FIREWALL_RULE_DENY : INetd.FIREWALL_RULE_ALLOW;
}
return rule;
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 62da3f8e01ba..6e5d31640e4f 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -37,6 +37,7 @@ import android.util.SparseArray;
import android.util.StatsLog;
import com.android.internal.util.ArrayUtils;
+import com.android.server.utils.FlagNamespaceUtils;
import java.io.File;
@@ -194,6 +195,8 @@ public class RescueParty {
RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
break;
}
+ FlagNamespaceUtils.addToKnownResetNamespaces(
+ FlagNamespaceUtils.NAMESPACE_NO_PACKAGE);
}
private static void resetAllSettings(Context context, int mode) throws Exception {
@@ -203,14 +206,19 @@ public class RescueParty {
final ContentResolver resolver = context.getContentResolver();
try {
Settings.Global.resetToDefaultsAsUser(resolver, null, mode, UserHandle.USER_SYSTEM);
- } catch (Throwable t) {
- res = new RuntimeException("Failed to reset global settings", t);
+ } catch (Exception e) {
+ res = new RuntimeException("Failed to reset global settings", e);
+ }
+ try {
+ FlagNamespaceUtils.resetDeviceConfig(mode);
+ } catch (Exception e) {
+ res = new RuntimeException("Failed to reset config settings", e);
}
for (int userId : getAllUserIds()) {
try {
Settings.Secure.resetToDefaultsAsUser(resolver, null, mode, userId);
- } catch (Throwable t) {
- res = new RuntimeException("Failed to reset secure settings for " + userId, t);
+ } catch (Exception e) {
+ res = new RuntimeException("Failed to reset secure settings for " + userId, e);
}
}
if (res != null) {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 2f1510e32311..fd946cdfa48a 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -26,6 +26,7 @@ import android.content.pm.PackageManager;
import android.net.LinkProperties;
import android.net.NetworkCapabilities;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -236,7 +237,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private PhoneCapability mPhoneCapability = null;
- private int mPreferredDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@TelephonyManager.RadioPowerState
private int mRadioPowerState = TelephonyManager.RADIO_POWER_UNAVAILABLE;
@@ -246,14 +247,18 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private PreciseDataConnectionState mPreciseDataConnectionState =
new PreciseDataConnectionState();
- static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK =
+ // Nothing here yet, but putting it here in case we want to add more in the future.
+ static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK = 0;
+
+ static final int ENFORCE_FINE_LOCATION_PERMISSION_MASK =
PhoneStateListener.LISTEN_CELL_LOCATION
| PhoneStateListener.LISTEN_CELL_INFO;
static final int ENFORCE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
| PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
- | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST;
+ | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST
+ | PhoneStateListener.LISTEN_ACTIVE_DATA_SUBID_CHANGE;
static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
@@ -637,8 +642,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
try {
if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]);
- r.callback.onServiceStateChanged(
- new ServiceState(mServiceState[phoneId]));
+ ServiceState rawSs = new ServiceState(mServiceState[phoneId]);
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ r.callback.onServiceStateChanged(rawSs);
+ } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
+ r.callback.onServiceStateChanged(rawSs.sanitizeLocationInfo(false));
+ } else {
+ r.callback.onServiceStateChanged(rawSs.sanitizeLocationInfo(true));
+ }
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -673,7 +684,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (DBG_LOC) log("listen: mCellLocation = "
+ mCellLocation[phoneId]);
- if (checkLocationAccess(r)) {
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellLocationChanged(
new Bundle(mCellLocation[phoneId]));
}
@@ -722,7 +733,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
- if (checkLocationAccess(r)) {
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
}
} catch (RemoteException ex) {
@@ -809,9 +820,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
remove(r.binder);
}
}
- if ((events & PhoneStateListener.LISTEN_PREFERRED_DATA_SUBID_CHANGE) != 0) {
+ if ((events & PhoneStateListener.LISTEN_ACTIVE_DATA_SUBID_CHANGE) != 0) {
try {
- r.callback.onPreferredDataSubIdChanged(mPreferredDataSubId);
+ r.callback.onActiveDataSubIdChanged(mActiveDataSubId);
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -1009,13 +1020,22 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SERVICE_STATE) &&
idMatch(r.subId, subId, phoneId)) {
+
try {
+ ServiceState stateToSend;
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ stateToSend = new ServiceState(state);
+ } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
+ stateToSend = state.sanitizeLocationInfo(false);
+ } else {
+ stateToSend = state.sanitizeLocationInfo(true);
+ }
if (DBG) {
log("notifyServiceStateForSubscriber: callback.onSSC r=" + r
+ " subId=" + subId + " phoneId=" + phoneId
+ " state=" + state);
}
- r.callback.onServiceStateChanged(new ServiceState(state));
+ r.callback.onServiceStateChanged(stateToSend);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -1198,7 +1218,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
idMatch(r.subId, subId, phoneId) &&
- checkLocationAccess(r)) {
+ checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
try {
if (DBG_LOC) {
log("notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
@@ -1500,7 +1520,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
idMatch(r.subId, subId, phoneId) &&
- checkLocationAccess(r)) {
+ checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
try {
if (DBG_LOC) {
log("notifyCellLocation: cellLocation=" + cellLocation
@@ -1738,23 +1758,23 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- public void notifyPreferredDataSubIdChanged(int preferredSubId) {
- if (!checkNotifyPermission("notifyPreferredDataSubIdChanged()")) {
+ public void notifyActiveDataSubIdChanged(int activeDataSubId) {
+ if (!checkNotifyPermission("notifyActiveDataSubIdChanged()")) {
return;
}
if (VDBG) {
- log("notifyPreferredDataSubIdChanged: preferredSubId=" + preferredSubId);
+ log("notifyActiveDataSubIdChanged: activeDataSubId=" + activeDataSubId);
}
synchronized (mRecords) {
- mPreferredDataSubId = preferredSubId;
+ mActiveDataSubId = activeDataSubId;
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_PREFERRED_DATA_SUBID_CHANGE)) {
+ PhoneStateListener.LISTEN_ACTIVE_DATA_SUBID_CHANGE)) {
try {
- r.callback.onPreferredDataSubIdChanged(preferredSubId);
+ r.callback.onActiveDataSubIdChanged(activeDataSubId);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -1890,7 +1910,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
pw.println("mBackgroundCallState=" + mBackgroundCallState);
pw.println("mSrvccState=" + mSrvccState);
pw.println("mPhoneCapability=" + mPhoneCapability);
- pw.println("mPreferredDataSubId=" + mPreferredDataSubId);
+ pw.println("mActiveDataSubId=" + mActiveDataSubId);
pw.println("mRadioPowerState=" + mRadioPowerState);
pw.println("mEmergencyNumberList=" + mEmergencyNumberList);
pw.println("mCallQuality=" + mCallQuality);
@@ -2108,12 +2128,35 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private boolean checkListenerPermission(
int events, int subId, String callingPackage, String message) {
+ LocationAccessPolicy.LocationPermissionQuery.Builder locationQueryBuilder =
+ new LocationAccessPolicy.LocationPermissionQuery.Builder()
+ .setCallingPackage(callingPackage)
+ .setMethod(message + " events: " + events)
+ .setCallingPid(Binder.getCallingPid())
+ .setCallingUid(Binder.getCallingUid());
+
+ boolean shouldCheckLocationPermissions = false;
if ((events & ENFORCE_COARSE_LOCATION_PERMISSION_MASK) != 0) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
- if (mAppOps.noteOp(AppOpsManager.OP_COARSE_LOCATION, Binder.getCallingUid(),
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return false;
+ locationQueryBuilder.setMinSdkVersionForCoarse(0);
+ shouldCheckLocationPermissions = true;
+ }
+
+ if ((events & ENFORCE_FINE_LOCATION_PERMISSION_MASK) != 0) {
+ // Everything that requires fine location started in Q. So far...
+ locationQueryBuilder.setMinSdkVersionForFine(Build.VERSION_CODES.Q);
+ shouldCheckLocationPermissions = true;
+ }
+
+ if (shouldCheckLocationPermissions) {
+ LocationAccessPolicy.LocationPermissionResult result =
+ LocationAccessPolicy.checkLocationPermission(
+ mContext, locationQueryBuilder.build());
+ switch (result) {
+ case DENIED_HARD:
+ throw new SecurityException("Unable to listen for events " + events + " due to "
+ + "insufficient location permissions.");
+ case DENIED_SOFT:
+ return false;
}
}
@@ -2139,14 +2182,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
}
- if ((events & PhoneStateListener.LISTEN_PREFERRED_DATA_SUBID_CHANGE) != 0) {
- // It can have either READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE.
- TelephonyPermissions.checkReadPhoneState(mContext,
- SubscriptionManager.INVALID_SUBSCRIPTION_ID, Binder.getCallingPid(),
- Binder.getCallingUid(), callingPackage, "listen to "
- + "LISTEN_PREFERRED_DATA_SUBID_CHANGE");
- }
-
if ((events & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
@@ -2228,15 +2263,38 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- private boolean checkLocationAccess(Record r) {
- long token = Binder.clearCallingIdentity();
- try {
- return LocationAccessPolicy.canAccessCellLocation(mContext,
- r.callingPackage, r.callerUid, r.callerPid,
- /*throwOnDeniedPermission*/ false);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ private boolean checkFineLocationAccess(Record r, int minSdk) {
+ LocationAccessPolicy.LocationPermissionQuery query =
+ new LocationAccessPolicy.LocationPermissionQuery.Builder()
+ .setCallingPackage(r.callingPackage)
+ .setCallingPid(r.callerPid)
+ .setCallingUid(r.callerUid)
+ .setMethod("TelephonyRegistry push")
+ .setMinSdkVersionForFine(minSdk)
+ .build();
+
+ return Binder.withCleanCallingIdentity(() -> {
+ LocationAccessPolicy.LocationPermissionResult locationResult =
+ LocationAccessPolicy.checkLocationPermission(mContext, query);
+ return locationResult == LocationAccessPolicy.LocationPermissionResult.ALLOWED;
+ });
+ }
+
+ private boolean checkCoarseLocationAccess(Record r, int minSdk) {
+ LocationAccessPolicy.LocationPermissionQuery query =
+ new LocationAccessPolicy.LocationPermissionQuery.Builder()
+ .setCallingPackage(r.callingPackage)
+ .setCallingPid(r.callerPid)
+ .setCallingUid(r.callerUid)
+ .setMethod("TelephonyRegistry push")
+ .setMinSdkVersionForCoarse(minSdk)
+ .build();
+
+ return Binder.withCleanCallingIdentity(() -> {
+ LocationAccessPolicy.LocationPermissionResult locationResult =
+ LocationAccessPolicy.checkLocationPermission(mContext, query);
+ return locationResult == LocationAccessPolicy.LocationPermissionResult.ALLOWED;
+ });
}
private void checkPossibleMissNotify(Record r, int phoneId) {
@@ -2286,7 +2344,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
}
- if (checkLocationAccess(r)) {
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
}
} catch (RemoteException ex) {
@@ -2336,7 +2394,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (DBG_LOC) log("checkPossibleMissNotify: onCellLocationChanged mCellLocation = "
+ mCellLocation[phoneId]);
- if (checkLocationAccess(r)) {
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId]));
}
} catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 6b57fcd31450..710a0ba34d4f 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -30,11 +30,13 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.BatteryManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
@@ -354,8 +356,12 @@ final class UiModeManagerService extends SystemService {
try {
synchronized (mLock) {
if (mNightMode != mode) {
- Settings.Secure.putIntForUser(getContext().getContentResolver(),
- Settings.Secure.UI_NIGHT_MODE, mode, user);
+ // Only persist setting if not transient night mode or not in car mode
+ if (!shouldTransientNightWhenInCarMode() || !mCarModeEnabled) {
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.UI_NIGHT_MODE, mode, user);
+ }
+
mNightMode = mode;
updateLocked(0, 0);
}
@@ -438,9 +444,39 @@ final class UiModeManagerService extends SystemService {
}
}
+ // Night mode settings in car mode are only persisted below Q.
+ // When targeting Q, changes are not saved and night mode will be re-read
+ // from settings when exiting car mode.
+ private boolean shouldTransientNightWhenInCarMode() {
+ int uid = Binder.getCallingUid();
+ PackageManager packageManager = getContext().getPackageManager();
+ String[] packagesForUid = packageManager.getPackagesForUid(uid);
+ if (packagesForUid == null || packagesForUid.length == 0) {
+ return false;
+ }
+
+ try {
+ ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser(
+ packagesForUid[0], 0, uid);
+
+ return appInfo.targetSdkVersion >= Build.VERSION_CODES.Q;
+ } catch (PackageManager.NameNotFoundException ignored) {
+ }
+
+ return false;
+ }
+
void setCarModeLocked(boolean enabled, int flags) {
if (mCarModeEnabled != enabled) {
mCarModeEnabled = enabled;
+
+ // When transient night mode and exiting car mode, restore night mode from settings
+ if (shouldTransientNightWhenInCarMode() && !mCarModeEnabled) {
+ Context context = getContext();
+ updateNightModeFromSettings(context,
+ context.getResources(),
+ UserHandle.getCallingUserId());
+ }
}
mCarModeEnableFlags = flags;
}
@@ -498,7 +534,9 @@ final class UiModeManagerService extends SystemService {
uiMode |= mNightMode << 4;
}
- if (mPowerSave) {
+ // Override night mode in power save mode if not transient night mode or not in car mode
+ boolean shouldOverrideNight = !mCarModeEnabled || !shouldTransientNightWhenInCarMode();
+ if (mPowerSave && shouldOverrideNight) {
uiMode &= ~Configuration.UI_MODE_NIGHT_NO;
uiMode |= Configuration.UI_MODE_NIGHT_YES;
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 026430b5469d..aebe2b78a853 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -319,10 +319,6 @@ public final class ActiveServices {
ServiceRecord r = mDelayedStartList.remove(0);
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"REM FR DELAY LIST (exec next): " + r);
- if (r.pendingStarts.size() <= 0) {
- Slog.w(TAG, "**** NO PENDING STARTS! " + r + " startReq=" + r.startRequested
- + " delayedStop=" + r.delayedStop);
- }
if (DEBUG_DELAYED_SERVICE) {
if (mDelayedStartList.size() > 0) {
Slog.v(TAG_SERVICE, "Remaining delayed list:");
@@ -332,11 +328,16 @@ public final class ActiveServices {
}
}
r.delayed = false;
- try {
- startServiceInnerLocked(this, r.pendingStarts.get(0).intent, r, false, true,
- false);
- } catch (TransactionTooLargeException e) {
- // Ignore, nobody upstack cares.
+ if (r.pendingStarts.size() <= 0) {
+ Slog.wtf(TAG, "**** NO PENDING STARTS! " + r + " startReq=" + r.startRequested
+ + " delayedStop=" + r.delayedStop);
+ } else {
+ try {
+ startServiceInnerLocked(this, r.pendingStarts.get(0).intent, r, false, true,
+ false);
+ } catch (TransactionTooLargeException e) {
+ // Ignore, nobody upstack cares.
+ }
}
}
if (mStartingBackground.size() > 0) {
@@ -2978,6 +2979,7 @@ public final class ActiveServices {
// Clear start entries.
r.clearDeliveredStartsLocked();
r.pendingStarts.clear();
+ smap.mDelayedStartList.remove(r);
if (r.app != null) {
synchronized (r.stats.getBatteryStats()) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c4a9db6b7262..98f2c9f21f3a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2704,8 +2704,8 @@ public class ActivityManagerService extends IActivityManager.Stub
public void batterySendBroadcast(Intent intent) {
synchronized (this) {
broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false,
- -1, SYSTEM_UID, UserHandle.USER_ALL);
+ OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
@@ -3823,12 +3823,13 @@ public class ActivityManagerService extends IActivityManager.Stub
intent.putExtra(Intent.EXTRA_USER_HANDLE, resolvedUserId);
if (isInstantApp) {
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
- broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
- null, null, permission.ACCESS_INSTANT_APPS, null, false, false,
- resolvedUserId, false);
+ broadcastIntentInPackage("android", SYSTEM_UID, uid, pid, intent, null,
+ null, 0, null, null, permission.ACCESS_INSTANT_APPS, null, false,
+ false, resolvedUserId, false);
} else {
- broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
- null, null, null, null, false, false, resolvedUserId, false);
+ broadcastIntentInPackage("android", SYSTEM_UID, uid, pid, intent, null,
+ null, 0, null, null, null, null, false, false, resolvedUserId,
+ false);
}
if (observer != null) {
@@ -4263,7 +4264,8 @@ public class ActivityManagerService extends IActivityManager.Stub
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, UserHandle.getUserId(uid));
+ null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.getUserId(uid));
}
private void cleanupDisabledPackageComponentsLocked(
@@ -8709,6 +8711,8 @@ public class ActivityManagerService extends IActivityManager.Stub
mAtmInternal.showSystemReadyErrorDialogsIfNeeded();
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
long ident = Binder.clearCallingIdentity();
try {
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
@@ -8717,7 +8721,7 @@ public class ActivityManagerService extends IActivityManager.Stub
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID,
+ null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
currentUserId);
intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -8731,7 +8735,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}, 0, null, null,
new String[] {INTERACT_ACROSS_USERS}, OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+ null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ UserHandle.USER_ALL);
} catch (Throwable t) {
Slog.wtf(TAG, "Failed sending first user broadcasts", t);
} finally {
@@ -14369,10 +14374,12 @@ public class ActivityManagerService extends IActivityManager.Stub
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
- boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
+ boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
+ int realCallingPid, int userId) {
return broadcastIntentLocked(callerApp, callerPackage, intent, resolvedType, resultTo,
resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions, ordered,
- sticky, callingPid, callingUid, userId, false /* allowBackgroundActivityStarts */);
+ sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId,
+ false /* allowBackgroundActivityStarts */);
}
@GuardedBy("this")
@@ -14380,8 +14387,8 @@ public class ActivityManagerService extends IActivityManager.Stub
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
- boolean ordered, boolean sticky, int callingPid, int callingUid, int userId,
- boolean allowBackgroundActivityStarts) {
+ boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
+ int realCallingPid, int userId, boolean allowBackgroundActivityStarts) {
intent = new Intent(intent);
final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
@@ -14430,7 +14437,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// PendingIntent), because that who is actually supplied the arguments.
if (checkComponentPermission(
android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
- Binder.getCallingPid(), Binder.getCallingUid(), -1, true)
+ realCallingPid, realCallingUid, -1, true)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: " + intent.getAction()
+ " broadcast from " + callerPackage + " (pid=" + callingPid
@@ -14448,6 +14455,25 @@ public class ActivityManagerService extends IActivityManager.Stub
+ " has background restrictions");
return ActivityManager.START_CANCELED;
}
+ if (brOptions.allowsBackgroundActivityStarts()) {
+ // See if the caller is allowed to do this. Note we are checking against
+ // the actual real caller (not whoever provided the operation as say a
+ // PendingIntent), because that who is actually supplied the arguments.
+ if (checkComponentPermission(
+ android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
+ realCallingPid, realCallingUid, -1, true)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: " + intent.getAction()
+ + " broadcast from " + callerPackage + " (pid=" + callingPid
+ + ", uid=" + callingUid + ")"
+ + " requires "
+ + android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ } else {
+ allowBackgroundActivityStarts = true;
+ }
+ }
}
// Verify that protected broadcasts are only being sent by system code,
@@ -15118,15 +15144,15 @@ public class ActivityManagerService extends IActivityManager.Stub
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, appOp, bOptions, serialized, sticky,
- callingPid, callingUid, userId);
+ callingPid, callingUid, callingUid, callingPid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
- int broadcastIntentInPackage(String packageName, int uid,
- Intent intent, String resolvedType, IIntentReceiver resultTo,
+ int broadcastIntentInPackage(String packageName, int uid, int realCallingUid,
+ int realCallingPid, Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
int userId, boolean allowBackgroundActivityStarts) {
@@ -15139,7 +15165,8 @@ public class ActivityManagerService extends IActivityManager.Stub
int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
resultTo, resultCode, resultData, resultExtras,
requiredPermissions, OP_NONE, bOptions, serialized,
- sticky, -1, uid, userId, allowBackgroundActivityStarts);
+ sticky, -1, uid, realCallingUid, realCallingPid, userId,
+ allowBackgroundActivityStarts);
Binder.restoreCallingIdentity(origId);
return res;
}
@@ -17721,15 +17748,16 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public int broadcastIntentInPackage(String packageName, int uid, Intent intent,
- String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData,
- Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
- boolean sticky, int userId, boolean allowBackgroundActivityStarts) {
+ public int broadcastIntentInPackage(String packageName, int uid, int realCallingUid,
+ int realCallingPid, Intent intent, String resolvedType, IIntentReceiver resultTo,
+ int resultCode, String resultData, Bundle resultExtras, String requiredPermission,
+ Bundle bOptions, boolean serialized, boolean sticky, int userId,
+ boolean allowBackgroundActivityStarts) {
synchronized (ActivityManagerService.this) {
return ActivityManagerService.this.broadcastIntentInPackage(packageName, uid,
- intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
- requiredPermission, bOptions, serialized, sticky, userId,
- allowBackgroundActivityStarts);
+ realCallingUid, realCallingPid, intent, resolvedType, resultTo, resultCode,
+ resultData, resultExtras, requiredPermission, bOptions, serialized, sticky,
+ userId, allowBackgroundActivityStarts);
}
}
@@ -17830,8 +17858,8 @@ public class ActivityManagerService extends IActivityManager.Stub
| Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- UserHandle.USER_ALL);
+ OP_NONE, null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.USER_ALL);
if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
@@ -17841,8 +17869,8 @@ public class ActivityManagerService extends IActivityManager.Stub
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- UserHandle.USER_ALL);
+ OP_NONE, null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.USER_ALL);
}
// Send a broadcast to PackageInstallers if the configuration change is interesting
@@ -17857,7 +17885,7 @@ public class ActivityManagerService extends IActivityManager.Stub
new String[] { android.Manifest.permission.INSTALL_PACKAGES };
broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
permissions, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- UserHandle.USER_ALL);
+ Binder.getCallingUid(), Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
}
@@ -17881,7 +17909,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, -1, SYSTEM_UID, UserHandle.USER_ALL);
+ OP_NONE, null, false, false, -1, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.USER_ALL);
}
}
@@ -18100,8 +18129,10 @@ public class ActivityManagerService extends IActivityManager.Stub
if (!queue.isIdle()) {
final String msg = "Waiting for queue " + queue + " to become idle...";
pw.println(msg);
+ pw.println(queue.describeState());
pw.flush();
Slog.v(TAG, msg);
+ queue.cancelDeferrals();
idle = false;
}
}
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index c7e4fc78c013..17ffd9c5e093 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -28,6 +28,7 @@ import static android.provider.DeviceConfig.ActivityManager.KEY_USE_COMPACTION;
import android.app.ActivityManager;
import android.app.ActivityThread;
+import android.os.Debug;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
@@ -410,6 +411,7 @@ public final class AppCompactor {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Compact "
+ ((pendingAction == COMPACT_PROCESS_SOME) ? "some" : "full")
+ ": " + name);
+ long zramFreeKbBefore = Debug.getZramFreeKb();
long[] rssBefore = Process.getRss(pid);
FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim");
fos.write(action.getBytes());
@@ -417,10 +419,12 @@ public final class AppCompactor {
long[] rssAfter = Process.getRss(pid);
long end = SystemClock.uptimeMillis();
long time = end - start;
+ long zramFreeKbAfter = Debug.getZramFreeKb();
EventLog.writeEvent(EventLogTags.AM_COMPACT, pid, name, action,
rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
- lastCompactAction, lastCompactTime, msg.arg1, msg.arg2);
+ lastCompactAction, lastCompactTime, msg.arg1, msg.arg2,
+ zramFreeKbBefore, zramFreeKbAfter);
// Note that as above not taking mPhenoTypeFlagLock here to avoid locking
// on every single compaction for a flag that will seldom change and the
// impact of reading the wrong value here is low.
@@ -429,7 +433,8 @@ public final class AppCompactor {
rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
lastCompactAction, lastCompactTime, msg.arg1,
- ActivityManager.processStateAmToProto(msg.arg2));
+ ActivityManager.processStateAmToProto(msg.arg2),
+ zramFreeKbBefore, zramFreeKbAfter);
}
synchronized (mAm) {
proc.lastCompactTime = end;
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 24543b7974df..236797b57556 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -477,6 +477,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
mStats.updateRpmStatsLocked();
}
+ if ((updateFlags & UPDATE_RAIL) != 0) {
+ mStats.updateRailStatsLocked();
+ }
+
if (bluetoothInfo != null) {
if (bluetoothInfo.isValid()) {
mStats.updateBluetoothStateLocked(bluetoothInfo);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 08900328a200..4d5cb8cb4473 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -59,6 +59,7 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.PowerProfile;
+import com.android.internal.os.RailStats;
import com.android.internal.os.RpmStats;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.ParseUtils;
@@ -84,7 +85,8 @@ import java.util.concurrent.Future;
*/
public final class BatteryStatsService extends IBatteryStats.Stub
implements PowerManagerInternal.LowPowerModeListener,
- BatteryStatsImpl.PlatformIdleStateCallback {
+ BatteryStatsImpl.PlatformIdleStateCallback,
+ BatteryStatsImpl.RailEnergyDataCallback {
static final String TAG = "BatteryStatsService";
static final boolean DBG = false;
@@ -98,6 +100,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
private native void getLowPowerStats(RpmStats rpmStats);
private native int getPlatformLowPowerStats(ByteBuffer outBuffer);
private native int getSubsystemLowPowerStats(ByteBuffer outBuffer);
+ private native void getRailEnergyPowerStats(RailStats railStats);
private CharsetDecoder mDecoderStat = StandardCharsets.UTF_8
.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
@@ -121,6 +124,16 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
@Override
+ public void fillRailDataStats(RailStats railStats) {
+ if (DBG) Slog.d(TAG, "begin getRailEnergyPowerStats");
+ try {
+ getRailEnergyPowerStats(railStats);
+ } finally {
+ if (DBG) Slog.d(TAG, "end getRailEnergyPowerStats");
+ }
+ }
+
+ @Override
public String getPlatformLowPowerStats() {
if (DBG) Slog.d(TAG, "begin getPlatformLowPowerStats");
try {
@@ -177,7 +190,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
return (umi != null) ? umi.getUserIds() : null;
}
};
- mStats = new BatteryStatsImpl(systemDir, handler, this, mUserManagerUserInfoProvider);
+ mStats = new BatteryStatsImpl(systemDir, handler, this,
+ this, mUserManagerUserInfoProvider);
mWorker = new BatteryExternalStatsWorker(context, mStats);
mStats.setExternalStatsSyncLocked(mWorker);
mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
@@ -1460,7 +1474,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
in.unmarshall(raw, 0, raw.length);
in.setDataPosition(0);
BatteryStatsImpl checkinStats = new BatteryStatsImpl(
- null, mStats.mHandler, null, mUserManagerUserInfoProvider);
+ null, mStats.mHandler, null, null,
+ mUserManagerUserInfoProvider);
checkinStats.readSummaryFromParcel(in);
in.recycle();
checkinStats.dumpProtoLocked(
@@ -1498,7 +1513,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
in.unmarshall(raw, 0, raw.length);
in.setDataPosition(0);
BatteryStatsImpl checkinStats = new BatteryStatsImpl(
- null, mStats.mHandler, null, mUserManagerUserInfoProvider);
+ null, mStats.mHandler, null, null,
+ mUserManagerUserInfoProvider);
checkinStats.readSummaryFromParcel(in);
in.recycle();
checkinStats.dumpCheckinLocked(mContext, pw, apps, flags,
diff --git a/services/core/java/com/android/server/am/BroadcastDispatcher.java b/services/core/java/com/android/server/am/BroadcastDispatcher.java
index 6371cd376d19..0b38ef94de1e 100644
--- a/services/core/java/com/android/server/am/BroadcastDispatcher.java
+++ b/services/core/java/com/android/server/am/BroadcastDispatcher.java
@@ -65,6 +65,14 @@ public class BroadcastDispatcher {
broadcasts.add(br);
}
+ int size() {
+ return broadcasts.size();
+ }
+
+ boolean isEmpty() {
+ return broadcasts.isEmpty();
+ }
+
void writeToProto(ProtoOutputStream proto, long fieldId) {
for (BroadcastRecord br : broadcasts) {
br.writeToProto(proto, fieldId);
@@ -252,22 +260,48 @@ public class BroadcastDispatcher {
synchronized (mLock) {
return mCurrentBroadcast == null
&& mOrderedBroadcasts.isEmpty()
- && mDeferredBroadcasts.isEmpty()
- && mAlarmBroadcasts.isEmpty();
+ && isDeferralsListEmpty(mDeferredBroadcasts)
+ && isDeferralsListEmpty(mAlarmBroadcasts);
+ }
+ }
+
+ private static int pendingInDeferralsList(ArrayList<Deferrals> list) {
+ int pending = 0;
+ final int numEntries = list.size();
+ for (int i = 0; i < numEntries; i++) {
+ pending += list.get(i).size();
}
+ return pending;
+ }
+
+ private static boolean isDeferralsListEmpty(ArrayList<Deferrals> list) {
+ return pendingInDeferralsList(list) == 0;
}
/**
- * Not quite the traditional size() measurement; includes any in-process but
- * not yet retired active outbound broadcast.
+ * Strictly for logging, describe the currently pending contents in a human-
+ * readable way
*/
- public int totalUndelivered() {
- synchronized (mLock) {
- return mAlarmBroadcasts.size()
- + mDeferredBroadcasts.size()
- + mOrderedBroadcasts.size()
- + (mCurrentBroadcast == null ? 0 : 1);
- }
+ public String describeStateLocked() {
+ final StringBuilder sb = new StringBuilder(128);
+ if (mCurrentBroadcast != null) {
+ sb.append("1 in flight, ");
+ }
+ sb.append(mOrderedBroadcasts.size());
+ sb.append(" ordered");
+ int n = pendingInDeferralsList(mAlarmBroadcasts);
+ if (n > 0) {
+ sb.append(", ");
+ sb.append(n);
+ sb.append(" deferrals in alarm recipients");
+ }
+ n = pendingInDeferralsList(mDeferredBroadcasts);
+ if (n > 0) {
+ sb.append(", ");
+ sb.append(n);
+ sb.append(" deferred");
+ }
+ return sb.toString();
}
// ----------------------------------
@@ -579,6 +613,26 @@ public class BroadcastDispatcher {
}
}
+ /**
+ * Cancel all current deferrals; that is, make all currently-deferred broadcasts
+ * immediately deliverable. Used by the wait-for-broadcast-idle mechanism.
+ */
+ public void cancelDeferrals() {
+ synchronized (mLock) {
+ zeroDeferralTimes(mAlarmBroadcasts);
+ zeroDeferralTimes(mDeferredBroadcasts);
+ }
+ }
+
+ private static void zeroDeferralTimes(ArrayList<Deferrals> list) {
+ final int num = list.size();
+ for (int i = 0; i < num; i++) {
+ Deferrals d = list.get(i);
+ // Safe to do this in-place because it won't break ordering
+ d.deferUntil = d.deferredBy = 0;
+ }
+ }
+
// ----------------------------------
/**
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index f0b137a6ccb1..d9ea1da79f56 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -898,6 +898,11 @@ public final class BroadcastQueue {
for (int i = perms.length-1; i >= 0; i--) {
try {
PermissionInfo pi = pm.getPermissionInfo(perms[i], "android", 0);
+ if (pi == null) {
+ // a required permission that no package has actually
+ // defined cannot be signature-required.
+ return false;
+ }
if ((pi.protectionLevel & (PermissionInfo.PROTECTION_MASK_BASE
| PermissionInfo.PROTECTION_FLAG_PRIVILEGED))
!= PermissionInfo.PROTECTION_SIGNATURE) {
@@ -923,8 +928,8 @@ public final class BroadcastQueue {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
+ mQueueName + "]: "
- + mParallelBroadcasts.size() + " parallel broadcasts, "
- + mDispatcher.totalUndelivered() + " ordered broadcasts");
+ + mParallelBroadcasts.size() + " parallel broadcasts; "
+ + mDispatcher.describeStateLocked());
mService.updateCpuStats();
@@ -1822,11 +1827,24 @@ public final class BroadcastQueue {
record.intent == null ? "" : record.intent.getAction());
}
- final boolean isIdle() {
+ boolean isIdle() {
return mParallelBroadcasts.isEmpty() && mDispatcher.isEmpty()
&& (mPendingBroadcast == null);
}
+ // Used by wait-for-broadcast-idle : fast-forward all current deferrals to
+ // be immediately deliverable.
+ void cancelDeferrals() {
+ mDispatcher.cancelDeferrals();
+ }
+
+ String describeState() {
+ synchronized (mService) {
+ return mParallelBroadcasts.size() + " parallel; "
+ + mDispatcher.describeStateLocked();
+ }
+ }
+
void writeToProto(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
proto.write(BroadcastQueueProto.QUEUE_NAME, mQueueName);
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 8ffb67a1405c..06d015234011 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -79,6 +79,7 @@ final class CoreSettingsObserver extends ContentObserver {
sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLIST, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_WHITELIST, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLISTS, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, String.class);
// add other global settings here...
}
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index a71f6af80bec..4b12e43692a6 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -138,4 +138,4 @@ option java_package com.android.server.am
30061 am_remove_task (Task ID|1|5), (Stack ID|1|5)
# The task is being compacted
-30063 am_compact (Pid|1|5),(Process Name|3),(Action|3),(BeforeRssTotal|2|2),(BeforeRssFile|2|2),(BeforeRssAnon|2|2),(BeforeRssSwap|2|2),(AfterRssTotal|2|2),(AfterRssFile|2|2),(AfterRssAnon|2|2),(AfterRssSwap|2|2),(Time|2|3),(LastAction|1|2),(LastActionTimestamp|2|3),(setAdj|1|2),(procState|1|2)
+30063 am_compact (Pid|1|5),(Process Name|3),(Action|3),(BeforeRssTotal|2|2),(BeforeRssFile|2|2),(BeforeRssAnon|2|2),(BeforeRssSwap|2|2),(AfterRssTotal|2|2),(AfterRssFile|2|2),(AfterRssAnon|2|2),(AfterRssSwap|2|2),(Time|2|3),(LastAction|1|2),(LastActionTimestamp|2|3),(setAdj|1|2),(procState|1|2),(BeforeZRAMFree|2|2),(AfterZRAMFree|2|2)
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 93a71e5a2ed4..4e03b72e6ce6 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1692,7 +1692,8 @@ public final class OomAdjuster {
(app.curAdj == ProcessList.PREVIOUS_APP_ADJ ||
app.curAdj == ProcessList.HOME_APP_ADJ)) {
mAppCompact.compactAppSome(app);
- } else if (app.setAdj < ProcessList.CACHED_APP_MIN_ADJ
+ } else if ((app.setAdj < ProcessList.CACHED_APP_MIN_ADJ
+ || app.setAdj > ProcessList.CACHED_APP_MAX_ADJ)
&& app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ
&& app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) {
mAppCompact.compactAppFull(app);
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index af56352b8cc0..a08c829f0576 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -423,9 +423,9 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
// If a completion callback has been requested, require
// that the broadcast be delivered synchronously
int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,
- uid, finalIntent, resolvedType, finishedReceiver, code, null, null,
- requiredPermission, options, (finishedReceiver != null),
- false, userId,
+ uid, callingUid, callingPid, finalIntent, resolvedType,
+ finishedReceiver, code, null, null, requiredPermission, options,
+ (finishedReceiver != null), false, userId,
mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken)
|| allowTrampoline);
if (sent == ActivityManager.BROADCAST_SUCCESS) {
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 3ea114758498..376999dfd80d 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -27,6 +27,7 @@ import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.ResolveInfo;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -108,7 +109,7 @@ public abstract class PreBootBroadcaster extends IIntentReceiver.Stub {
mIntent.setComponent(componentName);
mService.broadcastIntentLocked(null, null, mIntent, null, this, 0, null, null, null,
AppOpsManager.OP_NONE, null, true, false, ActivityManagerService.MY_PID,
- Process.SYSTEM_UID, mUserId);
+ Process.SYSTEM_UID, Binder.getCallingUid(), Binder.getCallingPid(), mUserId);
}
@Override
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 0d49e4cdc9d0..3a61dd987cf5 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1498,6 +1498,13 @@ public final class ProcessList {
// Also turn on CheckJNI for debuggable apps. It's quite
// awkward to turn on otherwise.
runtimeFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
+
+ // Check if the developer does not want ART verification
+ if (android.provider.Settings.Global.getInt(mService.mContext.getContentResolver(),
+ android.provider.Settings.Global.ART_VERIFIER_VERIFY_DEBUGGABLE, 1) == 0) {
+ runtimeFlags |= Zygote.DISABLE_VERIFIER;
+ Slog.w(TAG_PROCESSES, app + ": ART verification disabled");
+ }
}
// Run the app in safe mode if its manifest requests so or the
// system is booted in safe mode.
@@ -1705,9 +1712,15 @@ public final class ProcessList {
zygoteProcesses.remove(app);
if (zygoteProcesses.size() == 0) {
mService.mHandler.removeMessages(KILL_APP_ZYGOTE_MSG);
- Message msg = mService.mHandler.obtainMessage(KILL_APP_ZYGOTE_MSG);
- msg.obj = appZygote;
- mService.mHandler.sendMessageDelayed(msg, KILL_APP_ZYGOTE_DELAY_MS);
+ if (app.removed) {
+ // If we stopped this process because the package hosting it was removed,
+ // there's no point in delaying the app zygote kill.
+ killAppZygoteIfNeededLocked(appZygote);
+ } else {
+ Message msg = mService.mHandler.obtainMessage(KILL_APP_ZYGOTE_MSG);
+ msg.obj = appZygote;
+ mService.mHandler.sendMessageDelayed(msg, KILL_APP_ZYGOTE_DELAY_MS);
+ }
}
}
}
@@ -2162,6 +2175,29 @@ public final class ProcessList {
for (int i=0; i<N; i++) {
removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
}
+ // See if there are any app zygotes running for this packageName / UID combination,
+ // and kill it if so.
+ final ArrayList<AppZygote> zygotesToKill = new ArrayList<>();
+ for (SparseArray<AppZygote> appZygotes : mAppZygotes.getMap().values()) {
+ for (int i = 0; i < appZygotes.size(); ++i) {
+ final int appZygoteUid = appZygotes.keyAt(i);
+ if (userId != UserHandle.USER_ALL && UserHandle.getUserId(appZygoteUid) != userId) {
+ continue;
+ }
+ if (appId >= 0 && UserHandle.getAppId(appZygoteUid) != appId) {
+ continue;
+ }
+ final AppZygote appZygote = appZygotes.valueAt(i);
+ if (packageName != null
+ && !packageName.equals(appZygote.getAppInfo().packageName)) {
+ continue;
+ }
+ zygotesToKill.add(appZygote);
+ }
+ }
+ for (AppZygote appZygote : zygotesToKill) {
+ killAppZygoteIfNeededLocked(appZygote);
+ }
mService.updateOomAdjLocked();
return N > 0;
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 7f6648a3d174..ac20f6c7eaaf 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -371,7 +371,8 @@ class UserController implements Handler.Callback {
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mInjector.broadcastIntent(intent, null, resultTo, 0, null, null,
new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
- AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
+ AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID,
+ Binder.getCallingUid(), Binder.getCallingPid(), userId);
}
// We need to delay unlocking managed profiles until the parent user
@@ -471,7 +472,7 @@ class UserController implements Handler.Callback {
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
mInjector.broadcastIntent(unlockedIntent, null, null, 0, null,
null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- userId);
+ Binder.getCallingUid(), Binder.getCallingPid(), userId);
if (getUserInfo(userId).isManagedProfile()) {
UserInfo parent = mInjector.getUserManager().getProfileParent(userId);
@@ -484,8 +485,8 @@ class UserController implements Handler.Callback {
| Intent.FLAG_RECEIVER_FOREGROUND);
mInjector.broadcastIntent(profileUnlockedIntent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID,
- parent.id);
+ null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), parent.id);
}
}
@@ -543,7 +544,8 @@ class UserController implements Handler.Callback {
mInjector.getUserManager().makeInitialized(userInfo.id);
}
}, 0, null, null, null, AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, userId);
+ null, true, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), userId);
}
}
@@ -573,7 +575,8 @@ class UserController implements Handler.Callback {
}
}, 0, null, null,
new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
- AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
+ AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID,
+ Binder.getCallingUid(), Binder.getCallingPid(), userId);
}
int restartUser(final int userId, final boolean foreground) {
@@ -696,7 +699,8 @@ class UserController implements Handler.Callback {
mInjector.broadcastIntent(stoppingIntent,
null, stoppingReceiver, 0, null, null,
new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+ null, true, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.USER_ALL);
});
}
}
@@ -735,7 +739,8 @@ class UserController implements Handler.Callback {
mInjector.broadcastIntent(shutdownIntent,
null, shutdownReceiver, 0, null, null, null,
AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, userId);
+ null, true, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), userId);
}
void finishUserStopped(UserState uss) {
@@ -834,7 +839,8 @@ class UserController implements Handler.Callback {
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+ null, false, false, MY_PID, SYSTEM_UID, Binder.getCallingUid(),
+ Binder.getCallingPid(), UserHandle.USER_ALL);
}
/**
@@ -950,6 +956,8 @@ class UserController implements Handler.Callback {
Slog.i(TAG, "Starting userid:" + userId + " fg:" + foreground);
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
final long ident = Binder.clearCallingIdentity();
try {
final int oldUserId = getCurrentUserId();
@@ -1088,7 +1096,7 @@ class UserController implements Handler.Callback {
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, userId);
+ null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid, userId);
}
if (foreground) {
@@ -1111,7 +1119,8 @@ class UserController implements Handler.Callback {
}
}, 0, null, null,
new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
- null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+ null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ UserHandle.USER_ALL);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -1427,6 +1436,8 @@ class UserController implements Handler.Callback {
}
void sendUserSwitchBroadcasts(int oldUserId, int newUserId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
long ident = Binder.clearCallingIdentity();
try {
Intent intent;
@@ -1442,7 +1453,8 @@ class UserController implements Handler.Callback {
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, profileUserId);
+ null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ profileUserId);
}
}
if (newUserId >= 0) {
@@ -1457,7 +1469,8 @@ class UserController implements Handler.Callback {
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- null, false, false, MY_PID, SYSTEM_UID, profileUserId);
+ null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
+ profileUserId);
}
intent = new Intent(Intent.ACTION_USER_SWITCHED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
@@ -1466,8 +1479,8 @@ class UserController implements Handler.Callback {
mInjector.broadcastIntent(intent,
null, null, 0, null, null,
new String[] {android.Manifest.permission.MANAGE_USERS},
- AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- UserHandle.USER_ALL);
+ AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, callingUid,
+ callingPid, UserHandle.USER_ALL);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -2107,12 +2120,14 @@ class UserController implements Handler.Callback {
protected int broadcastIntent(Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
- boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
+ boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
+ int realCallingPid, int userId) {
// TODO b/64165549 Verify that mLock is not held before calling AMS methods
synchronized (mService) {
return mService.broadcastIntentLocked(null, null, intent, resolvedType, resultTo,
resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions,
- ordered, sticky, callingPid, callingUid, userId);
+ ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid,
+ userId);
}
}
diff --git a/services/core/java/com/android/server/appbinding/AppBindingService.java b/services/core/java/com/android/server/appbinding/AppBindingService.java
index 0b6a4329d15b..bbe4ed15b3a0 100644
--- a/services/core/java/com/android/server/appbinding/AppBindingService.java
+++ b/services/core/java/com/android/server/appbinding/AppBindingService.java
@@ -177,13 +177,12 @@ public class AppBindingService extends Binder {
* Handle boot phase PHASE_ACTIVITY_MANAGER_READY.
*/
private void onPhaseActivityManagerReady() {
+ // RoleManager doesn't tell us about upgrade, so we still need to listen for app upgrades.
+ // (app uninstall/disable will be notified by RoleManager.)
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
packageFilter.addDataScheme("package");
- packageFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiverAsUser(mPackageUserMonitor, UserHandle.ALL,
packageFilter, null, mHandler);
@@ -256,14 +255,6 @@ public class AppBindingService extends Binder {
handlePackageAddedReplacing(packageName, userId);
}
break;
- case Intent.ACTION_PACKAGE_REMOVED:
- if (!replacing) {
- handlePackageRemoved(packageName, userId);
- }
- break;
- case Intent.ACTION_PACKAGE_CHANGED:
- handlePackageChanged(packageName, userId);
- break;
}
}
};
@@ -371,31 +362,6 @@ public class AppBindingService extends Binder {
}
}
- private void handlePackageRemoved(String packageName, int userId) {
- if (DEBUG) {
- Slog.d(TAG, "handlePackageRemoved: u" + userId + " " + packageName);
- }
- synchronized (mLock) {
- final AppServiceFinder finder = findFinderLocked(userId, packageName);
- if (finder != null) {
- unbindServicesLocked(userId, finder, "package uninstall");
- }
- }
- }
-
- private void handlePackageChanged(String packageName, int userId) {
- if (DEBUG) {
- Slog.d(TAG, "handlePackageChanged: u" + userId + " " + packageName);
- }
- synchronized (mLock) {
- final AppServiceFinder finder = findFinderLocked(userId, packageName);
- if (finder != null) {
- unbindServicesLocked(userId, finder, "package changed");
- bindServicesLocked(userId, finder, "package changed");
- }
- }
- }
-
private void rebindAllLocked(String reason) {
for (int i = 0; i < mRunningUsers.size(); i++) {
if (!mRunningUsers.valueAt(i)) {
diff --git a/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java b/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java
index 4c5f1a1c7b49..3663518bf7b9 100644
--- a/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java
+++ b/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java
@@ -16,14 +16,10 @@
package com.android.server.appbinding.finders;
-import static android.provider.Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL;
-
import android.Manifest.permission;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
+import android.app.role.OnRoleHoldersChangedListener;
+import android.app.role.RoleManager;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ServiceInfo;
import android.os.Handler;
import android.os.IBinder;
@@ -35,7 +31,8 @@ import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.R;
-import com.android.internal.telephony.SmsApplication;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.CollectionUtils;
import com.android.server.appbinding.AppBindingConstants;
import java.util.function.BiConsumer;
@@ -45,10 +42,15 @@ import java.util.function.BiConsumer;
*/
public class CarrierMessagingClientServiceFinder
extends AppServiceFinder<CarrierMessagingClientService, ICarrierMessagingClientService> {
+
+ private final RoleManager mRoleManager;
+
public CarrierMessagingClientServiceFinder(Context context,
BiConsumer<AppServiceFinder, Integer> listener,
Handler callbackHandler) {
super(context, listener, callbackHandler);
+
+ mRoleManager = context.getSystemService(RoleManager.class);
}
@Override
@@ -84,9 +86,8 @@ public class CarrierMessagingClientServiceFinder
@Override
public String getTargetPackage(int userId) {
- final ComponentName cn = SmsApplication.getDefaultSmsApplicationAsUser(
- mContext, /* updateIfNeeded= */ true, userId);
- String ret = cn == null ? null : cn.getPackageName();
+ final String ret = CollectionUtils.firstOrNull(mRoleManager.getRoleHoldersAsUser(
+ RoleManager.ROLE_SMS, UserHandle.of(userId)));
if (DEBUG) {
Slog.d(TAG, "getTargetPackage()=" + ret);
@@ -97,9 +98,8 @@ public class CarrierMessagingClientServiceFinder
@Override
public void startMonitoring() {
- final IntentFilter filter = new IntentFilter(ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);
- mContext.registerReceiverAsUser(mSmsAppChangedWatcher, UserHandle.ALL, filter,
- /* permission= */ null, mHandler);
+ mRoleManager.addOnRoleHoldersChangedListenerAsUser(
+ BackgroundThread.getExecutor(), mRoleHolderChangedListener, UserHandle.ALL);
}
@Override
@@ -118,12 +118,9 @@ public class CarrierMessagingClientServiceFinder
return constants.SMS_APP_BIND_FLAGS;
}
- private final BroadcastReceiver mSmsAppChangedWatcher = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL.equals(intent.getAction())) {
- mListener.accept(CarrierMessagingClientServiceFinder.this, getSendingUserId());
- }
+ private final OnRoleHoldersChangedListener mRoleHolderChangedListener = (role, user) -> {
+ if (RoleManager.ROLE_SMS.equals(role)) {
+ mListener.accept(CarrierMessagingClientServiceFinder.this, user.getIdentifier());
}
};
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 0e3309088f21..70c28a854512 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -38,6 +38,7 @@ import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AppOpsManager.HistoricalOps;
+import android.app.AppOpsManager.HistoricalOpsRequest;
import android.app.AppOpsManagerInternal;
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
import android.content.BroadcastReceiver;
@@ -1024,25 +1025,29 @@ public class AppOpsService extends IAppOpsService.Stub {
@Override
public void getHistoricalOps(int uid, @NonNull String packageName,
- @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+ @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis,
@NonNull RemoteCallback callback) {
- Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
- "uid must be " + Process.INVALID_UID + " or non negative");
- Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
- "beginTimeMillis must be non negative and lesser than endTimeMillis");
+ // Use the builder to validate arguments.
+ final HistoricalOpsRequest request = new HistoricalOpsRequest.Builder(
+ beginTimeMillis, endTimeMillis)
+ .setUid(uid)
+ .setPackageName(packageName)
+ .setOpNames(opNames)
+ .build();
Preconditions.checkNotNull(callback, "callback cannot be null");
- checkValidOpsOrNull(opNames);
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
+ final String[] opNamesArray = (opNames != null)
+ ? opNames.toArray(new String[opNames.size()]) : null;
if (mHistoricalRegistry.getMode() == AppOpsManager.HISTORICAL_MODE_DISABLED) {
// TODO (bug:122218838): Remove once the feature fully enabled.
- getHistoricalPackagesOpsCompat(uid, packageName, opNames, beginTimeMillis,
+ getHistoricalPackagesOpsCompat(uid, packageName, opNamesArray, beginTimeMillis,
endTimeMillis, callback);
} else {
// Must not hold the appops lock
- mHistoricalRegistry.getHistoricalOps(uid, packageName, opNames,
+ mHistoricalRegistry.getHistoricalOps(uid, packageName, opNamesArray,
beginTimeMillis, endTimeMillis, callback);
}
}
@@ -1101,20 +1106,25 @@ public class AppOpsService extends IAppOpsService.Stub {
@Override
public void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
- @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+ @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis,
@NonNull RemoteCallback callback) {
- Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
- "uid must be " + Process.INVALID_UID + " or non negative");
- Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
- "beginTimeMillis must be non negative and lesser than endTimeMillis");
+ // Use the builder to validate arguments.
+ final HistoricalOpsRequest request = new HistoricalOpsRequest.Builder(
+ beginTimeMillis, endTimeMillis)
+ .setUid(uid)
+ .setPackageName(packageName)
+ .setOpNames(opNames)
+ .build();
Preconditions.checkNotNull(callback, "callback cannot be null");
- checkValidOpsOrNull(opNames);
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
+ final String[] opNamesArray = (opNames != null)
+ ? opNames.toArray(new String[opNames.size()]) : null;
+
// Must not hold the appops lock
- mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, opNames,
+ mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, opNamesArray,
beginTimeMillis, endTimeMillis, callback);
}
@@ -4266,16 +4276,6 @@ public class AppOpsService extends IAppOpsService.Stub {
return packageNames;
}
- private static void checkValidOpsOrNull(String[] opNames) {
- if (opNames != null) {
- for (String opName : opNames) {
- if (AppOpsManager.strOpToOp(opName) == AppOpsManager.OP_NONE) {
- throw new IllegalArgumentException("Unknown op: " + opName);
- }
- }
- }
- }
-
private final class ClientRestrictionState implements DeathRecipient {
private final IBinder token;
SparseArray<boolean[]> perUserRestrictions;
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 9a1d7bf0053d..47c9b8639760 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -104,8 +104,7 @@ public class AttentionManagerService extends SystemService {
@Override
public void onSwitchUser(int userId) {
- cancelAndUnbindLocked(peekUserStateLocked(userId),
- AttentionService.ATTENTION_FAILURE_UNKNOWN);
+ cancelAndUnbindLocked(peekUserStateLocked(userId));
}
/** Resolves and sets up the attention service if it had not been done yet. */
@@ -152,7 +151,8 @@ public class AttentionManagerService extends SystemService {
}
synchronized (mLock) {
- unbindAfterTimeoutLocked();
+ final long now = SystemClock.uptimeMillis();
+ freeIfInactiveLocked();
final UserState userState = getOrCreateCurrentUserStateLocked();
// lazily start the service, which should be very lightweight to start
@@ -172,7 +172,7 @@ public class AttentionManagerService extends SystemService {
try {
// throttle frequent requests
final AttentionCheckCache attentionCheckCache = userState.mAttentionCheckCache;
- if (attentionCheckCache != null && SystemClock.uptimeMillis()
+ if (attentionCheckCache != null && now
< attentionCheckCache.mLastComputed + STALE_AFTER_MILLIS) {
callback.onSuccess(requestCode, attentionCheckCache.mResult,
attentionCheckCache.mTimestamp);
@@ -190,6 +190,7 @@ public class AttentionManagerService extends SystemService {
userState.mAttentionCheckCache = new AttentionCheckCache(
SystemClock.uptimeMillis(), result,
timestamp);
+ userState.mCurrentAttentionCheckIsFulfilled = true;
}
StatsLog.write(StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
result);
@@ -198,14 +199,10 @@ public class AttentionManagerService extends SystemService {
@Override
public void onFailure(int requestCode, int error) {
callback.onFailure(requestCode, error);
+ userState.mCurrentAttentionCheckIsFulfilled = true;
StatsLog.write(StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
error);
}
-
- @Override
- public IBinder asBinder() {
- return null;
- }
});
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Cannot call into the AttentionService");
@@ -219,7 +216,10 @@ public class AttentionManagerService extends SystemService {
/** Cancels the specified attention check. */
public void cancelAttentionCheck(int requestCode) {
synchronized (mLock) {
- final UserState userState = getOrCreateCurrentUserStateLocked();
+ final UserState userState = peekCurrentUserStateLocked();
+ if (userState == null) {
+ return;
+ }
if (userState.mService == null) {
if (userState.mPendingAttentionCheck != null
&& userState.mPendingAttentionCheck.mRequestCode == requestCode) {
@@ -236,8 +236,12 @@ public class AttentionManagerService extends SystemService {
}
@GuardedBy("mLock")
- private void unbindAfterTimeoutLocked() {
- mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.CONNECTION_EXPIRED,
+ private void freeIfInactiveLocked() {
+ // If we are called here, it means someone used the API again - reset the timer then.
+ mAttentionHandler.removeMessages(AttentionHandler.CHECK_CONNECTION_EXPIRATION);
+
+ // Schedule resources cleanup if no one calls the API again.
+ mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.CHECK_CONNECTION_EXPIRATION,
CONNECTION_TTL_MILLIS);
}
@@ -264,12 +268,14 @@ public class AttentionManagerService extends SystemService {
}
@GuardedBy("mLock")
- UserState peekCurrentUserStateLocked() {
+ @Nullable
+ private UserState peekCurrentUserStateLocked() {
return peekUserStateLocked(ActivityManager.getCurrentUser());
}
@GuardedBy("mLock")
- UserState peekUserStateLocked(int userId) {
+ @Nullable
+ private UserState peekUserStateLocked(int userId) {
return mUserStates.get(userId);
}
@@ -406,6 +412,8 @@ public class AttentionManagerService extends SystemService {
@GuardedBy("mLock")
int mCurrentAttentionCheckRequestCode;
@GuardedBy("mLock")
+ boolean mCurrentAttentionCheckIsFulfilled;
+ @GuardedBy("mLock")
PendingAttentionCheck mPendingAttentionCheck;
@GuardedBy("mLock")
@@ -501,7 +509,7 @@ public class AttentionManagerService extends SystemService {
}
private class AttentionHandler extends Handler {
- private static final int CONNECTION_EXPIRED = 1;
+ private static final int CHECK_CONNECTION_EXPIRATION = 1;
private static final int ATTENTION_CHECK_TIMEOUT = 2;
AttentionHandler() {
@@ -511,19 +519,26 @@ public class AttentionManagerService extends SystemService {
public void handleMessage(Message msg) {
switch (msg.what) {
// Do not occupy resources when not in use - unbind proactively.
- case CONNECTION_EXPIRED: {
+ case CHECK_CONNECTION_EXPIRATION: {
for (int i = 0; i < mUserStates.size(); i++) {
- cancelAndUnbindLocked(mUserStates.valueAt(i),
- AttentionService.ATTENTION_FAILURE_UNKNOWN);
+ cancelAndUnbindLocked(mUserStates.valueAt(i));
}
-
}
break;
// Callee is no longer interested in the attention check result - cancel.
case ATTENTION_CHECK_TIMEOUT: {
- cancelAndUnbindLocked(peekCurrentUserStateLocked(),
- AttentionService.ATTENTION_FAILURE_TIMED_OUT);
+ synchronized (mLock) {
+ final UserState userState = peekCurrentUserStateLocked();
+ if (userState != null) {
+ // If not called back already.
+ if (!userState.mCurrentAttentionCheckIsFulfilled) {
+ cancel(userState,
+ AttentionService.ATTENTION_FAILURE_TIMED_OUT);
+ }
+
+ }
+ }
}
break;
@@ -533,25 +548,29 @@ public class AttentionManagerService extends SystemService {
}
}
+ private void cancel(UserState userState, @AttentionFailureCodes int failureCode) {
+ if (userState != null && userState.mService != null) {
+ try {
+ userState.mService.cancelAttentionCheck(
+ userState.mCurrentAttentionCheckRequestCode);
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Unable to cancel attention check");
+ }
+
+ if (userState.mPendingAttentionCheck != null) {
+ userState.mPendingAttentionCheck.cancel(failureCode);
+ }
+ }
+ }
+
@GuardedBy("mLock")
- private void cancelAndUnbindLocked(UserState userState,
- @AttentionFailureCodes int failureCode) {
+ private void cancelAndUnbindLocked(UserState userState) {
synchronized (mLock) {
- if (userState != null && userState.mService != null) {
- try {
- userState.mService.cancelAttentionCheck(
- userState.mCurrentAttentionCheckRequestCode);
- } catch (RemoteException e) {
- Slog.e(LOG_TAG, "Unable to cancel attention check");
- }
+ cancel(userState, AttentionService.ATTENTION_FAILURE_UNKNOWN);
- if (userState.mPendingAttentionCheck != null) {
- userState.mPendingAttentionCheck.cancel(failureCode);
- }
- mContext.unbindService(userState.mConnection);
- userState.mConnection.cleanupService();
- mUserStates.remove(userState.mUserId);
- }
+ mContext.unbindService(userState.mConnection);
+ userState.mConnection.cleanupService();
+ mUserStates.remove(userState.mUserId);
}
}
@@ -563,8 +582,7 @@ public class AttentionManagerService extends SystemService {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
- cancelAndUnbindLocked(peekCurrentUserStateLocked(),
- AttentionService.ATTENTION_FAILURE_UNKNOWN);
+ cancelAndUnbindLocked(peekCurrentUserStateLocked());
}
}
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 6df60d6bdd3a..9af57daa259b 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -280,9 +280,9 @@ import java.util.ArrayList;
AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
AudioSystem.FOR_RECORD, mForcedUseForComm, eventSource);
- // Un-mute ringtone stream volume
- mAudioService.setUpdateRingerModeServiceInt();
}
+ // Un-mute ringtone stream volume
+ mAudioService.postUpdateRingerModeServiceInt();
}
/*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index a6643d49c79f..d902201df212 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -248,6 +248,7 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_NOTIFY_VOL_EVENT = 22;
private static final int MSG_DISPATCH_AUDIO_SERVER_STATE = 23;
private static final int MSG_ENABLE_SURROUND_FORMATS = 24;
+ private static final int MSG_UPDATE_RINGER_MODE = 25;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -753,6 +754,7 @@ public class AudioService extends IAudioService.Stub
intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+ intentFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
@@ -2720,7 +2722,11 @@ public class AudioService extends IAudioService.Stub
}
}
- /*package*/ void setUpdateRingerModeServiceInt() {
+ /*package*/ void postUpdateRingerModeServiceInt() {
+ sendMsg(mAudioHandler, MSG_UPDATE_RINGER_MODE, SENDMSG_QUEUE, 0, 0, null, 0);
+ }
+
+ private void onUpdateRingerModeServiceInt() {
setRingerModeInt(getRingerModeInternal(), false);
}
@@ -3217,6 +3223,21 @@ public class AudioService extends IAudioService.Stub
if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
return;
}
+
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_PHONE_STATE)
+ != PackageManager.PERMISSION_GRANTED) {
+ synchronized (mSetModeDeathHandlers) {
+ for (SetModeDeathHandler h : mSetModeDeathHandlers) {
+ if (h.getMode() == AudioSystem.MODE_IN_CALL) {
+ Log.w(TAG, "getMode is call, Permission Denial: setSpeakerphoneOn from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+ }
+ }
+ }
+
// for logging only
final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on)
.append(") from u/pid:").append(Binder.getCallingUid()).append("/")
@@ -4944,6 +4965,10 @@ public class AudioService extends IAudioService.Stub
case MSG_ENABLE_SURROUND_FORMATS:
onEnableSurroundFormats((ArrayList<Integer>) msg.obj);
break;
+
+ case MSG_UPDATE_RINGER_MODE:
+ onUpdateRingerModeServiceInt();
+ break;
}
}
}
@@ -5159,6 +5184,20 @@ public class AudioService extends IAudioService.Stub
} else if (action.equals(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION) ||
action.equals(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)) {
handleAudioEffectBroadcast(context, intent);
+ } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
+ final int[] suspendedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+ final String[] suspendedPackages =
+ intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ if (suspendedPackages == null || suspendedUids == null
+ || suspendedPackages.length != suspendedUids.length) {
+ return;
+ }
+ for (int i = 0; i < suspendedUids.length; i++) {
+ if (!TextUtils.isEmpty(suspendedPackages[i])) {
+ mMediaFocusControl.noFocusForSuspendedApp(
+ suspendedPackages[i], suspendedUids[i]);
+ }
+ }
}
}
} // end class AudioServiceBroadcastReceiver
@@ -5323,6 +5362,11 @@ public class AudioService extends IAudioService.Stub
}
}
+ if (callingPackageName == null || clientId == null || aa == null) {
+ Log.e(TAG, "Invalid null parameter to request audio focus");
+ return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+ }
+
return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
clientId, callingPackageName, flags, sdk,
forceFocusDuckingForAccessibility(aa, durationHint, Binder.getCallingUid()));
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index 99f08405a375..db55138e446d 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -45,8 +45,8 @@ public class FocusRequester {
private AudioFocusDeathHandler mDeathHandler; // may be null
private IAudioFocusDispatcher mFocusDispatcher; // may be null
private final IBinder mSourceRef; // may be null
- private final String mClientId;
- private final String mPackageName;
+ private final @NonNull String mClientId;
+ private final @NonNull String mPackageName;
private final int mCallingUid;
private final MediaFocusControl mFocusController; // never null
private final int mSdkTarget;
@@ -72,7 +72,7 @@ public class FocusRequester {
/**
* the audio attributes associated with the focus request
*/
- private final AudioAttributes mAttributes;
+ private final @NonNull AudioAttributes mAttributes;
/**
* Class constructor
@@ -87,9 +87,10 @@ public class FocusRequester {
* @param uid
* @param ctlr cannot be null
*/
- FocusRequester(AudioAttributes aa, int focusRequest, int grantFlags,
- IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
- String pn, int uid, @NonNull MediaFocusControl ctlr, int sdk) {
+ FocusRequester(@NonNull AudioAttributes aa, int focusRequest, int grantFlags,
+ IAudioFocusDispatcher afl, IBinder source, @NonNull String id,
+ AudioFocusDeathHandler hdlr, @NonNull String pn, int uid,
+ @NonNull MediaFocusControl ctlr, int sdk) {
mAttributes = aa;
mFocusDispatcher = afl;
mSourceRef = source;
@@ -124,11 +125,7 @@ public class FocusRequester {
}
boolean hasSameClient(String otherClient) {
- try {
- return mClientId.compareTo(otherClient) == 0;
- } catch (NullPointerException e) {
- return false;
- }
+ return mClientId.compareTo(otherClient) == 0;
}
boolean isLockedFocusOwner() {
@@ -143,12 +140,8 @@ public class FocusRequester {
return (mFocusDispatcher != null) && mFocusDispatcher.equals(fd);
}
- boolean hasSamePackage(String pack) {
- try {
- return mPackageName.compareTo(pack) == 0;
- } catch (NullPointerException e) {
- return false;
- }
+ boolean hasSamePackage(@NonNull String pack) {
+ return mPackageName.compareTo(pack) == 0;
}
boolean hasSameUid(int uid) {
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index d023bd7827ff..b4bbbc729505 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -24,7 +24,6 @@ import android.media.AudioFocusInfo;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.IAudioFocusDispatcher;
-import android.media.audiopolicy.AudioPolicy;
import android.media.audiopolicy.IAudioPolicyCallback;
import android.os.Binder;
import android.os.Build;
@@ -35,6 +34,7 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
+import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@@ -44,7 +44,6 @@ import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;
-import java.text.DateFormat;
/**
* @hide
@@ -138,6 +137,30 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
private static final AudioEventLogger mEventLogger = new AudioEventLogger(50,
"focus commands as seen by MediaFocusControl");
+ /*package*/ void noFocusForSuspendedApp(@NonNull String packageName, int uid) {
+ synchronized (mAudioFocusLock) {
+ final Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
+ List<String> clientsToRemove = new ArrayList<>();
+ while (stackIterator.hasNext()) {
+ final FocusRequester focusOwner = stackIterator.next();
+ if (focusOwner.hasSameUid(uid) && focusOwner.hasSamePackage(packageName)) {
+ clientsToRemove.add(focusOwner.getClientId());
+ mEventLogger.log((new AudioEventLogger.StringEvent(
+ "focus owner:" + focusOwner.getClientId()
+ + " in uid:" + uid + " pack: " + packageName
+ + " getting AUDIOFOCUS_LOSS due to app suspension"))
+ .printLog(TAG));
+ // make the suspended app lose focus through its focus listener (if any)
+ focusOwner.dispatchFocusChange(AudioManager.AUDIOFOCUS_LOSS);
+ }
+ }
+ for (String clientToRemove : clientsToRemove) {
+ // update the stack but don't signal the change.
+ removeFocusStackEntry(clientToRemove, false, true);
+ }
+ }
+ }
+
/**
* Discard the current audio focus owner.
* Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
@@ -688,9 +711,9 @@ public class MediaFocusControl implements PlayerFocusEnforcer {
}
/** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */
- protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb,
- IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
- int sdk, boolean forceDuck) {
+ protected int requestAudioFocus(@NonNull AudioAttributes aa, int focusChangeHint, IBinder cb,
+ IAudioFocusDispatcher fd, @NonNull String clientId, @NonNull String callingPackageName,
+ int flags, int sdk, boolean forceDuck) {
mEventLogger.log((new AudioEventLogger.StringEvent(
"requestAudioFocus() from uid/pid " + Binder.getCallingUid()
+ "/" + Binder.getCallingPid()
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index bd4acdbf4070..7d4ac592a9df 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -34,7 +34,7 @@ public abstract class AuthenticationClient extends ClientMonitor {
private long mOpId;
public abstract int handleFailedAttempt();
- public abstract void resetFailedAttempts();
+ public void resetFailedAttempts() {}
public static final int LOCKOUT_NONE = 0;
public static final int LOCKOUT_TIMED = 1;
@@ -42,6 +42,11 @@ public abstract class AuthenticationClient extends ClientMonitor {
private final boolean mRequireConfirmation;
+ // We need to track this state since it's possible for applications to request for
+ // authentication while the device is already locked out. In that case, the client is created
+ // but not started yet. The user shouldn't receive the error haptics in this case.
+ private boolean mStarted;
+
/**
* This method is called when authentication starts.
*/
@@ -53,6 +58,11 @@ public abstract class AuthenticationClient extends ClientMonitor {
*/
public abstract void onStop();
+ /**
+ * @return true if the framework should handle lockout.
+ */
+ public abstract boolean shouldFrameworkHandleLockout();
+
public AuthenticationClient(Context context, Metrics metrics,
BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
BiometricServiceBase.ServiceListener listener, int targetUserId, int groupId, long opId,
@@ -91,6 +101,23 @@ public abstract class AuthenticationClient extends ClientMonitor {
}
@Override
+ public boolean onError(long deviceId, int error, int vendorCode) {
+ if (!shouldFrameworkHandleLockout()) {
+ switch (error) {
+ case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
+ case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
+ if (mStarted) {
+ vibrateError();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return super.onError(deviceId, error, vendorCode);
+ }
+
+ @Override
public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) {
super.logOnAuthenticated(authenticated, mRequireConfirmation, getTargetUserId(),
@@ -113,7 +140,9 @@ public abstract class AuthenticationClient extends ClientMonitor {
vibrateSuccess();
}
result = true;
- resetFailedAttempts();
+ if (shouldFrameworkHandleLockout()) {
+ resetFailedAttempts();
+ }
onStop();
final byte[] byteToken = new byte[token.size()];
@@ -147,9 +176,10 @@ public abstract class AuthenticationClient extends ClientMonitor {
if (listener != null) {
vibrateError();
}
+
// Allow system-defined limit of number of attempts before giving up
final int lockoutMode = handleFailedAttempt();
- if (lockoutMode != LOCKOUT_NONE) {
+ if (lockoutMode != LOCKOUT_NONE && shouldFrameworkHandleLockout()) {
Slog.w(getLogTag(), "Forcing lockout (driver code should do this!), mode("
+ lockoutMode + ")");
stop(false);
@@ -170,7 +200,7 @@ public abstract class AuthenticationClient extends ClientMonitor {
}
}
}
- result |= lockoutMode != LOCKOUT_NONE; // in a lockout mode
+ result = lockoutMode != LOCKOUT_NONE; // in a lockout mode
}
} catch (RemoteException e) {
Slog.e(getLogTag(), "Remote exception", e);
@@ -184,6 +214,7 @@ public abstract class AuthenticationClient extends ClientMonitor {
*/
@Override
public int start() {
+ mStarted = true;
onStart();
try {
final int result = getDaemonWrapper().authenticate(mOpId, getGroupId());
@@ -209,6 +240,8 @@ public abstract class AuthenticationClient extends ClientMonitor {
return 0;
}
+ mStarted = false;
+
onStop();
try {
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index bca84f7b7217..ddd416e14164 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -273,16 +273,13 @@ public class BiometricService extends SystemService {
*/
private static final int STATE_AUTH_STARTED = 2;
/**
- * Authentication is paused, waiting for the user to press "try again" button. Since the
- * try again button requires us to cancel authentication, this represents the state where
- * ERROR_CANCELED is not received yet.
+ * Authentication is paused, waiting for the user to press "try again" button. Only
+ * passive modalities such as Face or Iris should have this state. Note that for passive
+ * modalities, the HAL enters the idle state after onAuthenticated(false) which differs from
+ * fingerprint.
*/
private static final int STATE_AUTH_PAUSED = 3;
/**
- * Same as above, except the ERROR_CANCELED has been received.
- */
- private static final int STATE_AUTH_PAUSED_CANCELED = 4;
- /**
* Authentication is successful, but we're waiting for the user to press "confirm" button.
*/
private static final int STATE_AUTH_PENDING_CONFIRM = 5;
@@ -457,11 +454,6 @@ public class BiometricService extends SystemService {
// Pause authentication. onBiometricAuthenticated(false) causes the
// dialog to show a "try again" button for passive modalities.
mCurrentAuthSession.mState = STATE_AUTH_PAUSED;
- // Cancel authentication. Skip the token/package check since we are
- // cancelling from system server. The interface is permission protected so
- // this is fine.
- cancelInternal(null /* token */, null /* package */,
- false /* fromClient */);
}
mCurrentAuthSession.mClientReceiver.onAuthenticationFailed();
@@ -507,24 +499,15 @@ public class BiometricService extends SystemService {
}
}, BiometricPrompt.HIDE_DIALOG_DELAY);
}
- } else if (mCurrentAuthSession.mState == STATE_AUTH_PAUSED
- || mCurrentAuthSession.mState == STATE_AUTH_PAUSED_CANCELED) {
- if (mCurrentAuthSession.mState == STATE_AUTH_PAUSED
- && error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
- // Skip the first ERROR_CANCELED message when this happens, since
- // "try again" requires us to cancel authentication but keep
- // the prompt showing.
- mCurrentAuthSession.mState = STATE_AUTH_PAUSED_CANCELED;
- } else {
- // In the "try again" state, we should forward canceled errors to
- // the client and and clean up.
- mCurrentAuthSession.mClientReceiver.onError(error, message);
- mStatusBarService.onBiometricError(message);
- mActivityTaskManager.unregisterTaskStackListener(
- mTaskStackListener);
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
- }
+ } else if (mCurrentAuthSession.mState == STATE_AUTH_PAUSED) {
+ // In the "try again" state, we should forward canceled errors to
+ // the client and and clean up.
+ mCurrentAuthSession.mClientReceiver.onError(error, message);
+ mStatusBarService.onBiometricError(message);
+ mActivityTaskManager.unregisterTaskStackListener(
+ mTaskStackListener);
+ mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+ mCurrentAuthSession = null;
} else {
Slog.e(TAG, "Impossible session error state: "
+ mCurrentAuthSession.mState);
@@ -705,8 +688,7 @@ public class BiometricService extends SystemService {
if (mPendingAuthSession.mModalitiesWaiting.isEmpty()) {
final boolean continuing = mCurrentAuthSession != null &&
- (mCurrentAuthSession.mState == STATE_AUTH_PAUSED
- || mCurrentAuthSession.mState == STATE_AUTH_PAUSED_CANCELED);
+ (mCurrentAuthSession.mState == STATE_AUTH_PAUSED);
mCurrentAuthSession = mPendingAuthSession;
mPendingAuthSession = null;
@@ -1029,7 +1011,7 @@ public class BiometricService extends SystemService {
}
@Override // Binder call
- public void resetTimeout(byte[] token) {
+ public void resetLockout(byte[] token) {
checkInternalPermission();
final long ident = Binder.clearCallingIdentity();
try {
@@ -1037,7 +1019,7 @@ public class BiometricService extends SystemService {
mFingerprintService.resetTimeout(token);
}
if (mFaceService != null) {
- mFaceService.resetTimeout(token);
+ mFaceService.resetLockout(token);
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 9e0f2fcaa29f..92a8d9359b58 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -20,17 +20,12 @@ import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREG
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
-import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.IActivityTaskManager;
-import android.app.PendingIntent;
import android.app.SynchronousUserSwitchObserver;
import android.app.TaskStackListener;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -54,14 +49,11 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
import android.util.StatsLog;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.server.SystemService;
-import com.android.server.biometrics.fingerprint.FingerprintService;
import java.util.ArrayList;
import java.util.Collections;
@@ -80,38 +72,36 @@ public abstract class BiometricServiceBase extends SystemService
protected static final boolean DEBUG = true;
+ private static final boolean CLEANUP_UNKNOWN_TEMPLATES = true;
private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
private static final int MSG_USER_SWITCHING = 10;
- private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30 * 1000;
private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
private final Context mContext;
private final String mKeyguardPackage;
- private final SparseBooleanArray mTimedLockoutCleared;
- private final SparseIntArray mFailedAttempts;
private final IActivityTaskManager mActivityTaskManager;
- private final AlarmManager mAlarmManager;
private final PowerManager mPowerManager;
private final UserManager mUserManager;
private final MetricsLogger mMetricsLogger;
private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener();
private final ResetClientStateRunnable mResetClientState = new ResetClientStateRunnable();
- private final LockoutReceiver mLockoutReceiver = new LockoutReceiver();
private final ArrayList<LockoutResetMonitor> mLockoutMonitors = new ArrayList<>();
protected final IStatusBarService mStatusBarService;
protected final Map<Integer, Long> mAuthenticatorIds =
Collections.synchronizedMap(new HashMap<>());
- protected final ResetFailedAttemptsForUserRunnable mResetFailedAttemptsForCurrentUserRunnable =
- new ResetFailedAttemptsForUserRunnable();
protected final AppOpsManager mAppOps;
protected final H mHandler = new H();
+ private final IBinder mToken = new Binder(); // Used for internal enumeration
+ private final ArrayList<UserTemplate> mUnknownHALTemplates = new ArrayList<>();
+
private IBiometricService mBiometricService;
private ClientMonitor mCurrentClient;
private ClientMonitor mPendingClient;
private PerformanceStats mPerformanceStats;
protected int mCurrentUserId = UserHandle.USER_NULL;
+ protected long mHalDeviceId;
// Tracks if the current authentication makes use of CryptoObjects.
protected boolean mIsCrypto;
// Normal authentications are tracked by mPerformanceMap.
@@ -135,21 +125,14 @@ public abstract class BiometricServiceBase extends SystemService
protected abstract String getTag();
/**
- * @return the biometric utilities for a specific implementation.
- */
- protected abstract BiometricUtils getBiometricUtils();
-
- /**
- * @return the number of failed attempts after which the user will be temporarily locked out
- * from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
+ * @return wrapper for the HAL
*/
- protected abstract int getFailedAttemptsLockoutTimed();
+ protected abstract DaemonWrapper getDaemonWrapper();
/**
- * @return the number of failed attempts after which the user will be permanently locked out
- * from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
+ * @return the biometric utilities for a specific implementation.
*/
- protected abstract int getFailedAttemptsLockoutPermanent();
+ protected abstract BiometricUtils getBiometricUtils();
/**
* @return the metrics constants for a biometric implementation.
@@ -186,13 +169,6 @@ public abstract class BiometricServiceBase extends SystemService
protected abstract long getHalDeviceId();
/**
- * This method is called when the user switches. Implementations should probably notify the
- * HAL.
- * @param userId
- */
- protected abstract void handleUserSwitching(int userId);
-
- /**
* @param userId
* @return Returns true if the user has any enrolled biometrics.
*/
@@ -215,6 +191,9 @@ public abstract class BiometricServiceBase extends SystemService
*/
protected abstract boolean checkAppOps(int uid, String opPackageName);
+ protected abstract List<? extends BiometricAuthenticator.Identifier> getEnrolledTemplates(
+ int userId);
+
/**
* Notifies clients of any change in the biometric state (active / idle). This is mainly for
* Fingerprint navigation gestures.
@@ -224,6 +203,11 @@ public abstract class BiometricServiceBase extends SystemService
protected abstract int statsModality();
+ /**
+ * @return one of the AuthenticationClient LOCKOUT constants
+ */
+ protected abstract int getLockoutMode();
+
protected abstract class AuthenticationClientImpl extends AuthenticationClient {
// Used to check if the public API that was invoked was from FingerprintManager. Only
@@ -271,21 +255,12 @@ public abstract class BiometricServiceBase extends SystemService
}
@Override
- public void resetFailedAttempts() {
- resetFailedAttemptsForUser(true /* clearAttemptCounter */,
- ActivityManager.getCurrentUser());
- }
-
- @Override
public void notifyUserActivity() {
userActivity();
}
@Override
public int handleFailedAttempt() {
- final int currentUser = ActivityManager.getCurrentUser();
- mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
- mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
final int lockoutMode = getLockoutMode();
if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
mPerformanceStats.permanentLockout++;
@@ -295,7 +270,6 @@ public abstract class BiometricServiceBase extends SystemService
// Failing multiple times will continue to push out the lockout time
if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
- scheduleLockoutResetForUser(currentUser);
return lockoutMode;
}
return AuthenticationClient.LOCKOUT_NONE;
@@ -319,40 +293,106 @@ public abstract class BiometricServiceBase extends SystemService
}
}
- protected abstract class RemovalClientImpl extends RemovalClient {
- private boolean mShouldNotify;
-
- public RemovalClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
- IBinder token, ServiceListener listener, int fingerId, int groupId, int userId,
+ /**
+ * An internal class to help clean up unknown templates in HAL and Framework
+ */
+ private final class InternalRemovalClient extends RemovalClient {
+ InternalRemovalClient(Context context,
+ DaemonWrapper daemon, long halDeviceId, IBinder token,
+ ServiceListener listener, int templateId, int groupId, int userId,
boolean restricted, String owner) {
- super(context, getMetrics(), daemon, halDeviceId, token, listener, fingerId, groupId,
+ super(context, getMetrics(), daemon, halDeviceId, token, listener, templateId, groupId,
userId, restricted, owner, getBiometricUtils());
}
- public void setShouldNotifyUserActivity(boolean shouldNotify) {
- mShouldNotify = shouldNotify;
- }
-
@Override
- public void notifyUserActivity() {
- if (mShouldNotify) {
- userActivity();
- }
+ protected int statsModality() {
+ return BiometricServiceBase.this.statsModality();
}
}
- protected abstract class EnumerateClientImpl extends EnumerateClient {
-
- public EnumerateClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
- IBinder token, ServiceListener listener, int groupId, int userId,
- boolean restricted, String owner) {
+ /**
+ * Internal class to help clean up unknown templates in the HAL and Framework
+ */
+ private final class InternalEnumerateClient extends EnumerateClient {
+
+ private BiometricUtils mUtils;
+ // List of templates that are known to the Framework. Remove from this list when enumerate
+ // returns a template that contains a match.
+ private List<? extends BiometricAuthenticator.Identifier> mEnrolledList;
+ // List of templates to remove from the HAL
+ private List<BiometricAuthenticator.Identifier> mUnknownHALTemplates = new ArrayList<>();
+
+ InternalEnumerateClient(Context context,
+ DaemonWrapper daemon, long halDeviceId, IBinder token,
+ ServiceListener listener, int groupId, int userId, boolean restricted,
+ String owner, List<? extends BiometricAuthenticator.Identifier> enrolledList,
+ BiometricUtils utils) {
super(context, getMetrics(), daemon, halDeviceId, token, listener, groupId, userId,
restricted, owner);
+ mEnrolledList = enrolledList;
+ mUtils = utils;
+ }
+
+ private void handleEnumeratedTemplate(BiometricAuthenticator.Identifier identifier) {
+ if (identifier == null) {
+ return;
+ }
+ Slog.v(getTag(), "handleEnumeratedTemplate: " + identifier.getBiometricId());
+ boolean matched = false;
+ for (int i = 0; i < mEnrolledList.size(); i++) {
+ if (mEnrolledList.get(i).getBiometricId() == identifier.getBiometricId()) {
+ mEnrolledList.remove(i);
+ matched = true;
+ break;
+ }
+ }
+
+ // TemplateId 0 means no templates in HAL
+ if (!matched && identifier.getBiometricId() != 0) {
+ mUnknownHALTemplates.add(identifier);
+ }
+ Slog.v(getTag(), "Matched: " + matched);
+ }
+
+ private void doTemplateCleanup() {
+ if (mEnrolledList == null) {
+ return;
+ }
+
+ // At this point, mEnrolledList only contains templates known to the framework and
+ // not the HAL.
+ for (int i = 0; i < mEnrolledList.size(); i++) {
+ BiometricAuthenticator.Identifier identifier = mEnrolledList.get(i);
+ Slog.e(getTag(), "doTemplateCleanup(): Removing dangling template from framework: "
+ + identifier.getBiometricId() + " "
+ + identifier.getName());
+ mUtils.removeBiometricForUser(getContext(),
+ getTargetUserId(), identifier.getBiometricId());
+ StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
+ statsModality(),
+ BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK);
+ }
+ mEnrolledList.clear();
+ }
+
+ public List<BiometricAuthenticator.Identifier> getUnknownHALTemplates() {
+ return mUnknownHALTemplates;
}
@Override
- public void notifyUserActivity() {
- userActivity();
+ public boolean onEnumerationResult(BiometricAuthenticator.Identifier identifier,
+ int remaining) {
+ handleEnumeratedTemplate(identifier);
+ if (remaining == 0) {
+ doTemplateCleanup();
+ }
+ return remaining == 0;
+ }
+
+ @Override
+ protected int statsModality() {
+ return BiometricServiceBase.this.statsModality();
}
}
@@ -429,13 +469,14 @@ public abstract class BiometricServiceBase extends SystemService
* subclasses.
*/
protected interface DaemonWrapper {
- int ERROR_ESRCH = 3; // Likely fingerprint HAL is dead. see errno.h.
+ int ERROR_ESRCH = 3; // Likely HAL is dead. see errno.h.
int authenticate(long operationId, int groupId) throws RemoteException;
int cancel() throws RemoteException;
int remove(int groupId, int biometricId) throws RemoteException;
int enumerate() throws RemoteException;
- int enroll(byte[] cryptoToken, int groupId, int timeout,
+ int enroll(byte[] token, int groupId, int timeout,
ArrayList<Integer> disabledFeatures) throws RemoteException;
+ void resetLockout(byte[] token) throws RemoteException;
}
/**
@@ -506,24 +547,7 @@ public abstract class BiometricServiceBase extends SystemService
}
}
- private final class LockoutReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Slog.v(getTag(), "Resetting lockout: " + intent.getAction());
- if (getLockoutResetIntent().equals(intent.getAction())) {
- final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
- resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
- }
- }
- }
- private final class ResetFailedAttemptsForUserRunnable implements Runnable {
- @Override
- public void run() {
- resetFailedAttemptsForUser(true /* clearAttemptCounter */,
- ActivityManager.getCurrentUser());
- }
- }
private final class LockoutResetMonitor implements IBinder.DeathRecipient {
private static final long WAKELOCK_TIMEOUT_MS = 2000;
@@ -583,6 +607,19 @@ public abstract class BiometricServiceBase extends SystemService
}
/**
+ * Container for enumerated templates. Used to keep track when cleaning up unknown
+ * templates.
+ */
+ private final class UserTemplate {
+ final BiometricAuthenticator.Identifier mIdentifier;
+ final int mUserId;
+ UserTemplate(BiometricAuthenticator.Identifier identifier, int userId) {
+ this.mIdentifier = identifier;
+ this.mUserId = userId;
+ }
+ }
+
+ /**
* Initializes the system service.
* <p>
* Subclasses must define a single argument constructor that accepts the context
@@ -599,16 +636,11 @@ public abstract class BiometricServiceBase extends SystemService
mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
com.android.internal.R.string.config_keyguardComponent)).getPackageName();
mAppOps = context.getSystemService(AppOpsManager.class);
- mTimedLockoutCleared = new SparseBooleanArray();
- mFailedAttempts = new SparseIntArray();
mActivityTaskManager = ((ActivityTaskManager) context.getSystemService(
Context.ACTIVITY_TASK_SERVICE)).getService();
mPowerManager = mContext.getSystemService(PowerManager.class);
- mAlarmManager = mContext.getSystemService(AlarmManager.class);
mUserManager = UserManager.get(mContext);
mMetricsLogger = new MetricsLogger();
- mContext.registerReceiver(mLockoutReceiver, new IntentFilter(getLockoutResetIntent()),
- getLockoutBroadcastPermission(), null /* handler */);
}
@Override
@@ -688,6 +720,11 @@ public abstract class BiometricServiceBase extends SystemService
if (DEBUG) Slog.v(getTag(), "handleError(client="
+ (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
+ if (client instanceof InternalRemovalClient
+ || client instanceof InternalEnumerateClient) {
+ clearEnumerateState();
+ }
+
if (client != null && client.onError(deviceId, error, vendorCode)) {
removeClient(client);
}
@@ -721,6 +758,39 @@ public abstract class BiometricServiceBase extends SystemService
updateActiveGroup(userId, null);
}
}
+
+ if (client instanceof InternalRemovalClient && !mUnknownHALTemplates.isEmpty()) {
+ startCleanupUnknownHALTemplates();
+ } else if (client instanceof InternalRemovalClient) {
+ clearEnumerateState();
+ }
+ }
+
+ protected void handleEnumerate(BiometricAuthenticator.Identifier identifier, int remaining) {
+ ClientMonitor client = getCurrentClient();
+
+ client.onEnumerationResult(identifier, remaining);
+
+ // All templates in the HAL for this user were enumerated
+ if (remaining == 0) {
+ if (client instanceof InternalEnumerateClient) {
+ List<BiometricAuthenticator.Identifier> unknownHALTemplates =
+ ((InternalEnumerateClient) client).getUnknownHALTemplates();
+
+ if (!unknownHALTemplates.isEmpty()) {
+ Slog.w(getTag(), "Adding " + unknownHALTemplates.size()
+ + " templates for deletion");
+ }
+ for (int i = 0; i < unknownHALTemplates.size(); i++) {
+ mUnknownHALTemplates.add(new UserTemplate(unknownHALTemplates.get(i),
+ client.getTargetUserId()));
+ }
+ removeClient(client);
+ startCleanupUnknownHALTemplates();
+ } else {
+ removeClient(client);
+ }
+ }
}
/**
@@ -832,13 +902,13 @@ public abstract class BiometricServiceBase extends SystemService
});
}
- protected void removeInternal(RemovalClientImpl client) {
+ protected void removeInternal(RemovalClient client) {
mHandler.post(() -> {
startClient(client, true /* initiatedByClient */);
});
}
- protected void enumerateInternal(EnumerateClientImpl client) {
+ protected void enumerateInternal(EnumerateClient client) {
mHandler.post(() -> {
startClient(client, true /* initiatedByClient */);
});
@@ -919,19 +989,6 @@ public abstract class BiometricServiceBase extends SystemService
return mKeyguardPackage.equals(clientPackage);
}
- protected int getLockoutMode() {
- final int currentUser = ActivityManager.getCurrentUser();
- final int failedAttempts = mFailedAttempts.get(currentUser, 0);
- if (failedAttempts >= getFailedAttemptsLockoutPermanent()) {
- return AuthenticationClient.LOCKOUT_PERMANENT;
- } else if (failedAttempts > 0 &&
- mTimedLockoutCleared.get(currentUser, false) == false
- && (failedAttempts % getFailedAttemptsLockoutTimed() == 0)) {
- return AuthenticationClient.LOCKOUT_TIMED;
- }
- return AuthenticationClient.LOCKOUT_NONE;
- }
-
private boolean isForegroundActivity(int uid, int pid) {
try {
List<ActivityManager.RunningAppProcessInfo> procs =
@@ -965,10 +1022,10 @@ public abstract class BiometricServiceBase extends SystemService
currentClient.getOwnerString());
// This check only matters for FingerprintService, since enumerate may call back
// multiple times.
- if (currentClient instanceof FingerprintService.EnumerateClientImpl ||
- currentClient instanceof FingerprintService.RemovalClientImpl) {
+ if (currentClient instanceof InternalEnumerateClient
+ || currentClient instanceof InternalRemovalClient) {
// This condition means we're currently running internal diagnostics to
- // remove extra fingerprints in the hardware and/or the software
+ // remove extra templates in the hardware and/or the software
// TODO: design an escape hatch in case client never finishes
if (newClient != null) {
Slog.w(getTag(), "Internal cleanup in progress but trying to start client "
@@ -1124,16 +1181,75 @@ public abstract class BiometricServiceBase extends SystemService
return mAuthenticatorIds.getOrDefault(userId, 0L);
}
- private void scheduleLockoutResetForUser(int userId) {
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
- getLockoutResetIntentForUser(userId));
+ /**
+ * This method should be called upon connection to the daemon, and when user switches.
+ * @param userId
+ */
+ protected void doTemplateCleanupForUser(int userId) {
+ if (CLEANUP_UNKNOWN_TEMPLATES) {
+ enumerateUser(userId);
+ }
}
- private PendingIntent getLockoutResetIntentForUser(int userId) {
- return PendingIntent.getBroadcast(mContext, userId,
- new Intent(getLockoutResetIntent()).putExtra(KEY_LOCKOUT_RESET_USER, userId),
- PendingIntent.FLAG_UPDATE_CURRENT);
+ private void clearEnumerateState() {
+ if (DEBUG) Slog.v(getTag(), "clearEnumerateState()");
+ mUnknownHALTemplates.clear();
+ }
+
+ /**
+ * Remove unknown templates from HAL
+ */
+ private void startCleanupUnknownHALTemplates() {
+ if (!mUnknownHALTemplates.isEmpty()) {
+ UserTemplate template = mUnknownHALTemplates.get(0);
+ mUnknownHALTemplates.remove(template);
+ boolean restricted = !hasPermission(getManageBiometricPermission());
+ InternalRemovalClient client = new InternalRemovalClient(getContext(),
+ getDaemonWrapper(), mHalDeviceId, mToken, null /* listener */,
+ template.mIdentifier.getBiometricId(), 0 /* groupId */, template.mUserId,
+ restricted, getContext().getPackageName());
+ removeInternal(client);
+ StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
+ statsModality(),
+ BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL);
+ } else {
+ clearEnumerateState();
+ }
+ }
+
+ private void enumerateUser(int userId) {
+ if (DEBUG) Slog.v(getTag(), "Enumerating user(" + userId + ")");
+
+ final boolean restricted = !hasPermission(getManageBiometricPermission());
+ final List<? extends BiometricAuthenticator.Identifier> enrolledList =
+ getEnrolledTemplates(userId);
+
+ InternalEnumerateClient client = new InternalEnumerateClient(getContext(),
+ getDaemonWrapper(), mHalDeviceId, mToken, null /* serviceListener */, userId,
+ userId, restricted, getContext().getOpPackageName(), enrolledList,
+ getBiometricUtils());
+ enumerateInternal(client);
+ }
+
+ /**
+ * This method is called when the user switches. Implementations should probably notify the
+ * HAL.
+ */
+ protected void handleUserSwitching(int userId) {
+ if (getCurrentClient() instanceof InternalRemovalClient
+ || getCurrentClient() instanceof InternalEnumerateClient) {
+ Slog.w(getTag(), "User switched while performing cleanup");
+ removeClient(getCurrentClient());
+ clearEnumerateState();
+ }
+ updateActiveGroup(userId, null);
+ doTemplateCleanupForUser(userId);
+ }
+
+ protected void notifyLockoutResetMonitors() {
+ for (int i = 0; i < mLockoutMonitors.size(); i++) {
+ mLockoutMonitors.get(i).sendLockoutReset();
+ }
}
private void userActivity() {
@@ -1169,25 +1285,6 @@ public abstract class BiometricServiceBase extends SystemService
return userId;
}
- // Attempt counter should only be cleared when Keyguard goes away or when
- // a biometric is successfully authenticated.
- private void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
- if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
- Slog.v(getTag(), "Reset biometric lockout, clearAttemptCounter=" + clearAttemptCounter);
- }
- if (clearAttemptCounter) {
- mFailedAttempts.put(userId, 0);
- }
- mTimedLockoutCleared.put(userId, true);
- // If we're asked to reset failed attempts externally (i.e. from Keyguard),
- // the alarm might still be pending; remove it.
- cancelLockoutResetForUser(userId);
- notifyLockoutResetMonitors();
- }
-
- private void cancelLockoutResetForUser(int userId) {
- mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
- }
private void listenForUserSwitches() {
try {
@@ -1204,12 +1301,6 @@ public abstract class BiometricServiceBase extends SystemService
}
}
- private void notifyLockoutResetMonitors() {
- for (int i = 0; i < mLockoutMonitors.size(); i++) {
- mLockoutMonitors.get(i).sendLockoutReset();
- }
- }
-
private void removeLockoutResetCallback(
LockoutResetMonitor monitor) {
mLockoutMonitors.remove(monitor);
diff --git a/services/core/java/com/android/server/biometrics/EnumerateClient.java b/services/core/java/com/android/server/biometrics/EnumerateClient.java
index 0f57f484bb0a..44ac0373507a 100644
--- a/services/core/java/com/android/server/biometrics/EnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/EnumerateClient.java
@@ -39,6 +39,10 @@ public abstract class EnumerateClient extends ClientMonitor {
}
@Override
+ public void notifyUserActivity() {
+ }
+
+ @Override
protected int statsAction() {
return BiometricsProtoEnums.ACTION_ENUMERATE;
}
@@ -94,7 +98,9 @@ public abstract class EnumerateClient extends ClientMonitor {
public boolean onEnumerationResult(BiometricAuthenticator.Identifier identifier,
int remaining) {
try {
- getListener().onEnumerated(identifier, remaining);
+ if (getListener() != null) {
+ getListener().onEnumerated(identifier, remaining);
+ }
} catch (RemoteException e) {
Slog.w(getLogTag(), "Failed to notify enumerated:", e);
}
diff --git a/services/core/java/com/android/server/biometrics/RemovalClient.java b/services/core/java/com/android/server/biometrics/RemovalClient.java
index 0509067b4daf..a18f336f3ef4 100644
--- a/services/core/java/com/android/server/biometrics/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/RemovalClient.java
@@ -44,6 +44,10 @@ public abstract class RemovalClient extends ClientMonitor {
}
@Override
+ public void notifyUserActivity() {
+ }
+
+ @Override
protected int statsAction() {
return BiometricsProtoEnums.ACTION_REMOVE;
}
@@ -95,7 +99,9 @@ public abstract class RemovalClient extends ClientMonitor {
private boolean sendRemoved(BiometricAuthenticator.Identifier identifier,
int remaining) {
try {
- getListener().onRemoved(identifier, remaining);
+ if (getListener() != null) {
+ getListener().onRemoved(identifier, remaining);
+ }
} catch (RemoteException e) {
Slog.w(getLogTag(), "Failed to notify Removed:", e);
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 8995068ef504..d2d14829d597 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -51,9 +51,13 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemServerInitThreadPool;
+import com.android.server.biometrics.AuthenticationClient;
import com.android.server.biometrics.BiometricServiceBase;
import com.android.server.biometrics.BiometricUtils;
+import com.android.server.biometrics.ClientMonitor;
+import com.android.server.biometrics.EnumerateClient;
import com.android.server.biometrics.Metrics;
+import com.android.server.biometrics.RemovalClient;
import org.json.JSONArray;
import org.json.JSONException;
@@ -79,8 +83,6 @@ public class FaceService extends BiometricServiceBase {
private static final String FACE_DATA_DIR = "facedata";
private static final String ACTION_LOCKOUT_RESET =
"com.android.server.biometrics.face.ACTION_LOCKOUT_RESET";
- private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 3;
- private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 12;
private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
private final class FaceAuthClient extends AuthenticationClientImpl {
@@ -96,6 +98,25 @@ public class FaceService extends BiometricServiceBase {
protected int statsModality() {
return FaceService.this.statsModality();
}
+
+ @Override
+ public boolean shouldFrameworkHandleLockout() {
+ return false;
+ }
+
+ @Override
+ public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
+ boolean authenticated, ArrayList<Byte> token) {
+ final boolean result = super.onAuthenticated(identifier, authenticated, token);
+
+ // For face, the authentication lifecycle ends either when
+ // 1) Authenticated == true
+ // 2) Error occurred
+ // 3) Authenticated == false
+ // Fingerprint currently does not end when the third condition is met which is a bug,
+ // but let's leave it as-is for now.
+ return result || !authenticated;
+ }
}
/**
@@ -106,6 +127,7 @@ public class FaceService extends BiometricServiceBase {
/**
* The following methods contain common code which is shared in biometrics/common.
*/
+
@Override // Binder call
public long generateChallenge(IBinder token) {
checkPermission(MANAGE_BIOMETRIC);
@@ -216,15 +238,14 @@ public class FaceService extends BiometricServiceBase {
}
final boolean restricted = isRestricted();
- final RemovalClientImpl client = new RemovalClientImpl(getContext(), mDaemonWrapper,
- mHalDeviceId, token, new ServiceListenerImpl(receiver), faceId, 0 /* groupId */,
- userId, restricted, token.toString()) {
+ final RemovalClient client = new RemovalClient(getContext(), getMetrics(),
+ mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), faceId,
+ 0 /* groupId */, userId, restricted, token.toString(), getBiometricUtils()) {
@Override
protected int statsModality() {
return FaceService.this.statsModality();
}
};
- client.setShouldNotifyUserActivity(true);
removeInternal(client);
}
@@ -234,9 +255,9 @@ public class FaceService extends BiometricServiceBase {
checkPermission(MANAGE_BIOMETRIC);
final boolean restricted = isRestricted();
- final EnumerateClientImpl client = new EnumerateClientImpl(getContext(), mDaemonWrapper,
- mHalDeviceId, token, new ServiceListenerImpl(receiver), userId, userId,
- restricted, getContext().getOpPackageName()) {
+ final EnumerateClient client = new EnumerateClient(getContext(), getMetrics(),
+ mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), userId,
+ userId, restricted, getContext().getOpPackageName()) {
@Override
protected int statsModality() {
return FaceService.this.statsModality();
@@ -317,7 +338,7 @@ public class FaceService extends BiometricServiceBase {
return null;
}
- return FaceService.this.getEnrolledFaces(userId);
+ return FaceService.this.getEnrolledTemplates(userId);
}
@Override // Binder call
@@ -354,10 +375,13 @@ public class FaceService extends BiometricServiceBase {
}
@Override // Binder call
- public void resetTimeout(byte[] token) {
+ public void resetLockout(byte[] token) {
checkPermission(MANAGE_BIOMETRIC);
- // TODO: confirm security token when we move timeout management into the HAL layer.
- mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
+ try {
+ mDaemonWrapper.resetLockout(token);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to reset lockout", e);
+ }
}
@Override
@@ -511,7 +535,8 @@ public class FaceService extends BiometricServiceBase {
public void onEnumerated(BiometricAuthenticator.Identifier identifier, int remaining)
throws RemoteException {
if (mFaceServiceReceiver != null) {
-
+ mFaceServiceReceiver.onEnumerated(identifier.getDeviceId(),
+ identifier.getBiometricId(), remaining);
}
}
}
@@ -520,75 +545,107 @@ public class FaceService extends BiometricServiceBase {
@GuardedBy("this")
private IBiometricsFace mDaemon;
- private long mHalDeviceId;
+ // One of the AuthenticationClient constants
+ private int mCurrentUserLockoutMode;
/**
* Receives callbacks from the HAL.
*/
private IBiometricsFaceClientCallback mDaemonCallback =
new IBiometricsFaceClientCallback.Stub() {
- @Override
- public void onEnrollResult(final long deviceId, int faceId, int userId,
- int remaining) {
- mHandler.post(() -> {
- final Face face = new Face(getBiometricUtils()
- .getUniqueName(getContext(), userId), faceId, deviceId);
- FaceService.super.handleEnrollResult(face, remaining);
- });
- }
+ @Override
+ public void onEnrollResult(final long deviceId, int faceId, int userId,
+ int remaining) {
+ mHandler.post(() -> {
+ final Face face = new Face(getBiometricUtils()
+ .getUniqueName(getContext(), userId), faceId, deviceId);
+ FaceService.super.handleEnrollResult(face, remaining);
+ });
+ }
- @Override
- public void onAcquired(final long deviceId, final int userId,
- final int acquiredInfo,
- final int vendorCode) {
- mHandler.post(() -> {
- FaceService.super.handleAcquired(deviceId, acquiredInfo, vendorCode);
- });
- }
+ @Override
+ public void onAcquired(final long deviceId, final int userId,
+ final int acquiredInfo,
+ final int vendorCode) {
+ mHandler.post(() -> {
+ FaceService.super.handleAcquired(deviceId, acquiredInfo, vendorCode);
+ });
+ }
- @Override
- public void onAuthenticated(final long deviceId, final int faceId, final int userId,
- ArrayList<Byte> token) {
- mHandler.post(() -> {
- Face face = new Face("", faceId, deviceId);
- FaceService.super.handleAuthenticated(face, token);
- });
- }
+ @Override
+ public void onAuthenticated(final long deviceId, final int faceId, final int userId,
+ ArrayList<Byte> token) {
+ mHandler.post(() -> {
+ Face face = new Face("", faceId, deviceId);
+ FaceService.super.handleAuthenticated(face, token);
+ });
+ }
- @Override
- public void onError(final long deviceId, final int userId, final int error,
- final int vendorCode) {
- mHandler.post(() -> {
- FaceService.super.handleError(deviceId, error, vendorCode);
-
- // TODO: this chunk of code should be common to all biometric services
- if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) {
- // If we get HW_UNAVAILABLE, try to connect again later...
- Slog.w(TAG, "Got ERROR_HW_UNAVAILABLE; try reconnecting next client.");
- synchronized (this) {
- mDaemon = null;
- mHalDeviceId = 0;
- mCurrentUserId = UserHandle.USER_NULL;
- }
- }
- });
+ @Override
+ public void onError(final long deviceId, final int userId, final int error,
+ final int vendorCode) {
+ mHandler.post(() -> {
+ FaceService.super.handleError(deviceId, error, vendorCode);
+
+ // TODO: this chunk of code should be common to all biometric services
+ if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) {
+ // If we get HW_UNAVAILABLE, try to connect again later...
+ Slog.w(TAG, "Got ERROR_HW_UNAVAILABLE; try reconnecting next client.");
+ synchronized (this) {
+ mDaemon = null;
+ mHalDeviceId = 0;
+ mCurrentUserId = UserHandle.USER_NULL;
+ }
}
+ });
+ }
- @Override
- public void onRemoved(final long deviceId, final int faceId, final int userId,
- final int remaining) {
- mHandler.post(() -> {
- final Face face = new Face("", faceId, deviceId);
- FaceService.super.handleRemoved(face, remaining);
- });
+ @Override
+ public void onRemoved(final long deviceId, final int faceId, final int userId,
+ final int remaining) {
+ mHandler.post(() -> {
+ final Face face = new Face("", faceId, deviceId);
+ FaceService.super.handleRemoved(face, remaining);
+ });
+ }
+
+ @Override
+ public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId)
+ throws RemoteException {
+ mHandler.post(() -> {
+ if (!faceIds.isEmpty()) {
+ for (int i = 0; i < faceIds.size(); i++) {
+ final Face face = new Face("", faceIds.get(i), deviceId);
+ // Convert to old old behavior
+ FaceService.super.handleEnumerate(face, faceIds.size() - i - 1);
+ }
+ } else {
+ // For face, the HIDL contract is to receive an empty list when there are no
+ // templates enrolled. Send a null identifier since we don't consume them
+ // anywhere, and send remaining == 0 to plumb this with existing common code.
+ FaceService.super.handleEnumerate(null /* identifier */, 0);
}
+ });
+ }
- @Override
- public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId)
- throws RemoteException {
- // TODO
+ @Override
+ public void onLockoutChanged(long duration) {
+ Slog.d(TAG, "onLockoutChanged: " + duration);
+ if (duration == 0) {
+ mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_NONE;
+ } else if (duration == Long.MAX_VALUE) {
+ mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_PERMANENT;
+ } else {
+ mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_TIMED;
+ }
+
+ mHandler.post(() -> {
+ if (duration == 0) {
+ notifyLockoutResetMonitors();
}
- };
+ });
+ }
+ };
/**
* Wraps the HAL-specific code and is passed to the ClientMonitor implementations so that they
@@ -647,9 +704,22 @@ public class FaceService extends BiometricServiceBase {
for (int i = 0; i < cryptoToken.length; i++) {
token.add(cryptoToken[i]);
}
- // TODO: plumb requireAttention down from framework
return daemon.enroll(token, timeout, disabledFeatures);
}
+
+ @Override
+ public void resetLockout(byte[] cryptoToken) throws RemoteException {
+ IBiometricsFace daemon = getFaceDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "resetLockout(): no face HAL!");
+ return;
+ }
+ final ArrayList<Byte> token = new ArrayList<>();
+ for (int i = 0; i < cryptoToken.length; i++) {
+ token.add(cryptoToken[i]);
+ }
+ daemon.resetLockout(token);
+ }
};
@@ -670,18 +740,13 @@ public class FaceService extends BiometricServiceBase {
}
@Override
- protected BiometricUtils getBiometricUtils() {
- return FaceUtils.getInstance();
- }
-
- @Override
- protected int getFailedAttemptsLockoutTimed() {
- return MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED;
+ protected DaemonWrapper getDaemonWrapper() {
+ return mDaemonWrapper;
}
@Override
- protected int getFailedAttemptsLockoutPermanent() {
- return MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT;
+ protected BiometricUtils getBiometricUtils() {
+ return FaceUtils.getInstance();
}
@Override
@@ -693,7 +758,7 @@ public class FaceService extends BiometricServiceBase {
protected boolean hasReachedEnrollmentLimit(int userId) {
final int limit = getContext().getResources().getInteger(
com.android.internal.R.integer.config_faceMaxTemplatesPerUser);
- final int enrolled = FaceService.this.getEnrolledFaces(userId).size();
+ final int enrolled = FaceService.this.getEnrolledTemplates(userId).size();
if (enrolled >= limit) {
Slog.w(TAG, "Too many faces registered");
return true;
@@ -761,7 +826,9 @@ public class FaceService extends BiometricServiceBase {
@Override
protected void handleUserSwitching(int userId) {
- updateActiveGroup(userId, null);
+ super.handleUserSwitching(userId);
+ // Will be updated when we get the callback from HAL
+ mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_NONE;
}
@Override
@@ -780,7 +847,6 @@ public class FaceService extends BiometricServiceBase {
@Override
protected void checkUseBiometricPermission() {
// noop for Face. The permission checks are all done on the incoming binder call.
- // TODO: Perhaps do the same in FingerprintService
}
@Override
@@ -790,6 +856,11 @@ public class FaceService extends BiometricServiceBase {
}
@Override
+ protected List<Face> getEnrolledTemplates(int userId) {
+ return getBiometricUtils().getBiometricsForUser(getContext(), userId);
+ }
+
+ @Override
protected void notifyClientActiveCallbacks(boolean isActive) {
// noop for Face.
}
@@ -799,6 +870,11 @@ public class FaceService extends BiometricServiceBase {
return BiometricsProtoEnums.MODALITY_FACE;
}
+ @Override
+ protected int getLockoutMode() {
+ return mCurrentUserLockoutMode;
+ }
+
/** Gets the face daemon */
private synchronized IBiometricsFace getFaceDaemon() {
if (mDaemon == null) {
@@ -828,6 +904,7 @@ public class FaceService extends BiometricServiceBase {
if (mHalDeviceId != 0) {
loadAuthenticatorIds();
updateActiveGroup(ActivityManager.getCurrentUser(), null);
+ doTemplateCleanupForUser(ActivityManager.getCurrentUser());
} else {
Slog.w(TAG, "Failed to open Face HAL!");
MetricsLogger.count(getContext(), "faced_openhal_error", 1);
@@ -865,10 +942,6 @@ public class FaceService extends BiometricServiceBase {
return 0;
}
- private List<Face> getEnrolledFaces(int userId) {
- return getBiometricUtils().getBiometricsForUser(getContext(), userId);
- }
-
private void dumpInternal(PrintWriter pw) {
JSONObject dump = new JSONObject();
try {
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index d8544e324618..164468e99967 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -24,8 +24,13 @@ import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_FINGERPRINT;
import android.app.ActivityManager;
+import android.app.AlarmManager;
import android.app.AppOpsManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -46,21 +51,25 @@ import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SELinux;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
-import android.util.StatsLog;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemServerInitThreadPool;
+import com.android.server.biometrics.AuthenticationClient;
import com.android.server.biometrics.BiometricServiceBase;
import com.android.server.biometrics.BiometricUtils;
import com.android.server.biometrics.ClientMonitor;
import com.android.server.biometrics.EnumerateClient;
import com.android.server.biometrics.Metrics;
+import com.android.server.biometrics.RemovalClient;
import org.json.JSONArray;
import org.json.JSONException;
@@ -85,20 +94,30 @@ public class FingerprintService extends BiometricServiceBase {
protected static final String TAG = "FingerprintService";
private static final boolean DEBUG = true;
- private static final boolean CLEANUP_UNUSED_FP = true;
private static final String FP_DATA_DIR = "fpdata";
private static final String ACTION_LOCKOUT_RESET =
"com.android.server.biometrics.fingerprint.ACTION_LOCKOUT_RESET";
private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5;
private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;
+ private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30 * 1000;
+ private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
- // TODO: This should be refactored into BiometricService
- private final class UserFingerprint {
- Fingerprint f;
- int userId;
- public UserFingerprint(Fingerprint f, int userId) {
- this.f = f;
- this.userId = userId;
+ private final class ResetFailedAttemptsForUserRunnable implements Runnable {
+ @Override
+ public void run() {
+ resetFailedAttemptsForUser(true /* clearAttemptCounter */,
+ ActivityManager.getCurrentUser());
+ }
+ }
+
+ private final class LockoutReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Slog.v(getTag(), "Resetting lockout: " + intent.getAction());
+ if (getLockoutResetIntent().equals(intent.getAction())) {
+ final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
+ resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
+ }
}
}
@@ -121,6 +140,30 @@ public class FingerprintService extends BiometricServiceBase {
protected int statsModality() {
return FingerprintService.this.statsModality();
}
+
+ @Override
+ public void resetFailedAttempts() {
+ resetFailedAttemptsForUser(true /* clearAttemptCounter */,
+ ActivityManager.getCurrentUser());
+ }
+
+ @Override
+ public boolean shouldFrameworkHandleLockout() {
+ return true;
+ }
+
+ @Override
+ public int handleFailedAttempt() {
+ final int currentUser = ActivityManager.getCurrentUser();
+ mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
+ mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
+
+ if (getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
+ scheduleLockoutResetForUser(currentUser);
+ }
+
+ return super.handleFailedAttempt();
+ }
}
/**
@@ -241,15 +284,14 @@ public class FingerprintService extends BiometricServiceBase {
}
final boolean restricted = isRestricted();
- final RemovalClientImpl client = new RemovalClientImpl(getContext(), mDaemonWrapper,
- mHalDeviceId, token, new ServiceListenerImpl(receiver), fingerId, groupId,
- userId, restricted, token.toString()) {
+ final RemovalClient client = new RemovalClient(getContext(), getMetrics(),
+ mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
+ fingerId, groupId, userId, restricted, token.toString(), getBiometricUtils()) {
@Override
protected int statsModality() {
return FingerprintService.this.statsModality();
}
};
- client.setShouldNotifyUserActivity(true);
removeInternal(client);
}
@@ -259,9 +301,9 @@ public class FingerprintService extends BiometricServiceBase {
checkPermission(MANAGE_FINGERPRINT);
final boolean restricted = isRestricted();
- final EnumerateClientImpl client = new EnumerateClientImpl(getContext(), mDaemonWrapper,
- mHalDeviceId, token, new ServiceListenerImpl(receiver), userId, userId,
- restricted, getContext().getOpPackageName()) {
+ final EnumerateClient client = new EnumerateClient(getContext(), getMetrics(),
+ mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver), userId,
+ userId, restricted, getContext().getOpPackageName()) {
@Override
protected int statsModality() {
return FingerprintService.this.statsModality();
@@ -339,7 +381,7 @@ public class FingerprintService extends BiometricServiceBase {
return Collections.emptyList();
}
- return FingerprintService.this.getEnrolledFingerprints(userId);
+ return FingerprintService.this.getEnrolledTemplates(userId);
}
@Override // Binder call
@@ -445,7 +487,6 @@ public class FingerprintService extends BiometricServiceBase {
public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining)
throws RemoteException {
if (mFingerprintServiceReceiver != null) {
- // TODO: Pass up the fp directly instead
final Fingerprint fp = (Fingerprint) identifier;
mFingerprintServiceReceiver.onEnrollResult(fp.getDeviceId(), fp.getBiometricId(),
fp.getGroupId(), remaining);
@@ -493,7 +534,6 @@ public class FingerprintService extends BiometricServiceBase {
public void onRemoved(BiometricAuthenticator.Identifier identifier, int remaining)
throws RemoteException {
if (mFingerprintServiceReceiver != null) {
- // TODO: Pass up the fp directly instead
final Fingerprint fp = (Fingerprint) identifier;
mFingerprintServiceReceiver.onRemoved(fp.getDeviceId(), fp.getBiometricId(),
fp.getGroupId(), remaining);
@@ -511,105 +551,18 @@ public class FingerprintService extends BiometricServiceBase {
}
}
- /**
- * An internal class to help clean up unknown fingerprints in the hardware and software.
- */
- private final class InternalEnumerateClient extends BiometricServiceBase.EnumerateClientImpl {
-
- private List<Fingerprint> mEnrolledList;
- private List<Fingerprint> mUnknownFingerprints = new ArrayList<>(); // list of fp to delete
-
- public InternalEnumerateClient(Context context, DaemonWrapper daemon, long halDeviceId,
- IBinder token, ServiceListener listener, int groupId, int userId,
- boolean restricted, String owner, List<Fingerprint> enrolledList) {
- super(context, daemon, halDeviceId, token, listener, groupId, userId, restricted,
- owner);
- mEnrolledList = enrolledList;
- }
-
- private void handleEnumeratedFingerprint(
- BiometricAuthenticator.Identifier identifier, int remaining) {
- boolean matched = false;
- for (int i = 0; i < mEnrolledList.size(); i++) {
- if (mEnrolledList.get(i).getBiometricId() == identifier.getBiometricId()) {
- mEnrolledList.remove(i);
- matched = true;
- break;
- }
- }
-
- // fingerId 0 means no fingerprints are in hardware
- if (!matched && identifier.getBiometricId() != 0) {
- mUnknownFingerprints.add((Fingerprint) identifier);
- }
- }
-
- private void doFingerprintCleanup() {
- if (mEnrolledList == null) {
- return;
- }
-
- for (Fingerprint f : mEnrolledList) {
- Slog.e(TAG, "doFingerprintCleanup(): Removing dangling enrolled fingerprint: "
- + f.getName() + " " + f.getBiometricId() + " " + f.getGroupId()
- + " " + f.getDeviceId());
- FingerprintUtils.getInstance().removeBiometricForUser(getContext(),
- getTargetUserId(), f.getBiometricId());
- StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
- BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK);
- }
- mEnrolledList.clear();
- }
-
- public List<Fingerprint> getUnknownFingerprints() {
- return mUnknownFingerprints;
- }
-
- @Override
- public boolean onEnumerationResult(BiometricAuthenticator.Identifier identifier,
- int remaining) {
- handleEnumeratedFingerprint(identifier, remaining);
- if (remaining == 0) {
- doFingerprintCleanup();
- }
- return remaining == 0;
- }
-
- @Override
- protected int statsModality() {
- return FingerprintService.this.statsModality();
- }
- }
-
- /**
- * An internal class to help clean up unknown fingerprints in hardware and software.
- */
- private final class InternalRemovalClient extends BiometricServiceBase.RemovalClientImpl {
- public InternalRemovalClient(Context context,
- DaemonWrapper daemon, long halDeviceId, IBinder token,
- ServiceListener listener, int fingerId, int groupId, int userId, boolean restricted,
- String owner) {
- super(context, daemon, halDeviceId, token, listener, fingerId, groupId, userId,
- restricted,
- owner);
- }
-
- @Override
- protected int statsModality() {
- return FingerprintService.this.statsModality();
- }
- }
-
private final FingerprintMetrics mFingerprintMetrics = new FingerprintMetrics();
private final CopyOnWriteArrayList<IFingerprintClientActiveCallback> mClientActiveCallbacks =
new CopyOnWriteArrayList<>();
@GuardedBy("this")
private IBiometricsFingerprint mDaemon;
-
- private long mHalDeviceId;
- private IBinder mToken = new Binder(); // used for internal FingerprintService enumeration
- private ArrayList<UserFingerprint> mUnknownFingerprints = new ArrayList<>(); // hw fingerprints
+ private final SparseBooleanArray mTimedLockoutCleared;
+ private final SparseIntArray mFailedAttempts;
+ private final AlarmManager mAlarmManager;
+ private final LockoutReceiver mLockoutReceiver = new LockoutReceiver();
+ protected final ResetFailedAttemptsForUserRunnable mResetFailedAttemptsForCurrentUserRunnable =
+ new ResetFailedAttemptsForUserRunnable();
/**
* Receives callbacks from the HAL.
@@ -646,13 +599,7 @@ public class FingerprintService extends BiometricServiceBase {
@Override
public void onError(final long deviceId, final int error, final int vendorCode) {
mHandler.post(() -> {
- ClientMonitor client = getCurrentClient();
- if (client instanceof InternalRemovalClient
- || client instanceof InternalEnumerateClient) {
- clearEnumerateState();
- }
FingerprintService.super.handleError(deviceId, error, vendorCode);
-
// TODO: this chunk of code should be common to all biometric services
if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) {
// If we get HW_UNAVAILABLE, try to connect again later...
@@ -673,11 +620,6 @@ public class FingerprintService extends BiometricServiceBase {
ClientMonitor client = getCurrentClient();
final Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
FingerprintService.super.handleRemoved(fp, remaining);
- if (client instanceof InternalRemovalClient && !mUnknownFingerprints.isEmpty()) {
- cleanupUnknownFingerprints();
- } else if (client instanceof InternalRemovalClient){
- clearEnumerateState();
- }
});
}
@@ -685,9 +627,8 @@ public class FingerprintService extends BiometricServiceBase {
public void onEnumerate(final long deviceId, final int fingerId, final int groupId,
final int remaining) {
mHandler.post(() -> {
- // TODO: factor out common enumerate logic if possible
final Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
- FingerprintService.this.handleEnumerate(fp, remaining);
+ FingerprintService.super.handleEnumerate(fp, remaining);
});
}
@@ -748,10 +689,22 @@ public class FingerprintService extends BiometricServiceBase {
}
return daemon.enroll(cryptoToken, groupId, timeout);
}
+
+ @Override
+ public void resetLockout(byte[] token) throws RemoteException {
+ // TODO: confirm security token when we move timeout management into the HAL layer.
+ Slog.e(TAG, "Not supported");
+ return;
+ }
};
public FingerprintService(Context context) {
super(context);
+ mTimedLockoutCleared = new SparseBooleanArray();
+ mFailedAttempts = new SparseIntArray();
+ mAlarmManager = context.getSystemService(AlarmManager.class);
+ context.registerReceiver(mLockoutReceiver, new IntentFilter(getLockoutResetIntent()),
+ getLockoutBroadcastPermission(), null /* handler */);
}
@Override
@@ -767,18 +720,13 @@ public class FingerprintService extends BiometricServiceBase {
}
@Override
- protected BiometricUtils getBiometricUtils() {
- return FingerprintUtils.getInstance();
- }
-
- @Override
- protected int getFailedAttemptsLockoutTimed() {
- return MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED;
+ protected DaemonWrapper getDaemonWrapper() {
+ return mDaemonWrapper;
}
@Override
- protected int getFailedAttemptsLockoutPermanent() {
- return MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT;
+ protected BiometricUtils getBiometricUtils() {
+ return FingerprintUtils.getInstance();
}
@Override
@@ -790,7 +738,7 @@ public class FingerprintService extends BiometricServiceBase {
protected boolean hasReachedEnrollmentLimit(int userId) {
final int limit = getContext().getResources().getInteger(
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
- final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size();
+ final int enrolled = FingerprintService.this.getEnrolledTemplates(userId).size();
if (enrolled >= limit) {
Slog.w(TAG, "Too many fingerprints registered");
return true;
@@ -866,19 +814,6 @@ public class FingerprintService extends BiometricServiceBase {
}
@Override
- protected void handleUserSwitching(int userId) {
- if (getCurrentClient() instanceof InternalRemovalClient
- || getCurrentClient() instanceof InternalEnumerateClient) {
- Slog.w(TAG, "User switched while performing cleanup");
- removeClient(getCurrentClient());
- clearEnumerateState();
- }
- updateActiveGroup(userId, null);
- doFingerprintCleanupForUser(userId);
- }
-
-
- @Override
protected boolean hasEnrolledBiometrics(int userId) {
if (userId != UserHandle.getCallingUserId()) {
checkPermission(INTERACT_ACROSS_USERS);
@@ -913,6 +848,11 @@ public class FingerprintService extends BiometricServiceBase {
}
@Override
+ protected List<Fingerprint> getEnrolledTemplates(int userId) {
+ return getBiometricUtils().getBiometricsForUser(getContext(), userId);
+ }
+
+ @Override
protected void notifyClientActiveCallbacks(boolean isActive) {
List<IFingerprintClientActiveCallback> callbacks = mClientActiveCallbacks;
for (int i = 0; i < callbacks.size(); i++) {
@@ -930,6 +870,20 @@ public class FingerprintService extends BiometricServiceBase {
return BiometricsProtoEnums.MODALITY_FINGERPRINT;
}
+ @Override
+ protected int getLockoutMode() {
+ final int currentUser = ActivityManager.getCurrentUser();
+ final int failedAttempts = mFailedAttempts.get(currentUser, 0);
+ if (failedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) {
+ return AuthenticationClient.LOCKOUT_PERMANENT;
+ } else if (failedAttempts > 0
+ && !mTimedLockoutCleared.get(currentUser, false)
+ && (failedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) {
+ return AuthenticationClient.LOCKOUT_TIMED;
+ }
+ return AuthenticationClient.LOCKOUT_NONE;
+ }
+
/** Gets the fingerprint daemon */
private synchronized IBiometricsFingerprint getFingerprintDaemon() {
if (mDaemon == null) {
@@ -959,7 +913,7 @@ public class FingerprintService extends BiometricServiceBase {
if (mHalDeviceId != 0) {
loadAuthenticatorIds();
updateActiveGroup(ActivityManager.getCurrentUser(), null);
- doFingerprintCleanupForUser(ActivityManager.getCurrentUser());
+ doTemplateCleanupForUser(ActivityManager.getCurrentUser());
} else {
Slog.w(TAG, "Failed to open Fingerprint HAL!");
MetricsLogger.count(getContext(), "fingerprintd_openhal_error", 1);
@@ -969,79 +923,6 @@ public class FingerprintService extends BiometricServiceBase {
return mDaemon;
}
- /**
- * This method should be called upon connection to the daemon, and when user switches.
- * @param userId
- */
- private void doFingerprintCleanupForUser(int userId) {
- if (CLEANUP_UNUSED_FP) {
- enumerateUser(userId);
- }
- }
-
- private void clearEnumerateState() {
- if (DEBUG) Slog.v(TAG, "clearEnumerateState()");
- mUnknownFingerprints.clear();
- }
-
- private void enumerateUser(int userId) {
- if (DEBUG) Slog.v(TAG, "Enumerating user(" + userId + ")");
-
- final boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
- final List<Fingerprint> enrolledList = getEnrolledFingerprints(userId);
-
- InternalEnumerateClient client = new InternalEnumerateClient(getContext(), mDaemonWrapper,
- mHalDeviceId, mToken, new ServiceListenerImpl(null), userId, userId, restricted,
- getContext().getOpPackageName(), enrolledList);
- enumerateInternal(client);
- }
-
- // Remove unknown fingerprints from hardware
- private void cleanupUnknownFingerprints() {
- if (!mUnknownFingerprints.isEmpty()) {
- UserFingerprint uf = mUnknownFingerprints.get(0);
- mUnknownFingerprints.remove(uf);
- boolean restricted = !hasPermission(MANAGE_FINGERPRINT);
- InternalRemovalClient client = new InternalRemovalClient(getContext(), mDaemonWrapper,
- mHalDeviceId, mToken, new ServiceListenerImpl(null), uf.f.getBiometricId(),
- uf.f.getGroupId(), uf.userId, restricted, getContext().getOpPackageName());
- removeInternal(client);
- StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality(),
- BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL);
- } else {
- clearEnumerateState();
- }
- }
-
- private void handleEnumerate(Fingerprint fingerprint, int remaining) {
- ClientMonitor client = getCurrentClient();
-
- if ( !(client instanceof InternalRemovalClient) && !(client instanceof EnumerateClient) ) {
- return;
- }
- client.onEnumerationResult(fingerprint, remaining);
-
- // All fingerprints in hardware for this user were enumerated
- if (remaining == 0) {
- if (client instanceof InternalEnumerateClient) {
- List<Fingerprint> unknownFingerprints =
- ((InternalEnumerateClient) client).getUnknownFingerprints();
-
- if (!unknownFingerprints.isEmpty()) {
- Slog.w(TAG, "Adding " + unknownFingerprints.size() +
- " fingerprints for deletion");
- }
- for (Fingerprint f : unknownFingerprints) {
- mUnknownFingerprints.add(new UserFingerprint(f, client.getTargetUserId()));
- }
- removeClient(client);
- cleanupUnknownFingerprints();
- } else {
- removeClient(client);
- }
- }
- }
-
private long startPreEnroll(IBinder token) {
IBiometricsFingerprint daemon = getFingerprintDaemon();
if (daemon == null) {
@@ -1070,8 +951,38 @@ public class FingerprintService extends BiometricServiceBase {
return 0;
}
- private List<Fingerprint> getEnrolledFingerprints(int userId) {
- return getBiometricUtils().getBiometricsForUser(getContext(), userId);
+ // Attempt counter should only be cleared when Keyguard goes away or when
+ // a biometric is successfully authenticated. Lockout should eventually be done below the HAL.
+ // See AuthenticationClient#shouldFrameworkHandleLockout().
+ private void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
+ if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
+ Slog.v(getTag(), "Reset biometric lockout, clearAttemptCounter=" + clearAttemptCounter);
+ }
+ if (clearAttemptCounter) {
+ mFailedAttempts.put(userId, 0);
+ }
+ mTimedLockoutCleared.put(userId, true);
+ // If we're asked to reset failed attempts externally (i.e. from Keyguard),
+ // the alarm might still be pending; remove it.
+ cancelLockoutResetForUser(userId);
+ notifyLockoutResetMonitors();
+ }
+
+
+ private void cancelLockoutResetForUser(int userId) {
+ mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
+ }
+
+ private void scheduleLockoutResetForUser(int userId) {
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
+ getLockoutResetIntentForUser(userId));
+ }
+
+ private PendingIntent getLockoutResetIntentForUser(int userId) {
+ return PendingIntent.getBroadcast(getContext(), userId,
+ new Intent(getLockoutResetIntent()).putExtra(KEY_LOCKOUT_RESET_USER, userId),
+ PendingIntent.FLAG_UPDATE_CURRENT);
}
private void dumpInternal(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/biometrics/iris/IrisService.java b/services/core/java/com/android/server/biometrics/iris/IrisService.java
index eb457b6bedf1..cb8a772356cc 100644
--- a/services/core/java/com/android/server/biometrics/iris/IrisService.java
+++ b/services/core/java/com/android/server/biometrics/iris/IrisService.java
@@ -17,12 +17,16 @@
package com.android.server.biometrics.iris;
import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
+import com.android.server.biometrics.AuthenticationClient;
import com.android.server.biometrics.BiometricServiceBase;
import com.android.server.biometrics.BiometricUtils;
import com.android.server.biometrics.Metrics;
+import java.util.List;
+
/**
* A service to manage multiple clients that want to access the Iris HAL API.
* The service is responsible for maintaining a list of clients and dispatching all
@@ -61,18 +65,13 @@ public class IrisService extends BiometricServiceBase {
}
@Override
- protected BiometricUtils getBiometricUtils() {
+ protected DaemonWrapper getDaemonWrapper() {
return null;
}
@Override
- protected int getFailedAttemptsLockoutTimed() {
- return 0;
- }
-
- @Override
- protected int getFailedAttemptsLockoutPermanent() {
- return 0;
+ protected BiometricUtils getBiometricUtils() {
+ return null;
}
@Override
@@ -106,11 +105,6 @@ public class IrisService extends BiometricServiceBase {
}
@Override
- protected void handleUserSwitching(int userId) {
-
- }
-
- @Override
protected boolean hasEnrolledBiometrics(int userId) {
return false;
}
@@ -131,7 +125,17 @@ public class IrisService extends BiometricServiceBase {
}
@Override
+ protected List<? extends BiometricAuthenticator.Identifier> getEnrolledTemplates(int userId) {
+ return null;
+ }
+
+ @Override
protected int statsModality() {
return BiometricsProtoEnums.MODALITY_IRIS;
}
+
+ @Override
+ protected int getLockoutMode() {
+ return AuthenticationClient.LOCKOUT_NONE;
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 19bdc0969e6d..c91e1a12078e 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1859,7 +1859,7 @@ public class Tethering extends BaseNetworkObserver {
final TetherState tetherState = new TetherState(
new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
makeControlCallback(), mConfig.enableLegacyDhcpServer,
- mDeps.getIpServerDependencies(mContext)));
+ mDeps.getIpServerDependencies()));
mTetherStates.put(iface, tetherState);
tetherState.ipServer.start();
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e1af81b2f658..59fffb40fba7 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -241,7 +241,7 @@ public class Vpn {
mNetworkCapabilities = new NetworkCapabilities();
mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
- updateCapabilities();
+ updateCapabilities(null /* defaultNetwork */);
loadAlwaysOnPackage();
}
@@ -268,22 +268,44 @@ public class Vpn {
updateAlwaysOnNotification(detailedState);
}
- public void updateCapabilities() {
- final Network[] underlyingNetworks = (mConfig != null) ? mConfig.underlyingNetworks : null;
- // Only apps targeting Q and above can explicitly declare themselves as metered.
- final boolean isAlwaysMetered =
- mIsPackageTargetingAtLeastQ && (mConfig == null || mConfig.isMetered);
- updateCapabilities(mContext.getSystemService(ConnectivityManager.class), underlyingNetworks,
- mNetworkCapabilities, isAlwaysMetered);
+ /**
+ * Updates {@link #mNetworkCapabilities} based on current underlying networks and returns a
+ * defensive copy.
+ *
+ * <p>Does not propagate updated capabilities to apps.
+ *
+ * @param defaultNetwork underlying network for VPNs following platform's default
+ */
+ public synchronized NetworkCapabilities updateCapabilities(
+ @Nullable Network defaultNetwork) {
+ if (mConfig == null) {
+ // VPN is not running.
+ return null;
+ }
- if (mNetworkAgent != null) {
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ Network[] underlyingNetworks = mConfig.underlyingNetworks;
+ if (underlyingNetworks == null && defaultNetwork != null) {
+ // null underlying networks means to track the default.
+ underlyingNetworks = new Network[] { defaultNetwork };
}
+ // Only apps targeting Q and above can explicitly declare themselves as metered.
+ final boolean isAlwaysMetered = mIsPackageTargetingAtLeastQ && mConfig.isMetered;
+
+ applyUnderlyingCapabilities(
+ mContext.getSystemService(ConnectivityManager.class),
+ underlyingNetworks,
+ mNetworkCapabilities,
+ isAlwaysMetered);
+
+ return new NetworkCapabilities(mNetworkCapabilities);
}
@VisibleForTesting
- public static void updateCapabilities(ConnectivityManager cm, Network[] underlyingNetworks,
- NetworkCapabilities caps, boolean isAlwaysMetered) {
+ public static void applyUnderlyingCapabilities(
+ ConnectivityManager cm,
+ Network[] underlyingNetworks,
+ NetworkCapabilities caps,
+ boolean isAlwaysMetered) {
int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
@@ -296,6 +318,7 @@ public class Vpn {
boolean hadUnderlyingNetworks = false;
if (null != underlyingNetworks) {
for (Network underlying : underlyingNetworks) {
+ // TODO(b/124469351): Get capabilities directly from ConnectivityService instead.
final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying);
if (underlyingCaps == null) continue;
hadUnderlyingNetworks = true;
@@ -895,6 +918,7 @@ public class Vpn {
TreeSet<IpPrefix> ipv4Prefixes = new TreeSet<>(prefixLengthComparator);
TreeSet<IpPrefix> ipv6Prefixes = new TreeSet<>(prefixLengthComparator);
for (final RouteInfo route : routes) {
+ if (route.getType() == RouteInfo.RTN_UNREACHABLE) continue;
IpPrefix destination = route.getDestination();
if (destination.isIPv4()) {
ipv4Prefixes.add(destination);
@@ -1007,9 +1031,8 @@ public class Vpn {
}
/**
- * Establish a VPN network and return the file descriptor of the VPN
- * interface. This methods returns {@code null} if the application is
- * revoked or not prepared.
+ * Establish a VPN network and return the file descriptor of the VPN interface. This methods
+ * returns {@code null} if the application is revoked or not prepared.
*
* @param config The parameters to configure the network.
* @return The file descriptor of the VPN interface.
@@ -1101,8 +1124,6 @@ public class Vpn {
// as rules are deleted. This prevents data leakage as the rules are moved over.
agentDisconnect(oldNetworkAgent);
}
- // Set up VPN's capabilities such as meteredness.
- updateCapabilities();
if (oldConnection != null) {
mContext.unbindService(oldConnection);
@@ -1258,6 +1279,11 @@ public class Vpn {
return ranges;
}
+ /**
+ * Updates UID ranges for this VPN and also updates its internal capabilities.
+ *
+ * <p>Should be called on primary ConnectivityService thread.
+ */
public void onUserAdded(int userHandle) {
// If the user is restricted tie them to the parent user's VPN
UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
@@ -1268,8 +1294,9 @@ public class Vpn {
try {
addUserToRanges(existingRanges, userHandle, mConfig.allowedApplications,
mConfig.disallowedApplications);
+ // ConnectivityService will call {@link #updateCapabilities} and apply
+ // those for VPN network.
mNetworkCapabilities.setUids(existingRanges);
- updateCapabilities();
} catch (Exception e) {
Log.wtf(TAG, "Failed to add restricted user to owner", e);
}
@@ -1279,6 +1306,11 @@ public class Vpn {
}
}
+ /**
+ * Updates UID ranges for this VPN and also updates its capabilities.
+ *
+ * <p>Should be called on primary ConnectivityService thread.
+ */
public void onUserRemoved(int userHandle) {
// clean up if restricted
UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
@@ -1290,8 +1322,9 @@ public class Vpn {
final List<UidRange> removedRanges =
uidRangesForUser(userHandle, existingRanges);
existingRanges.removeAll(removedRanges);
+ // ConnectivityService will call {@link #updateCapabilities} and
+ // apply those for VPN network.
mNetworkCapabilities.setUids(existingRanges);
- updateCapabilities();
} catch (Exception e) {
Log.wtf(TAG, "Failed to remove restricted user to owner", e);
}
@@ -1504,6 +1537,12 @@ public class Vpn {
return success;
}
+ /**
+ * Updates underlying network set.
+ *
+ * <p>Note: Does not updates capabilities. Call {@link #updateCapabilities} from
+ * ConnectivityService thread to get updated capabilities.
+ */
public synchronized boolean setUnderlyingNetworks(Network[] networks) {
if (!isCallerEstablishedOwnerLocked()) {
return false;
@@ -1520,7 +1559,6 @@ public class Vpn {
}
}
}
- updateCapabilities();
return true;
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index 3fddac111ec5..173d7860e4ac 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -61,8 +61,8 @@ public class TetheringDependencies {
/**
* Get dependencies to be used by IpServer.
*/
- public IpServer.Dependencies getIpServerDependencies(Context context) {
- return new IpServer.Dependencies(context);
+ public IpServer.Dependencies getIpServerDependencies() {
+ return new IpServer.Dependencies();
}
/**
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 45f169ca0b6f..7dd3b363810d 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -129,240 +129,9 @@ public final class ColorDisplayService extends SystemService {
private final NightDisplayTintController mNightDisplayTintController =
new NightDisplayTintController();
- private final TintController mDisplayWhiteBalanceTintController = new TintController() {
- // Three chromaticity coordinates per color: X, Y, and Z
- private final int NUM_VALUES_PER_PRIMARY = 3;
- // Four colors: red, green, blue, and white
- private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
-
- private final Object mLock = new Object();
- private int mTemperatureMin;
- private int mTemperatureMax;
- private int mTemperatureDefault;
- private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
- private ColorSpace.Rgb mDisplayColorSpaceRGB;
- private float[] mChromaticAdaptationMatrix;
- private int mCurrentColorTemperature;
- private float[] mCurrentColorTemperatureXYZ;
- private boolean mSetUp = false;
- private float[] mMatrixDisplayWhiteBalance = new float[16];
- private Boolean mIsAvailable;
-
- @Override
- public void setUp(Context context, boolean needsLinear) {
- mSetUp = false;
- final Resources res = context.getResources();
-
- ColorSpace.Rgb displayColorSpaceRGB = getDisplayColorSpaceFromSurfaceControl();
- if (displayColorSpaceRGB == null) {
- Slog.w(TAG, "Failed to get display color space from SurfaceControl, trying res");
- displayColorSpaceRGB = getDisplayColorSpaceFromResources(res);
- if (displayColorSpaceRGB == null) {
- Slog.e(TAG, "Failed to get display color space from resources");
- return;
- }
- }
-
- final String[] nominalWhiteValues = res.getStringArray(
- R.array.config_displayWhiteBalanceDisplayNominalWhite);
- float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
- for (int i = 0; i < nominalWhiteValues.length; i++) {
- displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
- }
-
- final int colorTemperatureMin = res.getInteger(
- R.integer.config_displayWhiteBalanceColorTemperatureMin);
- if (colorTemperatureMin <= 0) {
- Slog.e(TAG, "Display white balance minimum temperature must be greater than 0");
- return;
- }
-
- final int colorTemperatureMax = res.getInteger(
- R.integer.config_displayWhiteBalanceColorTemperatureMax);
- if (colorTemperatureMax < colorTemperatureMin) {
- Slog.e(TAG, "Display white balance max temp must be greater or equal to min");
- return;
- }
-
- final int colorTemperature = res.getInteger(
- R.integer.config_displayWhiteBalanceColorTemperatureDefault);
-
- synchronized (mLock) {
- mDisplayColorSpaceRGB = displayColorSpaceRGB;
- mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
- mTemperatureMin = colorTemperatureMin;
- mTemperatureMax = colorTemperatureMax;
- mTemperatureDefault = colorTemperature;
- mSetUp = true;
- }
-
- setMatrix(mTemperatureDefault);
- }
-
- @Override
- public float[] getMatrix() {
- return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
- }
-
- @Override
- public void setMatrix(int cct) {
- if (!mSetUp) {
- Slog.w(TAG, "Can't set display white balance temperature: uninitialized");
- return;
- }
-
- if (cct < mTemperatureMin) {
- Slog.w(TAG, "Requested display color temperature is below allowed minimum");
- cct = mTemperatureMin;
- } else if (cct > mTemperatureMax) {
- Slog.w(TAG, "Requested display color temperature is above allowed maximum");
- cct = mTemperatureMax;
- }
-
- Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct);
-
- synchronized (mLock) {
- mCurrentColorTemperature = cct;
-
- // Adapt the display's nominal white point to match the requested CCT value
- mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
-
- mChromaticAdaptationMatrix =
- ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
- mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
-
- // Convert the adaptation matrix to RGB space
- float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix,
- mDisplayColorSpaceRGB.getTransform());
- result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
-
- // Normalize the transform matrix to peak white value in RGB space
- final float adaptedMaxR = result[0] + result[3] + result[6];
- final float adaptedMaxG = result[1] + result[4] + result[7];
- final float adaptedMaxB = result[2] + result[5] + result[8];
- final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
- for (int i = 0; i < result.length; i++) {
- result[i] /= denum;
- }
-
- Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
- java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
- java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
- java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
- }
- }
-
- @Override
- public int getLevel() {
- return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
- }
-
- @Override
- public boolean isAvailable(Context context) {
- if (mIsAvailable == null) {
- mIsAvailable = ColorDisplayManager.isDisplayWhiteBalanceAvailable(context);
- }
- return mIsAvailable;
- }
-
- /**
- * Format a given matrix into a string.
- *
- * @param matrix the matrix to format
- * @param cols number of columns in the matrix
- */
- private String matrixToString(float[] matrix, int cols) {
- if (matrix == null || cols <= 0) {
- Slog.e(TAG, "Invalid arguments when formatting matrix to string");
- return "";
- }
-
- StringBuilder sb = new StringBuilder("");
- for (int i = 0; i < matrix.length; i++) {
- if (i % cols == 0) {
- sb.append("\n ");
- }
- sb.append(String.format("%9.6f ", matrix[i]));
- }
- return sb.toString();
- }
-
- @Override
- public void dump(PrintWriter pw) {
- synchronized (mLock) {
- pw.println(" mSetUp = " + mSetUp);
- if (!mSetUp) {
- return;
- }
-
- pw.println(" isActivated = " + isActivated());
- pw.println(" mTemperatureMin = " + mTemperatureMin);
- pw.println(" mTemperatureMax = " + mTemperatureMax);
- pw.println(" mTemperatureDefault = " + mTemperatureDefault);
- pw.println(" mCurrentColorTemperature = " + mCurrentColorTemperature);
- pw.println(" mCurrentColorTemperatureXYZ = " +
- matrixToString(mCurrentColorTemperatureXYZ, 3));
- pw.println(" mDisplayColorSpaceRGB RGB-to-XYZ = " +
- matrixToString(mDisplayColorSpaceRGB.getTransform(), 3));
- pw.println(" mChromaticAdaptationMatrix = " +
- matrixToString(mChromaticAdaptationMatrix, 3));
- pw.println(" mDisplayColorSpaceRGB XYZ-to-RGB = " +
- matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3));
- pw.println(" mMatrixDisplayWhiteBalance = " +
- matrixToString(mMatrixDisplayWhiteBalance, 4));
- }
- }
-
- private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) {
- return new ColorSpace.Rgb(
- "Display Color Space",
- redGreenBlueXYZ,
- whiteXYZ,
- 2.2f // gamma, unused for display white balance
- );
- }
-
- private ColorSpace.Rgb getDisplayColorSpaceFromSurfaceControl() {
- final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
- if (displayToken == null) {
- return null;
- }
-
- DisplayPrimaries primaries = SurfaceControl.getDisplayNativePrimaries(displayToken);
- if (primaries == null || primaries.red == null || primaries.green == null ||
- primaries.blue == null || primaries.white == null) {
- return null;
- }
-
- return makeRgbColorSpaceFromXYZ(
- new float[] {
- primaries.red.X, primaries.red.Y, primaries.red.Z,
- primaries.green.X, primaries.green.Y, primaries.green.Z,
- primaries.blue.X, primaries.blue.Y, primaries.blue.Z,
- },
- new float[] { primaries.white.X, primaries.white.Y, primaries.white.Z }
- );
- }
-
- private ColorSpace.Rgb getDisplayColorSpaceFromResources(Resources res) {
- final String[] displayPrimariesValues = res.getStringArray(
- R.array.config_displayWhiteBalanceDisplayPrimaries);
- float[] displayRedGreenBlueXYZ =
- new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
- float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
-
- for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) {
- displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]);
- }
-
- for (int i = 0; i < displayWhiteXYZ.length; i++) {
- displayWhiteXYZ[i] = Float.parseFloat(
- displayPrimariesValues[displayRedGreenBlueXYZ.length + i]);
- }
-
- return makeRgbColorSpaceFromXYZ(displayRedGreenBlueXYZ, displayWhiteXYZ);
- }
- };
+ @VisibleForTesting
+ final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController =
+ new DisplayWhiteBalanceTintController();
private final TintController mGlobalSaturationTintController = new TintController() {
@@ -860,7 +629,8 @@ public final class ColorDisplayService extends SystemService {
return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
}
- private void updateDisplayWhiteBalanceStatus() {
+ @VisibleForTesting
+ void updateDisplayWhiteBalanceStatus() {
boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated();
mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled() &&
!mNightDisplayTintController.isActivated() &&
@@ -1101,6 +871,7 @@ public final class ColorDisplayService extends SystemService {
pw.println("Display white balance:");
if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
pw.println(" Activated: " + mDisplayWhiteBalanceTintController.isActivated());
+ mDisplayWhiteBalanceTintController.dump(pw);
} else {
pw.println(" Not available");
}
@@ -1533,6 +1304,244 @@ public final class ColorDisplayService extends SystemService {
}
}
+ final class DisplayWhiteBalanceTintController extends TintController {
+ // Three chromaticity coordinates per color: X, Y, and Z
+ private final int NUM_VALUES_PER_PRIMARY = 3;
+ // Four colors: red, green, blue, and white
+ private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
+
+ private final Object mLock = new Object();
+ @VisibleForTesting
+ int mTemperatureMin;
+ @VisibleForTesting
+ int mTemperatureMax;
+ private int mTemperatureDefault;
+ private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+ @VisibleForTesting
+ ColorSpace.Rgb mDisplayColorSpaceRGB;
+ private float[] mChromaticAdaptationMatrix;
+ @VisibleForTesting
+ int mCurrentColorTemperature;
+ private float[] mCurrentColorTemperatureXYZ;
+ private boolean mSetUp = false;
+ private float[] mMatrixDisplayWhiteBalance = new float[16];
+ private Boolean mIsAvailable;
+
+ @Override
+ public void setUp(Context context, boolean needsLinear) {
+ mSetUp = false;
+ final Resources res = context.getResources();
+
+ ColorSpace.Rgb displayColorSpaceRGB = getDisplayColorSpaceFromSurfaceControl();
+ if (displayColorSpaceRGB == null) {
+ Slog.w(TAG, "Failed to get display color space from SurfaceControl, trying res");
+ displayColorSpaceRGB = getDisplayColorSpaceFromResources(res);
+ if (displayColorSpaceRGB == null) {
+ Slog.e(TAG, "Failed to get display color space from resources");
+ return;
+ }
+ }
+
+ final String[] nominalWhiteValues = res.getStringArray(
+ R.array.config_displayWhiteBalanceDisplayNominalWhite);
+ float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+ for (int i = 0; i < nominalWhiteValues.length; i++) {
+ displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
+ }
+
+ final int colorTemperatureMin = res.getInteger(
+ R.integer.config_displayWhiteBalanceColorTemperatureMin);
+ if (colorTemperatureMin <= 0) {
+ Slog.e(TAG, "Display white balance minimum temperature must be greater than 0");
+ return;
+ }
+
+ final int colorTemperatureMax = res.getInteger(
+ R.integer.config_displayWhiteBalanceColorTemperatureMax);
+ if (colorTemperatureMax < colorTemperatureMin) {
+ Slog.e(TAG, "Display white balance max temp must be greater or equal to min");
+ return;
+ }
+
+ final int colorTemperature = res.getInteger(
+ R.integer.config_displayWhiteBalanceColorTemperatureDefault);
+
+ synchronized (mLock) {
+ mDisplayColorSpaceRGB = displayColorSpaceRGB;
+ mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
+ mTemperatureMin = colorTemperatureMin;
+ mTemperatureMax = colorTemperatureMax;
+ mTemperatureDefault = colorTemperature;
+ mSetUp = true;
+ }
+
+ setMatrix(mTemperatureDefault);
+ }
+
+ @Override
+ public float[] getMatrix() {
+ return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
+ }
+
+ @Override
+ public void setMatrix(int cct) {
+ if (!mSetUp) {
+ Slog.w(TAG, "Can't set display white balance temperature: uninitialized");
+ return;
+ }
+
+ if (cct < mTemperatureMin) {
+ Slog.w(TAG, "Requested display color temperature is below allowed minimum");
+ cct = mTemperatureMin;
+ } else if (cct > mTemperatureMax) {
+ Slog.w(TAG, "Requested display color temperature is above allowed maximum");
+ cct = mTemperatureMax;
+ }
+
+ Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct);
+
+ synchronized (mLock) {
+ mCurrentColorTemperature = cct;
+
+ // Adapt the display's nominal white point to match the requested CCT value
+ mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
+
+ mChromaticAdaptationMatrix =
+ ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
+ mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
+
+ // Convert the adaptation matrix to RGB space
+ float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix,
+ mDisplayColorSpaceRGB.getTransform());
+ result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
+
+ // Normalize the transform matrix to peak white value in RGB space
+ final float adaptedMaxR = result[0] + result[3] + result[6];
+ final float adaptedMaxG = result[1] + result[4] + result[7];
+ final float adaptedMaxB = result[2] + result[5] + result[8];
+ final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
+ for (int i = 0; i < result.length; i++) {
+ result[i] /= denum;
+ }
+
+ Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
+ java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
+ java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
+ java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
+ }
+ }
+
+ @Override
+ public int getLevel() {
+ return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
+ }
+
+ @Override
+ public boolean isAvailable(Context context) {
+ if (mIsAvailable == null) {
+ mIsAvailable = ColorDisplayManager.isDisplayWhiteBalanceAvailable(context);
+ }
+ return mIsAvailable;
+ }
+
+ /**
+ * Format a given matrix into a string.
+ *
+ * @param matrix the matrix to format
+ * @param cols number of columns in the matrix
+ */
+ private String matrixToString(float[] matrix, int cols) {
+ if (matrix == null || cols <= 0) {
+ Slog.e(TAG, "Invalid arguments when formatting matrix to string");
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder("");
+ for (int i = 0; i < matrix.length; i++) {
+ if (i % cols == 0) {
+ sb.append("\n ");
+ }
+ sb.append(String.format("%9.6f ", matrix[i]));
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public void dump(PrintWriter pw) {
+ synchronized (mLock) {
+ pw.println(" mSetUp = " + mSetUp);
+ if (!mSetUp) {
+ return;
+ }
+
+ pw.println(" mTemperatureMin = " + mTemperatureMin);
+ pw.println(" mTemperatureMax = " + mTemperatureMax);
+ pw.println(" mTemperatureDefault = " + mTemperatureDefault);
+ pw.println(" mCurrentColorTemperature = " + mCurrentColorTemperature);
+ pw.println(" mCurrentColorTemperatureXYZ = " +
+ matrixToString(mCurrentColorTemperatureXYZ, 3));
+ pw.println(" mDisplayColorSpaceRGB RGB-to-XYZ = " +
+ matrixToString(mDisplayColorSpaceRGB.getTransform(), 3));
+ pw.println(" mChromaticAdaptationMatrix = " +
+ matrixToString(mChromaticAdaptationMatrix, 3));
+ pw.println(" mDisplayColorSpaceRGB XYZ-to-RGB = " +
+ matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3));
+ pw.println(" mMatrixDisplayWhiteBalance = " +
+ matrixToString(mMatrixDisplayWhiteBalance, 4));
+ }
+ }
+
+ private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) {
+ return new ColorSpace.Rgb(
+ "Display Color Space",
+ redGreenBlueXYZ,
+ whiteXYZ,
+ 2.2f // gamma, unused for display white balance
+ );
+ }
+
+ private ColorSpace.Rgb getDisplayColorSpaceFromSurfaceControl() {
+ final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
+ if (displayToken == null) {
+ return null;
+ }
+
+ DisplayPrimaries primaries = SurfaceControl.getDisplayNativePrimaries(displayToken);
+ if (primaries == null || primaries.red == null || primaries.green == null ||
+ primaries.blue == null || primaries.white == null) {
+ return null;
+ }
+
+ return makeRgbColorSpaceFromXYZ(
+ new float[] {
+ primaries.red.X, primaries.red.Y, primaries.red.Z,
+ primaries.green.X, primaries.green.Y, primaries.green.Z,
+ primaries.blue.X, primaries.blue.Y, primaries.blue.Z,
+ },
+ new float[] { primaries.white.X, primaries.white.Y, primaries.white.Z }
+ );
+ }
+
+ private ColorSpace.Rgb getDisplayColorSpaceFromResources(Resources res) {
+ final String[] displayPrimariesValues = res.getStringArray(
+ R.array.config_displayWhiteBalanceDisplayPrimaries);
+ float[] displayRedGreenBlueXYZ =
+ new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
+ float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+
+ for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) {
+ displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]);
+ }
+
+ for (int i = 0; i < displayWhiteXYZ.length; i++) {
+ displayWhiteXYZ[i] = Float.parseFloat(
+ displayPrimariesValues[displayRedGreenBlueXYZ.length + i]);
+ }
+
+ return makeRgbColorSpaceFromXYZ(displayRedGreenBlueXYZ, displayWhiteXYZ);
+ }
+ };
+
/**
* Local service that allows color transforms to be enabled from other system services.
*/
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 6ee5665b9e42..e9ae516cc8d0 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -19,6 +19,7 @@ package com.android.server.display;
import android.graphics.Rect;
import android.hardware.display.DisplayViewport;
import android.os.IBinder;
+import android.view.DisplayAddress;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -225,8 +226,12 @@ abstract class DisplayDevice {
viewport.deviceHeight = isRotated ? info.width : info.height;
viewport.uniqueId = info.uniqueId;
- // TODO(b/112898898) Use an actual port here.
- viewport.physicalPort = null;
+
+ if (info.address instanceof DisplayAddress.Physical) {
+ viewport.physicalPort = ((DisplayAddress.Physical) info.address).getPort();
+ } else {
+ viewport.physicalPort = null;
+ }
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index ab64f61a3b22..729ea1772066 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -19,6 +19,7 @@ package com.android.server.display;
import android.hardware.display.DisplayViewport;
import android.util.DisplayMetrics;
import android.view.Display;
+import android.view.DisplayAddress;
import android.view.DisplayCutout;
import android.view.Surface;
@@ -274,7 +275,7 @@ final class DisplayDeviceInfo {
* Display address, or null if none.
* Interpretation varies by display type.
*/
- public String address;
+ public DisplayAddress address;
/**
* Display state.
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index dc5be6a6a074..15c7ef75866f 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1019,7 +1019,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if (mDisplayWhiteBalanceController != null) {
if (state == Display.STATE_ON && mDisplayWhiteBalanceSettings.isEnabled()) {
mDisplayWhiteBalanceController.setEnabled(true);
- mDisplayWhiteBalanceController.updateScreenColorTemperature();
+ mDisplayWhiteBalanceController.updateDisplayColorTemperature();
} else {
mDisplayWhiteBalanceController.setEnabled(false);
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 28f21f633ac4..489194726c5a 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -31,6 +31,7 @@ import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
+import android.view.DisplayAddress;
import android.view.DisplayCutout;
import android.view.DisplayEventReceiver;
import android.view.Surface;
@@ -382,6 +383,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.presentationDeadlineNanos = phys.presentationDeadlineNanos;
mInfo.state = mState;
mInfo.uniqueId = getUniqueId();
+ mInfo.address = DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
// Assume that all built-in displays that have secure output (eg. HDCP) also
// support compositing from gralloc protected buffers.
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index e65637f04975..2f507d17730e 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -308,7 +308,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
}
mInfo.type = Display.TYPE_OVERLAY;
- mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
+ mInfo.touch = DisplayDeviceInfo.TOUCH_VIRTUAL;
mInfo.state = mState;
}
return mInfo;
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index e8d6ad455fbf..9e4c1cb57dca 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -16,9 +16,6 @@
package com.android.server.display;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.IndentingPrintWriter;
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -35,9 +32,13 @@ import android.os.Message;
import android.os.UserHandle;
import android.util.Slog;
import android.view.Display;
+import android.view.DisplayAddress;
import android.view.Surface;
import android.view.SurfaceControl;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -581,7 +582,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
private final int mHeight;
private final float mRefreshRate;
private final int mFlags;
- private final String mAddress;
+ private final DisplayAddress mAddress;
private final Display.Mode mMode;
private Surface mSurface;
@@ -596,7 +597,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mHeight = height;
mRefreshRate = refreshRate;
mFlags = flags;
- mAddress = address;
+ mAddress = DisplayAddress.fromMacAddress(address);
mSurface = surface;
mMode = createMode(width, height, refreshRate);
}
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
index b9aa34e89216..d95e92b71357 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
@@ -29,14 +29,14 @@ import java.io.PrintWriter;
/**
* The DisplayWhiteBalanceController drives display white-balance (automatically correcting the
- * screen color temperature depending on the ambient color temperature).
+ * display color temperature depending on the ambient color temperature).
*
* The DisplayWhiteBalanceController:
* - Uses the AmbientColorTemperatureSensor to detect changes in the ambient color temperature;
* - Uses the AmbientColorTemperatureFilter to average these changes over time, filter out the
* noise, and arrive at an estimate of the actual ambient color temperature;
- * - Uses the DisplayWhiteBalanceThrottler to decide whether the screen color tempearture should be
- * updated, suppressing changes that are too frequent or too minor.
+ * - Uses the DisplayWhiteBalanceThrottler to decide whether the display color tempearture should
+ * be updated, suppressing changes that are too frequent or too minor.
*/
public class DisplayWhiteBalanceController implements
AmbientSensor.AmbientBrightnessSensor.Callbacks,
@@ -76,8 +76,8 @@ public class DisplayWhiteBalanceController implements
// Override the ambient color temperature for debugging purposes.
private float mAmbientColorTemperatureOverride;
- // A piecewise linear relationship between ambient and display color temperatures
- private Spline.LinearSpline mAmbientToDisplayTemperatureSpline;
+ // A piecewise linear relationship between ambient and display color temperatures.
+ private Spline.LinearSpline mAmbientToDisplayColorTemperatureSpline;
/**
* @param brightnessSensor
@@ -91,7 +91,7 @@ public class DisplayWhiteBalanceController implements
* The filter used to average ambient color temperature changes over time, filter out the
* noise and arrive at an estimate of the actual ambient color temperature.
* @param throttler
- * The throttler used to determine whether the new screen color temperature should be
+ * The throttler used to determine whether the new display color temperature should be
* updated or not.
* @param lowLightAmbientBrightnessThreshold
* The ambient brightness threshold beneath which we fall back to a fixed ambient color
@@ -99,6 +99,12 @@ public class DisplayWhiteBalanceController implements
* @param lowLightAmbientColorTemperature
* The ambient color temperature to which we fall back when the ambient brightness drops
* beneath a certain threshold.
+ * @param ambientColorTemperatures
+ * The ambient color tempeartures used to map the ambient color temperature to the display
+ * color temperature (or null if no mapping is necessary).
+ * @param displayColorTemperatures
+ * The display color temperatures used to map the ambient color temperature to the display
+ * color temperature (or null if no mapping is necessary).
*
* @throws NullPointerException
* - brightnessSensor is null;
@@ -114,7 +120,7 @@ public class DisplayWhiteBalanceController implements
@NonNull AmbientFilter colorTemperatureFilter,
@NonNull DisplayWhiteBalanceThrottler throttler,
float lowLightAmbientBrightnessThreshold, float lowLightAmbientColorTemperature,
- float[] ambientTemperatures, float[] displayTemperatures) {
+ float[] ambientColorTemperatures, float[] displayColorTemperatures) {
validateArguments(brightnessSensor, brightnessFilter, colorTemperatureSensor,
colorTemperatureFilter, throttler);
mLoggingEnabled = false;
@@ -134,10 +140,10 @@ public class DisplayWhiteBalanceController implements
mAmbientColorTemperatureOverride = -1.0f;
try {
- mAmbientToDisplayTemperatureSpline = new Spline.LinearSpline(ambientTemperatures,
- displayTemperatures);
+ mAmbientToDisplayColorTemperatureSpline = new Spline.LinearSpline(
+ ambientColorTemperatures, displayColorTemperatures);
} catch (Exception e) {
- mAmbientToDisplayTemperatureSpline = null;
+ mAmbientToDisplayColorTemperatureSpline = null;
}
mColorDisplayServiceInternal = LocalServices.getService(ColorDisplayServiceInternal.class);
@@ -160,7 +166,7 @@ public class DisplayWhiteBalanceController implements
}
/**
- * Set an object to call back to when the screen color temperature should be updated.
+ * Set an object to call back to when the display color temperature should be updated.
*
* @param callbacks
* The object to call back to.
@@ -201,7 +207,7 @@ public class DisplayWhiteBalanceController implements
*
* This is only applied when the ambient color temperature changes or is updated (in which case
* it overrides the ambient color temperature estimate); in other words, it doesn't necessarily
- * change the screen color temperature immediately.
+ * change the display color temperature immediately.
*
* @param ambientColorTemperatureOverride
* The ambient color temperature override.
@@ -240,9 +246,8 @@ public class DisplayWhiteBalanceController implements
writer.println(" mLastAmbientColorTemperature=" + mLastAmbientColorTemperature);
writer.println(" mAmbientColorTemperatureHistory=" + mAmbientColorTemperatureHistory);
writer.println(" mAmbientColorTemperatureOverride=" + mAmbientColorTemperatureOverride);
- writer.println(" mAmbientToDisplayTemperatureSpline="
- + (mAmbientToDisplayTemperatureSpline == null ? "unused" :
- mAmbientToDisplayTemperatureSpline));
+ writer.println(" mAmbientToDisplayColorTemperatureSpline="
+ + mAmbientToDisplayColorTemperatureSpline);
}
@Override // AmbientSensor.AmbientBrightnessSensor.Callbacks
@@ -266,9 +271,9 @@ public class DisplayWhiteBalanceController implements
final long time = System.currentTimeMillis();
float ambientColorTemperature = mColorTemperatureFilter.getEstimate(time);
- if (mAmbientToDisplayTemperatureSpline != null) {
+ if (mAmbientToDisplayColorTemperatureSpline != null) {
ambientColorTemperature =
- mAmbientToDisplayTemperatureSpline.interpolate(ambientColorTemperature);
+ mAmbientToDisplayColorTemperatureSpline.interpolate(ambientColorTemperature);
}
final float ambientBrightness = mBrightnessFilter.getEstimate(time);
@@ -290,7 +295,7 @@ public class DisplayWhiteBalanceController implements
ambientColorTemperature = mAmbientColorTemperatureOverride;
}
- // When the screen color temperature needs to be updated, we call DisplayPowerController to
+ // When the display color temperature needs to be updated, we call DisplayPowerController to
// call our updateColorTemperature. The reason we don't call it directly is that we want
// all changes to the system to happen in a predictable order in DPC's main loop
// (updatePowerState).
@@ -308,9 +313,9 @@ public class DisplayWhiteBalanceController implements
}
/**
- * Updates the screen color temperature.
+ * Updates the display color temperature.
*/
- public void updateScreenColorTemperature() {
+ public void updateDisplayColorTemperature() {
float ambientColorTemperature = -1.0f;
// If both the pending and the current ambient color temperatures are -1, it means the DWBC
@@ -353,7 +358,7 @@ public class DisplayWhiteBalanceController implements
* Called whenever the display white-balance state has changed.
*
* Usually, this means the estimated ambient color temperature has changed enough, and the
- * screen color temperature should be updated; but it is also called by
+ * display color temperature should be updated; but it is also called if settings change.
*/
void updateWhiteBalance();
}
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
index 56f4ca339eb3..449f115ad3e3 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
@@ -67,14 +67,14 @@ public class DisplayWhiteBalanceFactory {
final float lowLightAmbientColorTemperature = getFloat(resources,
com.android.internal.R.dimen
.config_displayWhiteBalanceLowLightAmbientColorTemperature);
- final float[] ambientTemperatures = getFloatArray(resources,
- com.android.internal.R.array.config_displayWhiteBalanceAmbientTemperatureValues);
- final float[] displayTemperatures = getFloatArray(resources,
- com.android.internal.R.array.config_displayWhiteBalanceDisplayTemperatureValues);
+ final float[] ambientColorTemperatures = getFloatArray(resources,
+ com.android.internal.R.array.config_displayWhiteBalanceAmbientColorTemperatures);
+ final float[] displayColorTempeartures = getFloatArray(resources,
+ com.android.internal.R.array.config_displayWhiteBalanceDisplayColorTemperatures);
final DisplayWhiteBalanceController controller = new DisplayWhiteBalanceController(
brightnessSensor, brightnessFilter, colorTemperatureSensor, colorTemperatureFilter,
throttler, lowLightAmbientBrightnessThreshold, lowLightAmbientColorTemperature,
- ambientTemperatures, displayTemperatures);
+ ambientColorTemperatures, displayColorTempeartures);
brightnessSensor.setCallbacks(controller);
colorTemperatureSensor.setCallbacks(controller);
return controller;
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceThrottler.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceThrottler.java
index c1f0e983a366..5941bbb62d94 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceThrottler.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceThrottler.java
@@ -23,7 +23,7 @@ import java.util.Arrays;
/**
* The DisplayWhiteBalanceController uses the DisplayWhiteBalanceThrottler to decide whether the
- * screen color temperature should be updated, suppressing changes that are too frequent or too
+ * display color temperature should be updated, suppressing changes that are too frequent or too
* minor.
*/
class DisplayWhiteBalanceThrottler {
diff --git a/services/core/java/com/android/server/gpu/GpuService.java b/services/core/java/com/android/server/gpu/GpuService.java
index a68ceed750ad..6899c3ffcbb1 100644
--- a/services/core/java/com/android/server/gpu/GpuService.java
+++ b/services/core/java/com/android/server/gpu/GpuService.java
@@ -22,24 +22,33 @@ import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.gamedriver.GameDriverProto.Blacklist;
+import android.gamedriver.GameDriverProto.Blacklists;
import android.net.Uri;
import android.os.Build;
+import android.os.Handler;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.Base64;
import android.util.Slog;
+import com.android.framework.protobuf.InvalidProtocolBufferException;
+import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
+import java.util.List;
/**
* Service to manage GPU related features.
@@ -52,17 +61,25 @@ public class GpuService extends SystemService {
public static final boolean DEBUG = false;
private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
- private static final String WHITELIST_FILENAME = "whitelist.txt";
+ private static final String GAME_DRIVER_WHITELIST_FILENAME = "whitelist.txt";
+ private static final int BASE64_FLAGS = Base64.NO_PADDING | Base64.NO_WRAP;
private final Context mContext;
private final String mDriverPackageName;
private final PackageManager mPackageManager;
+ private final Object mLock = new Object();
+ private ContentResolver mContentResolver;
+ private long mGameDriverVersionCode;
+ private SettingsObserver mSettingsObserver;
+ @GuardedBy("mLock")
+ private Blacklists mBlacklists;
public GpuService(Context context) {
super(context);
mContext = context;
mDriverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
+ mGameDriverVersionCode = -1;
mPackageManager = context.getPackageManager();
if (mDriverPackageName != null && !mDriverPackageName.isEmpty()) {
final IntentFilter packageFilter = new IntentFilter();
@@ -82,10 +99,37 @@ public class GpuService extends SystemService {
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_BOOT_COMPLETED) {
+ mContentResolver = mContext.getContentResolver();
+ mSettingsObserver = new SettingsObserver();
if (mDriverPackageName == null || mDriverPackageName.isEmpty()) {
return;
}
fetchGameDriverPackageProperties();
+ processBlacklists();
+ setBlacklist();
+ }
+ }
+
+ private final class SettingsObserver extends ContentObserver {
+ private final Uri mGameDriverBlackUri =
+ Settings.Global.getUriFor(Settings.Global.GAME_DRIVER_BLACKLISTS);
+
+ SettingsObserver() {
+ super(new Handler());
+ mContentResolver.registerContentObserver(mGameDriverBlackUri, false, this,
+ UserHandle.USER_ALL);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (uri == null) {
+ return;
+ }
+
+ if (mGameDriverBlackUri.equals(uri)) {
+ processBlacklists();
+ setBlacklist();
+ }
}
}
@@ -109,6 +153,7 @@ public class GpuService extends SystemService {
case ACTION_PACKAGE_CHANGED:
case ACTION_PACKAGE_REMOVED:
fetchGameDriverPackageProperties();
+ setBlacklist();
break;
default:
// do nothing
@@ -138,16 +183,22 @@ public class GpuService extends SystemService {
return;
}
+ // Reset the whitelist.
+ Settings.Global.putString(mContentResolver,
+ Settings.Global.GAME_DRIVER_WHITELIST, "");
+ mGameDriverVersionCode = driverInfo.longVersionCode;
+
try {
final Context driverContext = mContext.createPackageContext(mDriverPackageName,
Context.CONTEXT_RESTRICTED);
final BufferedReader reader = new BufferedReader(
- new InputStreamReader(driverContext.getAssets().open(WHITELIST_FILENAME)));
+ new InputStreamReader(driverContext.getAssets()
+ .open(GAME_DRIVER_WHITELIST_FILENAME)));
final ArrayList<String> whitelistedPackageNames = new ArrayList<>();
for (String packageName; (packageName = reader.readLine()) != null; ) {
whitelistedPackageNames.add(packageName);
}
- Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.putString(mContentResolver,
Settings.Global.GAME_DRIVER_WHITELIST,
String.join(",", whitelistedPackageNames));
} catch (PackageManager.NameNotFoundException e) {
@@ -160,4 +211,48 @@ public class GpuService extends SystemService {
}
}
}
+
+ private void processBlacklists() {
+ // TODO(b/121350991) Switch to DeviceConfig with property listener.
+ String base64String =
+ Settings.Global.getString(mContentResolver, Settings.Global.GAME_DRIVER_BLACKLISTS);
+ if (base64String == null || base64String.isEmpty()) {
+ return;
+ }
+
+ synchronized (mLock) {
+ // Reset all blacklists
+ mBlacklists = null;
+ try {
+ mBlacklists = Blacklists.parseFrom(Base64.decode(base64String, BASE64_FLAGS));
+ } catch (IllegalArgumentException e) {
+ if (DEBUG) {
+ Slog.w(TAG, "Can't parse blacklist, skip and continue...");
+ }
+ } catch (InvalidProtocolBufferException e) {
+ if (DEBUG) {
+ Slog.w(TAG, "Can't parse blacklist, skip and continue...");
+ }
+ }
+ }
+ }
+
+ private void setBlacklist() {
+ Settings.Global.putString(mContentResolver,
+ Settings.Global.GAME_DRIVER_BLACKLIST, "");
+ synchronized (mLock) {
+ if (mBlacklists == null) {
+ return;
+ }
+ List<Blacklist> blacklists = mBlacklists.getBlacklistsList();
+ for (Blacklist blacklist : blacklists) {
+ if (blacklist.getVersionCode() == mGameDriverVersionCode) {
+ Settings.Global.putString(mContentResolver,
+ Settings.Global.GAME_DRIVER_BLACKLIST,
+ String.join(",", blacklist.getPackageNamesList()));
+ return;
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/input/InputForwarder.java b/services/core/java/com/android/server/input/InputForwarder.java
deleted file mode 100644
index 00af8398d0ff..000000000000
--- a/services/core/java/com/android/server/input/InputForwarder.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.input;
-
-import android.app.IInputForwarder;
-import android.hardware.input.InputManagerInternal;
-import android.view.InputEvent;
-
-import com.android.server.LocalServices;
-
-import static android.hardware.input.InputManager.INJECT_INPUT_EVENT_MODE_ASYNC;
-
-/**
- * Basic implementation of {@link IInputForwarder}.
- */
-class InputForwarder extends IInputForwarder.Stub {
-
- private final InputManagerInternal mInputManagerInternal;
- private final int mDisplayId;
-
- InputForwarder(int displayId) {
- mDisplayId = displayId;
- mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
- }
-
- @Override
- public boolean forwardEvent(InputEvent event) {
- event.setDisplayId(mDisplayId);
- return mInputManagerInternal.injectInputEvent(event, INJECT_INPUT_EVENT_MODE_ASYNC);
- }
-} \ No newline at end of file
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 28393a209111..87c744138797 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -17,7 +17,6 @@
package com.android.server.input;
import android.annotation.NonNull;
-import android.app.IInputForwarder;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -1685,29 +1684,6 @@ public class InputManagerService extends IInputManager.Stub
nativeMonitor(mPtr);
}
- // Binder call
- @Override
- public IInputForwarder createInputForwarder(int displayId) throws RemoteException {
- if (!checkCallingPermission(android.Manifest.permission.INJECT_EVENTS,
- "createInputForwarder()")) {
- throw new SecurityException("Requires INJECT_EVENTS permission");
- }
- final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
- final Display display = displayManager.getDisplay(displayId);
- if (display == null) {
- throw new IllegalArgumentException(
- "Can't create input forwarder for non-existent displayId: " + displayId);
- }
- final int callingUid = Binder.getCallingUid();
- final int displayOwnerUid = display.getOwnerUid();
- if (callingUid != displayOwnerUid) {
- throw new SecurityException(
- "Only owner of the display can forward input events to it.");
- }
-
- return new InputForwarder(displayId);
- }
-
// Native callback.
private void notifyConfigurationChanged(long whenNanos) {
mWindowManagerCallbacks.notifyConfigurationChanged();
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 3abacc2c9c10..243b6fe7a30e 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -373,6 +373,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private final NtpTimeHelper mNtpTimeHelper;
private final GnssBatchingProvider mGnssBatchingProvider;
private final GnssGeofenceProvider mGnssGeofenceProvider;
+ // Available only on GNSS HAL 2.0 implementations and later.
private GnssVisibilityControl mGnssVisibilityControl;
// Handler for processing events
@@ -463,8 +464,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
};
- // TODO(b/119326010): replace OnSubscriptionsChangedListener with
- // ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED broadcast reseiver.
+ // TODO: replace OnSubscriptionsChangedListener with ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED
+ // broadcast receiver.
private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
new OnSubscriptionsChangedListener() {
@Override
@@ -676,8 +677,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mNtpTimeHelper.onNetworkAvailable();
if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
if (mSupportsXtra) {
- // Download only if supported, (prevents an unneccesary on-boot
- // download)
+ // Download only if supported, (prevents an unnecessary on-boot download)
xtraDownloadRequest();
}
}
@@ -764,7 +764,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
/** Returns true if the location request is too frequent. */
private boolean isRequestLocationRateLimited() {
- // TODO(b/73198123): implement exponential backoff.
+ // TODO: implement exponential backoff.
return false;
}
@@ -917,7 +917,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
synchronized (mLock) {
boolean enabled =
((mProviderRequest != null && mProviderRequest.reportLocation
- && mProviderRequest.forceLocation) || (
+ && mProviderRequest.locationSettingsIgnored) || (
mContext.getSystemService(LocationManager.class).isLocationEnabled()
&& !mDisableGps)) && !mShutdown;
if (enabled == mEnabled) {
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index c3f25bfa2e5e..20f872a213fd 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -24,10 +24,13 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.location.LocationManager;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.os.UserHandle;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.StatsLog;
@@ -70,7 +73,7 @@ class GnssVisibilityControl {
private final Handler mHandler;
private final Context mContext;
- private boolean mIsMasterLocationSettingsEnabled = true;
+ private boolean mIsDeviceLocationSettingsEnabled;
// Number of non-framework location access proxy apps is expected to be small (< 5).
private static final int HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
@@ -88,13 +91,9 @@ class GnssVisibilityControl {
mAppOps = mContext.getSystemService(AppOpsManager.class);
mPackageManager = mContext.getPackageManager();
- // Set to empty proxy app list initially until the configuration properties are loaded.
- updateNfwLocationAccessProxyAppsInGnssHal();
-
- // Listen for proxy app package installation, removal events.
- listenForProxyAppsPackageUpdates();
-
- // TODO(b/122855984): Handle global location settings on/off.
+ // Complete initialization as the first event to run in mHandler thread. After that,
+ // all object state read/update events run in the mHandler thread.
+ runOnHandler(this::handleInitialize);
}
void updateProxyApps(List<String> nfwLocationAccessProxyApps) {
@@ -105,10 +104,6 @@ class GnssVisibilityControl {
runOnHandler(() -> handleUpdateProxyApps(nfwLocationAccessProxyApps));
}
- void masterLocationSettingsUpdated(boolean enabled) {
- runOnHandler(() -> handleMasterLocationSettingsUpdated(enabled));
- }
-
void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
String otherProtocolStackName, byte requestor, String requestorId, byte responseType,
boolean inEmergencyMode, boolean isCachedLocation) {
@@ -117,7 +112,19 @@ class GnssVisibilityControl {
requestor, requestorId, responseType, inEmergencyMode, isCachedLocation)));
}
+ private void handleInitialize() {
+ disableNfwLocationAccess(); // Disable until config properties are loaded.
+ listenForProxyAppsPackageUpdates();
+ listenForDeviceLocationSettingsUpdate();
+ mIsDeviceLocationSettingsEnabled = getDeviceLocationSettings();
+ }
+
+ private boolean getDeviceLocationSettings() {
+ return mContext.getSystemService(LocationManager.class).isLocationEnabled();
+ }
+
private void listenForProxyAppsPackageUpdates() {
+ // Listen for proxy apps package installation, removal events.
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -143,11 +150,22 @@ class GnssVisibilityControl {
}, UserHandle.ALL, intentFilter, null, mHandler);
}
+ private void listenForDeviceLocationSettingsUpdate() {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE),
+ true,
+ new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ handleDeviceLocationSettingsUpdated();
+ }
+ }, UserHandle.USER_ALL);
+ }
+
private void handleProxyAppPackageUpdate(String pkgName, String action) {
final Boolean locationPermission = mProxyAppToLocationPermissions.get(pkgName);
- // pkgName is not one of the proxy apps in our list.
if (locationPermission == null) {
- return;
+ return; // ignore, pkgName is not one of the proxy apps in our list.
}
Log.i(TAG, "Proxy app " + pkgName + " package changed: " + action);
@@ -197,15 +215,33 @@ class GnssVisibilityControl {
return true;
}
}
-
return false;
}
- private void handleMasterLocationSettingsUpdated(boolean enabled) {
- mIsMasterLocationSettingsEnabled = enabled;
- Log.i(TAG, "Master location settings switch changed to "
- + (enabled ? "enabled" : "disabled"));
- updateNfwLocationAccessProxyAppsInGnssHal();
+ private void handleDeviceLocationSettingsUpdated() {
+ final boolean enabled = getDeviceLocationSettings();
+ Log.i(TAG, "Device location settings enabled: " + enabled);
+
+ if (mIsDeviceLocationSettingsEnabled == enabled) {
+ return;
+ }
+
+ mIsDeviceLocationSettingsEnabled = enabled;
+ if (!mIsDeviceLocationSettingsEnabled) {
+ disableNfwLocationAccess();
+ return;
+ }
+
+ // When device location settings was disabled, we already set the proxy app list
+ // to empty in GNSS HAL. Update only if the proxy app list is not empty.
+ String[] locationPermissionEnabledProxyApps = getLocationPermissionEnabledProxyApps();
+ if (locationPermissionEnabledProxyApps.length != 0) {
+ setNfwLocationAccessProxyAppsInGnssHal(locationPermissionEnabledProxyApps);
+ }
+ }
+
+ private void disableNfwLocationAccess() {
+ setNfwLocationAccessProxyAppsInGnssHal(NO_LOCATION_ENABLED_PROXY_APPS);
}
// Represents NfwNotification structure in IGnssVisibilityControlCallback.hal
@@ -316,8 +352,7 @@ class GnssVisibilityControl {
return mPackageManager.getApplicationInfo(pkgName, 0).uid;
} catch (PackageManager.NameNotFoundException e) {
if (DEBUG) {
- Log.d(TAG, "Non-framework location access proxy app "
- + pkgName + " is not found.");
+ Log.d(TAG, "Non-framework location access proxy app " + pkgName + " is not found.");
}
return null;
}
@@ -329,8 +364,14 @@ class GnssVisibilityControl {
}
private void updateNfwLocationAccessProxyAppsInGnssHal() {
- final String[] locationPermissionEnabledProxyApps = shouldDisableNfwLocationAccess()
- ? NO_LOCATION_ENABLED_PROXY_APPS : getLocationPermissionEnabledProxyApps();
+ if (!mIsDeviceLocationSettingsEnabled) {
+ return; // Keep non-framework location access disabled.
+ }
+ setNfwLocationAccessProxyAppsInGnssHal(getLocationPermissionEnabledProxyApps());
+ }
+
+ private void setNfwLocationAccessProxyAppsInGnssHal(
+ String[] locationPermissionEnabledProxyApps) {
final String proxyAppsStr = Arrays.toString(locationPermissionEnabledProxyApps);
Log.i(TAG, "Updating non-framework location access proxy apps in the GNSS HAL to: "
+ proxyAppsStr);
@@ -341,12 +382,8 @@ class GnssVisibilityControl {
}
}
- private boolean shouldDisableNfwLocationAccess() {
- return !mIsMasterLocationSettingsEnabled;
- }
-
private String[] getLocationPermissionEnabledProxyApps() {
- // Get a count of proxy apps with location permission enabled to array creation size.
+ // Get a count of proxy apps with location permission enabled for array creation size.
int countLocationPermissionEnabledProxyApps = 0;
for (Boolean hasLocationPermissionEnabled : mProxyAppToLocationPermissions.values()) {
if (hasLocationPermissionEnabled) {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index a9ae74f67de7..4b4788cd4a16 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -55,6 +55,8 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.sqlite.SQLiteDatabase;
import android.hardware.authsecret.V1_0.IAuthSecret;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.face.FaceManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -671,7 +673,6 @@ public class LockSettingsService extends ILockSettings.Stub {
mDeviceProvisionedObserver.onSystemReady();
// TODO: maybe skip this for split system user mode.
mStorage.prefetchUser(UserHandle.USER_SYSTEM);
- mStrongAuth.systemReady();
}
private void migrateOldData() {
@@ -2375,6 +2376,14 @@ public class LockSettingsService extends ILockSettings.Stub {
userCredential = null;
}
+ final PackageManager pm = mContext.getPackageManager();
+ // TODO: When lockout is handled under the HAL for all biometrics (fingerprint),
+ // we need to generate challenge for each one, have it signed by GK and reset lockout
+ // for each modality.
+ if (!hasChallenge && pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ challenge = mContext.getSystemService(FaceManager.class).generateChallenge();
+ }
+
final AuthenticationResult authResult;
VerifyCredentialResponse response;
synchronized (mSpManager) {
@@ -2413,6 +2422,17 @@ public class LockSettingsService extends ILockSettings.Stub {
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
notifyActivePasswordMetricsAvailable(userCredential, userId);
unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
+ // Reset lockout
+ if (BiometricManager.hasBiometrics(mContext)) {
+ BiometricManager bm = mContext.getSystemService(BiometricManager.class);
+ Slog.i(TAG, "Resetting lockout, length: "
+ + authResult.gkResponse.getPayload().length);
+ bm.resetLockout(authResult.gkResponse.getPayload());
+
+ if (!hasChallenge && pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ mContext.getSystemService(FaceManager.class).revokeChallenge();
+ }
+ }
final byte[] secret = authResult.authToken.deriveDiskEncryptionKey();
Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
index 44804350309d..a84306c97dc0 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
@@ -16,15 +16,16 @@
package com.android.server.locksettings;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker
+ .STRONG_AUTH_NOT_REQUIRED;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker
+ .STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
import android.app.AlarmManager;
import android.app.AlarmManager.OnAlarmListener;
import android.app.admin.DevicePolicyManager;
import android.app.trust.IStrongAuthTracker;
import android.content.Context;
-import android.hardware.biometrics.BiometricManager;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteCallbackList;
@@ -61,7 +62,6 @@ public class LockSettingsStrongAuth {
private final Context mContext;
private AlarmManager mAlarmManager;
- private BiometricManager mBiometricManager;
public LockSettingsStrongAuth(Context context) {
mContext = context;
@@ -69,12 +69,6 @@ public class LockSettingsStrongAuth {
mAlarmManager = context.getSystemService(AlarmManager.class);
}
- public void systemReady() {
- if (BiometricManager.hasBiometrics(mContext)) {
- mBiometricManager = mContext.getSystemService(BiometricManager.class);
- }
- }
-
private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
mTrackers.register(tracker);
@@ -185,11 +179,6 @@ public class LockSettingsStrongAuth {
}
public void reportSuccessfulStrongAuthUnlock(int userId) {
- if (mBiometricManager != null) {
- byte[] token = null; /* TODO: pass real auth token once HAL supports it */
- mBiometricManager.resetTimeout(token);
- }
-
final int argNotUsed = 0;
mHandler.obtainMessage(MSG_SCHEDULE_STRONG_AUTH_TIMEOUT, userId, argNotUsed).sendToTarget();
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java
index c62a31e24fb2..ff22a8dc934f 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java
@@ -20,6 +20,8 @@ import android.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import org.w3c.dom.Element;
+
import java.security.SecureRandom;
import java.security.cert.CertPath;
import java.security.cert.X509Certificate;
@@ -28,8 +30,6 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
-import org.w3c.dom.Element;
-
/**
* Parses and holds the XML file containing the list of THM public-key certificates and related
* metadata.
@@ -38,24 +38,20 @@ public final class CertXml {
private static final String METADATA_NODE_TAG = "metadata";
private static final String METADATA_SERIAL_NODE_TAG = "serial";
- private static final String METADATA_REFRESH_INTERVAL_NODE_TAG = "refresh-interval";
private static final String ENDPOINT_CERT_LIST_TAG = "endpoints";
private static final String ENDPOINT_CERT_ITEM_TAG = "cert";
private static final String INTERMEDIATE_CERT_LIST_TAG = "intermediates";
private static final String INTERMEDIATE_CERT_ITEM_TAG = "cert";
private final long serial;
- private final long refreshInterval;
private final List<X509Certificate> intermediateCerts;
private final List<X509Certificate> endpointCerts;
private CertXml(
long serial,
- long refreshInterval,
List<X509Certificate> intermediateCerts,
List<X509Certificate> endpointCerts) {
this.serial = serial;
- this.refreshInterval = refreshInterval;
this.intermediateCerts = intermediateCerts;
this.endpointCerts = endpointCerts;
}
@@ -65,15 +61,6 @@ public final class CertXml {
return serial;
}
- /**
- * Gets the refresh interval in the XML file containing public-key certificates. The refresh
- * interval denotes the number of seconds that the client should follow to contact the server to
- * refresh the XML file.
- */
- public long getRefreshInterval() {
- return refreshInterval;
- }
-
@VisibleForTesting
List<X509Certificate> getAllIntermediateCerts() {
return intermediateCerts;
@@ -121,7 +108,6 @@ public final class CertXml {
Element rootNode = CertUtils.getXmlRootNode(bytes);
return new CertXml(
parseSerial(rootNode),
- parseRefreshInterval(rootNode),
parseIntermediateCerts(rootNode),
parseEndpointCerts(rootNode));
}
@@ -136,16 +122,6 @@ public final class CertXml {
return Long.parseLong(contents.get(0));
}
- private static long parseRefreshInterval(Element rootNode) throws CertParsingException {
- List<String> contents =
- CertUtils.getXmlNodeContents(
- CertUtils.MUST_EXIST_EXACTLY_ONE,
- rootNode,
- METADATA_NODE_TAG,
- METADATA_REFRESH_INTERVAL_NODE_TAG);
- return Long.parseLong(contents.get(0));
- }
-
private static List<X509Certificate> parseIntermediateCerts(Element rootNode)
throws CertParsingException {
List<String> contents =
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index b6ef180f4b59..b221241c25e2 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -1207,6 +1207,15 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
}
+ public void setPlaybackSpeed(String packageName, int pid, int uid,
+ ControllerCallbackLink caller, float speed) {
+ try {
+ mCb.notifySetPlaybackSpeed(packageName, pid, uid, caller, speed);
+ } catch (RuntimeException e) {
+ Slog.e(TAG, "Remote failure in setPlaybackSpeed.", e);
+ }
+ }
+
public void adjustVolume(String packageName, int pid, int uid,
ControllerCallbackLink caller, boolean asSystemService, int direction) {
try {
@@ -1446,6 +1455,13 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
@Override
+ public void setPlaybackSpeed(String packageName, ControllerCallbackLink caller,
+ float speed) {
+ mSessionCb.setPlaybackSpeed(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+ caller, speed);
+ }
+
+ @Override
public void sendCustomAction(String packageName, ControllerCallbackLink caller,
String action, Bundle args) {
mSessionCb.sendCustomAction(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 9e5b92a6b944..3f15b381c18b 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -17,9 +17,6 @@
package com.android.server.net;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.provider.Settings.ACTION_VPN_SETTINGS;
import android.app.Notification;
@@ -30,17 +27,14 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
-import android.net.LinkProperties;
import android.net.LinkAddress;
+import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkInfo.State;
-import android.net.NetworkPolicyManager;
import android.os.INetworkManagementService;
-import android.os.RemoteException;
import android.security.Credentials;
import android.security.KeyStore;
-import android.system.Os;
import android.text.TextUtils;
import android.util.Slog;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 4bd8f450c76b..6d82c1c257ab 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -15,15 +15,15 @@
*/
package com.android.server.net;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
+import static android.net.INetd.FIREWALL_RULE_ALLOW;
+import static android.net.INetd.FIREWALL_RULE_DENY;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
import android.app.ActivityManager;
import android.net.NetworkPolicyManager;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index af55605975ca..75b62cb349af 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -38,6 +38,11 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
+import static android.net.INetd.FIREWALL_RULE_ALLOW;
+import static android.net.INetd.FIREWALL_RULE_DENY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -45,12 +50,7 @@ import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index e479a1539e25..d0c59c1b002e 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -320,6 +320,11 @@ public final class OverlayManagerService extends SystemService {
private final class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
+ final String action = intent.getAction();
+ if (action == null) {
+ Slog.e(TAG, "Cannot handle package broadcast with null action");
+ return;
+ }
final Uri data = intent.getData();
if (data == null) {
Slog.e(TAG, "Cannot handle package broadcast with null data");
@@ -337,7 +342,7 @@ public final class OverlayManagerService extends SystemService {
userIds = new int[] { UserHandle.getUserId(extraUid) };
}
- switch (intent.getAction()) {
+ switch (action) {
case ACTION_PACKAGE_ADDED:
if (replacing) {
onPackageUpgraded(packageName, userIds);
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index dac4b6ff39c3..8051abbdd417 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -27,6 +27,7 @@ import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
import android.util.Slog;
import com.android.internal.util.IndentingPrintWriter;
@@ -50,8 +51,12 @@ class ApexManager {
private final Map<String, PackageInfo> mActivePackagesCache;
ApexManager() {
- mApexService = IApexService.Stub.asInterface(
- ServiceManager.getService("apexservice"));
+ try {
+ mApexService = IApexService.Stub.asInterface(
+ ServiceManager.getServiceOrThrow("apexservice"));
+ } catch (ServiceNotFoundException e) {
+ throw new IllegalStateException("Required service apexservice not available");
+ }
mActivePackagesCache = populateActivePackagesCache();
}
@@ -151,7 +156,7 @@ class ApexManager {
}
/**
- * Mark a staged session previously submitted using {@cde submitStagedSession} as ready to be
+ * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be
* applied at next reboot.
*
* @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready.
@@ -167,6 +172,27 @@ class ApexManager {
}
/**
+ * Marks a staged session as successful.
+ *
+ * <p>Only activated session can be marked as successful.
+ *
+ * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as
+ * successful.
+ */
+ void markStagedSessionSuccessful(int sessionId) {
+ try {
+ mApexService.markStagedSessionSuccessful(sessionId);
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to contact apexservice", re);
+ throw new RuntimeException(re);
+ } catch (Exception e) {
+ // It is fine to just log an exception in this case. APEXd will be able to recover in
+ // case markStagedSessionSuccessful fails.
+ Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e);
+ }
+ }
+
+ /**
* Dumps various state information to the provided {@link PrintWriter} object.
*
* @param pw the {@link PrintWriter} object to send information to.
@@ -196,7 +222,7 @@ class ApexManager {
ipw.increaseIndent();
final ApexSessionInfo[] sessions = mApexService.getSessions();
for (ApexSessionInfo si : sessions) {
- ipw.println("Session ID: " + Integer.toString(si.sessionId));
+ ipw.println("Session ID: " + si.sessionId);
ipw.increaseIndent();
if (si.isUnknown) {
ipw.println("State: UNKNOWN");
@@ -206,8 +232,6 @@ class ApexManager {
ipw.println("State: STAGED");
} else if (si.isActivated) {
ipw.println("State: ACTIVATED");
- } else if (si.isActivationPendingRetry) {
- ipw.println("State: ACTIVATION PENDING RETRY");
} else if (si.isActivationFailed) {
ipw.println("State: ACTIVATION FAILED");
}
diff --git a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
index 5b765dfee3a4..d53d81cf0860 100644
--- a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
+++ b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
@@ -28,7 +28,7 @@ import android.util.ByteStringUtils;
import android.util.EventLog;
import android.util.Log;
-import com.android.server.pm.dex.DexLogger;
+import com.android.server.pm.dex.DynamicCodeLogger;
import java.util.ArrayList;
import java.util.List;
@@ -38,9 +38,10 @@ import java.util.regex.Pattern;
/**
* Scheduled jobs related to logging of app dynamic code loading. The idle logging job runs daily
- * while idle and charging and calls {@link DexLogger} to write dynamic code information to the
- * event log. The audit watching job scans the event log periodically while idle to find AVC audit
- * messages indicating use of dynamic native code and adds the information to {@link DexLogger}.
+ * while idle and charging and calls {@link DynamicCodeLogger} to write dynamic code information
+ * to the event log. The audit watching job scans the event log periodically while idle to find AVC
+ * audit messages indicating use of dynamic native code and adds the information to
+ * {@link DynamicCodeLogger}.
* {@hide}
*/
public class DynamicCodeLoggingService extends JobService {
@@ -130,9 +131,9 @@ public class DynamicCodeLoggingService extends JobService {
}
}
- private static DexLogger getDexLogger() {
+ private static DynamicCodeLogger getDynamicCodeLogger() {
PackageManagerService pm = (PackageManagerService) ServiceManager.getService("package");
- return pm.getDexManager().getDexLogger();
+ return pm.getDexManager().getDynamicCodeLogger();
}
private class IdleLoggingThread extends Thread {
@@ -149,14 +150,14 @@ public class DynamicCodeLoggingService extends JobService {
Log.d(TAG, "Starting IdleLoggingJob run");
}
- DexLogger dexLogger = getDexLogger();
- for (String packageName : dexLogger.getAllPackagesWithDynamicCodeLoading()) {
+ DynamicCodeLogger dynamicCodeLogger = getDynamicCodeLogger();
+ for (String packageName : dynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()) {
if (mIdleLoggingStopRequested) {
Log.w(TAG, "Stopping IdleLoggingJob run at scheduler request");
return;
}
- dexLogger.logDynamicCodeLoading(packageName);
+ dynamicCodeLogger.logDynamicCodeLoading(packageName);
}
jobFinished(mParams, /* reschedule */ false);
@@ -191,7 +192,7 @@ public class DynamicCodeLoggingService extends JobService {
private boolean processAuditEvents() {
// Scan the event log for SELinux (avc) audit messages indicating when an
// (untrusted) app has executed native code from an app data
- // file. Matches are recorded in DexLogger.
+ // file. Matches are recorded in DynamicCodeLogger.
//
// These messages come from the kernel audit system via logd. (Note that
// some devices may not generate these messages at all, or the format may
@@ -213,7 +214,7 @@ public class DynamicCodeLoggingService extends JobService {
// On each run we process all the matching events in the log. This may
// mean re-processing events we have already seen, and in any case there
// may be duplicate events for the same app+file. These are de-duplicated
- // by DexLogger.
+ // by DynamicCodeLogger.
//
// Note that any app can write a message to the event log, including one
// that looks exactly like an AVC audit message, so the information may
@@ -228,7 +229,7 @@ public class DynamicCodeLoggingService extends JobService {
return true;
}
- DexLogger dexLogger = getDexLogger();
+ DynamicCodeLogger dynamicCodeLogger = getDynamicCodeLogger();
List<EventLog.Event> events = new ArrayList<>();
EventLog.readEvents(tags, events);
@@ -267,7 +268,7 @@ public class DynamicCodeLoggingService extends JobService {
// hex-encodes the bytes; we need to undo that.
path = unhex(matcher.group(2));
}
- dexLogger.recordNative(uid, path);
+ dynamicCodeLogger.recordNative(uid, path);
}
return true;
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index 33b8641c145e..8ce2568ac3e2 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -9,6 +9,10 @@ svetoslavganov@google.com
toddke@android.com
toddke@google.com
+# apex support
+per-file ApexManager.java = dariofreni@google.com, narayan@google.com, toddke@android.com, toddke@google.com
+per-file StagingManager.java = dariofreni@google.com, narayan@google.com, toddke@android.com, toddke@google.com
+
# dex
per-file AbstractStatsBase.java = agampe@google.com
per-file AbstractStatsBase.java = calin@google.com
@@ -19,6 +23,9 @@ per-file BackgroundDexOptService.java = ngeoffray@google.com
per-file CompilerStats.java = agampe@google.com
per-file CompilerStats.java = calin@google.com
per-file CompilerStats.java = ngeoffray@google.com
+per-file DynamicCodeLoggingService.java = agampe@google.com
+per-file DynamicCodeLoggingService.java = calin@google.com
+per-file DynamicCodeLoggingService.java = ngeoffray@google.com
per-file InstructionSets.java = agampe@google.com
per-file InstructionSets.java = calin@google.com
per-file InstructionSets.java = ngeoffray@google.com
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 86083494f3d6..f5d88e3cf56f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -84,7 +84,7 @@ import com.android.internal.util.ImageUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.IoThread;
import com.android.server.LocalServices;
-import com.android.server.pm.permission.PermissionManagerInternal;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
import libcore.io.IoUtils;
@@ -131,7 +131,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
private final Context mContext;
private final PackageManagerService mPm;
private final StagingManager mStagingManager;
- private final PermissionManagerInternal mPermissionManager;
+ private final PermissionManagerServiceInternal mPermissionManager;
private AppOpsManager mAppOps;
@@ -189,7 +189,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
public PackageInstallerService(Context context, PackageManagerService pm, ApexManager am) {
mContext = context;
mPm = pm;
- mPermissionManager = LocalServices.getService(PermissionManagerInternal.class);
+ mPermissionManager = LocalServices.getService(PermissionManagerServiceInternal.class);
mInstallThread = new HandlerThread(TAG);
mInstallThread.start();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 400443a16fab..b1c186e9e9f8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -238,7 +238,6 @@ import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
-import android.permission.PermissionControllerManager;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings.Global;
@@ -291,7 +290,6 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.XmlUtils;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleController;
import com.android.server.EventLogTags;
@@ -315,9 +313,9 @@ import com.android.server.pm.dex.ViewCompiler;
import com.android.server.pm.permission.BasePermission;
import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
-import com.android.server.pm.permission.PermissionManagerInternal;
-import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
import com.android.server.pm.permission.PermissionManagerService;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
import com.android.server.pm.permission.PermissionsState;
import com.android.server.security.VerityUtils;
import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -371,7 +369,6 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -445,8 +442,6 @@ public class PackageManagerService extends IPackageManager.Stub
private static final boolean ENABLE_FREE_CACHE_V2 =
SystemProperties.getBoolean("fw.free_cache_v2", true);
- private static final long BACKUP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(60);
-
private static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts";
private static final int RADIO_UID = Process.PHONE_UID;
@@ -940,7 +935,7 @@ public class PackageManagerService extends IPackageManager.Stub
// TODO remove this and go through mPermissonManager directly
final DefaultPermissionGrantPolicy mDefaultPermissionPolicy;
- private final PermissionManagerInternal mPermissionManager;
+ private final PermissionManagerServiceInternal mPermissionManager;
private final ComponentResolver mComponentResolver;
// List of packages names to keep cached, even if they are uninstalled for all users
@@ -985,6 +980,9 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mPackages")
private PackageManagerInternal.DefaultBrowserProvider mDefaultBrowserProvider;
+ @GuardedBy("mPackages")
+ private PackageManagerInternal.DefaultHomeProvider mDefaultHomeProvider;
+
private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> {
private Context mContext;
private ComponentName mIntentFilterVerifierComponent;
@@ -1349,7 +1347,7 @@ public class PackageManagerService extends IPackageManager.Stub
final @Nullable String mRequiredVerifierPackage;
final @NonNull String mRequiredInstallerPackage;
final @NonNull String mRequiredUninstallerPackage;
- final String mRequiredPermissionControllerPackage;
+ final @NonNull String mRequiredPermissionControllerPackage;
final @Nullable String mSetupWizardPackage;
final @Nullable String mStorageManagerPackage;
final @Nullable String mSystemTextClassifierPackage;
@@ -1937,9 +1935,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- // We may also need to apply pending (restored) runtime
- // permission grants within these users.
- mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
+ // We may also need to apply pending (restored) runtime permission grants
+ // within these users.
+ mPermissionManager.restoreDelayedRuntimePermissions(packageName,
+ UserHandle.of(userId));
+
+ // Persistent preferred activity might have came into effect due to this
+ // install.
+ updateDefaultHomeLPw(userId);
}
}
}
@@ -3306,7 +3309,8 @@ public class PackageManagerService extends IPackageManager.Stub
// feature flags should cause us to invalidate any caches.
final String cacheName = SystemProperties.digestOf(
"ro.build.fingerprint",
- "persist.sys.isolated_storage");
+ StorageManager.PROP_ISOLATED_STORAGE,
+ StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT);
// Reconcile cache directories, keeping only what we'd actually use.
for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) {
@@ -12803,7 +12807,7 @@ public class PackageManagerService extends IPackageManager.Stub
public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames,
int restrictionFlags, int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS,
- "setPackagesSuspendedAsUser");
+ "setDistractingPackageRestrictionsAsUser");
final int callingUid = Binder.getCallingUid();
if (callingUid != Process.ROOT_UID && callingUid != Process.SYSTEM_UID
@@ -18817,7 +18821,7 @@ public class PackageManagerService extends IPackageManager.Stub
// permission as requiring a review as this is the initial state.
int flags = 0;
if (ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) {
- flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+ flags |= FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
}
if (permissionsState.updatePermissionFlags(bp, userId, userSettableMask, flags)) {
if (hasInstallState) {
@@ -19076,6 +19080,7 @@ public class PackageManagerService extends IPackageManager.Stub
pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
scheduleWritePackageRestrictionsLocked(userId);
postPreferredActivityChangedBroadcast(userId);
+ updateDefaultHomeLPw(userId);
}
}
@@ -19226,6 +19231,13 @@ public class PackageManagerService extends IPackageManager.Stub
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
@GuardedBy("mPackages")
boolean clearPackagePreferredActivitiesLPw(String packageName, int userId) {
+ return clearPackagePreferredActivitiesLPw(packageName, false, userId);
+ }
+
+ /** This method takes a specific user id as well as UserHandle.USER_ALL. */
+ @GuardedBy("mPackages")
+ private boolean clearPackagePreferredActivitiesLPw(String packageName,
+ boolean skipUpdateDefaultHome, int userId) {
ArrayList<PreferredActivity> removed = null;
boolean changed = false;
for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
@@ -19254,6 +19266,9 @@ public class PackageManagerService extends IPackageManager.Stub
pir.removeFilter(pa);
}
changed = true;
+ if (!skipUpdateDefaultHome) {
+ updateDefaultHomeLPw(thisUserId);
+ }
}
}
if (changed) {
@@ -19313,8 +19328,9 @@ public class PackageManagerService extends IPackageManager.Stub
// writer
try {
synchronized (mPackages) {
- clearPackagePreferredActivitiesLPw(null, userId);
+ clearPackagePreferredActivitiesLPw(null, true, userId);
mSettings.applyDefaultPreferredAppsLPw(userId);
+ updateDefaultHomeLPw(userId);
// TODO: We have to reset the default SMS and Phone. This requires
// significant refactoring to keep all default apps in the package
// manager (cleaner but more work) or have the services provide
@@ -19383,6 +19399,7 @@ public class PackageManagerService extends IPackageManager.Stub
new PersistentPreferredActivity(filter, activity));
scheduleWritePackageRestrictionsLocked(userId);
postPreferredActivityChangedBroadcast(userId);
+ updateDefaultHomeLPw(userId);
}
}
@@ -19426,6 +19443,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (changed) {
scheduleWritePackageRestrictionsLocked(userId);
postPreferredActivityChangedBroadcast(userId);
+ updateDefaultHomeLPw(userId);
}
}
}
@@ -19513,6 +19531,7 @@ public class PackageManagerService extends IPackageManager.Stub
(readParser, readUserId) -> {
synchronized (mPackages) {
mSettings.readPreferredActivitiesLPw(readParser, readUserId);
+ updateDefaultHomeLPw(readUserId);
}
});
} catch (Exception e) {
@@ -19568,8 +19587,17 @@ public class PackageManagerService extends IPackageManager.Stub
parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
restoreFromXml(parser, userId, TAG_DEFAULT_APPS,
(parser1, userId1) -> {
+ String defaultBrowser;
synchronized (mPackages) {
mSettings.readDefaultAppsLPw(parser1, userId1);
+ defaultBrowser = mSettings.removeDefaultBrowserPackageNameLPw(userId1);
+ }
+ if (defaultBrowser != null) {
+ PackageManagerInternal.DefaultBrowserProvider provider;
+ synchronized (mPackages) {
+ provider = mDefaultBrowserProvider;
+ }
+ provider.setDefaultBrowser(defaultBrowser, userId1);
}
});
} catch (Exception e) {
@@ -19633,139 +19661,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public byte[] getPermissionGrantBackup(int userId) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the system may call getPermissionGrantBackup()");
- }
-
- AtomicReference<byte[]> backup = new AtomicReference<>();
- mContext.getSystemService(PermissionControllerManager.class).getRuntimePermissionBackup(
- UserHandle.of(userId), mContext.getMainExecutor(), (b) -> {
- synchronized (backup) {
- backup.set(b);
- backup.notifyAll();
- }
- });
-
- long start = System.currentTimeMillis();
- synchronized (backup) {
- while (backup.get() == null) {
- long timeLeft = start + BACKUP_TIMEOUT_MILLIS - System.currentTimeMillis();
- if (timeLeft <= 0) {
- return null;
- }
-
- try {
- backup.wait(timeLeft);
- } catch (InterruptedException ignored) {
- return null;
- }
- }
- }
-
- return backup.get();
- }
-
- @Override
- public void restorePermissionGrants(byte[] backup, int userId) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the system may call restorePermissionGrants()");
- }
-
- try {
- final XmlPullParser parser = Xml.newPullParser();
- parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
- restoreFromXml(parser, userId, TAG_PERMISSION_BACKUP,
- (parser1, userId1) -> {
- synchronized (mPackages) {
- processRestoredPermissionGrantsLPr(parser1, userId1);
- }
- });
- } catch (Exception e) {
- if (DEBUG_BACKUP) {
- Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage());
- }
- }
- }
-
- @GuardedBy("mPackages")
- private void processRestoredPermissionGrantsLPr(XmlPullParser parser, int userId)
- throws XmlPullParserException, IOException {
- String pkgName = null;
- int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- final String tagName = parser.getName();
- if (tagName.equals(TAG_GRANT)) {
- pkgName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
- if (DEBUG_BACKUP) {
- Slog.v(TAG, "+++ Restoring grants for package " + pkgName);
- }
- } else if (tagName.equals(TAG_PERMISSION)) {
-
- final boolean isGranted = "true".equals(parser.getAttributeValue(null, ATTR_IS_GRANTED));
- final String permName = parser.getAttributeValue(null, ATTR_PERMISSION_NAME);
-
- int newFlagSet = 0;
- if ("true".equals(parser.getAttributeValue(null, ATTR_USER_SET))) {
- newFlagSet |= FLAG_PERMISSION_USER_SET;
- }
- if ("true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED))) {
- newFlagSet |= FLAG_PERMISSION_USER_FIXED;
- }
- if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) {
- newFlagSet |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;
- }
- if (DEBUG_BACKUP) {
- Slog.v(TAG, " + Restoring grant:"
- + " pkg=" + pkgName
- + " perm=" + permName
- + " granted=" + isGranted
- + " bits=0x" + Integer.toHexString(newFlagSet));
- }
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
- if (ps != null) {
- // Already installed so we apply the grant immediately
- if (DEBUG_BACKUP) {
- Slog.v(TAG, " + already installed; applying");
- }
- PermissionsState perms = ps.getPermissionsState();
- BasePermission bp =
- (BasePermission) mPermissionManager.getPermissionTEMP(permName);
- if (bp != null) {
- if (isGranted) {
- perms.grantRuntimePermission(bp, userId);
- }
- if (newFlagSet != 0) {
- perms.updatePermissionFlags(
- bp, userId, USER_RUNTIME_GRANT_MASK, newFlagSet);
- }
- }
- } else {
- // Need to wait for post-restore install to apply the grant
- if (DEBUG_BACKUP) {
- Slog.v(TAG, " - not yet installed; saving for later");
- }
- mSettings.processRestoredPermissionGrantLPr(pkgName, permName,
- isGranted, newFlagSet, userId);
- }
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Unknown element under <" + TAG_PERMISSION_BACKUP + ">: " + tagName);
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- scheduleWriteSettingsLocked();
- mSettings.writeRuntimePermissionsForUserLPr(userId, false);
- }
-
- @Override
public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
int sourceUserId, int targetUserId, int flags) {
mContext.enforceCallingOrSelfPermission(
@@ -19927,19 +19822,59 @@ public class PackageManagerService extends IPackageManager.Stub
ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
int userId) {
Intent intent = getHomeIntent();
- List<ResolveInfo> list = queryIntentActivitiesInternal(intent, null,
+ List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
PackageManager.GET_META_DATA, userId);
- ResolveInfo preferred = findPreferredActivity(intent, null, 0, list, 0,
- true, false, false, userId);
-
allHomeCandidates.clear();
- if (list != null) {
- allHomeCandidates.addAll(list);
+ if (resolveInfos == null) {
+ return null;
}
- return (preferred == null || preferred.activityInfo == null)
- ? null
- : new ComponentName(preferred.activityInfo.packageName,
- preferred.activityInfo.name);
+ allHomeCandidates.addAll(resolveInfos);
+
+ PackageManagerInternal.DefaultHomeProvider provider;
+ synchronized (mPackages) {
+ provider = mDefaultHomeProvider;
+ }
+ if (provider == null) {
+ Slog.e(TAG, "mDefaultHomeProvider is null");
+ return null;
+ }
+ String packageName = provider.getDefaultHome(userId);
+ if (packageName == null) {
+ return null;
+ }
+ int resolveInfosSize = resolveInfos.size();
+ for (int i = 0; i < resolveInfosSize; i++) {
+ ResolveInfo resolveInfo = resolveInfos.get(i);
+
+ if (resolveInfo.activityInfo != null && TextUtils.equals(
+ resolveInfo.activityInfo.packageName, packageName)) {
+ return new ComponentName(resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name);
+ }
+ }
+ return null;
+ }
+
+ private void updateDefaultHomeLPw(int userId) {
+ Intent intent = getHomeIntent();
+ List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
+ PackageManager.GET_META_DATA, userId);
+ ResolveInfo preferredResolveInfo = findPreferredActivity(intent, null, 0, resolveInfos,
+ 0, true, false, false, userId);
+ String packageName = preferredResolveInfo != null
+ && preferredResolveInfo.activityInfo != null
+ ? preferredResolveInfo.activityInfo.packageName : null;
+ String currentPackageName = mDefaultHomeProvider.getDefaultHome(userId);
+ if (TextUtils.equals(currentPackageName, packageName)) {
+ return;
+ }
+ String[] callingPackages = getPackagesForUid(Binder.getCallingUid());
+ if (callingPackages != null && ArrayUtils.contains(callingPackages,
+ mRequiredPermissionControllerPackage)) {
+ // PermissionController manages default home directly.
+ return;
+ }
+ mDefaultHomeProvider.setDefaultHomeAsync(packageName, userId);
}
@Override
@@ -21213,10 +21148,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS) && packageName == null) {
- mSettings.dumpRestoredPermissionGrantsLPr(pw, dumpState);
- }
-
if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) {
// XXX should handle packageName != null by dumping only install data that
// the given package is involved with.
@@ -23829,6 +23760,13 @@ public class PackageManagerService extends IPackageManager.Stub
mDefaultBrowserProvider = provider;
}
}
+
+ @Override
+ public void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider) {
+ synchronized (mPackages) {
+ mDefaultHomeProvider = provider;
+ }
+ }
}
@GuardedBy("mPackages")
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 975ffb25a784..92fe377e9495 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -19,10 +19,6 @@ package com.android.server.pm;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
@@ -249,23 +245,6 @@ public final class Settings {
private static final String ATTR_SDK_VERSION = "sdkVersion";
private static final String ATTR_DATABASE_VERSION = "databaseVersion";
- // Bookkeeping for restored permission grants
- private static final String TAG_RESTORED_RUNTIME_PERMISSIONS = "restored-perms";
- // package name: ATTR_PACKAGE_NAME
- private static final String TAG_PERMISSION_ENTRY = "perm";
- // permission name: ATTR_NAME
- // permission granted (boolean): ATTR_GRANTED
- private static final String ATTR_USER_SET = "set";
- private static final String ATTR_USER_FIXED = "fixed";
- private static final String ATTR_REVOKE_ON_UPGRADE = "rou";
- private static final String ATTR_REVOKE_WHEN_REQUESTED = "rwr";
-
- // Flag mask of restored permission grants that are applied at install time
- private static final int USER_RUNTIME_GRANT_MASK =
- FLAG_PERMISSION_USER_SET
- | FLAG_PERMISSION_USER_FIXED
- | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
-
private final Object mLock;
private final RuntimePermissionPersistence mRuntimePermissionsPersistence;
@@ -303,26 +282,6 @@ public final class Settings {
int[] excludedUserIds;
}
- // Bookkeeping for restored user permission grants
- final class RestoredPermissionGrant {
- String permissionName;
- boolean granted;
- int grantBits;
-
- RestoredPermissionGrant(String name, boolean isGranted, int theGrantBits) {
- permissionName = name;
- granted = isGranted;
- grantBits = theGrantBits;
- }
- }
-
- // This would be more compact as a flat array of restored grants or something, but we
- // may have quite a few, especially during early device lifetime, and avoiding all those
- // linear lookups will be important.
- private final SparseArray<ArrayMap<String, ArraySet<RestoredPermissionGrant>>>
- mRestoredUserGrants =
- new SparseArray<ArrayMap<String, ArraySet<RestoredPermissionGrant>>>();
-
private static int mFirstAvailableUid = 0;
/** Map from volume UUID to {@link VersionInfo} */
@@ -461,43 +420,6 @@ public final class Settings {
return mRenamedPackages.put(pkgName, origPkgName);
}
- void applyPendingPermissionGrantsLPw(String packageName, int userId) {
- ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
- mRestoredUserGrants.get(userId);
- if (grantsByPackage == null || grantsByPackage.size() == 0) {
- return;
- }
-
- ArraySet<RestoredPermissionGrant> grants = grantsByPackage.get(packageName);
- if (grants == null || grants.size() == 0) {
- return;
- }
-
- final PackageSetting ps = mPackages.get(packageName);
- if (ps == null) {
- Slog.e(TAG, "Can't find supposedly installed package " + packageName);
- return;
- }
- final PermissionsState perms = ps.getPermissionsState();
-
- for (RestoredPermissionGrant grant : grants) {
- BasePermission bp = mPermissions.getPermission(grant.permissionName);
- if (bp != null) {
- if (grant.granted) {
- perms.grantRuntimePermission(bp, userId);
- }
- perms.updatePermissionFlags(bp, userId, USER_RUNTIME_GRANT_MASK, grant.grantBits);
- }
- }
-
- // And remove it from the pending-grant bookkeeping
- grantsByPackage.remove(packageName);
- if (grantsByPackage.size() < 1) {
- mRestoredUserGrants.remove(userId);
- }
- writeRuntimePermissionsForUserLPr(userId, false);
- }
-
public boolean canPropagatePermissionToInstantApp(String permName) {
return mPermissions.canPropagatePermissionToInstantApp(permName);
}
@@ -1982,13 +1904,6 @@ public final class Settings {
}
}
- // Specifically for backup/restore
- public void processRestoredPermissionGrantLPr(String pkgName, String permission,
- boolean isGranted, int restoredFlagSet, int userId) {
- mRuntimePermissionsPersistence.rememberRestoredUserGrantLPr(
- pkgName, permission, isGranted, restoredFlagSet, userId);
- }
-
void writeDefaultAppsLPr(XmlSerializer serializer, int userId)
throws IllegalArgumentException, IllegalStateException, IOException {
serializer.startTag(null, TAG_DEFAULT_APPS);
@@ -5014,51 +4929,6 @@ public final class Settings {
pw.print(mReadMessages.toString());
}
- void dumpRestoredPermissionGrantsLPr(PrintWriter pw, DumpState dumpState) {
- if (mRestoredUserGrants.size() > 0) {
- pw.println();
- pw.println("Restored (pending) permission grants:");
- for (int userIndex = 0; userIndex < mRestoredUserGrants.size(); userIndex++) {
- ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
- mRestoredUserGrants.valueAt(userIndex);
- if (grantsByPackage != null && grantsByPackage.size() > 0) {
- final int userId = mRestoredUserGrants.keyAt(userIndex);
- pw.print(" User "); pw.println(userId);
-
- for (int pkgIndex = 0; pkgIndex < grantsByPackage.size(); pkgIndex++) {
- ArraySet<RestoredPermissionGrant> grants = grantsByPackage.valueAt(pkgIndex);
- if (grants != null && grants.size() > 0) {
- final String pkgName = grantsByPackage.keyAt(pkgIndex);
- pw.print(" "); pw.print(pkgName); pw.println(" :");
-
- for (RestoredPermissionGrant g : grants) {
- pw.print(" ");
- pw.print(g.permissionName);
- if (g.granted) {
- pw.print(" GRANTED");
- }
- if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) {
- pw.print(" user_set");
- }
- if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) {
- pw.print(" user_fixed");
- }
- if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
- pw.print(" revoke_on_upgrade");
- }
- if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
- pw.print(" revoke_when_requested");
- }
- pw.println();
- }
- }
- }
- }
- }
- pw.println();
- }
- }
-
private static void dumpSplitNames(PrintWriter pw, PackageParser.Package pkg) {
if (pkg == null) {
pw.print("unknown");
@@ -5328,55 +5198,6 @@ public final class Settings {
serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);
- // Now any restored permission grants that are waiting for the apps
- // in question to be installed. These are stored as per-package
- // TAG_RESTORED_RUNTIME_PERMISSIONS blocks, each containing some
- // number of individual permission grant entities.
- if (mRestoredUserGrants.get(userId) != null) {
- ArrayMap<String, ArraySet<RestoredPermissionGrant>> restoredGrants =
- mRestoredUserGrants.get(userId);
- if (restoredGrants != null) {
- final int pkgCount = restoredGrants.size();
- for (int i = 0; i < pkgCount; i++) {
- final ArraySet<RestoredPermissionGrant> pkgGrants =
- restoredGrants.valueAt(i);
- if (pkgGrants != null && pkgGrants.size() > 0) {
- final String pkgName = restoredGrants.keyAt(i);
- serializer.startTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
- serializer.attribute(null, ATTR_PACKAGE_NAME, pkgName);
-
- final int N = pkgGrants.size();
- for (int z = 0; z < N; z++) {
- RestoredPermissionGrant g = pkgGrants.valueAt(z);
- serializer.startTag(null, TAG_PERMISSION_ENTRY);
- serializer.attribute(null, ATTR_NAME, g.permissionName);
-
- if (g.granted) {
- serializer.attribute(null, ATTR_GRANTED, "true");
- }
-
- if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) {
- serializer.attribute(null, ATTR_USER_SET, "true");
- }
- if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) {
- serializer.attribute(null, ATTR_USER_FIXED, "true");
- }
- if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
- serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
- }
- if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED)
- != 0) {
- serializer.attribute(null, ATTR_REVOKE_WHEN_REQUESTED,
- "true");
- }
- serializer.endTag(null, TAG_PERMISSION_ENTRY);
- }
- serializer.endTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
- }
- }
- }
- }
-
serializer.endDocument();
destination.finishWrite(out);
@@ -5455,29 +5276,6 @@ public final class Settings {
}
}
- // Backup/restore support
-
- public void rememberRestoredUserGrantLPr(String pkgName, String permission,
- boolean isGranted, int restoredFlagSet, int userId) {
- // This change will be remembered at write-settings time
- ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
- mRestoredUserGrants.get(userId);
- if (grantsByPackage == null) {
- grantsByPackage = new ArrayMap<String, ArraySet<RestoredPermissionGrant>>();
- mRestoredUserGrants.put(userId, grantsByPackage);
- }
-
- ArraySet<RestoredPermissionGrant> grants = grantsByPackage.get(pkgName);
- if (grants == null) {
- grants = new ArraySet<RestoredPermissionGrant>();
- grantsByPackage.put(pkgName, grants);
- }
-
- RestoredPermissionGrant grant = new RestoredPermissionGrant(permission,
- isGranted, restoredFlagSet);
- grants.add(grant);
- }
-
// Private internals
@GuardedBy("Settings.this.mLock")
@@ -5520,50 +5318,6 @@ public final class Settings {
}
parsePermissionsLPr(parser, sus.getPermissionsState(), userId);
} break;
-
- case TAG_RESTORED_RUNTIME_PERMISSIONS: {
- final String pkgName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
- parseRestoredRuntimePermissionsLPr(parser, pkgName, userId);
- } break;
- }
- }
- }
-
- private void parseRestoredRuntimePermissionsLPr(XmlPullParser parser,
- final String pkgName, final int userId) throws IOException, XmlPullParserException {
- final int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- switch (parser.getName()) {
- case TAG_PERMISSION_ENTRY: {
- final String permName = parser.getAttributeValue(null, ATTR_NAME);
- final boolean isGranted = "true".equals(
- parser.getAttributeValue(null, ATTR_GRANTED));
-
- int permBits = 0;
- if ("true".equals(parser.getAttributeValue(null, ATTR_USER_SET))) {
- permBits |= FLAG_PERMISSION_USER_SET;
- }
- if ("true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED))) {
- permBits |= FLAG_PERMISSION_USER_FIXED;
- }
- if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) {
- permBits |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;
- }
- if ("true".equals(parser.getAttributeValue(null,
- ATTR_REVOKE_WHEN_REQUESTED))) {
- permBits |= FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
- }
-
- if (isGranted || permBits != 0) {
- rememberRestoredUserGrantLPr(pkgName, permName, isGranted, permBits, userId);
- }
- } break;
}
}
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 30c2281b07f1..d1ebc9400e4d 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -156,12 +156,8 @@ public class StagingManager {
boolean success = true;
// STOPSHIP: TODO(b/123753157): Verify APKs through Package Verifier.
- if (!sessionContainsApex(session)) {
- // TODO: Decide whether we want to fail fast by detecting signature mismatches for APKs,
- // right away.
- session.setStagedSessionReady();
- return;
- }
+ // TODO: Decide whether we want to fail fast by detecting signature mismatches for APKs,
+ // right away.
final ApexInfoList apexInfoList = new ApexInfoList();
// APEX checks. For single-package sessions, check if they contain an APEX. For
@@ -227,7 +223,8 @@ public class StagingManager {
}
session.setStagedSessionReady();
- if (!mApexManager.markStagedSessionReady(session.sessionId)) {
+ if (sessionContainsApex(session)
+ && !mApexManager.markStagedSessionReady(session.sessionId)) {
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"APEX staging failed, check logcat messages from apexd for more "
+ "details.");
@@ -250,7 +247,8 @@ public class StagingManager {
}
private void resumeSession(@NonNull PackageInstallerSession session) {
- if (sessionContainsApex(session)) {
+ boolean hasApex = sessionContainsApex(session);
+ if (hasApex) {
// Check with apexservice whether the apex packages have been activated.
ApexSessionInfo apexSessionInfo = mApexManager.getStagedSessionInfo(session.sessionId);
if (apexSessionInfo == null) {
@@ -274,7 +272,7 @@ public class StagingManager {
mBgHandler.post(() -> preRebootVerification(session));
return;
}
- if (!apexSessionInfo.isActivated) {
+ if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
// In all the remaining cases apexd will try to apply the session again at next
// boot. Nothing to do here for now.
Slog.w(TAG, "Staged session " + session.sessionId + " scheduled to be applied "
@@ -290,7 +288,11 @@ public class StagingManager {
+ "more information.");
return;
}
+
session.setStagedSessionApplied();
+ if (hasApex) {
+ mApexManager.markStagedSessionSuccessful(session.sessionId);
+ }
}
private String findFirstAPKInDir(File stageDir) {
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index ee6995b11430..3b805d515178 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -86,11 +86,11 @@ public class DexManager {
// encode and save the dex usage data.
private final PackageDexUsage mPackageDexUsage;
- // DexLogger handles recording of dynamic code loading - which is similar to PackageDexUsage
- // but records a different aspect of the data.
+ // DynamicCodeLogger handles recording of dynamic code loading - which is similar to
+ // PackageDexUsage but records a different aspect of the data.
// (It additionally includes DEX files loaded with unsupported class loaders, and doesn't
// record class loaders or ISAs.)
- private final DexLogger mDexLogger;
+ private final DynamicCodeLogger mDynamicCodeLogger;
private final IPackageManager mPackageManager;
private final PackageDexOptimizer mPackageDexOptimizer;
@@ -126,11 +126,11 @@ public class DexManager {
mPackageDexOptimizer = pdo;
mInstaller = installer;
mInstallLock = installLock;
- mDexLogger = new DexLogger(pms, installer);
+ mDynamicCodeLogger = new DynamicCodeLogger(pms, installer);
}
- public DexLogger getDexLogger() {
- return mDexLogger;
+ public DynamicCodeLogger getDynamicCodeLogger() {
+ return mDynamicCodeLogger;
}
/**
@@ -230,8 +230,8 @@ public class DexManager {
if (!primaryOrSplit) {
// Record loading of a DEX file from an app data directory.
- mDexLogger.recordDex(loaderUserId, dexPath, searchResult.mOwningPackageName,
- loadingAppInfo.packageName);
+ mDynamicCodeLogger.recordDex(loaderUserId, dexPath,
+ searchResult.mOwningPackageName, loadingAppInfo.packageName);
}
if (classLoaderContexts != null) {
@@ -269,7 +269,7 @@ public class DexManager {
loadInternal(existingPackages);
} catch (Exception e) {
mPackageDexUsage.clear();
- mDexLogger.clear();
+ mDynamicCodeLogger.clear();
Slog.w(TAG, "Exception while loading. Starting with a fresh state.", e);
}
}
@@ -320,12 +320,12 @@ public class DexManager {
if (mPackageDexUsage.removePackage(packageName)) {
mPackageDexUsage.maybeWriteAsync();
}
- mDexLogger.removePackage(packageName);
+ mDynamicCodeLogger.removePackage(packageName);
} else {
if (mPackageDexUsage.removeUserPackage(packageName, userId)) {
mPackageDexUsage.maybeWriteAsync();
}
- mDexLogger.removeUserPackage(packageName, userId);
+ mDynamicCodeLogger.removeUserPackage(packageName, userId);
}
}
@@ -404,9 +404,9 @@ public class DexManager {
}
try {
- mDexLogger.readAndSync(packageToUsersMap);
+ mDynamicCodeLogger.readAndSync(packageToUsersMap);
} catch (Exception e) {
- mDexLogger.clear();
+ mDynamicCodeLogger.clear();
Slog.w(TAG, "Exception while loading package dynamic code usage. "
+ "Starting with a fresh state.", e);
}
@@ -692,7 +692,7 @@ public class DexManager {
*/
public void writePackageDexUsageNow() {
mPackageDexUsage.writeNow();
- mDexLogger.writeNow();
+ mDynamicCodeLogger.writeNow();
}
/**
diff --git a/services/core/java/com/android/server/pm/dex/DexLogger.java b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
index 59cc0cfeef45..2c75bcdaa1ef 100644
--- a/services/core/java/com/android/server/pm/dex/DexLogger.java
+++ b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
@@ -11,7 +11,7 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
package com.android.server.pm.dex;
@@ -44,12 +44,12 @@ import java.util.Map;
import java.util.Set;
/**
- * This class is responsible for logging data about secondary dex files and, despite the name,
- * native code executed from an app's private directory. The data logged includes hashes of the
- * name and content of each file.
+ * This class is responsible for logging data about secondary dex files and native code executed
+ * from an app's private directory. The data logged includes hashes of the name and content of each
+ * file.
*/
-public class DexLogger {
- private static final String TAG = "DexLogger";
+public class DynamicCodeLogger {
+ private static final String TAG = "DynamicCodeLogger";
// Event log tag & subtags used for SafetyNet logging of dynamic code loading (DCL) -
// see b/63927552.
@@ -61,12 +61,12 @@ public class DexLogger {
private final PackageDynamicCodeLoading mPackageDynamicCodeLoading;
private final Installer mInstaller;
- public DexLogger(IPackageManager pms, Installer installer) {
+ DynamicCodeLogger(IPackageManager pms, Installer installer) {
this(pms, installer, new PackageDynamicCodeLoading());
}
@VisibleForTesting
- DexLogger(IPackageManager pms, Installer installer,
+ DynamicCodeLogger(IPackageManager pms, Installer installer,
PackageDynamicCodeLoading packageDynamicCodeLoading) {
mPackageManager = pms;
mPackageDynamicCodeLoading = packageDynamicCodeLoading;
@@ -217,7 +217,7 @@ public class DexLogger {
/**
* Record that an app running in the specified uid has executed native code from the file at
- * {@link path}.
+ * {@param path}.
*/
public void recordNative(int loadingUid, String path) {
String[] packages;
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 2036ed73fdf2..dacc6cd0fe76 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -721,7 +721,7 @@ public final class DefaultPermissionGrantPolicy {
grantSystemFixedPermissionsToSystemPackage(
getDefaultSystemHandlerActivityPackage(
RingtoneManager.ACTION_RINGTONE_PICKER, userId),
- userId, STORAGE_PERMISSIONS);
+ userId, STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS);
// TextClassifier Service
String textClassifierPackageName =
@@ -1462,14 +1462,15 @@ public final class DefaultPermissionGrantPolicy {
outGrantExceptions.get(packageName);
if (packageExceptions == null) {
// The package must be on the system image
- if (!isSystemPackage(packageName)) {
- Log.w(TAG, "Unknown package:" + packageName);
+ PackageInfo packageInfo = getSystemPackageInfo(packageName);
+ if (!isSystemPackage(packageInfo)) {
+ Log.w(TAG, "Unknown system package:" + packageName);
XmlUtils.skipCurrentTag(parser);
continue;
}
// The package must support runtime permissions
- if (!doesPackageSupportRuntimePermissions(getSystemPackageInfo(packageName))) {
+ if (!doesPackageSupportRuntimePermissions(packageInfo)) {
Log.w(TAG, "Skipping non supporting runtime permissions package:"
+ packageName);
XmlUtils.skipCurrentTag(parser);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 38940d6241a6..8df5a71de43e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -30,6 +30,7 @@ import static android.app.AppOpsManager.permissionToOpCode;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
@@ -43,6 +44,9 @@ import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING
import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS;
import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
import android.Manifest;
import android.annotation.NonNull;
@@ -69,7 +73,9 @@ import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
+import android.permission.PermissionControllerManager;
import android.permission.PermissionManager;
+import android.permission.PermissionManagerInternal;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -77,6 +83,7 @@ import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
@@ -91,9 +98,8 @@ import com.android.server.pm.PackageManagerServiceUtils;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.SharedUserSetting;
import com.android.server.pm.UserManagerService;
-import com.android.server.pm.permission.DefaultPermissionGrantPolicy
- .DefaultPermissionGrantedCallback;
-import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
+import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
import com.android.server.pm.permission.PermissionsState.PermissionState;
import libcore.util.EmptyArray;
@@ -106,6 +112,10 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* Manages all permissions and handles permissions related tasks.
@@ -122,6 +132,8 @@ public class PermissionManagerService {
/** Permission grant: grant as runtime a permission that was granted as an install time one. */
private static final int GRANT_UPGRADE = 4;
+ private static final long BACKUP_TIMEOUT_MILLIS = SECONDS.toMillis(60);
+
/** Cap the size of permission trees that 3rd party apps can define; in characters of text */
private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768;
/** Empty array to avoid allocations */
@@ -146,6 +158,9 @@ public class PermissionManagerService {
/** Internal connection to the user manager */
private final UserManagerInternal mUserManagerInt;
+ /** Permission controller: User space permission management */
+ private PermissionControllerManager mPermissionControllerManager;
+
/** Default permission policy to provide proper behaviour out-of-the-box */
private final DefaultPermissionGrantPolicy mDefaultPermissionGrantPolicy;
@@ -180,6 +195,16 @@ public class PermissionManagerService {
@GuardedBy("mLock")
private ArrayMap<String, List<String>> mBackgroundPermissions;
+ /**
+ * A permission backup might contain apps that are not installed. In this case we delay the
+ * restoration until the app is installed.
+ *
+ * <p>This array ({@code userId -> noDelayedBackupLeft}) is {@code true} for all the users where
+ * there is <u>no more</u> delayed backup left.
+ */
+ @GuardedBy("mLock")
+ private final SparseBooleanArray mHasNoDelayedPermBackup = new SparseBooleanArray();
+
PermissionManagerService(Context context,
@Nullable DefaultPermissionGrantedCallback defaultGrantCallback,
@NonNull Object externalLock) {
@@ -218,29 +243,31 @@ public class PermissionManagerService {
}
}
- LocalServices.addService(
- PermissionManagerInternal.class, new PermissionManagerInternalImpl());
+ PermissionManagerServiceInternalImpl localService =
+ new PermissionManagerServiceInternalImpl();
+ LocalServices.addService(PermissionManagerServiceInternal.class, localService);
+ LocalServices.addService(PermissionManagerInternal.class, localService);
}
/**
* Creates and returns an initialized, internal service for use by other components.
* <p>
* The object returned is identical to the one returned by the LocalServices class using:
- * {@code LocalServices.getService(PermissionManagerInternal.class);}
+ * {@code LocalServices.getService(PermissionManagerServiceInternal.class);}
* <p>
* NOTE: The external lock is temporary and should be removed. This needs to be a
* lock created by the permission manager itself.
*/
- public static PermissionManagerInternal create(Context context,
+ public static PermissionManagerServiceInternal create(Context context,
@Nullable DefaultPermissionGrantedCallback defaultGrantCallback,
@NonNull Object externalLock) {
- final PermissionManagerInternal permMgrInt =
- LocalServices.getService(PermissionManagerInternal.class);
+ final PermissionManagerServiceInternal permMgrInt =
+ LocalServices.getService(PermissionManagerServiceInternal.class);
if (permMgrInt != null) {
return permMgrInt;
}
new PermissionManagerService(context, defaultGrantCallback, externalLock);
- return LocalServices.getService(PermissionManagerInternal.class);
+ return LocalServices.getService(PermissionManagerServiceInternal.class);
}
@Nullable BasePermission getPermission(String permName) {
@@ -332,6 +359,74 @@ public class PermissionManagerService {
}
/**
+ * Get the state of the runtime permissions as xml file.
+ *
+ * <p>Can not be called on main thread.
+ *
+ * @param user The user the data should be extracted for
+ *
+ * @return The state as a xml file
+ */
+ private @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
+ CompletableFuture<byte[]> backup = new CompletableFuture<>();
+ mPermissionControllerManager.getRuntimePermissionBackup(user, mContext.getMainExecutor(),
+ backup::complete);
+
+ try {
+ return backup.get(BACKUP_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ Slog.e(TAG, "Cannot create permission backup for " + user, e);
+ return null;
+ }
+ }
+
+ /**
+ * Restore a permission state previously backed up via {@link #backupRuntimePermissions}.
+ *
+ * <p>If not all state can be restored, the un-appliable state will be delayed and can be
+ * applied via {@link #restoreDelayedRuntimePermissions}.
+ *
+ * @param backup The state as an xml file
+ * @param user The user the data should be restored for
+ */
+ private void restoreRuntimePermissions(@NonNull byte[] backup, @NonNull UserHandle user) {
+ synchronized (mLock) {
+ mHasNoDelayedPermBackup.delete(user.getIdentifier());
+ mPermissionControllerManager.restoreRuntimePermissionBackup(backup, user);
+ }
+ }
+
+ /**
+ * Try to apply permission backup that was previously not applied.
+ *
+ * <p>Can not be called on main thread.
+ *
+ * @param packageName The package that is newly installed
+ * @param user The user the package is installed for
+ *
+ * @see #restoreRuntimePermissions
+ */
+ private void restoreDelayedRuntimePermissions(@NonNull String packageName,
+ @NonNull UserHandle user) {
+ synchronized (mLock) {
+ if (mHasNoDelayedPermBackup.get(user.getIdentifier(), false)) {
+ return;
+ }
+
+ mPermissionControllerManager.restoreDelayedRuntimePermissionBackup(packageName, user,
+ mContext.getMainExecutor(), (hasMoreBackup) -> {
+ if (hasMoreBackup) {
+ return;
+ }
+
+ synchronized (mLock) {
+ mHasNoDelayedPermBackup.put(user.getIdentifier(), true);
+ }
+ });
+ }
+ }
+
+ /**
* Returns {@code true} if the permission can be implied from another granted permission.
* <p>Some permissions, such as ACCESS_FINE_LOCATION, imply other permissions,
* such as ACCESS_COURSE_LOCATION. If the caller holds an umbrella permission, give
@@ -741,7 +836,6 @@ public class PermissionManagerService {
if (ps == null) {
return;
}
- final boolean isLegacySystemApp = mPackageManagerInt.isLegacySystemApp(pkg);
final PermissionsState permissionsState = ps.getPermissionsState();
PermissionsState origPermissions = permissionsState;
@@ -828,17 +922,9 @@ public class PermissionManagerService {
// For all apps normal permissions are install time ones.
grant = GRANT_INSTALL;
} else if (bp.isRuntime()) {
- // If a permission review is required for legacy apps we represent
- // their permissions as always granted runtime ones since we need
- // to keep the review required permission flag per user while an
- // install permission's state is shared across all users.
if (origPermissions.hasInstallPermission(bp.getName())) {
- // For legacy apps that became modern, install becomes runtime.
- grant = GRANT_UPGRADE;
- } else if (isLegacySystemApp) {
- // For legacy system apps, install becomes runtime.
- // We cannot check hasInstallPermission() for system apps since those
- // permissions were granted implicitly and not persisted pre-M.
+ // Before Q we represented some runtime permissions as install permissions,
+ // in Q we cannot do this anymore. Hence upgrade them all.
grant = GRANT_UPGRADE;
} else {
// For modern apps keep runtime permissions unchanged.
@@ -891,110 +977,111 @@ public class PermissionManagerService {
}
// Grant an install permission.
if (permissionsState.grantInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ PERMISSION_OPERATION_FAILURE) {
changedInstallPermission = true;
}
} break;
case GRANT_RUNTIME: {
- // Grant previously granted runtime permissions.
- for (int userId : UserManagerService.getInstance().getUserIds()) {
- final PermissionState permissionState = origPermissions
+ for (int userId : currentUserIds) {
+ PermissionState permState = origPermissions
.getRuntimePermissionState(perm, userId);
- int flags = permissionState != null
- ? permissionState.getFlags() : 0;
- if (origPermissions.hasRuntimePermission(perm, userId)) {
- // Don't propagate the permission in a permission review
- // mode if the former was revoked, i.e. marked to not
- // propagate on upgrade. Note that in a permission review
- // mode install permissions are represented as constantly
- // granted runtime ones since we need to keep a per user
- // state associated with the permission. Also the revoke
- // on upgrade flag is no longer applicable and is reset.
- final boolean revokeOnUpgrade = (flags & PackageManager
- .FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;
- if (revokeOnUpgrade) {
- flags &= ~PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
- // Since we changed the flags, we have to write.
- updatedUserIds = ArrayUtils.appendInt(
- updatedUserIds, userId);
- }
- if (!revokeOnUpgrade) {
- if (permissionsState.grantRuntimePermission(bp, userId) ==
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // If we cannot put the permission as it was,
- // we have to write.
- updatedUserIds = ArrayUtils.appendInt(
- updatedUserIds, userId);
- }
+ int flags = permState != null ? permState.getFlags() : 0;
+
+ boolean wasChanged = false;
+
+ if (appSupportsRuntimePermissions) {
+ // Remove review flag as it is not necessary anymore
+ if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
+ flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;
+ wasChanged = true;
}
- // If the app supports runtime permissions no need for a review.
- if (appSupportsRuntimePermissions
- && (flags & PackageManager
- .FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- flags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
- // Since we changed the flags, we have to write.
- updatedUserIds = ArrayUtils.appendInt(
- updatedUserIds, userId);
+ if ((flags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
+ flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+ wasChanged = true;
+ } else {
+ if (permState != null && permState.isGranted()) {
+ if (permissionsState.grantRuntimePermission(bp, userId)
+ == PERMISSION_OPERATION_FAILURE) {
+ wasChanged = true;
+ }
+ }
}
- } else if (!appSupportsRuntimePermissions) {
- // For legacy apps that need a permission review, every new
- // runtime permission is granted but it is pending a review.
- // We also need to review only platform defined runtime
- // permissions as these are the only ones the platform knows
- // how to disable the API to simulate revocation as legacy
- // apps don't expect to run with revoked permissions.
- if (PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName())) {
- if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0
- && !bp.isRemoved()) {
- flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
- // We changed the flags, hence have to write.
- updatedUserIds = ArrayUtils.appendInt(
- updatedUserIds, userId);
+ } else {
+ if (permState == null) {
+ // New permission
+ if (PLATFORM_PACKAGE_NAME.equals(
+ bp.getSourcePackageName())) {
+ if (!bp.isRemoved()) {
+ flags |= FLAG_PERMISSION_REVIEW_REQUIRED
+ | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+ wasChanged = true;
+ }
}
}
+
if (permissionsState.grantRuntimePermission(bp, userId)
- != PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // We changed the permission, hence have to write.
- updatedUserIds = ArrayUtils.appendInt(
- updatedUserIds, userId);
+ != PERMISSION_OPERATION_FAILURE) {
+ wasChanged = true;
}
}
- // Propagate the permission flags.
+
+ if (wasChanged) {
+ updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
+ }
+
permissionsState.updatePermissionFlags(bp, userId, flags, flags);
}
} break;
case GRANT_UPGRADE: {
- // Grant runtime permissions for a previously held install permission.
- final PermissionState permissionState = origPermissions
+ // Upgrade from Pre-Q to Q permission model. Make all permissions
+ // runtime
+ PermissionState permState = origPermissions
.getInstallPermissionState(perm);
- final int flags =
- (permissionState != null) ? permissionState.getFlags() : 0;
+ int flags = (permState != null) ? permState.getFlags() : 0;
+ // Remove install permission
if (origPermissions.revokeInstallPermission(bp)
- != PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // We will be transferring the permission flags, so clear them.
+ != PERMISSION_OPERATION_FAILURE) {
origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL,
PackageManager.MASK_PERMISSION_FLAGS, 0);
changedInstallPermission = true;
}
- // If the permission is not to be promoted to runtime we ignore it and
- // also its other flags as they are not applicable to install permissions.
- if ((flags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) == 0) {
- for (int userId : currentUserIds) {
+ for (int userId : currentUserIds) {
+ boolean wasChanged = false;
+
+ if (appSupportsRuntimePermissions) {
+ // Remove review flag as it is not necessary anymore
+ if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
+ flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;
+ wasChanged = true;
+ }
+
+ if ((flags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
+ flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+ wasChanged = true;
+ } else {
+ if (permissionsState.grantRuntimePermission(bp, userId) !=
+ PERMISSION_OPERATION_FAILURE) {
+ wasChanged = true;
+ }
+ }
+ } else {
if (permissionsState.grantRuntimePermission(bp, userId) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // Transfer the permission flags.
- permissionsState.updatePermissionFlags(bp, userId,
- flags, flags);
- // If we granted the permission, we have to write.
- updatedUserIds = ArrayUtils.appendInt(
- updatedUserIds, userId);
+ PERMISSION_OPERATION_FAILURE) {
+ flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+ wasChanged = true;
}
}
+
+ if (wasChanged) {
+ updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
+ }
+
+ permissionsState.updatePermissionFlags(bp, userId, flags, flags);
}
} break;
@@ -1011,7 +1098,7 @@ public class PermissionManagerService {
}
} else {
if (permissionsState.revokeInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ PERMISSION_OPERATION_FAILURE) {
// Also drop the permission flags.
permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
PackageManager.MASK_PERMISSION_FLAGS, 0);
@@ -1095,6 +1182,8 @@ public class PermissionManagerService {
AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
String pkgName = pkg.packageName;
+ boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
+ >= Build.VERSION_CODES.M;
int[] users = UserManagerService.getInstance().getUserIds();
int numUsers = users.length;
@@ -1119,27 +1208,17 @@ public class PermissionManagerService {
if ((flags & (FLAG_PERMISSION_GRANTED_BY_DEFAULT
| FLAG_PERMISSION_POLICY_FIXED | FLAG_PERMISSION_SYSTEM_FIXED))
== 0) {
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
- if (permissionToOpCode(permission) != OP_NONE) {
- setAppOpMode(permission, pkg, userId, MODE_IGNORED);
-
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Revoking app-op "
- + permissionToOp(permission) + " for " + pkgName
- + " as it is now requested");
- }
- }
- } else {
+ if (supportsRuntimePermissions) {
int revokeResult = ps.revokeRuntimePermission(bp, userId);
- if (revokeResult
- != PermissionsState.PERMISSION_OPERATION_FAILURE) {
-
+ if (revokeResult != PERMISSION_OPERATION_FAILURE) {
if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Revoking runtime permission " + permission
- + " for " + pkgName
+ Slog.i(TAG, "Revoking runtime permission "
+ + permission + " for " + pkgName
+ " as it is now requested");
}
}
+ } else {
+ setAppOpMode(permission, pkg, userId, MODE_IGNORED);
}
List<String> fgPerms = mBackgroundPermissions.get(permission);
@@ -1925,7 +2004,7 @@ public class PermissionManagerService {
// Development permissions must be handled specially, since they are not
// normal runtime permissions. For now they apply to all users.
if (permissionsState.grantInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ PERMISSION_OPERATION_FAILURE) {
if (callback != null) {
callback.onInstallPermissionGranted();
}
@@ -1945,7 +2024,7 @@ public class PermissionManagerService {
final int result = permissionsState.grantRuntimePermission(bp, userId);
switch (result) {
- case PermissionsState.PERMISSION_OPERATION_FAILURE: {
+ case PERMISSION_OPERATION_FAILURE: {
return;
}
@@ -2045,7 +2124,7 @@ public class PermissionManagerService {
// Development permissions must be handled specially, since they are not
// normal runtime permissions. For now they apply to all users.
if (permissionsState.revokeInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ PERMISSION_OPERATION_FAILURE) {
if (callback != null) {
callback.onInstallPermissionRevoked();
}
@@ -2054,7 +2133,7 @@ public class PermissionManagerService {
}
if (permissionsState.revokeRuntimePermission(bp, userId) ==
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ PERMISSION_OPERATION_FAILURE) {
return;
}
@@ -2522,6 +2601,8 @@ public class PermissionManagerService {
throw new IllegalStateException("Signature|privileged permissions not in "
+ "privapp-permissions whitelist: " + mPrivappPermissionsViolations);
}
+
+ mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
}
private static String getVolumeUuidForPackage(PackageParser.Package pkg) {
@@ -2574,7 +2655,7 @@ public class PermissionManagerService {
return mBackgroundPermissions;
}
- private class PermissionManagerInternalImpl extends PermissionManagerInternal {
+ private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {
@Override
public void systemReady() {
PermissionManagerService.this.systemReady();
@@ -2737,5 +2818,21 @@ public class PermissionManagerService {
return mSettings.getPermissionLocked(permName);
}
}
+
+ @Override
+ public @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
+ return PermissionManagerService.this.backupRuntimePermissions(user);
+ }
+
+ @Override
+ public void restoreRuntimePermissions(@NonNull byte[] backup, @NonNull UserHandle user) {
+ PermissionManagerService.this.restoreRuntimePermissions(backup, user);
+ }
+
+ @Override
+ public void restoreDelayedRuntimePermissions(@NonNull String packageName,
+ @NonNull UserHandle user) {
+ PermissionManagerService.this.restoreDelayedRuntimePermissions(packageName, user);
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index f4979746bae3..1dd2408686c1 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,19 +18,22 @@ package com.android.server.pm.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.PackageManager.PermissionInfoFlags;
import android.content.pm.PackageParser;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
-import android.content.pm.PackageManager.PermissionInfoFlags;
+import android.permission.PermissionManagerInternal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
- * Internal interfaces to be used by other components within the system server.
+ * Internal interfaces services.
+ *
+ * TODO: Should be merged into PermissionManagerInternal, but currently uses internal classes.
*/
-public abstract class PermissionManagerInternal {
+public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal {
/**
* Callbacks invoked when interesting actions have been taken on a permission.
* <p>
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 0892b32a6b91..2280d3fd9134 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -16,6 +16,9 @@
},
{
"include-filter": "android.permission.cts.SplitPermissionTest"
+ },
+ {
+ "include-filter": "android.permission.cts.PermissionFlagsTest"
}
]
},
diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java
index fdcafa77a378..0c6b773396c8 100644
--- a/services/core/java/com/android/server/policy/DisplayFoldController.java
+++ b/services/core/java/com/android/server/policy/DisplayFoldController.java
@@ -42,10 +42,12 @@ class DisplayFoldController {
private final WindowManagerInternal mWindowManagerInternal;
private final DisplayManagerInternal mDisplayManagerInternal;
private final int mDisplayId;
+ private final Handler mHandler;
/** The display area while device is folded. */
private final Rect mFoldedArea;
- private final Handler mHandler;
+ /** The display area to override the original folded area. */
+ private Rect mOverrideFoldedArea = new Rect();
private final DisplayInfo mNonOverrideDisplayInfo = new DisplayInfo();
private final RemoteCallbackList<IDisplayFoldListener> mListeners = new RemoteCallbackList<>();
@@ -70,14 +72,23 @@ class DisplayFoldController {
return;
}
if (folded) {
+ Rect foldedArea;
+ if (!mOverrideFoldedArea.isEmpty()) {
+ foldedArea = mOverrideFoldedArea;
+ } else if (!mFoldedArea.isEmpty()) {
+ foldedArea = mFoldedArea;
+ } else {
+ return;
+ }
+
mDisplayManagerInternal.getNonOverrideDisplayInfo(mDisplayId, mNonOverrideDisplayInfo);
- final int dx = (mNonOverrideDisplayInfo.logicalWidth - mFoldedArea.width()) / 2
- - mFoldedArea.left;
- final int dy = (mNonOverrideDisplayInfo.logicalHeight - mFoldedArea.height()) / 2
- - mFoldedArea.top;
+ final int dx = (mNonOverrideDisplayInfo.logicalWidth - foldedArea.width()) / 2
+ - foldedArea.left;
+ final int dy = (mNonOverrideDisplayInfo.logicalHeight - foldedArea.height()) / 2
+ - foldedArea.top;
- mWindowManagerInternal.setForcedDisplaySize(mDisplayId, mFoldedArea.width(),
- mFoldedArea.height());
+ mWindowManagerInternal.setForcedDisplaySize(mDisplayId,
+ foldedArea.width(), foldedArea.height());
mDisplayManagerInternal.setDisplayOffsets(mDisplayId, -dx, -dy);
} else {
mWindowManagerInternal.clearForcedDisplaySize(mDisplayId);
@@ -114,6 +125,18 @@ class DisplayFoldController {
mListeners.unregister(listener);
}
+ void setOverrideFoldedArea(Rect area) {
+ mOverrideFoldedArea.set(area);
+ }
+
+ Rect getFoldedArea() {
+ if (!mOverrideFoldedArea.isEmpty()) {
+ return mOverrideFoldedArea;
+ } else {
+ return mFoldedArea;
+ }
+ }
+
/**
* Only used for the case that persist.debug.force_foldable is set.
* This is using proximity sensor to simulate the fold state switch.
@@ -125,7 +148,7 @@ class DisplayFoldController {
return null;
}
- final DisplayFoldController result = create(displayId);
+ final DisplayFoldController result = create(context, displayId);
sensorManager.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
@@ -141,13 +164,17 @@ class DisplayFoldController {
return result;
}
- static DisplayFoldController create(int displayId) {
+ static DisplayFoldController create(Context context, int displayId) {
final DisplayManagerInternal displayService =
LocalServices.getService(DisplayManagerInternal.class);
- final DisplayInfo displayInfo = new DisplayInfo();
- displayService.getNonOverrideDisplayInfo(displayId, displayInfo);
- final Rect foldedArea = new Rect(0, displayInfo.logicalHeight / 2,
- displayInfo.logicalWidth, displayInfo.logicalHeight);
+ final String configFoldedArea = context.getResources().getString(
+ com.android.internal.R.string.config_foldedArea);
+ final Rect foldedArea;
+ if (configFoldedArea == null || configFoldedArea.isEmpty()) {
+ foldedArea = new Rect();
+ } else {
+ foldedArea = Rect.unflattenFromString(configFoldedArea);
+ }
return new DisplayFoldController(LocalServices.getService(WindowManagerInternal.class),
displayService, displayId, foldedArea, DisplayThread.getHandler());
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2e3e3e430839..c87a81db16e4 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -125,6 +125,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.hardware.hdmi.HdmiAudioSystemClient;
@@ -1858,7 +1859,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
readConfigurationDependentBehaviors();
if (mLidControlsDisplayFold) {
- mDisplayFoldController = DisplayFoldController.create(DEFAULT_DISPLAY);
+ mDisplayFoldController = DisplayFoldController.create(context, DEFAULT_DISPLAY);
} else if (SystemProperties.getBoolean("persist.debug.force_foldable", false)) {
mDisplayFoldController = DisplayFoldController.createWithProxSensor(context,
DEFAULT_DISPLAY);
@@ -3221,6 +3222,21 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
+ public void setOverrideFoldedArea(Rect area) {
+ if (mDisplayFoldController != null) {
+ mDisplayFoldController.setOverrideFoldedArea(area);
+ }
+ }
+
+ @Override
+ public Rect getFoldedArea() {
+ if (mDisplayFoldController != null) {
+ return mDisplayFoldController.getFoldedArea();
+ }
+ return new Rect();
+ }
+
+ @Override
public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService)
throws RemoteException {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 870d61b2ab90..d7e4b6cff4d8 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -64,6 +64,7 @@ import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.content.Context;
@@ -1470,6 +1471,20 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
default void unregisterDisplayFoldListener(IDisplayFoldListener listener) {}
/**
+ * Overrides the folded area.
+ *
+ * @param area the overriding folded area or an empty {@code Rect} to clear the override.
+ */
+ default void setOverrideFoldedArea(@NonNull Rect area) {}
+
+ /**
+ * Get the display folded area.
+ */
+ default @NonNull Rect getFoldedArea() {
+ return new Rect();
+ }
+
+ /**
* Updates the flag about whether AOD is showing.
*
* @return whether the value was changed.
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
index 3534cf30e2bf..888dd9992bdf 100644
--- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
@@ -17,10 +17,13 @@
package com.android.server.policy.role;
import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.app.role.RoleManager;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
import android.os.Debug;
import android.provider.Settings;
import android.telecom.TelecomManager;
@@ -33,6 +36,7 @@ import com.android.internal.util.CollectionUtils;
import com.android.server.LocalServices;
import com.android.server.role.RoleManagerService;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -54,19 +58,44 @@ public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHolder
@NonNull
private final Context mContext;
- public LegacyRoleResolutionPolicy(Context context) {
+ public LegacyRoleResolutionPolicy(@NonNull Context context) {
mContext = context;
}
+ @NonNull
@Override
- public List<String> getRoleHolders(String roleName, int userId) {
+ public List<String> getRoleHolders(@NonNull String roleName, @UserIdInt int userId) {
switch (roleName) {
+ case RoleManager.ROLE_ASSISTANT: {
+ String legacyAssistant = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(), Settings.Secure.ASSISTANT, userId);
+ if (legacyAssistant == null || legacyAssistant.isEmpty()) {
+ return Collections.emptyList();
+ } else {
+ return Collections.singletonList(
+ ComponentName.unflattenFromString(legacyAssistant).getPackageName());
+ }
+ }
+ case RoleManager.ROLE_BROWSER: {
+ PackageManagerInternal packageManagerInternal = LocalServices.getService(
+ PackageManagerInternal.class);
+ String packageName = packageManagerInternal.removeLegacyDefaultBrowserPackageName(
+ userId);
+ return CollectionUtils.singletonOrEmpty(packageName);
+ }
+ case RoleManager.ROLE_DIALER: {
+ String setting = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.DIALER_DEFAULT_APPLICATION, userId);
+ return CollectionUtils.singletonOrEmpty(!TextUtils.isEmpty(setting)
+ ? setting
+ : mContext.getSystemService(TelecomManager.class).getSystemDialerPackage());
+ }
case RoleManager.ROLE_SMS: {
// Moved over from SmsApplication#getApplication
String result = Settings.Secure.getStringForUser(
mContext.getContentResolver(),
Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
-
// TODO: STOPSHIP: Remove the following code once we read the value of
// config_defaultSms in RoleControllerService.
if (result == null) {
@@ -92,34 +121,13 @@ public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHolder
SmsApplication.SmsApplicationData app = applicationData;
result = app == null ? null : app.mPackageName;
}
-
return CollectionUtils.singletonOrEmpty(result);
}
- case RoleManager.ROLE_ASSISTANT: {
- String legacyAssistant = Settings.Secure.getStringForUser(
- mContext.getContentResolver(), Settings.Secure.ASSISTANT, userId);
-
- if (legacyAssistant == null || legacyAssistant.isEmpty()) {
- return Collections.emptyList();
- } else {
- return Collections.singletonList(
- ComponentName.unflattenFromString(legacyAssistant).getPackageName());
- }
- }
- case RoleManager.ROLE_DIALER: {
- String setting = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.DIALER_DEFAULT_APPLICATION, userId);
-
- return CollectionUtils.singletonOrEmpty(!TextUtils.isEmpty(setting)
- ? setting
- : mContext.getSystemService(TelecomManager.class).getSystemDialerPackage());
- }
- case RoleManager.ROLE_BROWSER: {
- PackageManagerInternal packageManagerInternal = LocalServices.getService(
- PackageManagerInternal.class);
- String packageName = packageManagerInternal.removeLegacyDefaultBrowserPackageName(
- userId);
+ case RoleManager.ROLE_HOME: {
+ PackageManager packageManager = mContext.getPackageManager();
+ List<ResolveInfo> resolveInfos = new ArrayList<>();
+ ComponentName componentName = packageManager.getHomeActivities(resolveInfos);
+ String packageName = componentName != null ? componentName.getPackageName() : null;
return CollectionUtils.singletonOrEmpty(packageName);
}
default: {
diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java
index 4186154016e2..8740256af04d 100644
--- a/services/core/java/com/android/server/power/AttentionDetector.java
+++ b/services/core/java/com/android/server/power/AttentionDetector.java
@@ -123,6 +123,9 @@ public class AttentionDetector {
public AttentionDetector(Runnable onUserAttention, Object lock) {
mOnUserAttention = onUserAttention;
mLock = lock;
+
+ // Device starts with an awake state upon boot.
+ mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
}
public void systemReady(Context context) {
@@ -145,7 +148,7 @@ public class AttentionDetector {
if (DEBUG) {
Slog.d(TAG, "Do not check for attention yet, wait " + (whenToCheck - now));
}
- return nextScreenDimming;
+ return whenToCheck;
} else if (whenToStopExtending < whenToCheck) {
if (DEBUG) {
Slog.d(TAG, "Let device sleep to avoid false results and improve security "
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 1782b6a8aa78..176dbbf6a965 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -538,6 +538,9 @@ public final class PowerManagerService extends SystemService
// True if we are currently in VR Mode.
private boolean mIsVrModeEnabled;
+ // True if we in the process of performing a forceSuspend
+ private boolean mForceSuspendActive;
+
private final class ForegroundProfileObserver extends SynchronousUserSwitchObserver {
@Override
public void onUserSwitching(int newUserId) throws RemoteException {}
@@ -684,6 +687,11 @@ public final class PowerManagerService extends SystemService
public void nativeSetFeature(int featureId, int data) {
PowerManagerService.nativeSetFeature(featureId, data);
}
+
+ /** Wrapper for PowerManager.nativeForceSuspend */
+ public boolean nativeForceSuspend() {
+ return PowerManagerService.nativeForceSuspend();
+ }
}
@VisibleForTesting
@@ -718,6 +726,7 @@ public final class PowerManagerService extends SystemService
private static native void nativeSetAutoSuspend(boolean enable);
private static native void nativeSendPowerHint(int hintId, int data);
private static native void nativeSetFeature(int featureId, int data);
+ private static native boolean nativeForceSuspend();
public PowerManagerService(Context context) {
this(context, new Injector());
@@ -1427,7 +1436,7 @@ public final class PowerManagerService extends SystemService
}
if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
- || !mBootCompleted || !mSystemReady) {
+ || !mBootCompleted || !mSystemReady || mForceSuspendActive) {
return false;
}
@@ -1463,8 +1472,13 @@ public final class PowerManagerService extends SystemService
}
}
- // This method is called goToSleep for historical reasons but we actually start
- // dozing before really going to sleep.
+ /**
+ * Puts the system in doze.
+ *
+ * This method is called goToSleep for historical reasons but actually attempts to DOZE,
+ * and only tucks itself in to SLEEP if requested with the flag
+ * {@link PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE}.
+ */
@SuppressWarnings("deprecation")
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
if (DEBUG_SPEW) {
@@ -1481,35 +1495,10 @@ public final class PowerManagerService extends SystemService
Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");
try {
- switch (reason) {
- case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
- Slog.i(TAG, "Going to sleep due to device administration policy "
- + "(uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
- Slog.i(TAG, "Going to sleep due to screen timeout (uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH:
- Slog.i(TAG, "Going to sleep due to lid switch (uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON:
- Slog.i(TAG, "Going to sleep due to power button (uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON:
- Slog.i(TAG, "Going to sleep due to sleep button (uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_HDMI:
- Slog.i(TAG, "Going to sleep due to HDMI standby (uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_ACCESSIBILITY:
- Slog.i(TAG, "Going to sleep by an accessibility service request (uid "
- + uid +")...");
- break;
- default:
- Slog.i(TAG, "Going to sleep by application request (uid " + uid +")...");
- reason = PowerManager.GO_TO_SLEEP_REASON_APPLICATION;
- break;
- }
+ reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX,
+ Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN));
+ Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
+ + " (uid " + uid + ")...");
mLastSleepTime = eventTime;
mLastSleepReason = reason;
@@ -3063,10 +3052,10 @@ public final class PowerManagerService extends SystemService
if (appid >= Process.FIRST_APPLICATION_UID) {
// Cached inactive processes are never allowed to hold wake locks.
if (mConstants.NO_CACHED_WAKE_LOCKS) {
- disabled = !wakeLock.mUidState.mActive &&
- wakeLock.mUidState.mProcState
+ disabled = mForceSuspendActive
+ || (!wakeLock.mUidState.mActive && wakeLock.mUidState.mProcState
!= ActivityManager.PROCESS_STATE_NONEXISTENT &&
- wakeLock.mUidState.mProcState > ActivityManager.PROCESS_STATE_RECEIVER;
+ wakeLock.mUidState.mProcState > ActivityManager.PROCESS_STATE_RECEIVER);
}
if (mDeviceIdleMode) {
// If we are in idle mode, we will also ignore all partial wake locks that are
@@ -3241,6 +3230,34 @@ public final class PowerManagerService extends SystemService
}
}
+ private boolean forceSuspendInternal(int uid) {
+ try {
+ synchronized (mLock) {
+ mForceSuspendActive = true;
+ // Place the system in an non-interactive state
+ goToSleepInternal(SystemClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_FORCE_SUSPEND,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, uid);
+
+ // Disable all the partial wake locks as well
+ updateWakeLockDisabledStatesLocked();
+ }
+
+ Slog.i(TAG, "Force-Suspending (uid " + uid + ")...");
+ boolean success = mNativeWrapper.nativeForceSuspend();
+ if (!success) {
+ Slog.i(TAG, "Force-Suspending failed in native.");
+ }
+ return success;
+ } finally {
+ synchronized (mLock) {
+ mForceSuspendActive = false;
+ // Re-enable wake locks once again.
+ updateWakeLockDisabledStatesLocked();
+ }
+ }
+ }
+
/**
* Low-level function turn the device off immediately, without trying
* to be clean. Most people should use {@link ShutdownThread} for a clean shutdown.
@@ -4743,6 +4760,20 @@ public final class PowerManagerService extends SystemService
}
}
+ @Override // binder call
+ public boolean forceSuspend() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.DEVICE_POWER, null);
+
+ final int uid = Binder.getCallingUid();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return forceSuspendInternal(uid);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
@Override // Binder call
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 21bf9de5c8b0..c145a22de6cd 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -111,7 +111,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
/** @see #getRoleHolders(String, int) */
public interface RoleHoldersResolver {
/** @return a list of packages that hold a given role for a given user */
- List<String> getRoleHolders(String roleName, int userId);
+ @NonNull
+ List<String> getRoleHolders(@NonNull String roleName, @UserIdInt int userId);
}
/**
@@ -154,6 +155,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
PackageManagerInternal packageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
packageManagerInternal.setDefaultBrowserProvider(new DefaultBrowserProvider());
+ packageManagerInternal.setDefaultHomeProvider(new DefaultHomeProvider());
registerUserRemovedReceiver();
}
@@ -194,7 +196,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
}
performInitialGrantsIfNecessary(userId);
}
- }, UserHandle.SYSTEM, intentFilter, null /* broadcastPermission */, null /* handler */);
+ }, UserHandle.ALL, intentFilter, null, null);
getContext().getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED), false,
@@ -741,4 +743,33 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
}
}
}
+
+ private class DefaultHomeProvider implements PackageManagerInternal.DefaultHomeProvider {
+
+ @Nullable
+ @Override
+ public String getDefaultHome(@UserIdInt int userId) {
+ return CollectionUtils.firstOrNull(getOrCreateUserState(userId).getRoleHolders(
+ RoleManager.ROLE_HOME));
+ }
+
+ @Override
+ public void setDefaultHomeAsync(@Nullable String packageName, @UserIdInt int userId) {
+ IRoleManagerCallback callback = new IRoleManagerCallback.Stub() {
+ @Override
+ public void onSuccess() {}
+ @Override
+ public void onFailure() {
+ Slog.e(LOG_TAG, "Failed to set default home: " + packageName);
+ }
+ };
+ if (packageName != null) {
+ getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_HOME,
+ packageName, 0, callback);
+ } else {
+ getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_HOME, 0,
+ callback);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 95c3f4c43313..05d3c17e5c25 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.rollback;
+import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -40,6 +41,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.provider.DeviceConfig;
import android.util.IntArray;
import android.util.Log;
import android.util.SparseBooleanArray;
@@ -61,6 +63,7 @@ import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
/**
* Implementation of service that manages APK level rollbacks.
@@ -71,13 +74,19 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
// Rollbacks expire after 48 hours.
// TODO: How to test rollback expiration works properly?
- private static final long ROLLBACK_LIFETIME_DURATION_MILLIS = 48 * 60 * 60 * 1000;
+ private static final long DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS =
+ TimeUnit.HOURS.toMillis(48);
// Lock used to synchronize accesses to in-memory rollback data
// structures. By convention, methods with the suffix "Locked" require
// mLock is held when they are called.
private final Object mLock = new Object();
+ // No need for guarding with lock because value is only accessed in handler thread
+ // and the value will be written on boot complete. Initialization here happens before
+ // handler threads are running so that's fine.
+ private long mRollbackLifetimeDurationInMillis = DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS;
+
// Used for generating rollback IDs.
private final Random mRandom = new SecureRandom();
@@ -484,7 +493,25 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
});
}
+ private void updateRollbackLifetimeDurationInMillis() {
+ String strRollbackLifetimeInMillis = DeviceConfig.getProperty(
+ DeviceConfig.Rollback.BOOT_NAMESPACE,
+ DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS);
+
+ try {
+ mRollbackLifetimeDurationInMillis = (strRollbackLifetimeInMillis == null)
+ ? DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS
+ : Long.parseLong(strRollbackLifetimeInMillis);
+ } catch (NumberFormatException e) {
+ mRollbackLifetimeDurationInMillis = DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS;
+ }
+ }
+
void onBootCompleted() {
+ getHandler().post(() -> updateRollbackLifetimeDurationInMillis());
+ // Also posts to handler thread
+ scheduleExpiration(0);
+
getHandler().post(() -> {
// Check to see if any staged sessions with rollback enabled have
// been applied.
@@ -565,8 +592,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
for (RollbackInfo info : mRecentlyExecutedRollbacks) {
mAllocatedRollbackIds.put(info.getRollbackId(), true);
}
-
- scheduleExpiration(0);
}
/**
@@ -700,8 +725,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
if (!data.isAvailable) {
continue;
}
-
- if (!now.isBefore(data.timestamp.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS))) {
+ if (!now.isBefore(data.timestamp.plusMillis(mRollbackLifetimeDurationInMillis))) {
iter.remove();
deleteRollback(data);
} else if (oldest == null || oldest.isAfter(data.timestamp)) {
@@ -711,7 +735,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
if (oldest != null) {
- scheduleExpiration(now.until(oldest.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS),
+ scheduleExpiration(now.until(oldest.plusMillis(mRollbackLifetimeDurationInMillis),
ChronoUnit.MILLIS));
}
}
@@ -819,6 +843,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
String packageName = newPackage.packageName;
for (PackageRollbackInfo info : rd.packages) {
if (info.getPackageName().equals(packageName)) {
+ info.getInstalledUsers().addAll(IntArray.wrap(installedUsers));
AppDataRollbackHelper.SnapshotAppDataResult rs =
mAppDataRollbackHelper.snapshotAppData(packageName, installedUsers);
info.getPendingBackups().addAll(rs.pendingBackups);
@@ -851,7 +876,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
* the child sessions, not the parent session.
*/
private boolean enableRollbackForSession(PackageInstaller.SessionInfo session,
- int[] installedUsers, boolean snapshotUserData) {
+ @NonNull int[] installedUsers, boolean snapshotUserData) {
// TODO: Don't attempt to enable rollback for split installs.
final int installFlags = session.installFlags;
if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
@@ -993,7 +1018,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
if (!session.isMultiPackage()) {
- if (!enableRollbackForSession(session, null, false)) {
+ if (!enableRollbackForSession(session, new int[0], false)) {
Log.e(TAG, "Unable to enable rollback for session: " + sessionId);
result.offer(false);
return;
@@ -1007,7 +1032,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
result.offer(false);
return;
}
- if (!enableRollbackForSession(childSession, null, false)) {
+ if (!enableRollbackForSession(childSession, new int[0], false)) {
Log.e(TAG, "Unable to enable rollback for session: " + sessionId);
result.offer(false);
return;
@@ -1144,8 +1169,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
packages.add(data.packages.get(i).getPackageName());
}
mPackageHealthObserver.startObservingHealth(packages,
- ROLLBACK_LIFETIME_DURATION_MILLIS);
- scheduleExpiration(ROLLBACK_LIFETIME_DURATION_MILLIS);
+ mRollbackLifetimeDurationInMillis);
+ scheduleExpiration(mRollbackLifetimeDurationInMillis);
} catch (IOException e) {
Log.e(TAG, "Unable to enable rollback", e);
deleteRollback(data);
diff --git a/services/core/java/com/android/server/rollback/TEST_MAPPING b/services/core/java/com/android/server/rollback/TEST_MAPPING
index c1d95ac85c23..6be93a0a199b 100644
--- a/services/core/java/com/android/server/rollback/TEST_MAPPING
+++ b/services/core/java/com/android/server/rollback/TEST_MAPPING
@@ -2,6 +2,9 @@
"presubmit": [
{
"name": "RollbackTest"
+ },
+ {
+ "name": "StagedRollbackTest"
}
]
}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index f3393e2f29da..4815e5cd7b83 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -85,7 +85,9 @@ import android.os.SystemProperties;
import android.os.Temperature;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.DiskInfo;
import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
import android.telephony.ModemActivityInfo;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
@@ -1942,6 +1944,41 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
}
+ private void pullTimeZoneDataInfo(int tagId,
+ long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
+ String tzDbVersion = "Unknown";
+ try {
+ tzDbVersion = android.icu.util.TimeZone.getTZDataVersion();
+ } catch (Exception e) {
+ Log.e(TAG, "Getting tzdb version failed: ", e);
+ }
+
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+ e.writeString(tzDbVersion);
+ pulledData.add(e);
+ }
+
+ private void pullSDCardInfo(int tagId, long elapsedNanos, long wallClockNanos,
+ List<StatsLogEventWrapper> pulledData) {
+ StorageManager storageManager = mContext.getSystemService(StorageManager.class);
+ if (storageManager != null) {
+ List<VolumeInfo> volumes = storageManager.getVolumes();
+ for (VolumeInfo vol : volumes) {
+ final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
+ final DiskInfo diskInfo = vol.getDisk();
+ if (diskInfo != null && diskInfo.isSd()) {
+ if (envState.equals(Environment.MEDIA_MOUNTED)) {
+ StatsLogEventWrapper e =
+ new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+ e.writeInt(vol.getType() + 1);
+ e.writeLong(diskInfo.size);
+ pulledData.add(e);
+ }
+ }
+ }
+ }
+ }
+
/**
* Pulls various data.
*/
@@ -2130,6 +2167,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pullDangerousPermissionState(elapsedNanos, wallClockNanos, ret);
break;
}
+ case StatsLog.TIME_ZONE_DATA_INFO: {
+ pullTimeZoneDataInfo(tagId, elapsedNanos, wallClockNanos, ret);
+ break;
+ }
+ case StatsLog.SDCARD_INFO: {
+ pullSDCardInfo(tagId, elapsedNanos, wallClockNanos, ret);
+ break;
+ }
default:
Slog.w(TAG, "No such tagId data as " + tagId);
return null;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
index ff01d46e6909..b12129835ca1 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
@@ -19,6 +19,7 @@ import static android.app.StatusBarManager.DEFAULT_SETUP_DISABLE_FLAGS;
import static android.app.StatusBarManager.DISABLE2_NONE;
import static android.app.StatusBarManager.DISABLE_NONE;
+import android.app.StatusBarManager.DisableInfo;
import android.content.ComponentName;
import android.content.Context;
import android.os.Binder;
@@ -26,6 +27,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.service.quicksettings.TileService;
+import android.util.Pair;
import java.io.PrintWriter;
@@ -68,6 +70,8 @@ public class StatusBarShellCommand extends ShellCommand {
return runGetStatusIcons();
case "disable-for-setup":
return runDisableForSetup();
+ case "send-disable-flag":
+ return runSendDisableFlag();
default:
return handleDefaultCommands(cmd);
}
@@ -132,6 +136,47 @@ public class StatusBarShellCommand extends ShellCommand {
return 0;
}
+ private int runSendDisableFlag() {
+ String pkg = mContext.getPackageName();
+ int disable1 = DISABLE_NONE;
+ int disable2 = DISABLE2_NONE;
+
+ DisableInfo info = new DisableInfo();
+
+ String arg = getNextArg();
+ while (arg != null) {
+ switch (arg) {
+ case "search":
+ info.setSearchDisabled(true);
+ break;
+ case "home":
+ info.setNagivationHomeDisabled(true);
+ break;
+ case "recents":
+ info.setRecentsDisabled(true);
+ break;
+ case "notification-alerts":
+ info.setNotificationPeekingDisabled(true);
+ break;
+ case "statusbar-expansion":
+ info.setStatusBarExpansionDisabled(true);
+ break;
+
+ default:
+ break;
+ }
+
+ arg = getNextArg();
+ }
+
+ Pair<Integer, Integer> flagPair = info.toFlags();
+
+ mInterface.disable(flagPair.first, sToken, pkg);
+ mInterface.disable2(flagPair.second, sToken, pkg);
+
+ return 0;
+ }
+
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -166,6 +211,17 @@ public class StatusBarShellCommand extends ShellCommand {
pw.println(" disable-for-setup DISABLE");
pw.println(" If true, disable status bar components unsuitable for device setup");
pw.println("");
+ pw.println(" send-disable-flag FLAG...");
+ pw.println(" Send zero or more disable flags (parsed individually) to StatusBarManager");
+ pw.println(" Valid options:");
+ pw.println(" <blank> - equivalent to \"none\"");
+ pw.println(" none - re-enables all components");
+ pw.println(" search - disable search");
+ pw.println(" home - disable naviagation home");
+ pw.println(" recents - disable recents/overview");
+ pw.println(" notification-peek - disable notification peeking");
+ pw.println(" statusbar-expansion - disable status bar expansion");
+ pw.println("");
}
/**
diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
index 7a3f030f9dd7..f581bc0bca46 100644
--- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java
+++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
@@ -44,7 +44,7 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
-import com.android.server.pm.permission.PermissionManagerInternal;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
/**
* Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup
@@ -133,7 +133,7 @@ public class TelecomLoaderService extends SystemService {
}
private DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy() {
- return LocalServices.getService(PermissionManagerInternal.class)
+ return LocalServices.getService(PermissionManagerServiceInternal.class)
.getDefaultPermissionGrantPolicy();
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 423ec4c869c1..c7044a15dd5d 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -366,17 +366,22 @@ public class TrustManagerService extends SystemService {
} catch (RemoteException e) {
}
- if (mSettingsObserver.getTrustAgentsExtendUnlock()) {
- trusted = trusted && (!showingKeyguard || isFromUnlock) && userId == mCurrentUser;
- if (DEBUG) {
- Slog.d(TAG, "Extend unlock setting trusted as " + Boolean.toString(trusted)
- + " && " + Boolean.toString(!showingKeyguard)
- + " && " + Boolean.toString(userId == mCurrentUser));
- }
- }
-
boolean changed;
synchronized (mUserIsTrusted) {
+ if (mSettingsObserver.getTrustAgentsExtendUnlock()) {
+ // In extend unlock trust agents can only set the device to trusted if it already
+ // trusted or the device is unlocked. Attempting to set the device as trusted
+ // when the device is locked will be ignored.
+ changed = mUserIsTrusted.get(userId) != trusted;
+ trusted = trusted
+ && (!showingKeyguard || isFromUnlock || !changed)
+ && userId == mCurrentUser;
+ if (DEBUG) {
+ Slog.d(TAG, "Extend unlock setting trusted as " + Boolean.toString(trusted)
+ + " && " + Boolean.toString(!showingKeyguard)
+ + " && " + Boolean.toString(userId == mCurrentUser));
+ }
+ }
changed = mUserIsTrusted.get(userId) != trusted;
mUserIsTrusted.put(userId, trusted);
}
diff --git a/services/core/java/com/android/server/utils/FlagNamespaceUtils.java b/services/core/java/com/android/server/utils/FlagNamespaceUtils.java
new file mode 100644
index 000000000000..f26121eac939
--- /dev/null
+++ b/services/core/java/com/android/server/utils/FlagNamespaceUtils.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import android.annotation.Nullable;
+import android.provider.DeviceConfig;
+
+import com.android.server.RescueParty;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Utilities for interacting with the {@link android.provider.DeviceConfig}.
+ *
+ * @hide
+ */
+public final class FlagNamespaceUtils {
+ /**
+ * Special String used for communicating through {@link #RESET_PLATFORM_PACKAGE_FLAG} that
+ * Settings were reset by the RescueParty, no actual namespace with this name exists in
+ * {@link DeviceConfig}.
+ */
+ public static final String NAMESPACE_NO_PACKAGE = "no_package";
+
+ /**
+ * Name of the special namespace in DeviceConfig table used for communicating resets.
+ */
+ private static final String NAMESPACE_RESCUE_PARTY = "rescue_party_namespace";
+ /**
+ * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY}, holding all known {@link
+ * DeviceConfig} namespaces, as a {@link #DELIMITER} separated String. It's updated after the
+ * first time flags are written to the new namespace in the {@link DeviceConfig}.
+ */
+ private static final String ALL_KNOWN_NAMESPACES_FLAG = "all_known_namespaces";
+ /**
+ * Flag in the {@link DeviceConfig} in {@link #NAMESPACE_RESCUE_PARTY} with integer counter
+ * suffix added to it, holding {@link DeviceConfig} namespace value whose flags were recently
+ * reset by the {@link RescueParty}. It's updated by {@link RescueParty} every time given
+ * namespace flags are reset.
+ */
+ private static final String RESET_PLATFORM_PACKAGE_FLAG = "reset_platform_package";
+ private static final String DELIMITER = ":";
+ /**
+ * Maximum value of the counter used in combination with {@link #RESET_PLATFORM_PACKAGE_FLAG}
+ * when communicating recently reset by the RescueParty namespace values.
+ */
+ private static final int MAX_COUNTER_VALUE = 50;
+
+ private static int sKnownResetNamespacesFlagCounter = -1;
+
+ /**
+ * Sets the union of {@link #RESET_PLATFORM_PACKAGE_FLAG} with
+ * {@link #sKnownResetNamespacesFlagCounter} in the DeviceConfig for each namespace
+ * in the consumed namespacesList. These flags are used for communicating the namespaces
+ * (aka platform packages) whose flags in {@link DeviceConfig} were just reset
+ * by the RescueParty.
+ */
+ public static void addToKnownResetNamespaces(@Nullable List<String> namespacesList) {
+ if (namespacesList == null) {
+ return;
+ }
+ for (String namespace : namespacesList) {
+ addToKnownResetNamespaces(namespace);
+ }
+ }
+
+ /**
+ * Sets the union of {@link #RESET_PLATFORM_PACKAGE_FLAG} with
+ * {@link #sKnownResetNamespacesFlagCounter} in the DeviceConfig for the consumed namespace.
+ * This flag is used for communicating the namespace (aka platform package) whose flags
+ * in {@link DeviceConfig} were just reset by the RescueParty.
+ */
+ public static void addToKnownResetNamespaces(String namespace) {
+ int nextFlagCounter = incrementAndRetrieveResetNamespacesFlagCounter();
+ DeviceConfig.setProperty(NAMESPACE_RESCUE_PARTY,
+ RESET_PLATFORM_PACKAGE_FLAG + nextFlagCounter,
+ namespace, /*makeDefault=*/ true);
+ }
+
+ /**
+ * Reset all namespaces in DeviceConfig with consumed resetMode.
+ */
+ public static void resetDeviceConfig(int resetMode) {
+ List<String> allKnownNamespaces = getAllKnownDeviceConfigNamespacesList();
+ for (String namespace : allKnownNamespaces) {
+ DeviceConfig.resetToDefaults(resetMode, namespace);
+ }
+ addToKnownResetNamespaces(allKnownNamespaces);
+ }
+
+ /**
+ * Returns a list of all known DeviceConfig namespaces, except for the special {@link
+ * #NAMESPACE_RESCUE_PARTY}
+ */
+ private static List<String> getAllKnownDeviceConfigNamespacesList() {
+ String namespacesStr = DeviceConfig.getProperty(NAMESPACE_RESCUE_PARTY,
+ ALL_KNOWN_NAMESPACES_FLAG);
+ List<String> namespacesList = toStringList(namespacesStr);
+ namespacesList.remove(NAMESPACE_RESCUE_PARTY);
+ return namespacesList;
+ }
+
+ private static List<String> toStringList(String serialized) {
+ if (serialized == null || serialized.length() == 0) {
+ return new ArrayList<>();
+ }
+ return Arrays.asList(serialized.split(DELIMITER));
+ }
+
+ private static int incrementAndRetrieveResetNamespacesFlagCounter() {
+ sKnownResetNamespacesFlagCounter++;
+ if (sKnownResetNamespacesFlagCounter == MAX_COUNTER_VALUE) {
+ sKnownResetNamespacesFlagCounter = 0;
+ }
+ return sKnownResetNamespacesFlagCounter;
+ }
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index b0ef8a0d4209..071dde74f103 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2243,12 +2243,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
synchronized (mLock) {
mInAmbientMode = inAmbientMode;
final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
- final boolean hasConnection = data != null && data.connection != null;
- final WallpaperInfo info = hasConnection ? data.connection.mInfo : null;
-
// The wallpaper info is null for image wallpaper, also use the engine in this case.
- if (hasConnection && (info == null && isAodImageWallpaperEnabled()
- || info != null && info.supportsAmbientMode())) {
+ if (data != null && data.connection != null && (data.connection.mInfo == null
+ || data.connection.mInfo.supportsAmbientMode())) {
// TODO(multi-display) Extends this method with specific display.
engine = data.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
} else {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0251efb872bc..087de69b6c12 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -87,8 +87,6 @@ import static android.os.Build.VERSION_CODES.HONEYCOMB;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Process.SYSTEM_UID;
import static android.view.Display.INVALID_DISPLAY;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER;
import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK;
@@ -2677,8 +2675,9 @@ final class ActivityRecord extends ConfigurationContainer {
* Get the configuration orientation by the requested screen orientation
* ({@link ActivityInfo.ScreenOrientation}) of this activity.
*
- * @return orientation in ({@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT},
- * {@link #ORIENTATION_UNDEFINED}).
+ * @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE},
+ * {@link Configuration#ORIENTATION_PORTRAIT},
+ * {@link Configuration#ORIENTATION_UNDEFINED}).
*/
int getRequestedConfigurationOrientation() {
final int screenOrientation = getOrientation();
@@ -2827,28 +2826,6 @@ final class ActivityRecord extends ConfigurationContainer {
outAppBounds.setEmpty();
}
- // TODO(b/112288258): Remove below calculation because the position information in bounds
- // will be replaced by the offset of surface.
- final Rect appBounds = parentConfig.windowConfiguration.getAppBounds();
- if (appBounds != null) {
- final Rect outBounds = inOutConfig.windowConfiguration.getBounds();
- final int activityWidth = outBounds.width();
- final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId());
- if (navBarPosition == NAV_BAR_LEFT) {
- // Position the activity frame on the opposite side of the nav bar.
- outBounds.left = appBounds.right - activityWidth;
- outBounds.right = appBounds.right;
- } else if (navBarPosition == NAV_BAR_RIGHT) {
- // Position the activity frame on the opposite side of the nav bar.
- outBounds.left = 0;
- outBounds.right = activityWidth + appBounds.left;
- } else if (appBounds.width() > activityWidth) {
- // Horizontally center the frame.
- outBounds.left = appBounds.left + (appBounds.width() - activityWidth) / 2;
- outBounds.right = outBounds.left + activityWidth;
- }
- }
-
task.computeConfigResourceOverrides(inOutConfig, parentConfig, insideParentBounds);
}
@@ -2936,14 +2913,36 @@ final class ActivityRecord extends ConfigurationContainer {
// should be given the aspect ratio.
activityWidth = (int) ((activityHeight * maxAspectRatio) + 0.5f);
}
- } else if (containingRatio < minAspectRatio && minAspectRatio != 0) {
- if (containingAppWidth < containingAppHeight) {
- // Width is the shorter side, so we use the height to figure-out what the max. width
- // should be given the aspect ratio.
+ } else if (containingRatio < minAspectRatio) {
+ boolean adjustWidth;
+ switch (getRequestedConfigurationOrientation()) {
+ case ORIENTATION_LANDSCAPE:
+ // Width should be the longer side for this landscape app, so we use the width
+ // to figure-out what the max. height should be given the aspect ratio.
+ adjustWidth = false;
+ break;
+ case ORIENTATION_PORTRAIT:
+ // Height should be the longer side for this portrait app, so we use the height
+ // to figure-out what the max. width should be given the aspect ratio.
+ adjustWidth = true;
+ break;
+ default:
+ // This app doesn't have a preferred orientation, so we keep the length of the
+ // longer side, and use it to figure-out the length of the shorter side.
+ if (containingAppWidth < containingAppHeight) {
+ // Width is the shorter side, so we use the height to figure-out what the
+ // max. width should be given the aspect ratio.
+ adjustWidth = true;
+ } else {
+ // Height is the shorter side, so we use the width to figure-out what the
+ // max. height should be given the aspect ratio.
+ adjustWidth = false;
+ }
+ break;
+ }
+ if (adjustWidth) {
activityWidth = (int) ((activityHeight / minAspectRatio) + 0.5f);
} else {
- // Height is the shorter side, so we use the width to figure-out what the max.
- // height should be given the aspect ratio.
activityHeight = (int) ((activityWidth / minAspectRatio) + 0.5f);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 0a3c2fba3930..c685b05e99e0 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2332,6 +2332,20 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
if (!task.canBeLaunchedOnDisplay(actualDisplayId)) {
throw new IllegalStateException("Task resolved to incompatible display");
}
+
+ final ActivityDisplay preferredDisplay =
+ mRootActivityContainer.getActivityDisplay(preferredDisplayId);
+
+ final boolean singleTaskInstance = preferredDisplay != null
+ && preferredDisplay.isSingleTaskInstance();
+
+ if (singleTaskInstance) {
+ // Suppress the warning toast if the preferredDisplay was set to singleTask.
+ // The singleTaskInstance displays will only contain one task and any attempt to
+ // launch new task will re-route to the default display.
+ return;
+ }
+
if (preferredDisplayId != actualDisplayId) {
Slog.w(TAG, "Failed to put " + task + " on display " + preferredDisplayId);
// Display a warning toast that we failed to put a task on a secondary display.
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index c33a2c179ab7..538813e9b21c 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -98,6 +98,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
@@ -115,6 +116,7 @@ import android.util.Pools.SynchronizedPool;
import android.util.Slog;
import android.widget.Toast;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
@@ -761,11 +763,11 @@ class ActivityStarter {
abort |= (abortBackgroundStart && !mService.isBackgroundActivityStartsEnabled());
// TODO: remove this toast after feature development is done
if (abortBackgroundStart) {
- final String toastMsg = abort
- ? "Background activity start from " + callingPackage
- + " blocked. See go/q-bg-block."
- : "This background activity start from " + callingPackage
- + " will be blocked in future Q builds. See go/q-bg-block.";
+ final Resources res = mService.mContext.getResources();
+ final String toastMsg = res.getString(abort
+ ? R.string.activity_starter_block_bg_activity_starts_enforcing
+ : R.string.activity_starter_block_bg_activity_starts_permissive,
+ callingPackage);
mService.mUiHandler.post(() -> {
Toast.makeText(mService.mContext, toastMsg, Toast.LENGTH_LONG).show();
});
@@ -830,12 +832,25 @@ class ActivityStarter {
new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
| PendingIntent.FLAG_ONE_SHOT, null);
- final int flags = intent.getFlags();
Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
- newIntent.setFlags(flags
- | FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+
+ int flags = intent.getFlags();
+ flags |= Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+
+ /*
+ * Prevent reuse of review activity: Each app needs their own review activity. By
+ * default activities launched with NEW_TASK or NEW_DOCUMENT try to reuse activities
+ * with the same launch parameters (extras are ignored). Hence to avoid possible
+ * reuse force a new activity via the MULTIPLE_TASK flag.
+ *
+ * Activities that are not launched with NEW_TASK or NEW_DOCUMENT are not re-used,
+ * hence no need to add the flag in this case.
+ */
+ if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0) {
+ flags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+ }
+ newIntent.setFlags(flags);
+
newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
if (resultRecord != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 258819fdece9..df73d1dbc7c6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2467,7 +2467,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
final Rect destBounds = new Rect();
stack.getAnimationOrCurrentBounds(destBounds);
- if (!destBounds.isEmpty() || !destBounds.equals(compareBounds)) {
+ if (destBounds.isEmpty() || !destBounds.equals(compareBounds)) {
Slog.w(TAG, "The current stack bounds does not matched! It may be obsolete.");
return;
}
@@ -3202,23 +3202,34 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public void exitFreeformMode(IBinder token) {
+ public void toggleFreeformWindowingMode(IBinder token) {
synchronized (mGlobalLock) {
long ident = Binder.clearCallingIdentity();
try {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r == null) {
throw new IllegalArgumentException(
- "exitFreeformMode: No activity record matching token=" + token);
+ "toggleFreeformWindowingMode: No activity record matching token="
+ + token);
}
final ActivityStack stack = r.getActivityStack();
- if (stack == null || !stack.inFreeformWindowingMode()) {
- throw new IllegalStateException(
- "exitFreeformMode: You can only go fullscreen from freeform.");
+ if (stack == null) {
+ throw new IllegalStateException("toggleFreeformWindowingMode: the activity "
+ + "doesn't have a stack");
+ }
+
+ if (!stack.inFreeformWindowingMode()
+ && stack.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
+ throw new IllegalStateException("toggleFreeformWindowingMode: You can only "
+ + "toggle between fullscreen and freeform.");
}
- stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ if (stack.inFreeformWindowingMode()) {
+ stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ } else {
+ stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 6dc73bbb80cb..19ff43822923 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -1879,6 +1879,9 @@ public class AppTransition implements Dump {
mNextAppTransitionAnimationsSpecsFuture = specsFuture;
mNextAppTransitionScaleUp = scaleUp;
mNextAppTransitionFutureCallback = callback;
+ if (isReady()) {
+ fetchAppTransitionSpecsFromFuture();
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 97062a6065e2..5c528c7f6047 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -568,7 +568,7 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
final long token = proto.start(fieldId);
mRequestedOverrideConfiguration.writeToProto(proto, OVERRIDE_CONFIGURATION,
- logLevel != WindowTraceLogLevel.CRITICAL);
+ logLevel == WindowTraceLogLevel.CRITICAL);
if (logLevel == WindowTraceLogLevel.ALL) {
mFullConfiguration.writeToProto(proto, FULL_CONFIGURATION, false /* critical */);
mMergedOverrideConfiguration.writeToProto(proto, MERGED_OVERRIDE_CONFIGURATION,
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 5cfc20b6339f..4795555e8ed2 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1500,8 +1500,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / mBaseDisplayDensity;
final int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / mBaseDisplayDensity;
- mDisplayRotation.configure(width, height, shortSizeDp, longSizeDp);
mDisplayPolicy.configure(width, height, shortSizeDp);
+ mDisplayRotation.configure(width, height, shortSizeDp, longSizeDp);
mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo,
calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 2ee30ac5c8ff..91d573defc16 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2617,9 +2617,8 @@ public class DisplayPolicy {
DisplayCutout displayCutout) {
int width = fullWidth;
if (hasNavigationBar()) {
- // For a basic navigation bar, when we are in landscape mode we place
- // the navigation bar to the side.
- if (navigationBarCanMove() && fullWidth > fullHeight) {
+ final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
+ if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
width -= getNavigationBarWidth(rotation, uiMode);
}
}
@@ -2646,9 +2645,8 @@ public class DisplayPolicy {
DisplayCutout displayCutout) {
int height = fullHeight;
if (hasNavigationBar()) {
- // For a basic navigation bar, when we are in portrait mode we place
- // the navigation bar to the bottom.
- if (!navigationBarCanMove() || fullWidth < fullHeight) {
+ final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
+ if (navBarPosition == NAV_BAR_BOTTOM) {
height -= getNavigationBarHeight(rotation, uiMode);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 5f341ee8002c..543f19655350 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -38,6 +38,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.DisplayCutout;
import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
@@ -70,6 +71,8 @@ public class DisplayRotation {
private final int mDeskDockRotation;
private final int mUndockedHdmiRotation;
+ private final float mCloseToSquareMaxAspectRatio;
+
private OrientationListener mOrientationListener;
private StatusBarManagerInternal mStatusBarManagerInternal;
private SettingsObserver mSettingsObserver;
@@ -132,6 +135,9 @@ public class DisplayRotation {
mUndockedHdmiRotation = readRotation(
com.android.internal.R.integer.config_undockedHdmiRotation);
+ mCloseToSquareMaxAspectRatio = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_closeToSquareDisplayMaxAspectRatio);
+
if (isDefaultDisplay) {
final Handler uiHandler = UiThread.getHandler();
mOrientationListener = new OrientationListener(mContext, uiHandler);
@@ -212,10 +218,12 @@ public class DisplayRotation {
// so if the orientation is forced, we need to respect that no matter what.
final boolean isTv = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_LEANBACK);
+ final boolean isCloseToSquare =
+ isNonDecorDisplayCloseToSquare(Surface.ROTATION_0, width, height);
final boolean forceDefaultOrientationInRes =
res.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation);
final boolean forceDefaultOrienation =
- ((longSizeDp >= 960 && shortSizeDp >= 720) || isCar || isTv)
+ ((longSizeDp >= 960 && shortSizeDp >= 720) || isCar || isTv || isCloseToSquare)
&& forceDefaultOrientationInRes
// For debug purposes the next line turns this feature off with:
// $ adb shell setprop config.override_forced_orient true
@@ -227,6 +235,18 @@ public class DisplayRotation {
setFixedToUserRotation(forceDefaultOrienation);
}
+ private boolean isNonDecorDisplayCloseToSquare(int rotation, int width, int height) {
+ final DisplayCutout displayCutout =
+ mDisplayContent.calculateDisplayCutoutForRotation(rotation).getDisplayCutout();
+ final int uiMode = mService.mPolicy.getUiMode();
+ final int w = mDisplayPolicy.getNonDecorDisplayWidth(
+ width, height, rotation, uiMode, displayCutout);
+ final int h = mDisplayPolicy.getNonDecorDisplayHeight(
+ width, height, rotation, uiMode, displayCutout);
+ final float aspectRatio = Math.max(w, h) / (float) Math.min(w, h);
+ return aspectRatio <= mCloseToSquareMaxAspectRatio;
+ }
+
void setRotation(int rotation) {
if (mOrientationListener != null) {
mOrientationListener.setCurrentRotation(rotation);
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ea65dd99077a..1d76a71aaea1 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -396,6 +396,10 @@ public class DockedStackDividerController {
if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight)
|| mAdjustedForDivider != adjustedForDivider) {
if (animate && !mAnimatingForMinimizedDockedStack) {
+ // Notify SystemUI to set the target docked stack size according current docked
+ // state without animation when calling startImeAdjustAnimation.
+ notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
+ isHomeStackResizable());
startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
} else {
// Animation might be delayed, so only notify if we don't run an animation.
@@ -889,7 +893,10 @@ public class DockedStackDividerController {
}
if (mAnimatingForMinimizedDockedStack) {
return animateForMinimizedDockedStack(now);
- } else if (mAnimatingForIme) {
+ } else if (mAnimatingForIme && !mDisplayContent.mAppTransition.isRunning()) {
+ // To prevent task stack resize animation may flicking when playing app transition
+ // animation & IME window enter animation in parallel, make sure app transition is done
+ // and then start to animate for IME.
return animateForIme(now);
}
return false;
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 5c91d9e6fff2..698835772df5 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -1126,6 +1126,13 @@ class RootActivityContainer extends ConfigurationContainer
if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
continue;
}
+ if (stack == targetStack) {
+ // Simply update the result for targetStack because the targetStack had
+ // already resumed in above. We don't want to resume it again, especially in
+ // some cases, it would cause a second launch failure if app process was dead.
+ resumedOnDisplay |= result;
+ continue;
+ }
if (topRunningActivity.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront operation.
stack.executeAppTransition(targetOptions);
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 59d7560fc5b0..9d3112fec0f2 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -2134,7 +2134,7 @@ class TaskRecord extends ConfigurationContainer {
if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
inOutConfig.screenHeightDp = insideParentBounds
- ? Math.min(overrideScreenHeightDp, parentConfig.screenWidthDp)
+ ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
: overrideScreenHeightDp;
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 7b742fd2e0f3..b91519903eb8 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1163,6 +1163,14 @@ public class TaskStack extends WindowContainer<Task> implements
}
private boolean adjustForIME(final WindowState imeWin) {
+ // To prevent task stack resize animation may flicking when playing app transition
+ // animation & IME window enter animation in parallel, we need to make sure app
+ // transition is done and then adjust task size for IME, skip the new adjusted frame when
+ // app transition is still running.
+ if (getDisplayContent().mAppTransition.isRunning()) {
+ return false;
+ }
+
final int dockedSide = getDockSide();
final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
if (imeWin == null || !dockedTopOrBottom) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c747c6d95fcd..7beee0e33355 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -22,6 +22,7 @@ import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
import static android.Manifest.permission.RESTRICTED_VR_ACCESS;
+import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
@@ -446,7 +447,8 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean mLimitedAlphaCompositing;
final int mMaxUiWidth;
- final WindowManagerPolicy mPolicy;
+ @VisibleForTesting
+ WindowManagerPolicy mPolicy;
final IActivityManager mActivityManager;
// TODO: Probably not needed once activities are fully in WM.
@@ -3758,6 +3760,41 @@ public class WindowManagerService extends IWindowManager.Stub
mPolicy.unregisterDisplayFoldListener(listener);
}
+ /**
+ * Overrides the folded area.
+ *
+ * @param area the overriding folded area or an empty {@code Rect} to clear the override.
+ */
+ void setOverrideFoldedArea(@NonNull Rect area) {
+ if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS);
+ }
+
+ long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ mPolicy.setOverrideFoldedArea(area);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ /**
+ * Get the display folded area.
+ */
+ @NonNull Rect getFoldedArea() {
+ long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ return mPolicy.getFoldedArea();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
@Override
public int getPreferredOptionsPanelGravity(int displayId) {
synchronized (mGlobalLock) {
@@ -4263,9 +4300,12 @@ public class WindowManagerService extends IWindowManager.Stub
if (mMaxUiWidth > 0) {
mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth));
}
- applyForcedPropertiesForDefaultDisplay();
+ final boolean changed = applyForcedPropertiesForDefaultDisplay();
mAnimator.ready();
mDisplayReady = true;
+ if (changed) {
+ reconfigureDisplayLocked(getDefaultDisplayContentLocked());
+ }
mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TOUCHSCREEN);
}
@@ -4822,11 +4862,9 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void setForcedDisplaySize(int displayId, int width, int height) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Must hold permission " +
- android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS);
}
final long ident = Binder.clearCallingIdentity();
@@ -4844,11 +4882,9 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void setForcedDisplayScalingMode(int displayId, int mode) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Must hold permission " +
- android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS);
}
final long ident = Binder.clearCallingIdentity();
@@ -4865,7 +4901,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
/** The global settings only apply to default display. */
- private void applyForcedPropertiesForDefaultDisplay() {
+ private boolean applyForcedPropertiesForDefaultDisplay() {
+ boolean changed = false;
final DisplayContent displayContent = getDefaultDisplayContentLocked();
// Display size.
String sizeStr = Settings.Global.getString(mContext.getContentResolver(),
@@ -4885,6 +4922,7 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.i(TAG_WM, "FORCED DISPLAY SIZE: " + width + "x" + height);
displayContent.updateBaseDisplayMetrics(width, height,
displayContent.mBaseDisplayDensity);
+ changed = true;
}
} catch (NumberFormatException ex) {
}
@@ -4893,26 +4931,27 @@ public class WindowManagerService extends IWindowManager.Stub
// Display density.
final int density = getForcedDisplayDensityForUserLocked(mCurrentUserId);
- if (density != 0) {
+ if (density != 0 && density != displayContent.mBaseDisplayDensity) {
displayContent.mBaseDisplayDensity = density;
+ changed = true;
}
// Display scaling mode.
int mode = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DISPLAY_SCALING_FORCE, 0);
- if (mode != 0) {
+ if (displayContent.mDisplayScalingDisabled != (mode != 0)) {
Slog.i(TAG_WM, "FORCED DISPLAY SCALING DISABLED");
displayContent.mDisplayScalingDisabled = true;
+ changed = true;
}
+ return changed;
}
@Override
public void clearForcedDisplaySize(int displayId) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Must hold permission " +
- android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS);
}
final long ident = Binder.clearCallingIdentity();
@@ -4953,11 +4992,9 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void setForcedDisplayDensityForUser(int displayId, int density, int userId) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Must hold permission " +
- android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS);
}
final int targetUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
@@ -4978,11 +5015,9 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void clearForcedDisplayDensityForUser(int displayId, int userId) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Must hold permission " +
- android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS);
}
final int callingUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
@@ -5047,11 +5082,9 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void setOverscan(int displayId, int left, int top, int right, int bottom) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Must hold permission " +
- android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS);
}
final long ident = Binder.clearCallingIdentity();
try {
@@ -5081,11 +5114,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void startWindowTrace(){
- try {
- mWindowTracing.startTrace(null /* printwriter */);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ mWindowTracing.startTrace(null /* printwriter */);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 83e3c71cbee3..d13ee459c115 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -62,6 +62,8 @@ public class WindowManagerShellCommand extends ShellCommand {
return runDisplaySize(pw);
case "density":
return runDisplayDensity(pw);
+ case "folded-area":
+ return runDisplayFoldedArea(pw);
case "overscan":
return runDisplayOverscan(pw);
case "scaling":
@@ -207,6 +209,40 @@ public class WindowManagerShellCommand extends ShellCommand {
return 0;
}
+ private void printFoldedArea(PrintWriter pw) {
+ final Rect foldedArea = mInternal.getFoldedArea();
+ if (foldedArea.isEmpty()) {
+ pw.println("Folded area: none");
+ } else {
+ pw.println("Folded area: " + foldedArea.left + "," + foldedArea.top + ","
+ + foldedArea.right + "," + foldedArea.bottom);
+ }
+ }
+
+ private int runDisplayFoldedArea(PrintWriter pw) {
+ final String areaStr = getNextArg();
+ final Rect rect = new Rect();
+ if (areaStr == null) {
+ printFoldedArea(pw);
+ return 0;
+ } else if ("reset".equals(areaStr)) {
+ rect.setEmpty();
+ } else {
+ final Pattern flattenedPattern = Pattern.compile(
+ "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)");
+ final Matcher matcher = flattenedPattern.matcher(areaStr);
+ if (!matcher.matches()) {
+ getErrPrintWriter().println("Error: area should be LEFT,TOP,RIGHT,BOTTOM");
+ return -1;
+ }
+ rect.set(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)),
+ Integer.parseInt(matcher.group(3)), Integer.parseInt(matcher.group(4)));
+ }
+
+ mInternal.setOverrideFoldedArea(rect);
+ return 0;
+ }
+
private int runDisplayOverscan(PrintWriter pw) throws RemoteException {
String overscanStr = getNextArgRequired();
Rect rect = new Rect();
@@ -335,6 +371,8 @@ public class WindowManagerShellCommand extends ShellCommand {
pw.println(" width and height in pixels unless suffixed with 'dp'.");
pw.println(" density [reset|DENSITY] [-d DISPLAY_ID]");
pw.println(" Return or override display density.");
+ pw.println(" folded-area [reset|LEFT,TOP,RIGHT,BOTTOM]");
+ pw.println(" Return or override folded area.");
pw.println(" overscan [reset|LEFT,TOP,RIGHT,BOTTOM] [-d DISPLAY ID]");
pw.println(" Set overscan area for display.");
pw.println(" scaling [off|auto] [-d DISPLAY_ID]");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3430987f4736..21a557e6809e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2164,9 +2164,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// A modal window uses the whole compatibility bounds.
flags |= FLAG_NOT_TOUCH_MODAL;
mTmpRect.set(mAppToken.getResolvedOverrideBounds());
- // TODO(b/112288258): Remove the forced offset when the override bounds always
- // starts from zero (See {@link ActivityRecord#resolveOverrideConfiguration}).
- mTmpRect.offsetTo(0, 0);
} else {
// Non-modal uses the application based frame.
mTmpRect.set(mWindowFrames.mCompatFrame);
diff --git a/services/core/java/com/android/server/wm/WindowTraceBuffer.java b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
index e4461ea90c91..2ce6e6c1d049 100644
--- a/services/core/java/com/android/server/wm/WindowTraceBuffer.java
+++ b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
@@ -20,7 +20,6 @@ import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
-import android.os.Trace;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
@@ -36,24 +35,30 @@ import java.util.Queue;
/**
* Buffer used for window tracing.
*/
-abstract class WindowTraceBuffer {
+class WindowTraceBuffer {
private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
- final Object mBufferLock = new Object();
- final Queue<ProtoOutputStream> mBuffer = new ArrayDeque<>();
- final File mTraceFile;
- int mBufferSize;
- private final int mBufferCapacity;
+ private final Object mBufferLock = new Object();
- WindowTraceBuffer(int size, File traceFile) throws IOException {
- mBufferCapacity = size;
- mTraceFile = traceFile;
+ private final Queue<ProtoOutputStream> mBuffer = new ArrayDeque<>();
+ private int mBufferUsedSize;
+ private int mBufferCapacity;
- initTraceFile();
+ WindowTraceBuffer(int bufferCapacity) {
+ mBufferCapacity = bufferCapacity;
+ resetBuffer();
}
int getAvailableSpace() {
- return mBufferCapacity - mBufferSize;
+ return mBufferCapacity - mBufferUsedSize;
+ }
+
+ int size() {
+ return mBuffer.size();
+ }
+
+ void setCapacity(int capacity) {
+ mBufferCapacity = capacity;
}
/**
@@ -70,42 +75,37 @@ abstract class WindowTraceBuffer {
+ mBufferCapacity + " Object size: " + protoLength);
}
synchronized (mBufferLock) {
- boolean canAdd = canAdd(protoLength);
- if (canAdd) {
- mBuffer.add(proto);
- mBufferSize += protoLength;
- }
+ discardOldest(protoLength);
+ mBuffer.add(proto);
+ mBufferUsedSize += protoLength;
mBufferLock.notify();
}
}
- /**
- * Stops the buffer execution and flush all buffer content to the disk.
- *
- * @throws IOException if the buffer cannot write its contents to the {@link #mTraceFile}
- */
- void dump() throws IOException, InterruptedException {
- try {
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeTraceToFile");
- writeTraceToFile();
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- }
- }
-
- @VisibleForTesting
boolean contains(byte[] other) {
return mBuffer.stream()
.anyMatch(p -> Arrays.equals(p.getBytes(), other));
}
- private void initTraceFile() throws IOException {
- mTraceFile.delete();
- try (OutputStream os = new FileOutputStream(mTraceFile)) {
- mTraceFile.setReadable(true, false);
- ProtoOutputStream proto = new ProtoOutputStream(os);
- proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
- proto.flush();
+ /**
+ * Writes the trace buffer to disk.
+ */
+ void writeTraceToFile(File traceFile) throws IOException {
+ synchronized (mBufferLock) {
+ traceFile.delete();
+ traceFile.setReadable(true, false);
+ try (OutputStream os = new FileOutputStream(traceFile)) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ os.write(proto.getBytes());
+ while (!mBuffer.isEmpty()) {
+ proto = mBuffer.poll();
+ mBufferUsedSize -= proto.getRawSize();
+ byte[] protoBytes = proto.getBytes();
+ os.write(protoBytes);
+ }
+ os.flush();
+ }
}
}
@@ -114,59 +114,48 @@ abstract class WindowTraceBuffer {
* smaller than the overall buffer size.
*
* @param protoLength byte array representation of the Proto object to add
- * @return {@code true} if the element can be added to the buffer or not
- */
- abstract boolean canAdd(int protoLength);
-
- /**
- * Flush all buffer content to the disk.
- *
- * @throws IOException if the buffer cannot write its contents to the {@link #mTraceFile}
*/
- abstract void writeTraceToFile() throws IOException, InterruptedException;
-
- /**
- * Builder for a {@code WindowTraceBuffer} which creates a {@link WindowTraceRingBuffer} for
- * continuous mode or a {@link WindowTraceQueueBuffer} otherwise
- */
- static class Builder {
- private boolean mContinuous;
- private File mTraceFile;
- private int mBufferCapacity;
-
- Builder setContinuousMode(boolean continuous) {
- mContinuous = continuous;
- return this;
- }
+ private void discardOldest(int protoLength) {
+ long availableSpace = getAvailableSpace();
- Builder setTraceFile(File traceFile) {
- mTraceFile = traceFile;
- return this;
- }
+ while (availableSpace < protoLength) {
- Builder setBufferCapacity(int size) {
- mBufferCapacity = size;
- return this;
+ ProtoOutputStream item = mBuffer.poll();
+ if (item == null) {
+ throw new IllegalStateException("No element to discard from buffer");
+ }
+ mBufferUsedSize -= item.getRawSize();
+ availableSpace = getAvailableSpace();
}
+ }
- File getFile() {
- return mTraceFile;
+ /**
+ * Removes all elements form the buffer
+ */
+ void resetBuffer() {
+ synchronized (mBufferLock) {
+ mBuffer.clear();
+ mBufferUsedSize = 0;
}
+ }
- WindowTraceBuffer build() throws IOException {
- if (mBufferCapacity <= 0) {
- throw new IllegalStateException("Buffer capacity must be greater than 0.");
- }
-
- if (mTraceFile == null) {
- throw new IllegalArgumentException("A valid trace file must be specified.");
- }
+ @VisibleForTesting
+ int getBufferSize() {
+ return mBufferUsedSize;
+ }
- if (mContinuous) {
- return new WindowTraceRingBuffer(mBufferCapacity, mTraceFile);
- } else {
- return new WindowTraceQueueBuffer(mBufferCapacity, mTraceFile);
- }
+ String getStatus() {
+ synchronized (mBufferLock) {
+ return "Buffer size: "
+ + mBufferCapacity
+ + " bytes"
+ + "\n"
+ + "Buffer usage: "
+ + mBufferUsedSize
+ + " bytes"
+ + "\n"
+ + "Elements in the buffer: "
+ + mBuffer.size();
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java b/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
deleted file mode 100644
index 5888b7a799cf..000000000000
--- a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.os.Build.IS_USER;
-
-import android.util.Log;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * A buffer structure backed by a {@link java.util.concurrent.BlockingQueue} to store the first
- * {@code #size size} bytes of window trace elements.
- * Once the buffer is full it will no longer accepts new elements.
- */
-class WindowTraceQueueBuffer extends WindowTraceBuffer {
- private static final String TAG = "WindowTracing";
-
- private Thread mConsumerThread;
- private boolean mCancel;
-
- @VisibleForTesting
- WindowTraceQueueBuffer(int size, File traceFile, boolean startConsumerThread)
- throws IOException {
- super(size, traceFile);
- if (startConsumerThread) {
- initializeConsumerThread();
- }
- }
-
- WindowTraceQueueBuffer(int size, File traceFile) throws IOException {
- this(size, traceFile, !IS_USER);
- }
-
- private void initializeConsumerThread() {
- mCancel = false;
- mConsumerThread = new Thread(() -> {
- try {
- loop();
- } catch (InterruptedException e) {
- Log.i(TAG, "Interrupting trace consumer thread");
- } catch (IOException e) {
- Log.e(TAG, "Failed to execute trace consumer thread", e);
- }
- }, "window_tracing");
- mConsumerThread.start();
- }
-
- private void loop() throws IOException, InterruptedException {
- while (!mCancel) {
- ProtoOutputStream proto;
- synchronized (mBufferLock) {
- mBufferLock.wait();
- proto = mBuffer.poll();
- if (proto != null) {
- mBufferSize -= proto.getRawSize();
- }
- }
- if (proto != null) {
- try (OutputStream os = new FileOutputStream(mTraceFile, true)) {
- byte[] protoBytes = proto.getBytes();
- os.write(protoBytes);
- }
- }
- }
- }
-
- @Override
- boolean canAdd(int protoLength) {
- long availableSpace = getAvailableSpace();
- return availableSpace >= protoLength;
- }
-
- @Override
- void writeTraceToFile() throws InterruptedException {
- synchronized (mBufferLock) {
- mCancel = true;
- mBufferLock.notify();
- }
- if (mConsumerThread != null) {
- mConsumerThread.join();
- mConsumerThread = null;
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java b/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java
deleted file mode 100644
index 77d30be816bc..000000000000
--- a/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import android.util.proto.ProtoOutputStream;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * A ring buffer to store the {@code #size size} bytes of window trace data.
- * The buffer operates on a trace entry level, that is, if the new trace data is larger than the
- * available buffer space, the buffer will discard as many full trace entries as necessary to fit
- * the new trace.
- */
-class WindowTraceRingBuffer extends WindowTraceBuffer {
- WindowTraceRingBuffer(int size, File traceFile) throws IOException {
- super(size, traceFile);
- }
-
- @Override
- boolean canAdd(int protoLength) {
- long availableSpace = getAvailableSpace();
-
- while (availableSpace < protoLength) {
- discardOldest();
- availableSpace = getAvailableSpace();
- }
-
- return true;
- }
-
- @Override
- void writeTraceToFile() throws IOException {
- synchronized (mBufferLock) {
- try (OutputStream os = new FileOutputStream(mTraceFile, true)) {
- while (!mBuffer.isEmpty()) {
- ProtoOutputStream proto = mBuffer.poll();
- mBufferSize -= proto.getRawSize();
- byte[] protoBytes = proto.getBytes();
- os.write(protoBytes);
- }
- }
- }
- }
-
- private void discardOldest() {
- ProtoOutputStream item = mBuffer.poll();
- if (item == null) {
- throw new IllegalStateException("No element to discard from buffer");
- }
- mBufferSize -= item.getRawSize();
- }
-}
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index abc474d756b7..0ce215c88dad 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -31,8 +31,6 @@ import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.Choreographer;
-import com.android.internal.annotations.VisibleForTesting;
-
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
@@ -47,139 +45,191 @@ class WindowTracing {
* Maximum buffer size, currently defined as 512 KB
* Size was experimentally defined to fit between 100 to 150 elements.
*/
- private static final int WINDOW_TRACE_BUFFER_SIZE = 512 * 1024;
+ private static final int BUFFER_CAPACITY_CRITICAL = 512 * 1024;
+ private static final int BUFFER_CAPACITY_TRIM = 2048 * 1024;
+ private static final int BUFFER_CAPACITY_ALL = 4096 * 1024;
+ private static final String TRACE_FILENAME = "/data/misc/wmtrace/wm_trace.pb";
private static final String TAG = "WindowTracing";
private final WindowManagerService mService;
private final Choreographer mChoreographer;
private final WindowManagerGlobalLock mGlobalLock;
- private final Object mLock = new Object();
- private final WindowTraceBuffer.Builder mBufferBuilder;
-
- private WindowTraceBuffer mTraceBuffer;
+ private final Object mEnabledLock = new Object();
+ private final File mTraceFile;
+ private final WindowTraceBuffer mBuffer;
+ private final Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) ->
+ log("onFrame" /* where */);
- private @WindowTraceLogLevel int mWindowTraceLogLevel = WindowTraceLogLevel.TRIM;
- private boolean mContinuousMode;
+ private @WindowTraceLogLevel int mLogLevel = WindowTraceLogLevel.TRIM;
+ private boolean mLogOnFrame = false;
private boolean mEnabled;
private volatile boolean mEnabledLockFree;
private boolean mScheduled;
- private Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) ->
- log("onFrame" /* where */);
- private WindowTracing(File file, WindowManagerService service, Choreographer choreographer) {
- this(file, service, choreographer, service.mGlobalLock);
+ static WindowTracing createDefaultAndStartLooper(WindowManagerService service,
+ Choreographer choreographer) {
+ File file = new File(TRACE_FILENAME);
+ return new WindowTracing(file, service, choreographer, BUFFER_CAPACITY_TRIM);
}
- @VisibleForTesting
- WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
- WindowManagerGlobalLock globalLock) {
- mBufferBuilder = new WindowTraceBuffer.Builder()
- .setTraceFile(file)
- .setBufferCapacity(WINDOW_TRACE_BUFFER_SIZE);
+ private WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
+ int bufferCapacity) {
+ this(file, service, choreographer, service.mGlobalLock, bufferCapacity);
+ }
+ WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
+ WindowManagerGlobalLock globalLock, int bufferCapacity) {
mChoreographer = choreographer;
mService = service;
mGlobalLock = globalLock;
+ mTraceFile = file;
+ mBuffer = new WindowTraceBuffer(bufferCapacity);
+ setLogLevel(WindowTraceLogLevel.TRIM, null /* pw */);
}
- void startTrace(@Nullable PrintWriter pw) throws IOException {
+ void startTrace(@Nullable PrintWriter pw) {
if (IS_USER) {
logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
return;
}
- synchronized (mLock) {
- logAndPrintln(pw, "Start tracing to " + mBufferBuilder.getFile() + ".");
- if (mTraceBuffer != null) {
- writeTraceToFileLocked();
- }
- mTraceBuffer = mBufferBuilder
- .setContinuousMode(mContinuousMode)
- .build();
+ synchronized (mEnabledLock) {
+ logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
+ mBuffer.resetBuffer();
mEnabled = mEnabledLockFree = true;
}
}
- private void logAndPrintln(@Nullable PrintWriter pw, String msg) {
- Log.i(TAG, msg);
- if (pw != null) {
- pw.println(msg);
- pw.flush();
- }
- }
-
void stopTrace(@Nullable PrintWriter pw) {
if (IS_USER) {
logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
return;
}
- synchronized (mLock) {
- logAndPrintln(pw, "Stop tracing to " + mBufferBuilder.getFile()
- + ". Waiting for traces to flush.");
+ synchronized (mEnabledLock) {
+ logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
mEnabled = mEnabledLockFree = false;
- synchronized (mLock) {
- if (mEnabled) {
- logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
- throw new IllegalStateException("tracing enabled while waiting for flush.");
- }
- writeTraceToFileLocked();
- mTraceBuffer = null;
+ if (mEnabled) {
+ logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
+ throw new IllegalStateException("tracing enabled while waiting for flush.");
}
- logAndPrintln(pw, "Trace written to " + mBufferBuilder.getFile() + ".");
+ writeTraceToFileLocked();
+ logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
}
}
- @VisibleForTesting
- void setContinuousMode(boolean continuous, PrintWriter pw) {
- logAndPrintln(pw, "Setting window tracing continuous mode to " + continuous);
+ private void setLogLevel(@WindowTraceLogLevel int logLevel, PrintWriter pw) {
+ logAndPrintln(pw, "Setting window tracing log level to " + logLevel);
+ mLogLevel = logLevel;
- if (mEnabled) {
- logAndPrintln(pw, "Trace is currently active, change will take effect once the "
- + "trace is restarted.");
+ switch (logLevel) {
+ case WindowTraceLogLevel.ALL: {
+ setBufferCapacity(BUFFER_CAPACITY_ALL, pw);
+ break;
+ }
+ case WindowTraceLogLevel.TRIM: {
+ setBufferCapacity(BUFFER_CAPACITY_TRIM, pw);
+ break;
+ }
+ case WindowTraceLogLevel.CRITICAL: {
+ setBufferCapacity(BUFFER_CAPACITY_CRITICAL, pw);
+ break;
+ }
}
- mContinuousMode = continuous;
- mWindowTraceLogLevel = (continuous) ? WindowTraceLogLevel.CRITICAL :
- WindowTraceLogLevel.TRIM;
}
- boolean isEnabled() {
- return mEnabledLockFree;
+ private void setLogFrequency(boolean onFrame, PrintWriter pw) {
+ logAndPrintln(pw, "Setting window tracing log frequency to "
+ + ((onFrame) ? "frame" : "transaction"));
+ mLogOnFrame = onFrame;
}
- static WindowTracing createDefaultAndStartLooper(WindowManagerService service,
- Choreographer choreographer) {
- File file = new File("/data/misc/wmtrace/wm_trace.pb");
- return new WindowTracing(file, service, choreographer);
+ private void setBufferCapacity(int capacity, PrintWriter pw) {
+ logAndPrintln(pw, "Setting window tracing buffer capacity to " + capacity + "bytes");
+ mBuffer.setCapacity(capacity);
+ }
+
+ boolean isEnabled() {
+ return mEnabledLockFree;
}
int onShellCommand(ShellCommand shell) {
PrintWriter pw = shell.getOutPrintWriter();
- try {
- String cmd = shell.getNextArgRequired();
- switch (cmd) {
- case "start":
- startTrace(pw);
- return 0;
- case "stop":
- stopTrace(pw);
- return 0;
- case "continuous":
- setContinuousMode(Boolean.valueOf(shell.getNextArgRequired()), pw);
- return 0;
- default:
- pw.println("Unknown command: " + cmd);
- return -1;
- }
- } catch (IOException e) {
- logAndPrintln(pw, e.toString());
- throw new RuntimeException(e);
+ String cmd = shell.getNextArgRequired();
+ switch (cmd) {
+ case "start":
+ startTrace(pw);
+ return 0;
+ case "stop":
+ stopTrace(pw);
+ return 0;
+ case "status":
+ logAndPrintln(pw, getStatus());
+ return 0;
+ case "frame":
+ setLogFrequency(true /* onFrame */, pw);
+ mBuffer.resetBuffer();
+ return 0;
+ case "transaction":
+ setLogFrequency(false /* onFrame */, pw);
+ mBuffer.resetBuffer();
+ return 0;
+ case "level":
+ String logLevelStr = shell.getNextArgRequired().toLowerCase();
+ switch (logLevelStr) {
+ case "all": {
+ setLogLevel(WindowTraceLogLevel.ALL, pw);
+ break;
+ }
+ case "trim": {
+ setLogLevel(WindowTraceLogLevel.TRIM, pw);
+ break;
+ }
+ case "critical": {
+ setLogLevel(WindowTraceLogLevel.CRITICAL, pw);
+ break;
+ }
+ default: {
+ setLogLevel(WindowTraceLogLevel.TRIM, pw);
+ break;
+ }
+ }
+ mBuffer.resetBuffer();
+ return 0;
+ case "size":
+ setBufferCapacity(Integer.parseInt(shell.getNextArgRequired()) * 1024, pw);
+ mBuffer.resetBuffer();
+ return 0;
+ default:
+ pw.println("Unknown command: " + cmd);
+ pw.println("Window manager trace options:");
+ pw.println(" start: Start logging");
+ pw.println(" stop: Stop logging");
+ pw.println(" frame: Log trace once per frame");
+ pw.println(" transaction: Log each transaction");
+ pw.println(" size: Set the maximum log size (in KB)");
+ pw.println(" level [lvl]: Set the log level between");
+ pw.println(" lvl may be one of:");
+ pw.println(" critical: Only visible windows with reduced information");
+ pw.println(" trim: All windows with reduced");
+ pw.println(" all: All window and information");
+ return -1;
}
}
+ private String getStatus() {
+ return "Status: "
+ + ((isEnabled()) ? "Enabled" : "Disabled")
+ + "\n"
+ + "Log level: "
+ + mLogLevel
+ + "\n"
+ + mBuffer.getStatus();
+ }
+
/**
* If tracing is enabled, log the current state or schedule the next frame to be logged,
- * according to {@link #mContinuousMode}.
+ * according to {@link #mLogOnFrame}.
*
* @param where Logging point descriptor
*/
@@ -188,7 +238,7 @@ class WindowTracing {
return;
}
- if (mContinuousMode) {
+ if (mLogOnFrame) {
schedule();
} else {
log(where);
@@ -215,25 +265,24 @@ class WindowTracing {
private void log(String where) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "traceStateLocked");
try {
- synchronized (mGlobalLock) {
- ProtoOutputStream os = new ProtoOutputStream();
- long tokenOuter = os.start(ENTRY);
- os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
- os.write(WHERE, where);
+ ProtoOutputStream os = new ProtoOutputStream();
+ long tokenOuter = os.start(ENTRY);
+ os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
+ os.write(WHERE, where);
+ long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
+ synchronized (mGlobalLock) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToProtoLocked");
try {
- long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
- mService.writeToProtoLocked(os, mWindowTraceLogLevel);
- os.end(tokenInner);
+ mService.writeToProtoLocked(os, mLogLevel);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
- os.end(tokenOuter);
- mTraceBuffer.add(os);
-
- mScheduled = false;
}
+ os.end(tokenInner);
+ os.end(tokenOuter);
+ mBuffer.add(os);
+ mScheduled = false;
} catch (Exception e) {
Log.wtf(TAG, "Exception while tracing state", e);
} finally {
@@ -242,31 +291,37 @@ class WindowTracing {
}
/**
- * Writes the trace buffer to disk. This method has no internal synchronization and should be
- * externally synchronized
+ * Writes the trace buffer to new file for the bugreport.
+ *
+ * This method is synchronized with {@code #startTrace(PrintWriter)} and
+ * {@link #stopTrace(PrintWriter)}.
*/
- private void writeTraceToFileLocked() {
- if (mTraceBuffer == null) {
- return;
+ void writeTraceToFile() {
+ synchronized (mEnabledLock) {
+ writeTraceToFileLocked();
}
+ }
- try {
- mTraceBuffer.dump();
- } catch (IOException e) {
- Log.e(TAG, "Unable to write buffer to file", e);
- } catch (InterruptedException e) {
- Log.e(TAG, "Unable to interrupt window tracing file write thread", e);
+ private void logAndPrintln(@Nullable PrintWriter pw, String msg) {
+ Log.i(TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ pw.flush();
}
}
/**
- * Writes the trace buffer to disk and clones it into a new file for the bugreport.
- * This method is synchronized with {@code #startTrace(PrintWriter)} and
- * {@link #stopTrace(PrintWriter)}.
+ * Writes the trace buffer to disk. This method has no internal synchronization and should be
+ * externally synchronized
*/
- void writeTraceToFile() {
- synchronized (mLock) {
- writeTraceToFileLocked();
+ private void writeTraceToFileLocked() {
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeTraceToFileLocked");
+ mBuffer.writeTraceToFile(mTraceFile);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to write buffer to file", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
}
-}
+} \ No newline at end of file
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 5c19ad33617c..9cbb58d35b9f 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "BatteryStatsService"
//#define LOG_NDEBUG 0
+#include <climits>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -28,6 +29,7 @@
#include <sys/types.h>
#include <unistd.h>
#include <unordered_map>
+#include <utility>
#include <android/hardware/power/1.0/IPower.h>
#include <android/hardware/power/1.1/IPower.h>
@@ -87,6 +89,15 @@ std::function<void(JNIEnv*, jobject)> gGetLowPowerStatsImpl = {};
std::function<jint(JNIEnv*, jobject)> gGetPlatformLowPowerStatsImpl = {};
std::function<jint(JNIEnv*, jobject)> gGetSubsystemLowPowerStatsImpl = {};
+// Cellular/Wifi power monitor rail information
+static jmethodID jupdateRailData = NULL;
+static jmethodID jsetRailStatsAvailability = NULL;
+
+std::function<void(JNIEnv*, jobject)> gGetRailEnergyPowerStatsImpl = {};
+
+std::unordered_map<uint32_t, std::pair<std::string, std::string>> gPowerStatsHalRailNames = {};
+static bool power_monitor_available = false;
+
// The caller must be holding gPowerHalMutex.
static void deinitPowerStatsLocked() {
gPowerStatsHalV1_0 = nullptr;
@@ -258,6 +269,7 @@ static bool initializePowerStats() {
gPowerStatsHalStateNames.clear();
gPowerStatsHalPlatformIds.clear();
gPowerStatsHalSubsystemIds.clear();
+ gPowerStatsHalRailNames.clear();
Return<void> ret;
ret = gPowerStatsHalV1_0->getPowerEntityInfo([](auto infos, auto status) {
@@ -301,6 +313,27 @@ static bool initializePowerStats() {
return false;
}
+ // Get Power monitor rails available
+ ret = gPowerStatsHalV1_0->getRailInfo([](auto rails, auto status) {
+ if (status != Status::SUCCESS) {
+ ALOGW("Rail information is not available");
+ power_monitor_available = false;
+ return;
+ }
+
+ // Fill out rail names/subsystems into gPowerStatsHalRailNames
+ for (auto rail : rails) {
+ gPowerStatsHalRailNames.emplace(rail.index,
+ std::make_pair(rail.railName, rail.subsysName));
+ }
+ if (!gPowerStatsHalRailNames.empty()) {
+ power_monitor_available = true;
+ }
+ });
+ if (!checkResultLocked(ret, __func__)) {
+ return false;
+ }
+
return (!gPowerStatsHalEntityNames.empty()) && (!gPowerStatsHalStateNames.empty());
}
@@ -517,6 +550,50 @@ static jint getPowerStatsHalSubsystemData(JNIEnv* env, jobject outBuf) {
return total_added;
}
+static void getPowerStatsHalRailEnergyData(JNIEnv* env, jobject jrailStats) {
+ using android::hardware::power::stats::V1_0::Status;
+ using android::hardware::power::stats::V1_0::EnergyData;
+
+ if (!getPowerStatsHalLocked()) {
+ ALOGE("failed to get power stats");
+ return;
+ }
+
+ if (!power_monitor_available) {
+ env->CallVoidMethod(jrailStats, jsetRailStatsAvailability, false);
+ ALOGW("Rail energy data is not available");
+ return;
+ }
+
+ // Get power rail energySinceBoot data
+ Return<void> ret = gPowerStatsHalV1_0->getEnergyData({},
+ [&env, &jrailStats](auto energyData, auto status) {
+ if (status == Status::NOT_SUPPORTED) {
+ ALOGW("getEnergyData is not supported");
+ return;
+ }
+
+ for (auto data : energyData) {
+ if (!(data.timestamp > LLONG_MAX || data.energy > LLONG_MAX)) {
+ env->CallVoidMethod(jrailStats,
+ jupdateRailData,
+ data.index,
+ env->NewStringUTF(
+ gPowerStatsHalRailNames.at(data.index).first.c_str()),
+ env->NewStringUTF(
+ gPowerStatsHalRailNames.at(data.index).second.c_str()),
+ data.timestamp,
+ data.energy);
+ } else {
+ ALOGE("Java long overflow seen. Rail index %d not updated", data.index);
+ }
+ }
+ });
+ if (!checkResultLocked(ret, __func__)) {
+ ALOGE("getEnergyData failed");
+ }
+}
+
// The caller must be holding powerHalMutex.
static void getPowerHalLowPowerData(JNIEnv* env, jobject jrpmStats) {
sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
@@ -761,11 +838,13 @@ static void setUpPowerStatsLocked() {
gGetLowPowerStatsImpl = getPowerStatsHalLowPowerData;
gGetPlatformLowPowerStatsImpl = getPowerStatsHalPlatformData;
gGetSubsystemLowPowerStatsImpl = getPowerStatsHalSubsystemData;
+ gGetRailEnergyPowerStatsImpl = getPowerStatsHalRailEnergyData;
} else if (android::hardware::power::V1_0::IPower::getService() != nullptr) {
ALOGI("Using power HAL");
gGetLowPowerStatsImpl = getPowerHalLowPowerData;
gGetPlatformLowPowerStatsImpl = getPowerHalPlatformData;
gGetSubsystemLowPowerStatsImpl = getPowerHalSubsystemData;
+ gGetRailEnergyPowerStatsImpl = NULL;
}
}
@@ -835,11 +914,44 @@ static jint getSubsystemLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject
return -1;
}
+static void getRailEnergyPowerStats(JNIEnv* env, jobject /* clazz */, jobject jrailStats) {
+ if (jrailStats == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "The railstats jni input jobject jrailStats is null.");
+ return;
+ }
+ if (jupdateRailData == NULL) {
+ ALOGE("A railstats jni jmethodID is null.");
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+
+ if (!gGetRailEnergyPowerStatsImpl) {
+ setUpPowerStatsLocked();
+ }
+
+ if (gGetRailEnergyPowerStatsImpl) {
+ gGetRailEnergyPowerStatsImpl(env, jrailStats);
+ return;
+ }
+
+ if (jsetRailStatsAvailability == NULL) {
+ ALOGE("setRailStatsAvailability jni jmethodID is null.");
+ return;
+ }
+ env->CallVoidMethod(jrailStats, jsetRailStatsAvailability, false);
+ ALOGE("Unable to load Power.Stats.HAL. Setting rail availability to false");
+ return;
+}
+
static const JNINativeMethod method_table[] = {
{ "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup },
{ "getLowPowerStats", "(Lcom/android/internal/os/RpmStats;)V", (void*)getLowPowerStats },
{ "getPlatformLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getPlatformLowPowerStats },
{ "getSubsystemLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getSubsystemLowPowerStats },
+ { "getRailEnergyPowerStats", "(Lcom/android/internal/os/RailStats;)V",
+ (void*)getRailEnergyPowerStats },
};
int register_android_server_BatteryStatsService(JNIEnv *env)
@@ -850,8 +962,9 @@ int register_android_server_BatteryStatsService(JNIEnv *env)
env->FindClass("com/android/internal/os/RpmStats$PowerStatePlatformSleepState");
jclass clsPowerStateSubsystem =
env->FindClass("com/android/internal/os/RpmStats$PowerStateSubsystem");
+ jclass clsRailStats = env->FindClass("com/android/internal/os/RailStats");
if (clsRpmStats == NULL || clsPowerStatePlatformSleepState == NULL
- || clsPowerStateSubsystem == NULL) {
+ || clsPowerStateSubsystem == NULL || clsRailStats == NULL) {
ALOGE("A rpmstats jni jclass is null.");
} else {
jgetAndUpdatePlatformState = env->GetMethodID(clsRpmStats, "getAndUpdatePlatformState",
@@ -862,6 +975,10 @@ int register_android_server_BatteryStatsService(JNIEnv *env)
"(Ljava/lang/String;JI)V");
jputState = env->GetMethodID(clsPowerStateSubsystem, "putState",
"(Ljava/lang/String;JI)V");
+ jupdateRailData = env->GetMethodID(clsRailStats, "updateRailData",
+ "(JLjava/lang/String;Ljava/lang/String;JJ)V");
+ jsetRailStatsAvailability = env->GetMethodID(clsRailStats, "setRailStatsAvailability",
+ "(Z)V");
}
return jniRegisterNativeMethods(env, "com/android/server/am/BatteryStatsService",
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 9be728bac532..ec7a78beb122 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -295,6 +295,12 @@ static void nativeSetFeature(JNIEnv* /* env */, jclass /* clazz */, jint feature
}
}
+static bool nativeForceSuspend(JNIEnv* /* env */, jclass /* clazz */) {
+ bool retval = false;
+ getSuspendControl()->forceSuspend(&retval);
+ return retval;
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gPowerManagerServiceMethods[] = {
@@ -303,6 +309,8 @@ static const JNINativeMethod gPowerManagerServiceMethods[] = {
(void*) nativeInit },
{ "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
(void*) nativeAcquireSuspendBlocker },
+ { "nativeForceSuspend", "()Z",
+ (void*) nativeForceSuspend },
{ "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
(void*) nativeReleaseSuspendBlocker },
{ "nativeSetInteractive", "(Z)V",
diff --git a/services/devicepolicy/TEST_MAPPING b/services/devicepolicy/TEST_MAPPING
new file mode 100644
index 000000000000..ab85a6873cf6
--- /dev/null
+++ b/services/devicepolicy/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "CtsDevicePolicyManagerTestCases"
+ }
+ ]
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 9523202cbb0e..ae48dad7b8f9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5181,7 +5181,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkNotNull(who, "ComponentName is null");
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
- ActiveAdmin ap = getActiveAdminForCallerLocked(
+ final ActiveAdmin ap = getActiveAdminForCallerLocked(
who, DeviceAdminInfo.USES_POLICY_FORCE_LOCK, parent);
if (ap.maximumTimeToUnlock != timeMs) {
ap.maximumTimeToUnlock = timeMs;
@@ -8388,7 +8388,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return true;
}
- Log.w(LOG_TAG, String.format("Package if %s (uid=%d, pid=%d) cannot access Device IDs",
+ Log.w(LOG_TAG, String.format("Package %s (uid=%d, pid=%d) cannot access Device IDs",
packageName, uid, pid));
return false;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a6017f2c1e86..aae159c2edcb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -36,6 +36,7 @@ import android.content.res.Configuration;
import android.content.res.Resources.Theme;
import android.database.sqlite.SQLiteCompatibilityWalFlags;
import android.database.sqlite.SQLiteGlobal;
+import android.net.NetworkStackClient;
import android.os.BaseBundle;
import android.os.Binder;
import android.os.Build;
@@ -1350,9 +1351,7 @@ public final class SystemServer {
traceBeginAndSlog("StartNetworkStack");
try {
- final android.net.NetworkStack networkStack =
- context.getSystemService(android.net.NetworkStack.class);
- networkStack.start(context);
+ NetworkStackClient.getInstance().start(context);
} catch (Throwable e) {
reportWtf("starting Network Stack", e);
}
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 638ec95ec544..8ad4d7679107 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -1,6 +1,10 @@
java_library_static {
name: "services.net",
srcs: ["java/**/*.java"],
+ static_libs: [
+ "netd_aidl_interface-java",
+ "networkstack-aidl-interfaces-java",
+ ]
}
filegroup {
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
new file mode 100644
index 000000000000..1eb7b98d801a
--- /dev/null
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.net.dhcp.DhcpServingParamsParcel;
+import android.net.dhcp.IDhcpServerCallbacks;
+import android.net.ip.IIpClientCallbacks;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+
+/**
+ * Service used to communicate with the network stack, which is running in a separate module.
+ * @hide
+ */
+public class NetworkStackClient {
+ private static final String TAG = NetworkStackClient.class.getSimpleName();
+
+ private static final int NETWORKSTACK_TIMEOUT_MS = 10_000;
+
+ private static NetworkStackClient sInstance;
+
+ @NonNull
+ @GuardedBy("mPendingNetStackRequests")
+ private final ArrayList<NetworkStackCallback> mPendingNetStackRequests = new ArrayList<>();
+ @Nullable
+ @GuardedBy("mPendingNetStackRequests")
+ private INetworkStackConnector mConnector;
+
+ private volatile boolean mNetworkStackStartRequested = false;
+
+ private interface NetworkStackCallback {
+ void onNetworkStackConnected(INetworkStackConnector connector);
+ }
+
+ private NetworkStackClient() { }
+
+ /**
+ * Get the NetworkStackClient singleton instance.
+ */
+ public static synchronized NetworkStackClient getInstance() {
+ if (sInstance == null) {
+ sInstance = new NetworkStackClient();
+ }
+ return sInstance;
+ }
+
+ /**
+ * Create a DHCP server according to the specified parameters.
+ *
+ * <p>The server will be returned asynchronously through the provided callbacks.
+ */
+ public void makeDhcpServer(final String ifName, final DhcpServingParamsParcel params,
+ final IDhcpServerCallbacks cb) {
+ requestConnector(connector -> {
+ try {
+ connector.makeDhcpServer(ifName, params, cb);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ });
+ }
+
+ /**
+ * Create an IpClient on the specified interface.
+ *
+ * <p>The IpClient will be returned asynchronously through the provided callbacks.
+ */
+ public void makeIpClient(String ifName, IIpClientCallbacks cb) {
+ requestConnector(connector -> {
+ try {
+ connector.makeIpClient(ifName, cb);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ });
+ }
+
+ /**
+ * Create a NetworkMonitor.
+ *
+ * <p>The INetworkMonitor will be returned asynchronously through the provided callbacks.
+ */
+ public void makeNetworkMonitor(
+ NetworkParcelable network, String name, INetworkMonitorCallbacks cb) {
+ requestConnector(connector -> {
+ try {
+ connector.makeNetworkMonitor(network, name, cb);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ });
+ }
+
+ private class NetworkStackConnection implements ServiceConnection {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ registerNetworkStackService(service);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ // TODO: crash/reboot the system ?
+ Slog.wtf(TAG, "Lost network stack connector");
+ }
+ };
+
+ private void registerNetworkStackService(@NonNull IBinder service) {
+ final INetworkStackConnector connector = INetworkStackConnector.Stub.asInterface(service);
+
+ ServiceManager.addService(Context.NETWORK_STACK_SERVICE, service, false /* allowIsolated */,
+ DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
+
+ final ArrayList<NetworkStackCallback> requests;
+ synchronized (mPendingNetStackRequests) {
+ requests = new ArrayList<>(mPendingNetStackRequests);
+ mPendingNetStackRequests.clear();
+ mConnector = connector;
+ }
+
+ for (NetworkStackCallback r : requests) {
+ r.onNetworkStackConnected(connector);
+ }
+ }
+
+ /**
+ * Start the network stack. Should be called only once on device startup.
+ *
+ * <p>This method will start the network stack either in the network stack process, or inside
+ * the system server on devices that do not support the network stack module. The network stack
+ * connector will then be delivered asynchronously to clients that requested it before it was
+ * started.
+ */
+ public void start(Context context) {
+ mNetworkStackStartRequested = true;
+ // Try to bind in-process if the library is available
+ IBinder connector = null;
+ try {
+ final Class service = Class.forName(
+ "com.android.server.NetworkStackService",
+ true /* initialize */,
+ context.getClassLoader());
+ connector = (IBinder) service.getMethod("makeConnector", Context.class)
+ .invoke(null, context);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ Slog.wtf(TAG, "Could not create network stack connector from NetworkStackService");
+ // TODO: crash/reboot system here ?
+ return;
+ } catch (ClassNotFoundException e) {
+ // Normal behavior if stack is provided by the app: fall through
+ }
+
+ // In-process network stack. Add the service to the service manager here.
+ if (connector != null) {
+ registerNetworkStackService(connector);
+ return;
+ }
+ // Start the network stack process. The service will be added to the service manager in
+ // NetworkStackConnection.onServiceConnected().
+ final Intent intent = new Intent(INetworkStackConnector.class.getName());
+ final ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
+ intent.setComponent(comp);
+
+ if (comp == null) {
+ Slog.wtf(TAG, "Could not resolve the network stack with " + intent);
+ // TODO: crash/reboot system server ?
+ return;
+ }
+ final PackageManager pm = context.getPackageManager();
+ int uid = -1;
+ try {
+ uid = pm.getPackageUid(comp.getPackageName(), UserHandle.USER_SYSTEM);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.wtf("Network stack package not found", e);
+ // Fall through
+ }
+ if (uid != Process.NETWORK_STACK_UID) {
+ throw new SecurityException("Invalid network stack UID: " + uid);
+ }
+
+ final int hasPermission =
+ pm.checkPermission(PERMISSION_MAINLINE_NETWORK_STACK, comp.getPackageName());
+ if (hasPermission != PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "Network stack does not have permission " + PERMISSION_MAINLINE_NETWORK_STACK);
+ }
+
+ if (!context.bindServiceAsUser(intent, new NetworkStackConnection(),
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
+ Slog.wtf(TAG,
+ "Could not bind to network stack in-process, or in app with " + intent);
+ // TODO: crash/reboot system server if no network stack after a timeout ?
+ }
+ }
+
+ /**
+ * For non-system server clients, get the connector registered by the system server.
+ */
+ private INetworkStackConnector getRemoteConnector() {
+ // Block until the NetworkStack connector is registered in ServiceManager.
+ // <p>This is only useful for non-system processes that do not have a way to be notified of
+ // registration completion. Adding a callback system would be too heavy weight considering
+ // that the connector is registered on boot, so it is unlikely that a client would request
+ // it before it is registered.
+ // TODO: consider blocking boot on registration and simplify much of the logic in this class
+ IBinder connector;
+ try {
+ final long before = System.currentTimeMillis();
+ while ((connector = ServiceManager.getService(Context.NETWORK_STACK_SERVICE)) == null) {
+ Thread.sleep(20);
+ if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
+ Slog.e(TAG, "Timeout waiting for NetworkStack connector");
+ return null;
+ }
+ }
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Error waiting for NetworkStack connector", e);
+ return null;
+ }
+
+ return INetworkStackConnector.Stub.asInterface(connector);
+ }
+
+ private void requestConnector(@NonNull NetworkStackCallback request) {
+ // TODO: PID check.
+ final int caller = Binder.getCallingUid();
+ if (caller != Process.SYSTEM_UID && !UserHandle.isSameApp(caller, Process.BLUETOOTH_UID)) {
+ // Don't even attempt to obtain the connector and give a nice error message
+ throw new SecurityException(
+ "Only the system server should try to bind to the network stack.");
+ }
+
+ if (!mNetworkStackStartRequested) {
+ // The network stack is not being started in this process, e.g. this process is not
+ // the system server. Get a remote connector registered by the system server.
+ final INetworkStackConnector connector = getRemoteConnector();
+ synchronized (mPendingNetStackRequests) {
+ mConnector = connector;
+ }
+ request.onNetworkStackConnected(connector);
+ return;
+ }
+
+ final INetworkStackConnector connector;
+ synchronized (mPendingNetStackRequests) {
+ connector = mConnector;
+ if (connector == null) {
+ mPendingNetStackRequests.add(request);
+ return;
+ }
+ }
+
+ request.onNetworkStackConnected(connector);
+ }
+}
diff --git a/services/net/java/android/net/dhcp/DhcpServerCallbacks.java b/services/net/java/android/net/dhcp/DhcpServerCallbacks.java
new file mode 100644
index 000000000000..bb56876c77f5
--- /dev/null
+++ b/services/net/java/android/net/dhcp/DhcpServerCallbacks.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.dhcp;
+
+/**
+ * Convenience wrapper around IDhcpServerCallbacks.Stub that implements getInterfaceVersion().
+ * @hide
+ */
+public abstract class DhcpServerCallbacks extends IDhcpServerCallbacks.Stub {
+ // TODO: add @Override here once the API is versioned
+
+ /**
+ * Get the version of the aidl interface implemented by the callbacks.
+ */
+ public int getInterfaceVersion() {
+ // TODO: return IDhcpServerCallbacks.VERSION;
+ return 0;
+ }
+}
diff --git a/services/net/java/android/net/ip/IpClientCallbacks.java b/services/net/java/android/net/ip/IpClientCallbacks.java
new file mode 100644
index 000000000000..db01ae4d4d9c
--- /dev/null
+++ b/services/net/java/android/net/ip/IpClientCallbacks.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import android.net.DhcpResults;
+import android.net.LinkProperties;
+
+/**
+ * Callbacks for handling IpClient events.
+ *
+ * This is a convenience class to allow clients not to override all methods of IIpClientCallbacks,
+ * and avoid unparceling arguments.
+ * These methods are called asynchronously on a Binder thread, as IpClient lives in a different
+ * process.
+ * @hide
+ */
+public class IpClientCallbacks {
+
+ /**
+ * Callback called upon IpClient creation.
+ *
+ * @param ipClient The Binder token to communicate with IpClient.
+ */
+ public void onIpClientCreated(IIpClient ipClient) {}
+
+ /**
+ * Callback called prior to DHCP discovery/renewal.
+ *
+ * <p>In order to receive onPreDhcpAction(), call #withPreDhcpAction() when constructing a
+ * ProvisioningConfiguration.
+ *
+ * <p>Implementations of onPreDhcpAction() must call IpClient#completedPreDhcpAction() to
+ * indicate that DHCP is clear to proceed.
+ */
+ public void onPreDhcpAction() {}
+
+ /**
+ * Callback called after DHCP discovery/renewal.
+ */
+ public void onPostDhcpAction() {}
+
+ /**
+ * Callback called when new DHCP results are available.
+ *
+ * <p>This is purely advisory and not an indication of provisioning success or failure. This is
+ * only here for callers that want to expose DHCPv4 results to other APIs
+ * (e.g., WifiInfo#setInetAddress).
+ *
+ * <p>DHCPv4 or static IPv4 configuration failure or success can be determined by whether or not
+ * the passed-in DhcpResults object is null.
+ */
+ public void onNewDhcpResults(DhcpResults dhcpResults) {}
+
+ /**
+ * Indicates that provisioning was successful.
+ */
+ public void onProvisioningSuccess(LinkProperties newLp) {}
+
+ /**
+ * Indicates that provisioning failed.
+ */
+ public void onProvisioningFailure(LinkProperties newLp) {}
+
+ /**
+ * Invoked on LinkProperties changes.
+ */
+ public void onLinkPropertiesChange(LinkProperties newLp) {}
+
+ /**Called when the internal IpReachabilityMonitor (if enabled) has
+ * detected the loss of a critical number of required neighbors.
+ */
+ public void onReachabilityLost(String logMsg) {}
+
+ /**
+ * Called when the IpClient state machine terminates.
+ */
+ public void onQuit() {}
+
+ /**
+ * Called to indicate that a new APF program must be installed to filter incoming packets.
+ */
+ public void installPacketFilter(byte[] filter) {}
+
+ /**
+ * Called to indicate that the APF Program & data buffer must be read asynchronously from the
+ * wifi driver.
+ *
+ * <p>Due to Wifi HAL limitations, the current implementation only supports dumping the entire
+ * buffer. In response to this request, the driver returns the data buffer asynchronously
+ * by sending an IpClient#EVENT_READ_PACKET_FILTER_COMPLETE message.
+ */
+ public void startReadPacketFilter() {}
+
+ /**
+ * If multicast filtering cannot be accomplished with APF, this function will be called to
+ * actuate multicast filtering using another means.
+ */
+ public void setFallbackMulticastFilter(boolean enabled) {}
+
+ /**
+ * Enabled/disable Neighbor Discover offload functionality. This is called, for example,
+ * whenever 464xlat is being started or stopped.
+ */
+ public void setNeighborDiscoveryOffload(boolean enable) {}
+}
diff --git a/services/net/java/android/net/ip/IpClientUtil.java b/services/net/java/android/net/ip/IpClientUtil.java
index 2a2a67a92a86..bf917bf88b2d 100644
--- a/services/net/java/android/net/ip/IpClientUtil.java
+++ b/services/net/java/android/net/ip/IpClientUtil.java
@@ -23,8 +23,7 @@ import android.content.Context;
import android.net.DhcpResultsParcelable;
import android.net.LinkProperties;
import android.net.LinkPropertiesParcelable;
-import android.net.NetworkStack;
-import android.net.ip.IIpClientCallbacks;
+import android.net.NetworkStackClient;
import android.os.ConditionVariable;
import java.io.FileDescriptor;
@@ -76,30 +75,17 @@ public class IpClientUtil {
*
* <p>This is a convenience method to allow clients to use {@link IpClientCallbacks} instead of
* {@link IIpClientCallbacks}.
- * @see {@link NetworkStack#makeIpClient(String, IIpClientCallbacks)}
+ * @see {@link NetworkStackClient#makeIpClient(String, IIpClientCallbacks)}
*/
public static void makeIpClient(Context context, String ifName, IpClientCallbacks callback) {
- context.getSystemService(NetworkStack.class)
- .makeIpClient(ifName, new IpClientCallbacksProxy(callback));
- }
-
- /**
- * Create a new IpClient.
- *
- * <p>This is a convenience method to allow clients to use {@link IpClientCallbacksProxy}
- * instead of {@link IIpClientCallbacks}.
- * @see {@link NetworkStack#makeIpClient(String, IIpClientCallbacks)}
- */
- public static void makeIpClient(
- Context context, String ifName, IpClientCallbacksProxy callback) {
- context.getSystemService(NetworkStack.class)
- .makeIpClient(ifName, callback);
+ // TODO: migrate clients and remove context argument
+ NetworkStackClient.getInstance().makeIpClient(ifName, new IpClientCallbacksProxy(callback));
}
/**
* Wrapper to relay calls from {@link IIpClientCallbacks} to {@link IpClientCallbacks}.
*/
- public static class IpClientCallbacksProxy extends IIpClientCallbacks.Stub {
+ private static class IpClientCallbacksProxy extends IIpClientCallbacks.Stub {
protected final IpClientCallbacks mCb;
/**
diff --git a/services/net/java/android/net/ip/IpServer.java b/services/net/java/android/net/ip/IpServer.java
index 7910c9a69310..34fc7354d63e 100644
--- a/services/net/java/android/net/ip/IpServer.java
+++ b/services/net/java/android/net/ip/IpServer.java
@@ -22,7 +22,6 @@ import static android.net.util.NetworkConstants.FF;
import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
import static android.net.util.NetworkConstants.asByte;
-import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.INetworkStackStatusCallback;
@@ -31,7 +30,7 @@ import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
-import android.net.NetworkStack;
+import android.net.NetworkStackClient;
import android.net.RouteInfo;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
@@ -132,10 +131,6 @@ public class IpServer extends StateMachine {
}
public static class Dependencies {
- private final Context mContext;
- public Dependencies(Context context) {
- mContext = context;
- }
public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
return new RouterAdvertisementDaemon(ifParams);
}
@@ -153,7 +148,7 @@ public class IpServer extends StateMachine {
*/
public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
DhcpServerCallbacks cb) {
- mContext.getSystemService(NetworkStack.class).makeDhcpServer(ifName, params, cb);
+ NetworkStackClient.getInstance().makeDhcpServer(ifName, params, cb);
}
}
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java
index 8df08262c9fa..8df08262c9fa 100644
--- a/services/robotests/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java
index 2af6f2bee8ff..2af6f2bee8ff 100644
--- a/services/robotests/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java
index 73baf80a2c70..73baf80a2c70 100644
--- a/services/robotests/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-refresh-intervals.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-refresh-intervals.xml
deleted file mode 100644
index 0f4e8a3ca0c6..000000000000
--- a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-refresh-intervals.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<certificates>
- <metadata>
- <serial>
- 1000
- </serial>
- <creation-time>
- 1515697631
- </creation-time>
- <refresh-interval>
- 2592000
- </refresh-interval>
- <refresh-interval>
- 2592000
- </refresh-interval>
- <previous>
- <serial>
- 0
- </serial>
- <hash>
- 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
- </hash>
- </previous>
- </metadata>
- <endpoints>
- <cert>
- MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi
- R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1
- NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW
- YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu
- tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl
- 4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21
- tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu
- HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr
- GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb
- UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe
- 33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5
- 7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ
- hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa
- 79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4
- M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf
- JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp
- BuwwuQxvQDF4pmQd
- </cert>
- </endpoints>
-</certificates>
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-refresh-interval.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file-no-refresh-interval.xml
index 3da012257d8f..3da012257d8f 100644
--- a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-refresh-interval.xml
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file-no-refresh-interval.xml
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java
index 4bac200a22c6..ebbebcb02923 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java
@@ -16,12 +16,12 @@
package com.android.server;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
+import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
+import static android.net.INetd.FIREWALL_RULE_ALLOW;
+import static android.net.INetd.FIREWALL_RULE_DENY;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
import static android.util.DebugUtils.valueToString;
import static org.junit.Assert.assertEquals;
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index bd03a8d22643..04abeca1192e 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -403,7 +403,8 @@ public class UserControllerTest {
protected int broadcastIntent(Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered,
- boolean sticky, int callingPid, int callingUid, int userId) {
+ boolean sticky, int callingPid, int callingUid, int realCallingUid,
+ int realCallingPid, int userId) {
Log.i(TAG, "broadcastIntentLocked " + intent);
mSentIntents.add(intent);
return 0;
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index a3f36b720398..3e5ce46e8e3a 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -57,6 +57,8 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.backup.utils.RandomAccessFileUtils;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -125,6 +127,7 @@ public class TrampolineTest {
private File mTestDir;
private File mSuppressFile;
private File mActivatedFile;
+ private File mRememberActivatedFile;
@Before
public void setUp() throws Exception {
@@ -153,6 +156,8 @@ public class TrampolineTest {
mActivatedFile = new File(mTestDir, "activate-" + NON_USER_SYSTEM);
TrampolineTestable.sActivatedFiles.append(NON_USER_SYSTEM, mActivatedFile);
+ mRememberActivatedFile = new File(mTestDir, "rem-activate-" + NON_USER_SYSTEM);
+ TrampolineTestable.sRememberActivatedFiles.append(NON_USER_SYSTEM, mRememberActivatedFile);
mTrampoline = new TrampolineTestable(mContextMock);
}
@@ -411,6 +416,34 @@ public class TrampolineTest {
}
@Test
+ public void setBackupServiceActive_forNonSystemUser_remembersActivated() {
+ mTrampoline.initializeService();
+
+ mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+ assertTrue(RandomAccessFileUtils.readBoolean(mRememberActivatedFile, false));
+ }
+
+ @Test
+ public void setBackupServiceActiveFalse_forNonSystemUser_remembersActivated() {
+ mTrampoline.initializeService();
+
+ mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
+
+ assertFalse(RandomAccessFileUtils.readBoolean(mRememberActivatedFile, true));
+ }
+
+ @Test
+ public void setBackupServiceActiveTwice_forNonSystemUser_remembersLastActivated() {
+ mTrampoline.initializeService();
+
+ mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+ mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, false);
+
+ assertFalse(RandomAccessFileUtils.readBoolean(mRememberActivatedFile, true));
+ }
+
+ @Test
public void dataChanged_calledBeforeInitialize_ignored() throws Exception {
mTrampoline.dataChanged(PACKAGE_NAME);
verifyNoMoreInteractions(mBackupManagerServiceMock);
@@ -1291,6 +1324,7 @@ public class TrampolineTest {
static BackupManagerService sBackupManagerServiceMock = null;
static File sSuppressFile = null;
static SparseArray<File> sActivatedFiles = new SparseArray<>();
+ static SparseArray<File> sRememberActivatedFiles = new SparseArray<>();
static UserManager sUserManagerMock = null;
private int mCreateServiceCallsCount = 0;
@@ -1314,6 +1348,11 @@ public class TrampolineTest {
}
@Override
+ protected File getRememberActivatedFileForNonSystemUser(int userId) {
+ return sRememberActivatedFiles.get(userId);
+ }
+
+ @Override
protected File getActivatedFileForNonSystemUser(int userId) {
return sActivatedFiles.get(userId);
}
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
index 0355e84d884d..5cb6cbb93b5b 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
@@ -556,16 +556,6 @@ public class IPackageManagerStub implements IPackageManager {
}
@Override
- public byte[] getPermissionGrantBackup(int userId) throws RemoteException {
- return new byte[0];
- }
-
- @Override
- public void restorePermissionGrants(byte[] backup, int userId) throws RemoteException {
-
- }
-
- @Override
public ComponentName getHomeActivities(List<ResolveInfo> outHomeCandidates)
throws RemoteException {
return null;
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/FileUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/FileUtilsTest.java
new file mode 100644
index 000000000000..eaa9c4520979
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/FileUtilsTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.utils;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.io.Files;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class FileUtilsTest {
+ private static File sTemporaryDir;
+ private File mTemporaryFile;
+
+ @BeforeClass
+ public static void setUpClass() {
+ sTemporaryDir = Files.createTempDir();
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ if (sTemporaryDir != null) {
+ sTemporaryDir.delete();
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mTemporaryFile = new File(sTemporaryDir, "fileutilstest.txt");
+ }
+
+ /** Test that if file does not exist, {@link FileUtils#createNewFile()} creates the file. */
+ @Test
+ public void testEnsureFileExists_fileDoesNotAlreadyExist_getsCreated() {
+ assertThat(!mTemporaryFile.exists());
+
+ FileUtils.createNewFile(mTemporaryFile);
+
+ assertThat(mTemporaryFile.exists());
+ }
+
+ /** Test that if file does exist, {@link FileUtils#createNewFile()} does not error out. */
+ @Test
+ public void testEnsureFileExists_fileAlreadyExists_doesNotErrorOut() throws IOException {
+ mTemporaryFile.createNewFile();
+
+ FileUtils.createNewFile(mTemporaryFile);
+
+ assertThat(mTemporaryFile.exists());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/RandomAccessFileUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/RandomAccessFileUtilsTest.java
new file mode 100644
index 000000000000..ca699bd7b85c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/RandomAccessFileUtilsTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.utils;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class RandomAccessFileUtilsTest {
+ private File mTemporaryFile;
+
+ @Before
+ public void setUp() throws Exception {
+ mTemporaryFile = File.createTempFile("fileutilstest", ".txt");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mTemporaryFile != null) {
+ mTemporaryFile.delete();
+ }
+ }
+
+ /**
+ * Test that if we write true, we read back true.
+ */
+ @Test
+ public void testWriteTrue_readReturnsTrue() {
+ RandomAccessFileUtils.writeBoolean(mTemporaryFile, true);
+
+ assertThat(RandomAccessFileUtils.readBoolean(mTemporaryFile, false)).isEqualTo(true);
+ }
+
+ /**
+ * Test that if we write false, we read back false.
+ */
+ @Test
+ public void testWriteFalse_readReturnsFalse() {
+ RandomAccessFileUtils.writeBoolean(mTemporaryFile, false);
+
+ assertThat(RandomAccessFileUtils.readBoolean(mTemporaryFile, true)).isEqualTo(false);
+ }
+
+ /**
+ * Test that if we write true twice, we read back true.
+ */
+ @Test
+ public void testWriteTrueTwice_readReturnsTrue() {
+ RandomAccessFileUtils.writeBoolean(mTemporaryFile, true);
+ RandomAccessFileUtils.writeBoolean(mTemporaryFile, true);
+
+ assertThat(RandomAccessFileUtils.readBoolean(mTemporaryFile, false)).isEqualTo(true);
+ }
+
+ /**
+ * Test that if we write false twice, we read back false.
+ */
+ @Test
+ public void testWriteFalseTwice_readReturnsFalse() {
+ RandomAccessFileUtils.writeBoolean(mTemporaryFile, false);
+ RandomAccessFileUtils.writeBoolean(mTemporaryFile, false);
+
+ assertThat(RandomAccessFileUtils.readBoolean(mTemporaryFile, true)).isEqualTo(false);
+ }
+
+ /**
+ * Test that if we write true and then false, we read back false.
+ */
+ @Test
+ public void testWriteTrueFalse_readReturnsFalse() {
+ RandomAccessFileUtils.writeBoolean(mTemporaryFile, true);
+ RandomAccessFileUtils.writeBoolean(mTemporaryFile, false);
+
+ assertThat(RandomAccessFileUtils.readBoolean(mTemporaryFile, true)).isEqualTo(false);
+ }
+
+ /**
+ * Test that if we write false and then true, we read back true.
+ */
+ @Test
+ public void testWriteFalseTrue_readReturnsTrue() {
+ RandomAccessFileUtils.writeBoolean(mTemporaryFile, false);
+ RandomAccessFileUtils.writeBoolean(mTemporaryFile, true);
+
+ assertThat(RandomAccessFileUtils.readBoolean(mTemporaryFile, false)).isEqualTo(true);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
index 5900fc57296c..01759d2e8f4a 100644
--- a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
@@ -98,6 +98,8 @@ public class ColorDisplayServiceTest {
mColorDisplayService = new ColorDisplayService(mContext);
mBinderService = mColorDisplayService.new BinderService();
+ LocalServices.addService(ColorDisplayService.ColorDisplayServiceInternal.class,
+ mColorDisplayService.new ColorDisplayServiceInternal());
}
@After
@@ -110,6 +112,8 @@ public class ColorDisplayServiceTest {
mUserId = UserHandle.USER_NULL;
mContext = null;
+
+ LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class);
}
@AfterClass
@@ -979,6 +983,99 @@ public class ColorDisplayServiceTest {
assertActiveColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
}
+ @Test
+ public void displayWhiteBalance_enable() {
+ setWhiteBalance(true /* Enable DWB Setting */);
+ setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+ mBinderService.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+ startService();
+ assertDwbActive(true);
+ }
+
+ @Test
+ public void displayWhiteBalance_disableAfterNightDisplayEnable() {
+ setWhiteBalance(true /* Enable DWB Setting */);
+
+ startService();
+ /* Enable nightlight */
+ setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+ setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ /* Since we are using FakeSettingsProvider which could not trigger observer change,
+ * force an update here.*/
+ mColorDisplayService.updateDisplayWhiteBalanceStatus();
+ assertDwbActive(false);
+ }
+
+ @Test
+ public void displayWhiteBalance_enableAfterNightDisplayDisable() {
+ setWhiteBalance(true /* Enable DWB Setting */);
+ startService();
+ /* Enable nightlight */
+ setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+ setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ mColorDisplayService.updateDisplayWhiteBalanceStatus();
+ assertDwbActive(false);
+
+ /* Disable nightlight */
+ setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+ mColorDisplayService.updateDisplayWhiteBalanceStatus();
+ assertDwbActive(true);
+ }
+
+ @Test
+ public void displayWhiteBalance_enableAfterLinearColorMode() {
+ setWhiteBalance(true /* Enable DWB Setting */);
+ setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+ startService();
+ mBinderService.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+
+ mColorDisplayService.updateDisplayWhiteBalanceStatus();
+ assertDwbActive(true);
+ }
+
+ @Test
+ public void displayWhiteBalance_setTemperatureOverMax() {
+ int max = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMax;
+
+ ColorDisplayService.ColorDisplayServiceInternal cdsInternal = LocalServices.getService(
+ ColorDisplayService.ColorDisplayServiceInternal.class);
+ cdsInternal.setDisplayWhiteBalanceColorTemperature(max+1);
+
+ assertWithMessage("Unexpected temperature set")
+ .that(mColorDisplayService.mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
+ .isEqualTo(max);
+ }
+
+ @Test
+ public void displayWhiteBalance_setTemperatureBelowMin() {
+ int min = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMin;
+
+ ColorDisplayService.ColorDisplayServiceInternal cdsInternal = LocalServices.getService(
+ ColorDisplayService.ColorDisplayServiceInternal.class);
+ cdsInternal.setDisplayWhiteBalanceColorTemperature(min - 1);
+
+ assertWithMessage("Unexpected temperature set")
+ .that(mColorDisplayService.mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
+ .isEqualTo(min);
+ }
+
+ @Test
+ public void displayWhiteBalance_setValidTemperature() {
+ int min = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMin;
+ int max = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMax;
+ int valToSet = (min + max) / 2;
+
+ ColorDisplayService.ColorDisplayServiceInternal cdsInternal = LocalServices.getService(
+ ColorDisplayService.ColorDisplayServiceInternal.class);
+ cdsInternal.setDisplayWhiteBalanceColorTemperature(valToSet);
+
+ assertWithMessage("Unexpected temperature set")
+ .that(mColorDisplayService.mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
+ .isEqualTo(valToSet);
+ }
+
/**
* Configures Night display to use a custom schedule.
*
@@ -1041,6 +1138,16 @@ public class ColorDisplayServiceTest {
}
/**
+ * Configures the Display White Balance setting state.
+ *
+ * @param state {@code true} if display white balance should be enabled
+ */
+ private void setWhiteBalance(boolean state) {
+ Secure.putIntForUser(mContext.getContentResolver(),
+ Secure.DISPLAY_WHITE_BALANCE_ENABLED, state ? 1 : 0, mUserId);
+ }
+
+ /**
* Configures color mode.
*/
private void setColorMode(int colorMode) {
@@ -1111,6 +1218,17 @@ public class ColorDisplayServiceTest {
}
/**
+ * Convenience method for asserting that the DWB active status matches expectation.
+ *
+ * @param enabled the expected active status.
+ */
+ private void assertDwbActive(boolean enabled) {
+ assertWithMessage("Incorrect Display White Balance state")
+ .that(mColorDisplayService.mDisplayWhiteBalanceTintController.isActivated())
+ .isEqualTo(enabled);
+ }
+
+ /**
* Convenience for making a {@link LocalTime} instance with an offset relative to now.
*
* @param offsetMinutes the offset relative to now (in minutes)
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java
index bbcc41113f5a..9836c64ea5b5 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java
@@ -47,7 +47,6 @@ public final class CertXmlTest {
public void parse_succeeds() throws Exception {
CertXml certXml = CertXml.parse(certXmlBytes);
assertThat(certXml.getSerial()).isEqualTo(1000L);
- assertThat(certXml.getRefreshInterval()).isEqualTo(2592000L);
}
@Test
@@ -75,27 +74,22 @@ public final class CertXmlTest {
}
@Test
- public void parse_throwsIfNoEndpointCert() throws Exception {
- CertParsingException expected =
- expectThrows(
- CertParsingException.class,
- () ->
- CertXml.parse(
- TestData.readTestFile(
- "xml/invalid-cert-file-no-endpoint-cert.xml")));
- assertThat(expected.getMessage()).contains("at least one");
+ public void parse_doesNotThrowIfNoRefreshInterval() throws Exception {
+ CertXml.parse(
+ TestData.readTestFile(
+ "xml/valid-cert-file-no-refresh-interval.xml"));
}
@Test
- public void parse_throwsIfNoRefreshInterval() throws Exception {
+ public void parse_throwsIfNoEndpointCert() throws Exception {
CertParsingException expected =
expectThrows(
CertParsingException.class,
() ->
CertXml.parse(
TestData.readTestFile(
- "xml/invalid-cert-file-no-refresh-interval.xml")));
- assertThat(expected.getMessage()).contains("exactly one");
+ "xml/invalid-cert-file-no-endpoint-cert.xml")));
+ assertThat(expected.getMessage()).contains("at least one");
}
@Test
@@ -111,19 +105,6 @@ public final class CertXmlTest {
}
@Test
- public void parse_throwsIfTwoRefreshIntervals() throws Exception {
- CertParsingException expected =
- expectThrows(
- CertParsingException.class,
- () ->
- CertXml.parse(
- TestData.readTestFile(
- "xml/invalid-cert-file-two-refresh-intervals"
- + ".xml")));
- assertThat(expected.getMessage()).contains("exactly one");
- }
-
- @Test
public void parse_throwsIfTwoSerials() throws Exception {
CertParsingException expected =
expectThrows(
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 6d28ed19af4f..50734efacac9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -55,8 +55,8 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.AtomicFile;
import com.android.server.LocalServices;
-import com.android.server.pm.permission.PermissionManagerInternal;
import com.android.server.pm.permission.PermissionManagerService;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
import org.junit.After;
import org.junit.Before;
@@ -88,7 +88,8 @@ public class PackageManagerSettingsTests {
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
Settings settings =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -103,7 +104,8 @@ public class PackageManagerSettingsTests {
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
Settings settings =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -120,7 +122,8 @@ public class PackageManagerSettingsTests {
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
Settings settings =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -143,7 +146,8 @@ public class PackageManagerSettingsTests {
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
Settings settings =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -313,7 +317,8 @@ public class PackageManagerSettingsTests {
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
Settings settings =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -507,7 +512,8 @@ public class PackageManagerSettingsTests {
public void testUpdatePackageSetting03() {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
final Settings testSettings01 =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
final SharedUserSetting testUserSetting01 = createSharedUserSetting(
@@ -625,7 +631,8 @@ public class PackageManagerSettingsTests {
public void testCreateNewSetting03() {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
final Settings testSettings01 =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
final SharedUserSetting testUserSetting01 = createSharedUserSetting(
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 48ab8d6698bd..0196279cbf56 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -568,7 +568,8 @@ public class DexManagerTests {
}
private PackageDynamicCode getPackageDynamicCodeInfo(TestData testData) {
- return mDexManager.getDexLogger().getPackageDynamicCodeInfo(testData.getPackageName());
+ return mDexManager.getDynamicCodeLogger()
+ .getPackageDynamicCodeInfo(testData.getPackageName());
}
private void assertNoUseInfo(TestData testData) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DynamicCodeLoggerTests.java
index 6da202b93065..7992ba33c8da 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DynamicCodeLoggerTests.java
@@ -53,7 +53,7 @@ import org.mockito.stubbing.Stubber;
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class DexLoggerTests {
+public class DynamicCodeLoggerTests {
private static final String OWNING_PACKAGE_NAME = "package.name";
private static final String VOLUME_UUID = "volUuid";
private static final String FILE_PATH = "/bar/foo.jar";
@@ -85,7 +85,7 @@ public class DexLoggerTests {
@Mock IPackageManager mPM;
@Mock Installer mInstaller;
- private DexLogger mDexLogger;
+ private DynamicCodeLogger mDynamicCodeLogger;
private final ListMultimap<Integer, String> mMessagesForUid = ArrayListMultimap.create();
private boolean mWriteTriggered = false;
@@ -106,7 +106,7 @@ public class DexLoggerTests {
};
// For test purposes capture log messages as well as sending to the event log.
- mDexLogger = new DexLogger(mPM, mInstaller, packageDynamicCodeLoading) {
+ mDynamicCodeLogger = new DynamicCodeLogger(mPM, mInstaller, packageDynamicCodeLoading) {
@Override
void writeDclEvent(String subtag, int uid, String message) {
super.writeDclEvent(subtag, uid, message);
@@ -131,13 +131,13 @@ public class DexLoggerTests {
whenFileIsHashed(FILE_PATH, doReturn(CONTENT_HASH_BYTES));
recordLoad(OWNING_PACKAGE_NAME, FILE_PATH);
- mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
+ mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
assertThat(mMessagesForUid.keys()).containsExactly(OWNER_UID);
assertThat(mMessagesForUid).containsEntry(OWNER_UID, EXPECTED_MESSAGE_WITH_CONTENT_HASH);
assertThat(mWriteTriggered).isFalse();
- assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading())
+ assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading())
.containsExactly(OWNING_PACKAGE_NAME);
}
@@ -146,14 +146,14 @@ public class DexLoggerTests {
whenFileIsHashed(FILE_PATH, doReturn(EMPTY_BYTES));
recordLoad(OWNING_PACKAGE_NAME, FILE_PATH);
- mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
+ mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
assertThat(mMessagesForUid.keys()).containsExactly(OWNER_UID);
assertThat(mMessagesForUid).containsEntry(OWNER_UID, EXPECTED_MESSAGE_WITHOUT_CONTENT_HASH);
// File should be removed from the DCL list, since we can't hash it.
assertThat(mWriteTriggered).isTrue();
- assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty();
+ assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty();
}
@Test
@@ -162,24 +162,24 @@ public class DexLoggerTests {
doThrow(new InstallerException("Intentional failure for test")));
recordLoad(OWNING_PACKAGE_NAME, FILE_PATH);
- mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
+ mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
assertThat(mMessagesForUid.keys()).containsExactly(OWNER_UID);
assertThat(mMessagesForUid).containsEntry(OWNER_UID, EXPECTED_MESSAGE_WITHOUT_CONTENT_HASH);
// File should be removed from the DCL list, since we can't hash it.
assertThat(mWriteTriggered).isTrue();
- assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty();
+ assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty();
}
@Test
public void testOneLoader_ownFile_unknownPath() {
recordLoad(OWNING_PACKAGE_NAME, "other/path");
- mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
+ mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
assertThat(mMessagesForUid).isEmpty();
assertThat(mWriteTriggered).isTrue();
- assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty();
+ assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty();
}
@Test
@@ -189,7 +189,7 @@ public class DexLoggerTests {
setPackageUid(OWNING_PACKAGE_NAME, -1);
recordLoad(OWNING_PACKAGE_NAME, filePath);
- mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
+ mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
assertThat(mMessagesForUid).isEmpty();
}
@@ -200,7 +200,7 @@ public class DexLoggerTests {
setPackageUid("other.package.name", 1001);
recordLoad("other.package.name", FILE_PATH);
- mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
+ mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
assertThat(mMessagesForUid.keys()).containsExactly(1001);
assertThat(mMessagesForUid).containsEntry(1001, EXPECTED_MESSAGE_WITH_CONTENT_HASH);
@@ -213,7 +213,7 @@ public class DexLoggerTests {
setPackageUid("other.package.name", -1);
recordLoad("other.package.name", FILE_PATH);
- mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
+ mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
assertThat(mMessagesForUid).isEmpty();
assertThat(mWriteTriggered).isFalse();
@@ -224,14 +224,14 @@ public class DexLoggerTests {
whenFileIsHashed(FILE_PATH, doReturn(CONTENT_HASH_BYTES));
recordLoadNative(FILE_PATH);
- mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
+ mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
assertThat(mMessagesForUid.keys()).containsExactly(OWNER_UID);
assertThat(mMessagesForUid)
.containsEntry(OWNER_UID, EXPECTED_MESSAGE_NATIVE_WITH_CONTENT_HASH);
assertThat(mWriteTriggered).isFalse();
- assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading())
+ assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading())
.containsExactly(OWNING_PACKAGE_NAME);
}
@@ -247,7 +247,7 @@ public class DexLoggerTests {
recordLoad("other.package.name1", otherDexPath);
recordLoad("other.package.name2", FILE_PATH);
recordLoad(OWNING_PACKAGE_NAME, FILE_PATH);
- mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
+ mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
assertThat(mMessagesForUid.keys()).containsExactly(1001, 1001, 1002, OWNER_UID);
assertThat(mMessagesForUid).containsEntry(1001, EXPECTED_MESSAGE_WITH_CONTENT_HASH);
@@ -256,10 +256,10 @@ public class DexLoggerTests {
assertThat(mMessagesForUid).containsEntry(OWNER_UID, EXPECTED_MESSAGE_WITH_CONTENT_HASH);
assertThat(mWriteTriggered).isTrue();
- assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading())
+ assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading())
.containsExactly(OWNING_PACKAGE_NAME);
- // Check the DexLogger caching is working
+ // Check the DynamicCodeLogger caching is working
verify(mPM, atMost(1)).getPackageInfo(OWNING_PACKAGE_NAME, /*flags*/ 0, OWNER_USER_ID);
}
@@ -267,7 +267,7 @@ public class DexLoggerTests {
public void testUnknownOwner() {
reset(mPM);
recordLoad(OWNING_PACKAGE_NAME, FILE_PATH);
- mDexLogger.logDynamicCodeLoading("other.package.name");
+ mDynamicCodeLogger.logDynamicCodeLoading("other.package.name");
assertThat(mMessagesForUid).isEmpty();
assertThat(mWriteTriggered).isFalse();
@@ -278,11 +278,11 @@ public class DexLoggerTests {
public void testUninstalledPackage() {
reset(mPM);
recordLoad(OWNING_PACKAGE_NAME, FILE_PATH);
- mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
+ mDynamicCodeLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
assertThat(mMessagesForUid).isEmpty();
assertThat(mWriteTriggered).isTrue();
- assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty();
+ assertThat(mDynamicCodeLogger.getAllPackagesWithDynamicCodeLoading()).isEmpty();
}
private void setPackageUid(String packageName, int uid) throws Exception {
@@ -295,7 +295,8 @@ public class DexLoggerTests {
}
private void recordLoad(String loadingPackageName, String dexPath) {
- mDexLogger.recordDex(OWNER_USER_ID, dexPath, OWNING_PACKAGE_NAME, loadingPackageName);
+ mDynamicCodeLogger.recordDex(
+ OWNER_USER_ID, dexPath, OWNING_PACKAGE_NAME, loadingPackageName);
mWriteTriggered = false;
}
@@ -304,7 +305,7 @@ public class DexLoggerTests {
String[] packageNames = { OWNING_PACKAGE_NAME };
when(mPM.getPackagesForUid(loadingUid)).thenReturn(packageNames);
- mDexLogger.recordNative(loadingUid, nativePath);
+ mDynamicCodeLogger.recordNative(loadingUid, nativePath);
mWriteTriggered = false;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
index 9f1cbcd7ec27..6a937fabd3ec 100644
--- a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
@@ -98,6 +98,15 @@ public class AttentionDetectorTest extends AndroidTestCase {
}
@Test
+ public void testUpdateUserActivity_schedulesTheNextCheck() {
+ long now = SystemClock.uptimeMillis();
+ mNextDimming = now;
+ mAttentionDetector.onUserActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH);
+ long nextTimeout = mAttentionDetector.updateUserActivity(mNextDimming + 5000L);
+ assertThat(nextTimeout).isEqualTo(mNextDimming + 5000L);
+ }
+
+ @Test
public void testOnUserActivity_ignoresAfterMaximumExtension() {
long now = SystemClock.uptimeMillis();
mAttentionDetector.onUserActivity(now - 15000L, PowerManager.USER_ACTIVITY_EVENT_TOUCH);
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 63341b6ea38a..911c4a2f4122 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -21,15 +21,21 @@ import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.ActivityManagerInternal;
+import android.attention.AttentionManagerInternal;
import android.content.Context;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.os.BatteryManagerInternal;
+import android.os.Binder;
import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerSaveState;
@@ -53,6 +59,9 @@ import org.junit.Rule;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* Tests for {@link com.android.server.power.PowerManagerService}
*/
@@ -67,6 +76,7 @@ public class PowerManagerServiceTest extends AndroidTestCase {
private @Mock DisplayManagerInternal mDisplayManagerInternalMock;
private @Mock BatteryManagerInternal mBatteryManagerInternalMock;
private @Mock ActivityManagerInternal mActivityManagerInternalMock;
+ private @Mock AttentionManagerInternal mAttentionManagerInternalMock;
private @Mock PowerManagerService.NativeWrapper mNativeWrapperMock;
private @Mock Notifier mNotifierMock;
private PowerManagerService mService;
@@ -93,6 +103,7 @@ public class PowerManagerServiceTest extends AndroidTestCase {
addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock);
addLocalServiceMock(BatteryManagerInternal.class, mBatteryManagerInternalMock);
addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock);
+ addLocalServiceMock(AttentionManagerInternal.class, mAttentionManagerInternalMock);
mService = new PowerManagerService(getContext(), new Injector() {
Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
@@ -210,4 +221,80 @@ public class PowerManagerServiceTest extends AndroidTestCase {
mService.onUserActivity();
assertThat(mService.wasDeviceIdleForInternal(interval)).isFalse();
}
+
+ @SmallTest
+ public void testForceSuspend_putsDeviceToSleep() {
+ mService.systemReady(null);
+ mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+
+ // Verify that we start awake
+ assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ // Grab the wakefulness value when PowerManager finally calls into the
+ // native component to actually perform the suspend.
+ when(mNativeWrapperMock.nativeForceSuspend()).then(inv -> {
+ assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ return true;
+ });
+
+ boolean retval = mService.getBinderServiceInstance().forceSuspend();
+ assertThat(retval).isTrue();
+
+ // Still asleep when the function returns.
+ assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ }
+
+ @SmallTest
+ public void testForceSuspend_pakeLocksDisabled() {
+ final String tag = "TestWakelockTag_098213";
+ final int flags = PowerManager.PARTIAL_WAKE_LOCK;
+ final String pkg = getContext().getOpPackageName();
+
+ // Set up the Notification mock to keep track of the wakelocks that are currently
+ // active or disabled. We'll use this to verify that wakelocks are disabled when
+ // they should be.
+ final Map<String, Integer> wakelockMap = new HashMap<>(1);
+ doAnswer(inv -> {
+ wakelockMap.put((String) inv.getArguments()[1], (int) inv.getArguments()[0]);
+ return null;
+ }).when(mNotifierMock).onWakeLockAcquired(anyInt(), anyString(), anyString(), anyInt(),
+ anyInt(), any(), any());
+ doAnswer(inv -> {
+ wakelockMap.remove((String) inv.getArguments()[1]);
+ return null;
+ }).when(mNotifierMock).onWakeLockReleased(anyInt(), anyString(), anyString(), anyInt(),
+ anyInt(), any(), any());
+
+ //
+ // TEST STARTS HERE
+ //
+ mService.systemReady(null);
+ mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+
+ // Verify that we start awake
+ assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ // Create a wakelock
+ mService.getBinderServiceInstance().acquireWakeLock(new Binder(), flags, tag, pkg,
+ null /* workSource */, null /* historyTag */);
+ assertThat(wakelockMap.get(tag)).isEqualTo(flags); // Verify wakelock is active.
+
+ // Confirm that the wakelocks have been disabled when the forceSuspend is in flight.
+ when(mNativeWrapperMock.nativeForceSuspend()).then(inv -> {
+ // Verify that the wakelock is disabled by the time we get to the native force
+ // suspend call.
+ assertThat(wakelockMap.containsKey(tag)).isFalse();
+ return true;
+ });
+
+ assertThat(mService.getBinderServiceInstance().forceSuspend()).isTrue();
+ assertThat(wakelockMap.get(tag)).isEqualTo(flags);
+
+ }
+
+ @SmallTest
+ public void testForceSuspend_forceSuspendFailurePropogated() {
+ when(mNativeWrapperMock.nativeForceSuspend()).thenReturn(false);
+ assertThat(mService.getBinderServiceInstance().forceSuspend()).isFalse();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 8c36905d8422..a1db3e8d8ded 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -27,9 +27,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
@@ -158,35 +155,6 @@ public class ActivityRecordTests extends ActivityTestsBase {
assertTrue(mActivity.isState(STOPPED));
}
- @Test
- public void testPositionLimitedAspectRatioNavBarBottom() {
- verifyPositionWithLimitedAspectRatio(NAV_BAR_BOTTOM, new Rect(0, 0, 1000, 2000), 1.5f,
- new Rect(0, 0, 1000, 1500));
- }
-
- @Test
- public void testPositionLimitedAspectRatioNavBarLeft() {
- verifyPositionWithLimitedAspectRatio(NAV_BAR_LEFT, new Rect(0, 0, 2000, 1000), 1.5f,
- new Rect(500, 0, 2000, 1000));
- }
-
- @Test
- public void testPositionLimitedAspectRatioNavBarRight() {
- verifyPositionWithLimitedAspectRatio(NAV_BAR_RIGHT, new Rect(0, 0, 2000, 1000), 1.5f,
- new Rect(0, 0, 1500, 1000));
- }
-
- private void verifyPositionWithLimitedAspectRatio(int navBarPosition, Rect taskBounds,
- float aspectRatio, Rect expectedActivityBounds) {
- // Verify with nav bar on the right.
- when(mService.mWindowManager.getNavBarPosition(mActivity.getDisplayId()))
- .thenReturn(navBarPosition);
- mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds);
- mActivity.info.maxAspectRatio = aspectRatio;
- ensureActivityConfiguration();
- assertEquals(expectedActivityBounds, mActivity.getBounds());
- }
-
private void ensureActivityConfiguration() {
mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index a7520dcbcff9..2627ec762d7a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -30,6 +30,7 @@ import static org.junit.Assert.assertTrue;
import android.graphics.Rect;
import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
import android.view.Display;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
@@ -48,6 +49,7 @@ import org.junit.Test;
* atest WmTests:AppChangeTransitionTests
*/
@SmallTest
+@Presubmit
public class AppChangeTransitionTests extends WindowTestsBase {
private TaskStack mStack;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index cd1320986972..1dd72ec4fd71 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -51,7 +51,6 @@ import android.platform.test.annotations.Presubmit;
import android.view.Surface;
import android.view.WindowManager;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
@@ -142,7 +141,6 @@ public class AppWindowTokenTests extends WindowTestsBase {
mToken.removeImmediately();
}
- @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
@Test
public void testLandscapeSeascapeRotationByApp() {
// Some plumbing to get the service ready for rotation updates.
@@ -303,7 +301,6 @@ public class AppWindowTokenTests extends WindowTestsBase {
}
@Test
- @FlakyTest(detail = "Promote once confirmed non-flaky")
public void testStuckExitingWindow() {
final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
"closingWindow");
@@ -346,7 +343,6 @@ public class AppWindowTokenTests extends WindowTestsBase {
assertNoStartingWindow(mToken);
}
- @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
@Test
public void testAddRemoveRace() {
// There was once a race condition between adding and removing starting windows
diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
index 3f83caea613a..1e02a12e83db 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
@@ -46,6 +46,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.platform.test.annotations.Presubmit;
import android.util.Log;
import android.view.IWindowManager;
@@ -71,6 +72,7 @@ import java.util.concurrent.TimeUnit;
* atest WmTests:AssistDataRequesterTest
*/
@MediumTest
+@Presubmit
public class AssistDataRequesterTest extends ActivityTestsBase {
private static final String TAG = AssistDataRequesterTest.class.getSimpleName();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index a62bc713db40..2452ef0425e1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -61,7 +61,6 @@ import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.view.DisplayCutout;
-import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.Surface;
@@ -87,18 +86,22 @@ import java.util.List;
* Tests for the {@link DisplayContent} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:DisplayContentTests
+ * atest WmTests:DisplayContentTests
*/
@SmallTest
@Presubmit
public class DisplayContentTests extends WindowTestsBase {
@Test
- @FlakyTest(bugId = 77772044)
+ @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
public void testForAllWindows() {
final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
mDisplayContent, "exiting app");
final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
+ // Wait until everything in animation handler get executed to prevent the exiting window
+ // from being removed during WindowSurfacePlacer Traversal.
+ waitUntilHandlersIdle();
+
exitingAppToken.mIsExiting = true;
exitingAppToken.getTask().mStack.mExitingAppTokens.add(exitingAppToken);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 198e7ce63f52..b15e99aaa8c2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -60,6 +60,7 @@ import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.wm.utils.WmDisplayCutout;
import org.junit.After;
import org.junit.Before;
@@ -113,6 +114,7 @@ public class DisplayRotationTests {
public static void setUpOnce() {
sMockWm = mock(WindowManagerService.class);
sMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class);
+ sMockWm.mPolicy = mock(WindowManagerPolicy.class);
}
@Before
@@ -807,6 +809,8 @@ public class DisplayRotationTests {
mMockDisplayContent = mock(WindowTestUtils.TestDisplayContent.class);
mMockDisplayContent.isDefaultDisplay = mIsDefaultDisplay;
+ when(mMockDisplayContent.calculateDisplayCutoutForRotation(anyInt()))
+ .thenReturn(WmDisplayCutout.NO_CUTOUT);
mMockDisplayPolicy = mock(DisplayPolicy.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index bc62e8c5ab24..2d906d1683d5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.view.InsetsState.TYPE_IME;
import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
import static android.view.InsetsState.TYPE_TOP_BAR;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static org.junit.Assert.assertEquals;
@@ -28,15 +29,33 @@ import static org.junit.Assert.assertNull;
import android.platform.test.annotations.Presubmit;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.ViewRootImpl;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.Test;
@SmallTest
@Presubmit
public class InsetsStateControllerTest extends WindowTestsBase {
+ private static int sPreviousNewInsetsMode;
+
+ @BeforeClass
+ public static void setUpOnce() {
+ // TODO: Make use of SettingsSession when it becomes feasible for this.
+ sPreviousNewInsetsMode = ViewRootImpl.sNewInsetsMode;
+ // To let the insets provider control the insets visibility, the insets mode has to be
+ // NEW_INSETS_MODE_FULL.
+ ViewRootImpl.sNewInsetsMode = NEW_INSETS_MODE_FULL;
+ }
+
+ @AfterClass
+ public static void tearDownOnce() {
+ ViewRootImpl.sNewInsetsMode = sPreviousNewInsetsMode;
+ }
@Test
public void testStripForDispatch_notOwn() {
@@ -47,7 +66,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
assertNotNull(getController().getInsetsForDispatch(app).getSource(TYPE_TOP_BAR));
}
- @FlakyTest(bugId = 69229402)
+ @FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
@Test
public void testStripForDispatch_own() {
final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
@@ -57,7 +76,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
assertEquals(new InsetsState(), getController().getInsetsForDispatch(topBar));
}
- @FlakyTest(bugId = 124088319)
+ @FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
@Test
public void testStripForDispatch_navBar() {
final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
@@ -69,7 +88,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
assertEquals(new InsetsState(), getController().getInsetsForDispatch(navBar));
}
- @FlakyTest(bugId = 124088319)
+ @FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
@Test
public void testBarControllingWinChanged() {
final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
@@ -82,7 +101,7 @@ public class InsetsStateControllerTest extends WindowTestsBase {
assertEquals(2, controls.length);
}
- @FlakyTest(bugId = 124088319)
+ @FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
@Test
public void testControlRevoked() {
final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
diff --git a/services/tests/wmtests/src/com/android/server/wm/KeyguardDisableHandlerTest.java b/services/tests/wmtests/src/com/android/server/wm/KeyguardDisableHandlerTest.java
index ce22788f7cb9..df26679dc1fb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/KeyguardDisableHandlerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/KeyguardDisableHandlerTest.java
@@ -34,6 +34,7 @@ import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
import android.util.SparseBooleanArray;
import com.android.server.wm.LockTaskController.LockTaskToken;
@@ -43,6 +44,7 @@ import org.junit.Test;
import java.lang.reflect.Constructor;
+@Presubmit
public class KeyguardDisableHandlerTest {
private KeyguardDisableHandler mKeyguardDisable;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index cc6a58a81635..763ea6293fcc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -112,8 +112,8 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
}
}
- @FlakyTest(bugId = 117117823)
@Test
+ @FlakyTest(bugId = 117117823)
public void testIncludedApps_expectTargetAndVisible() {
mWm.setRecentsAnimationController(mController);
final AppWindowToken homeAppWindow = createAppWindowToken(mDisplayContent,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index c595868db484..2377df406fbc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -34,10 +34,12 @@ import static org.junit.Assert.assertTrue;
import android.app.IActivityTaskManager;
import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
@@ -50,6 +52,8 @@ import org.junit.Test;
* atest WmTests:TaskPositionerTests
*/
@SmallTest
+@Presubmit
+@FlakyTest
public class TaskPositionerTests extends WindowTestsBase {
private static final boolean DEBUGGING = false;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index bcf9dd218835..388f98ffe4a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -24,6 +24,7 @@ import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -307,6 +308,41 @@ public class TaskRecordTests extends ActivityTestsBase {
assertEquals(fullScreenBounds, task.getBounds());
}
+ @Test
+ public void testComputeConfigResourceOverrides() {
+ final TaskRecord task = new TaskBuilder(mSupervisor).build();
+ final Configuration inOutConfig = new Configuration();
+ final Configuration parentConfig = new Configuration();
+ final int longSide = 1200;
+ final int shortSide = 600;
+ parentConfig.densityDpi = 400;
+ parentConfig.screenHeightDp = 200; // 200 * 400 / 160 = 500px
+ parentConfig.screenWidthDp = 100; // 100 * 400 / 160 = 250px
+
+ // Portrait bounds.
+ inOutConfig.windowConfiguration.getBounds().set(0, 0, shortSide, longSide);
+ // By default, the parent bounds should limit the existing input bounds.
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig);
+
+ assertEquals(parentConfig.screenHeightDp, inOutConfig.screenHeightDp);
+ assertEquals(parentConfig.screenWidthDp, inOutConfig.screenWidthDp);
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, inOutConfig.orientation);
+
+ inOutConfig.setToDefaults();
+ // Landscape bounds.
+ inOutConfig.windowConfiguration.getBounds().set(0, 0, longSide, shortSide);
+ // Without limiting to be inside the parent bounds, the out screen size should keep relative
+ // to the input bounds.
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig,
+ false /* insideParentBounds */);
+
+ assertEquals(shortSide * DENSITY_DEFAULT / parentConfig.densityDpi,
+ inOutConfig.screenHeightDp);
+ assertEquals(longSide * DENSITY_DEFAULT / parentConfig.densityDpi,
+ inOutConfig.screenWidthDp);
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, inOutConfig.orientation);
+ }
+
/** Ensures that the alias intent won't have target component resolved. */
@Test
public void testTaskIntentActivityAlias() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index dcca3167c752..42a205a2fb3d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -100,7 +100,7 @@ public class TaskStackChangedListenerTest {
}
@Test
- @FlakyTest(bugId = 119893767)
+ @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
public void testTaskDescriptionChanged() throws Exception {
final Object[] params = new Object[2];
final CountDownLatch latch = new CountDownLatch(1);
@@ -122,14 +122,18 @@ public class TaskStackChangedListenerTest {
}
}
});
- final Activity activity = startTestActivity(ActivityTaskDescriptionChange.class);
+
+ int taskId;
+ synchronized (sLock) {
+ taskId = startTestActivity(ActivityTaskDescriptionChange.class).getTaskId();
+ }
waitForCallback(latch);
- assertEquals(activity.getTaskId(), params[0]);
+ assertEquals(taskId, params[0]);
assertEquals("Test Label", ((TaskDescription) params[1]).getLabel());
}
@Test
- @FlakyTest(bugId = 119893767)
+ @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
public void testActivityRequestedOrientationChanged() throws Exception {
final int[] params = new int[2];
final CountDownLatch latch = new CountDownLatch(1);
@@ -142,9 +146,12 @@ public class TaskStackChangedListenerTest {
latch.countDown();
}
});
- final Activity activity = startTestActivity(ActivityRequestedOrientationChange.class);
+ int taskId;
+ synchronized (sLock) {
+ taskId = startTestActivity(ActivityRequestedOrientationChange.class).getTaskId();
+ }
waitForCallback(latch);
- assertEquals(activity.getTaskId(), params[0]);
+ assertEquals(taskId, params[0]);
assertEquals(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, params[1]);
}
@@ -152,7 +159,7 @@ public class TaskStackChangedListenerTest {
* Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted.
*/
@Test
- @FlakyTest(bugId = 119893767)
+ @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
public void testTaskChangeCallBacks() throws Exception {
final Object[] params = new Object[2];
final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
@@ -245,7 +252,7 @@ public class TaskStackChangedListenerTest {
private void waitForCallback(CountDownLatch latch) {
try {
- final boolean result = latch.await(2, TimeUnit.SECONDS);
+ final boolean result = latch.await(4, TimeUnit.SECONDS);
if (!result) {
throw new RuntimeException("Timed out waiting for task stack change notification");
}
@@ -324,7 +331,11 @@ public class TaskStackChangedListenerTest {
protected void onPostResume() {
super.onPostResume();
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- finish();
+ synchronized (sLock) {
+ // Hold the lock to ensure no one is trying to access fields of this Activity in
+ // this test.
+ finish();
+ }
}
}
@@ -333,7 +344,11 @@ public class TaskStackChangedListenerTest {
protected void onPostResume() {
super.onPostResume();
setTaskDescription(new TaskDescription("Test Label"));
- finish();
+ synchronized (sLock) {
+ // Hold the lock to ensure no one is trying to access fields of this Activity in
+ // this test.
+ finish();
+ }
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 3eb9085b68f6..b0e20b89b811 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -35,6 +35,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
@@ -54,7 +55,6 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doNothing;
import android.graphics.Insets;
import android.graphics.Matrix;
@@ -87,6 +87,7 @@ import java.util.LinkedList;
*/
@SmallTest
@Presubmit
+@FlakyTest(bugId = 124127512)
public class WindowStateTests extends WindowTestsBase {
private static int sPreviousNewInsetsMode;
@@ -389,6 +390,7 @@ public class WindowStateTests extends WindowTestsBase {
}
@Test
+ @FlakyTest(bugId = 74078662)
public void testLayoutSeqResetOnReparent() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
app.mLayoutSeq = 1;
@@ -445,6 +447,7 @@ public class WindowStateTests extends WindowTestsBase {
}
@Test
+ @FlakyTest(bugId = 74078662)
public void testDisplayCutoutIsCalculatedRelativeToFrame() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
WindowFrames wf = app.getWindowFrames();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
index 2b8e307e23b7..b299f0dd7253 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
@@ -36,11 +36,10 @@ import org.junit.Before;
import org.junit.Test;
import java.io.File;
-import java.io.IOException;
/**
- * Test class for {@link WindowTraceBuffer} and {@link WindowTraceQueueBuffer}.
+ * Test class for {@link WindowTraceBuffer}.
*
* Build/Install/Run:
* atest WmTests:WindowTraceBufferTest
@@ -49,12 +48,15 @@ import java.io.IOException;
@Presubmit
public class WindowTraceBufferTest {
private File mFile;
+ private WindowTraceBuffer mBuffer;
@Before
public void setUp() throws Exception {
final Context testContext = getInstrumentation().getContext();
mFile = testContext.getFileStreamPath("tracing_test.dat");
mFile.delete();
+
+ mBuffer = new WindowTraceBuffer(10);
}
@After
@@ -63,145 +65,112 @@ public class WindowTraceBufferTest {
}
@Test
- public void testTraceQueueBuffer_addItem() throws Exception {
- ProtoOutputStream toWrite1 = getDummy(1);
- ProtoOutputStream toWrite2 = getDummy(2);
- ProtoOutputStream toWrite3 = getDummy(3);
- final int objectSize = toWrite1.getRawSize();
- final int bufferCapacity = objectSize * 2;
-
- final WindowTraceBuffer buffer = buildQueueBuffer(bufferCapacity);
-
- buffer.add(toWrite1);
- byte[] toWrite1Bytes = toWrite1.getBytes();
- assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
-
- buffer.add(toWrite2);
- byte[] toWrite2Bytes = toWrite2.getBytes();
- assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
- assertTrue("Second element should be in the list",
- buffer.contains(toWrite2Bytes));
-
- buffer.add(toWrite3);
- byte[] toWrite3Bytes = toWrite3.getBytes();
- assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
- assertTrue("Second element should be in the list",
- buffer.contains(toWrite2Bytes));
- assertTrue("Third element should not be in the list",
- !buffer.contains(toWrite3Bytes));
-
- assertEquals("Buffer should have 2 elements", buffer.mBuffer.size(), 2);
- assertEquals(String.format("Buffer is full, used space should be %d", bufferCapacity),
- buffer.mBufferSize, bufferCapacity);
- assertEquals("Buffer is full, available space should be 0",
- buffer.getAvailableSpace(), 0);
- }
-
- @Test
- public void testTraceRingBuffer_addItem() throws Exception {
+ public void test_addItem() {
ProtoOutputStream toWrite = getDummy(1);
final int objectSize = toWrite.getRawSize();
+ mBuffer.setCapacity(objectSize);
+ mBuffer.resetBuffer();
- final WindowTraceBuffer buffer = buildRingBuffer(objectSize);
-
- Preconditions.checkArgument(buffer.mBuffer.isEmpty());
+ Preconditions.checkArgument(mBuffer.size() == 0);
- buffer.add(toWrite);
+ mBuffer.add(toWrite);
- assertEquals("Item was not added to the buffer", buffer.mBuffer.size(), 1);
+ assertEquals("Item was not added to the buffer", 1, mBuffer.size());
assertEquals("Total buffer getSize differs from inserted object",
- buffer.mBufferSize, objectSize);
- assertEquals("Available buffer space does not match used one",
- buffer.getAvailableSpace(), 0);
+ mBuffer.getBufferSize(), objectSize);
+ assertEquals("Available buffer space does not match used one", 0,
+ mBuffer.getAvailableSpace());
}
@Test
- public void testTraceRingBuffer_addItemMustOverwriteOne() throws Exception {
+ public void test_addItemMustOverwriteOne() {
ProtoOutputStream toWrite1 = getDummy(1);
ProtoOutputStream toWrite2 = getDummy(2);
ProtoOutputStream toWrite3 = getDummy(3);
final int objectSize = toWrite1.getRawSize();
-
final int bufferCapacity = objectSize * 2 + 1;
- final WindowTraceBuffer buffer = buildRingBuffer(bufferCapacity);
+ mBuffer.setCapacity(bufferCapacity);
+ mBuffer.resetBuffer();
- buffer.add(toWrite1);
+ mBuffer.add(toWrite1);
byte[] toWrite1Bytes = toWrite1.getBytes();
assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
+ mBuffer.contains(toWrite1Bytes));
- buffer.add(toWrite2);
+ mBuffer.add(toWrite2);
byte[] toWrite2Bytes = toWrite2.getBytes();
assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
+ mBuffer.contains(toWrite1Bytes));
assertTrue("Second element should be in the list",
- buffer.contains(toWrite2Bytes));
+ mBuffer.contains(toWrite2Bytes));
- buffer.add(toWrite3);
+ mBuffer.add(toWrite3);
byte[] toWrite3Bytes = toWrite3.getBytes();
assertTrue("First element should not be in the list",
- !buffer.contains(toWrite1Bytes));
+ !mBuffer.contains(toWrite1Bytes));
assertTrue("Second element should be in the list",
- buffer.contains(toWrite2Bytes));
+ mBuffer.contains(toWrite2Bytes));
assertTrue("Third element should be in the list",
- buffer.contains(toWrite3Bytes));
- assertEquals("Buffer should have 2 elements", buffer.mBuffer.size(), 2);
+ mBuffer.contains(toWrite3Bytes));
+ assertEquals("Buffer should have 2 elements", 2, mBuffer.size());
assertEquals(String.format("Buffer is full, used space should be %d", bufferCapacity),
- buffer.mBufferSize, bufferCapacity - 1);
- assertEquals(" Buffer is full, available space should be 0",
- buffer.getAvailableSpace(), 1);
+ mBuffer.getBufferSize(), bufferCapacity - 1);
+ assertEquals(" Buffer is full, available space should be 0", 1,
+ mBuffer.getAvailableSpace());
}
@Test
- public void testTraceRingBuffer_addItemMustOverwriteMultiple() throws Exception {
+ public void test_addItemMustOverwriteMultiple() {
ProtoOutputStream toWriteSmall1 = getDummy(1);
ProtoOutputStream toWriteSmall2 = getDummy(2);
final int objectSize = toWriteSmall1.getRawSize();
-
final int bufferCapacity = objectSize * 2;
- final WindowTraceBuffer buffer = buildRingBuffer(bufferCapacity);
+ mBuffer.setCapacity(bufferCapacity);
+ mBuffer.resetBuffer();
ProtoOutputStream toWriteBig = new ProtoOutputStream();
toWriteBig.write(MAGIC_NUMBER, 1);
toWriteBig.write(MAGIC_NUMBER, 2);
- buffer.add(toWriteSmall1);
+ mBuffer.add(toWriteSmall1);
byte[] toWriteSmall1Bytes = toWriteSmall1.getBytes();
assertTrue("First element should be in the list",
- buffer.contains(toWriteSmall1Bytes));
+ mBuffer.contains(toWriteSmall1Bytes));
- buffer.add(toWriteSmall2);
+ mBuffer.add(toWriteSmall2);
byte[] toWriteSmall2Bytes = toWriteSmall2.getBytes();
assertTrue("First element should be in the list",
- buffer.contains(toWriteSmall1Bytes));
+ mBuffer.contains(toWriteSmall1Bytes));
assertTrue("Second element should be in the list",
- buffer.contains(toWriteSmall2Bytes));
+ mBuffer.contains(toWriteSmall2Bytes));
- buffer.add(toWriteBig);
+ mBuffer.add(toWriteBig);
byte[] toWriteBigBytes = toWriteBig.getBytes();
assertTrue("Third element should overwrite all others",
- !buffer.contains(toWriteSmall1Bytes));
+ !mBuffer.contains(toWriteSmall1Bytes));
assertTrue("Third element should overwrite all others",
- !buffer.contains(toWriteSmall2Bytes));
+ !mBuffer.contains(toWriteSmall2Bytes));
assertTrue("Third element should overwrite all others",
- buffer.contains(toWriteBigBytes));
+ mBuffer.contains(toWriteBigBytes));
- assertEquals(" Buffer should have only 1 big element", buffer.mBuffer.size(), 1);
+ assertEquals(" Buffer should have only 1 big element", 1, mBuffer.size());
assertEquals(String.format(" Buffer is full, used space should be %d", bufferCapacity),
- buffer.mBufferSize, bufferCapacity);
- assertEquals(" Buffer is full, available space should be 0",
- buffer.getAvailableSpace(), 0);
+ mBuffer.getBufferSize(), bufferCapacity);
+ assertEquals(" Buffer is full, available space should be 0", 0,
+ mBuffer.getAvailableSpace());
}
- private WindowTraceBuffer buildRingBuffer(int capacity) throws IOException {
- return new WindowTraceBuffer.Builder()
- .setContinuousMode(true)
- .setBufferCapacity(capacity)
- .setTraceFile(mFile)
- .build();
+ @Test
+ public void test_startResetsBuffer() {
+ ProtoOutputStream toWrite = getDummy(1);
+ mBuffer.resetBuffer();
+ Preconditions.checkArgument(mBuffer.size() == 0);
+
+ mBuffer.add(toWrite);
+ assertEquals("Item was not added to the buffer", 1, mBuffer.size());
+ mBuffer.resetBuffer();
+ assertEquals("Buffer should be empty after reset", 0, mBuffer.size());
+ assertEquals("Buffer size should be 0 after reset", 0, mBuffer.getBufferSize());
}
private ProtoOutputStream getDummy(int value) {
@@ -212,7 +181,4 @@ public class WindowTraceBufferTest {
return toWrite;
}
- private WindowTraceBuffer buildQueueBuffer(int size) throws IOException {
- return new WindowTraceQueueBuffer(size, mFile, false);
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
index 3c6e2405adff..8358fdd18e0e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
@@ -88,8 +88,7 @@ public class WindowTracingTest {
mFile.delete();
mWindowTracing = new WindowTracing(mFile, mWmMock, mChoreographer,
- new WindowManagerGlobalLock());
- mWindowTracing.setContinuousMode(false /* continuous */, null /* pw */);
+ new WindowManagerGlobalLock(), 1024);
}
@After
@@ -103,13 +102,13 @@ public class WindowTracingTest {
}
@Test
- public void isEnabled_returnsTrueAfterStart() throws Exception {
+ public void isEnabled_returnsTrueAfterStart() {
mWindowTracing.startTrace(mock(PrintWriter.class));
assertTrue(mWindowTracing.isEnabled());
}
@Test
- public void isEnabled_returnsFalseAfterStop() throws Exception {
+ public void isEnabled_returnsFalseAfterStop() {
mWindowTracing.startTrace(mock(PrintWriter.class));
mWindowTracing.stopTrace(mock(PrintWriter.class));
assertFalse(mWindowTracing.isEnabled());
@@ -133,6 +132,8 @@ public class WindowTracingTest {
mWindowTracing.startTrace(mock(PrintWriter.class));
mWindowTracing.stopTrace(mock(PrintWriter.class));
+ assertTrue("Trace file should exist", mFile.exists());
+
byte[] header = new byte[MAGIC_HEADER.length];
try (InputStream is = new FileInputStream(mFile)) {
assertEquals(MAGIC_HEADER.length, is.read(header));
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/CoordinateTransformsTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
index 649b785c992b..99ceb2011db3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/CoordinateTransformsTest.java
@@ -31,6 +31,7 @@ import static org.junit.Assert.*;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
+import android.platform.test.annotations.Presubmit;
import android.view.DisplayInfo;
import org.junit.Before;
@@ -42,6 +43,7 @@ import org.junit.rules.ErrorCollector;
* Build/Install/Run:
* atest WmTests:CoordinateTransformsTest
*/
+@Presubmit
public class CoordinateTransformsTest {
private static final int W = 200;
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index f1ddfe4cd0d5..8feed7fdb785 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -15,7 +15,6 @@
*/
package com.android.server.usage;
-import static android.app.usage.UsageEvents.Event.ACTIVITY_DESTROYED;
import static android.app.usage.UsageEvents.Event.ACTIVITY_PAUSED;
import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED;
@@ -302,27 +301,6 @@ public class IntervalStats {
UsageStats usageStats = packageStats.valueAt(i);
usageStats.update(null, timeStamp, eventType, instanceId);
}
- } else if (eventType == ACTIVITY_DESTROYED) {
- UsageStats usageStats = packageStats.get(packageName);
- if (usageStats != null) {
- // If previous event is not ACTIVITY_STOPPED, convert ACTIVITY_DESTROYED
- // to ACTIVITY_STOPPED and add to event list.
- // Otherwise do not add anything to event list. (Because we want to save space
- // and we do not want a ACTIVITY_STOPPED followed by
- // ACTIVITY_DESTROYED in event list).
- final int index = usageStats.mActivities.indexOfKey(instanceId);
- if (index >= 0) {
- final int type = usageStats.mActivities.valueAt(index);
- if (type != ACTIVITY_STOPPED) {
- Event event = new Event(ACTIVITY_STOPPED, timeStamp);
- event.mPackage = packageName;
- event.mClass = className;
- event.mInstanceId = instanceId;
- addEvent(event);
- }
- }
- usageStats.update(className, timeStamp, ACTIVITY_DESTROYED, instanceId);
- }
} else {
UsageStats usageStats = getOrCreateUsageStats(packageName);
usageStats.update(className, timeStamp, eventType, instanceId);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index af5278f222b8..ebb0210cb553 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -145,8 +145,16 @@ public class UsageStatsService extends SystemService implements
AppTimeLimitController mAppTimeLimit;
final SparseArray<ArraySet<String>> mUsageReporters = new SparseArray();
- final SparseArray<String> mVisibleActivities = new SparseArray();
+ final SparseArray<ActivityData> mVisibleActivities = new SparseArray();
+ private static class ActivityData {
+ private final String mTaskRootPackage;
+ private final String mTaskRootClass;
+ private ActivityData(String taskRootPackage, String taskRootClass) {
+ mTaskRootPackage = taskRootPackage;
+ mTaskRootClass = taskRootClass;
+ }
+ }
private UsageStatsManagerInternal.AppIdleStateChangeListener mStandbyChangeListener =
new UsageStatsManagerInternal.AppIdleStateChangeListener() {
@@ -464,47 +472,57 @@ public class UsageStatsService extends SystemService implements
final long elapsedRealtime = SystemClock.elapsedRealtime();
convertToSystemTimeLocked(event);
- if (event.getPackageName() != null
- && mPackageManagerInternal.isPackageEphemeral(userId, event.getPackageName())) {
+ if (event.mPackage != null
+ && mPackageManagerInternal.isPackageEphemeral(userId, event.mPackage)) {
event.mFlags |= Event.FLAG_IS_PACKAGE_INSTANT_APP;
}
- final UserUsageStatsService service =
- getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- service.reportEvent(event);
-
- mAppStandby.reportEvent(event, elapsedRealtime, userId);
-
- String packageName;
-
- switch(mUsageSource) {
- case USAGE_SOURCE_CURRENT_ACTIVITY:
- packageName = event.getPackageName();
- break;
- case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
- default:
- packageName = event.getTaskRootPackageName();
- if (packageName == null) {
- packageName = event.getPackageName();
- }
- break;
- }
-
switch (event.mEventType) {
case Event.ACTIVITY_RESUMED:
- synchronized (mVisibleActivities) {
- // check if this activity has already been resumed
- if (mVisibleActivities.get(event.mInstanceId) != null) break;
- mVisibleActivities.put(event.mInstanceId, event.getClassName());
- try {
- mAppTimeLimit.noteUsageStart(packageName, userId);
- } catch (IllegalArgumentException iae) {
- Slog.e(TAG, "Failed to note usage start", iae);
+ // check if this activity has already been resumed
+ if (mVisibleActivities.get(event.mInstanceId) != null) break;
+ mVisibleActivities.put(event.mInstanceId,
+ new ActivityData(event.mTaskRootPackage, event.mTaskRootClass));
+ try {
+ switch(mUsageSource) {
+ case USAGE_SOURCE_CURRENT_ACTIVITY:
+ mAppTimeLimit.noteUsageStart(event.mPackage, userId);
+ break;
+ case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
+ default:
+ mAppTimeLimit.noteUsageStart(event.mTaskRootPackage, userId);
+ break;
+ }
+ } catch (IllegalArgumentException iae) {
+ Slog.e(TAG, "Failed to note usage start", iae);
+ }
+ break;
+ case Event.ACTIVITY_PAUSED:
+ if (event.mTaskRootPackage == null) {
+ // Task Root info is missing. Repair the event based on previous data
+ final ActivityData prevData = mVisibleActivities.get(event.mInstanceId);
+ if (prevData == null) {
+ Slog.w(TAG, "Unexpected activity event reported! (" + event.mPackage
+ + "/" + event.mClass + " event : " + event.mEventType
+ + " instanceId : " + event.mInstanceId + ")");
+ } else {
+ event.mTaskRootPackage = prevData.mTaskRootPackage;
+ event.mTaskRootClass = prevData.mTaskRootClass;
}
}
break;
- case Event.ACTIVITY_STOPPED:
case Event.ACTIVITY_DESTROYED:
+ // Treat activity destroys like activity stops.
+ event.mEventType = Event.ACTIVITY_STOPPED;
+ // Fallthrough
+ case Event.ACTIVITY_STOPPED:
+ final ActivityData prevData =
+ mVisibleActivities.removeReturnOld(event.mInstanceId);
+ if (prevData == null) {
+ // The activity stop was already handled.
+ return;
+ }
+
ArraySet<String> tokens;
synchronized (mUsageReporters) {
tokens = mUsageReporters.removeReturnOld(event.mInstanceId);
@@ -517,7 +535,7 @@ public class UsageStatsService extends SystemService implements
final String token = tokens.valueAt(i);
try {
mAppTimeLimit.noteUsageStop(
- buildFullToken(event.getPackageName(), token), userId);
+ buildFullToken(event.mPackage, token), userId);
} catch (IllegalArgumentException iae) {
Slog.w(TAG, "Failed to stop usage for during reporter death: "
+ iae);
@@ -525,18 +543,32 @@ public class UsageStatsService extends SystemService implements
}
}
}
-
- synchronized (mVisibleActivities) {
- if (mVisibleActivities.removeReturnOld(event.mInstanceId) != null) {
- try {
- mAppTimeLimit.noteUsageStop(packageName, userId);
- } catch (IllegalArgumentException iae) {
- Slog.w(TAG, "Failed to note usage stop", iae);
- }
+ if (event.mTaskRootPackage == null) {
+ // Task Root info is missing. Repair the event based on previous data
+ event.mTaskRootPackage = prevData.mTaskRootPackage;
+ event.mTaskRootClass = prevData.mTaskRootClass;
+ }
+ try {
+ switch(mUsageSource) {
+ case USAGE_SOURCE_CURRENT_ACTIVITY:
+ mAppTimeLimit.noteUsageStop(event.mPackage, userId);
+ break;
+ case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
+ default:
+ mAppTimeLimit.noteUsageStop(event.mTaskRootPackage, userId);
+ break;
}
+ } catch (IllegalArgumentException iae) {
+ Slog.w(TAG, "Failed to note usage stop", iae);
}
break;
}
+
+ final UserUsageStatsService service =
+ getUserDataAndInitializeIfNeededLocked(userId, timeNow);
+ service.reportEvent(event);
+
+ mAppStandby.reportEvent(event, elapsedRealtime, userId);
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 93f758c2a9ad..b9440ebd88f6 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1193,7 +1193,7 @@ public class VoiceInteractionManagerService extends SystemService {
}
@Override
- public void setTranscription(IVoiceInteractionService service, String transcription) {
+ public void setUiHints(IVoiceInteractionService service, Bundle hints) {
synchronized (this) {
enforceIsCurrentVoiceInteractionService(service);
@@ -1202,47 +1202,9 @@ public class VoiceInteractionManagerService extends SystemService {
final IVoiceInteractionSessionListener listener =
mVoiceInteractionSessionListeners.getBroadcastItem(i);
try {
- listener.onTranscriptionUpdate(transcription);
+ listener.onSetUiHints(hints);
} catch (RemoteException e) {
- Slog.e(TAG, "Error delivering voice transcription.", e);
- }
- }
- mVoiceInteractionSessionListeners.finishBroadcast();
- }
- }
-
- @Override
- public void clearTranscription(IVoiceInteractionService service, boolean immediate) {
- synchronized (this) {
- enforceIsCurrentVoiceInteractionService(service);
-
- final int size = mVoiceInteractionSessionListeners.beginBroadcast();
- for (int i = 0; i < size; ++i) {
- final IVoiceInteractionSessionListener listener =
- mVoiceInteractionSessionListeners.getBroadcastItem(i);
- try {
- listener.onTranscriptionComplete(immediate);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error delivering transcription complete event.", e);
- }
- }
- mVoiceInteractionSessionListeners.finishBroadcast();
- }
- }
-
- @Override
- public void setVoiceState(IVoiceInteractionService service, int state) {
- synchronized (this) {
- enforceIsCurrentVoiceInteractionService(service);
-
- final int size = mVoiceInteractionSessionListeners.beginBroadcast();
- for (int i = 0; i < size; ++i) {
- final IVoiceInteractionSessionListener listener =
- mVoiceInteractionSessionListeners.getBroadcastItem(i);
- try {
- listener.onVoiceStateChange(state);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error delivering voice state change.", e);
+ Slog.e(TAG, "Error delivering UI hints.", e);
}
}
mVoiceInteractionSessionListeners.finishBroadcast();