summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/os/OWNERS1
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java3
-rw-r--r--apex/permission/Android.bp49
-rw-r--r--apex/permission/OWNERS6
-rw-r--r--apex/permission/TEST_MAPPING7
-rw-r--r--apex/permission/apex_manifest.json4
-rw-r--r--apex/permission/com.android.permission.avbpubkeybin1032 -> 0 bytes
-rw-r--r--apex/permission/com.android.permission.pem51
-rw-r--r--apex/permission/com.android.permission.pk8bin2376 -> 0 bytes
-rw-r--r--apex/permission/com.android.permission.x509.pem35
-rw-r--r--apex/permission/framework-s/Android.bp72
-rw-r--r--apex/permission/framework-s/api/current.txt19
-rw-r--r--apex/permission/framework-s/api/module-lib-current.txt11
-rw-r--r--apex/permission/framework-s/api/module-lib-removed.txt1
-rw-r--r--apex/permission/framework-s/api/removed.txt1
-rw-r--r--apex/permission/framework-s/api/system-current.txt43
-rw-r--r--apex/permission/framework-s/api/system-removed.txt1
-rw-r--r--apex/permission/framework-s/java/android/app/role/IOnRoleHoldersChangedListener.aidl25
-rw-r--r--apex/permission/framework-s/java/android/app/role/IRoleController.aidl43
-rw-r--r--apex/permission/framework-s/java/android/app/role/IRoleManager.aidl61
-rw-r--r--apex/permission/framework-s/java/android/app/role/OnRoleHoldersChangedListener.java38
-rw-r--r--apex/permission/framework-s/java/android/app/role/RoleControllerManager.java265
-rw-r--r--apex/permission/framework-s/java/android/app/role/RoleControllerService.java304
-rw-r--r--apex/permission/framework-s/java/android/app/role/RoleFrameworkInitializer.java44
-rw-r--r--apex/permission/framework-s/java/android/app/role/RoleManager.java773
-rw-r--r--apex/permission/framework-s/java/android/app/role/TEST_MAPPING12
-rw-r--r--apex/permission/framework/Android.bp50
-rw-r--r--apex/permission/framework/api/current.txt1
-rw-r--r--apex/permission/framework/api/module-lib-current.txt1
-rw-r--r--apex/permission/framework/api/module-lib-removed.txt1
-rw-r--r--apex/permission/framework/api/removed.txt1
-rw-r--r--apex/permission/framework/api/system-current.txt1
-rw-r--r--apex/permission/framework/api/system-removed.txt1
-rw-r--r--apex/permission/framework/java/android/permission/PermissionState.java22
-rw-r--r--apex/permission/jarjar-rules.txt5
-rw-r--r--apex/permission/service/Android.bp106
-rw-r--r--apex/permission/service/api/current.txt1
-rw-r--r--apex/permission/service/api/removed.txt1
-rw-r--r--apex/permission/service/api/system-server-current.txt54
-rw-r--r--apex/permission/service/api/system-server-removed.txt1
-rw-r--r--apex/permission/service/java/com/android/permission/compat/UserHandleCompat.java48
-rw-r--r--apex/permission/service/java/com/android/permission/compat/package-info.java22
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/IoUtils.java40
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java74
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java265
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java222
-rw-r--r--apex/permission/service/java/com/android/permission/util/ArrayUtils.java70
-rw-r--r--apex/permission/service/java/com/android/permission/util/BackgroundThread.java93
-rw-r--r--apex/permission/service/java/com/android/permission/util/CollectionUtils.java72
-rw-r--r--apex/permission/service/java/com/android/permission/util/ForegroundThread.java93
-rw-r--r--apex/permission/service/java/com/android/permission/util/ThrottledRunnable.java75
-rw-r--r--apex/permission/service/java/com/android/permission/util/package-info.java22
-rw-r--r--apex/permission/service/java/com/android/role/RoleManagerLocal.java42
-rw-r--r--apex/permission/service/java/com/android/role/RoleService.java736
-rw-r--r--apex/permission/service/java/com/android/role/RoleShellCommand.java151
-rw-r--r--apex/permission/service/java/com/android/role/RoleUserState.java476
-rw-r--r--apex/permission/service/java/com/android/role/TEST_MAPPING20
-rw-r--r--apex/permission/service/java/com/android/role/package-info.java22
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesPersistence.java73
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java218
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesState.java115
-rw-r--r--apex/permission/service/proto/com/android/role/roleservice.proto56
-rw-r--r--apex/permission/testing/Android.bp25
-rw-r--r--apex/permission/testing/test_manifest.json4
-rw-r--r--apex/permission/tests/Android.bp37
-rw-r--r--apex/permission/tests/AndroidManifest.xml32
-rw-r--r--apex/permission/tests/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt110
-rw-r--r--apex/permission/tests/java/com/android/role/persistence/RolesPersistenceTest.kt101
-rw-r--r--core/api/current.txt9
-rw-r--r--core/api/system-current.txt116
-rw-r--r--core/java/android/content/integrity/OWNERS5
-rw-r--r--core/java/android/provider/CallLog.java8
-rw-r--r--core/java/android/view/SyncRtSurfaceTransactionApplier.java9
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java67
-rw-r--r--core/java/com/android/internal/os/ScreenPowerCalculator.java64
-rw-r--r--core/proto/android/os/incident.proto2
-rw-r--r--core/proto/android/server/powerstatsservice.proto3
-rw-r--r--core/tests/coretests/src/android/content/OWNERS3
-rw-r--r--core/tests/coretests/src/android/content/integrity/OWNERS1
-rw-r--r--core/tests/coretests/src/android/content/pm/OWNERS4
-rw-r--r--core/tests/coretests/src/android/content/res/OWNERS1
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java23
-rw-r--r--keystore/java/android/security/KeyStore2.java39
-rw-r--r--keystore/java/android/security/KeyStoreOperation.java3
-rw-r--r--keystore/java/android/security/KeyStoreSecurityLevel.java11
-rw-r--r--keystore/java/android/security/keystore/BackendBusyException.java37
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java5
-rw-r--r--packages/SystemUI/res/layout/long_screenshot.xml84
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java5
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java3
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java14
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java7
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ImageTile.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java185
-rw-r--r--services/core/java/com/android/server/am/PhantomProcessList.java27
-rw-r--r--services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java4
-rw-r--r--services/core/java/com/android/server/powerstats/ProtoStreamUtils.java7
-rw-r--r--services/core/java/com/android/server/vcn/VcnGatewayConnection.java113
-rw-r--r--services/core/jni/com_android_server_powerstats_PowerStatsService.cpp5
-rw-r--r--services/java/com/android/server/SystemServer.java36
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java5
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java12
-rw-r--r--telephony/java/android/telephony/TelephonyLocalConnection.java47
-rw-r--r--telephony/java/android/telephony/ims/RcsContactPresenceTuple.java144
-rw-r--r--telephony/java/android/telephony/ims/RcsContactUceCapability.java48
-rw-r--r--telephony/java/android/telephony/ims/RcsUceAdapter.java49
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl2
-rw-r--r--telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java100
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl5
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java105
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java8
-rw-r--r--tools/powerstats/PowerStatsServiceProtoParser.java2
117 files changed, 1197 insertions, 5705 deletions
diff --git a/apct-tests/perftests/core/src/android/os/OWNERS b/apct-tests/perftests/core/src/android/os/OWNERS
new file mode 100644
index 000000000000..a1719c9c31d1
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/OWNERS
@@ -0,0 +1 @@
+per-file PackageParsingPerfTest.kt = file:/services/core/java/com/android/server/pm/OWNERS \ No newline at end of file
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index d44169d16d5d..d4ee9bb813c9 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -151,8 +151,7 @@ public class AlarmManagerService extends SystemService {
static final boolean DEBUG_BG_LIMIT = localLOGV || false;
static final boolean DEBUG_STANDBY = localLOGV || false;
static final boolean RECORD_ALARMS_IN_HISTORY = true;
- // TODO (b/178484639): Turn off once allow-while-idle revamp is completed.
- static final boolean RECORD_DEVICE_IDLE_ALARMS = true;
+ static final boolean RECORD_DEVICE_IDLE_ALARMS = false;
static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
static final int TICK_HISTORY_DEPTH = 10;
diff --git a/apex/permission/Android.bp b/apex/permission/Android.bp
deleted file mode 100644
index be51143e4730..000000000000
--- a/apex/permission/Android.bp
+++ /dev/null
@@ -1,49 +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.
-
-apex {
- name: "com.android.permission",
- defaults: ["com.android.permission-defaults"],
- manifest: "apex_manifest.json",
-}
-
-apex_defaults {
- name: "com.android.permission-defaults",
- updatable: true,
- min_sdk_version: "30",
- key: "com.android.permission.key",
- certificate: ":com.android.permission.certificate",
- java_libs: [
- "framework-permission",
- "framework-permission-s",
- "service-permission",
- ],
- apps: ["PermissionController"],
-}
-
-apex_key {
- name: "com.android.permission.key",
- public_key: "com.android.permission.avbpubkey",
- private_key: "com.android.permission.pem",
-}
-
-android_app_certificate {
- name: "com.android.permission.certificate",
- certificate: "com.android.permission",
-}
-
-filegroup {
- name: "permission-jarjar-rules",
- srcs: ["jarjar-rules.txt"],
-}
diff --git a/apex/permission/OWNERS b/apex/permission/OWNERS
deleted file mode 100644
index 957e10a582a0..000000000000
--- a/apex/permission/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-svetoslavganov@google.com
-moltmann@google.com
-eugenesusla@google.com
-zhanghai@google.com
-evanseverson@google.com
-ntmyren@google.com
diff --git a/apex/permission/TEST_MAPPING b/apex/permission/TEST_MAPPING
deleted file mode 100644
index 6e67ce92a27e..000000000000
--- a/apex/permission/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "presubmit" : [
- {
- "name" : "PermissionApexTests"
- }
- ]
-}
diff --git a/apex/permission/apex_manifest.json b/apex/permission/apex_manifest.json
deleted file mode 100644
index 6350d54d695e..000000000000
--- a/apex/permission/apex_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "com.android.permission",
- "version": 309999999
-}
diff --git a/apex/permission/com.android.permission.avbpubkey b/apex/permission/com.android.permission.avbpubkey
deleted file mode 100644
index 9eaf85259637..000000000000
--- a/apex/permission/com.android.permission.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/apex/permission/com.android.permission.pem b/apex/permission/com.android.permission.pem
deleted file mode 100644
index 3d584be5440d..000000000000
--- a/apex/permission/com.android.permission.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKgIBAAKCAgEA6snt4eqoz85xiL9Sf6w1S1b9FgSHK05zYTh2JYPvQKQ3yeZp
-E6avJ6FN6XcbmkDzSd658BvUGDBSPhOlzuUO4BsoKBuLMxP6TxIQXFKidzDqY0vQ
-4qkS++bdIhUjwBP3OSZ3Czu0BiihK8GC75Abr//EyCyObGIGGfHEGANiOgrpP4X5
-+OmLzQLCjk4iE1kg+U6cRSRI/XLaoWC0TvIIuzxznrQ6r5GmzgTOwyBWyIB+bj73
-bmsweHTU+w9Y7kGOx4hO3XCLIhoBWEw0EbuW9nZmQ4sZls5Jo/CbyJlCclF11yVo
-SCf2LG/T+9pah5NOmDQ1kPbU+0iKZIV4YFHGTIhyGDE/aPOuUT05ziCGDifgHr0u
-SG1x/RLqsVh/POvNxnvP9cQFMQ08BvbEJaTTgB785iwKsvdqCfmng/SAyxSetmzP
-StXVB3fh1OoZ8vunRbQYxnmUxycVqaA96zmBx2wLvbvzKo7pZFDE6nbhnT5+MRAM
-z/VIK89W26uB4gj8sBFslqZjT0jPqsAZuvDm7swOtMwIcEolyGJuFLqlhN7UwMz2
-9y8+IpYixR+HvD1TZI9NtmuCmv3kPrWgoMZg6yvaBayTIr8RdYzi6FO/C1lLiraz
-48dH3sXWRa8cgw6VcSUwYrEBIc3sotdsupO1iOjcFybIwaee0YTZJfjvbqkCAwEA
-AQKCAgEArRnfdpaJi1xLPGTCMDsIt9kUku0XswgN7PmxsYsKFAB+2S40/jYAIRm9
-1YjpItsMA8RgFfSOdJ77o6TctCMQyo17F8bm4+uwuic5RLfv7Cx2QmsdQF8jDfFx
-y7UGPJD7znjbf76uxXOjEB2FqZX3s9TAgkzHXIUQtoQW7RVhkCWHPjxKxgd5+NY2
-FrDoUpd9xhD9CcTsw1+wbRZdGW88nL6/B50dP2AFORM2VYo8MWr6y9FEn3YLsGOC
-uu7fxBk1aUrHyl81VRkTMMROB1zkuiUk1FtzrEm+5U15rXXBFYOVe9+qeLhtuOlh
-wueDoz0pzvF/JLe24uTik6YL0Ae6SD0pFXQ2KDrdH3cUHLok3r76/yGzaDNTFjS2
-2WbQ8dEJV8veNHk8gjGpFTJIsBUlcZpmUCDHlfvVMb3+2ahQ+28piQUt5t3zqJdZ
-NDqsOHzY6BRPc+Wm85Xii/lWiQceZSee/b1Enu+nchsyXhSenBfC6bIGZReyMI0K
-KKKuVhyR6OSOiR5ZdZ/NyXGqsWy05fn/h0X9hnpETsNaNYNKWvpHLfKll+STJpf7
-AZquJPIclQyiq5NONx6kfPztoCLkKV/zOgIj3Sx5oSZq+5gpO91nXWVwkTbqK1d1
-004q2Mah6UQyAk1XGQc2pHx7ouVcWawjU30vZ4C015Hv2lm/gVkCggEBAPltATYS
-OqOSL1YAtIHPiHxMjNAgUdglq8JiJFXVfkocGU9eNub3Ed3sSWu6GB9Myu/sSKje
-bJ5DZqxJnvB2Fqmu9I9OunLGFSD0aXs4prwsQ1Rm5FcbImtrxcciASdkoo8Pj0z4
-vk2r2NZD3VtER5Uh+YjSDkxcS9gBStXUpCL6gj69UpOxMmWqZVjyHatVB4lEvYJl
-N82uT7N7QVNL1DzcZ9z4C4r7ks1Pm7ka12s5m/oaAlAMdVeofiPJe1xA9zRToSr4
-tIbMkOeXFLVRLuji/7XsOgal5Rl59p+OwLshX5cswPVOMrH6zt+hbsJ5q8M5dqnX
-VAOBK7KNQ/EKZwcCggEBAPD6KVvyCim46n5EbcEqCkO7gevwZkw/9vLwmM5YsxTh
-z9FQkPO0iB7mwbX8w04I91Pre4NdfcgMG0pP1b13Sb4KHBchqW1a+TCs3kSGC6gn
-1SxmXHnA9jRxAkrWlGkoAQEz+aP61cXiiy2tXpQwJ8xQCKprfoqWZwhkCtEVU6CE
-S7v9cscOHIqgNxx4WoceMmq4EoihHAZzHxTcNVbByckMjb2XQJ0iNw3lDP4ddvc+
-a4HzHfHkhzeQ5ZNc8SvWU8z80aSCOKRsSD3aUTZzxhZ4O2tZSW7v7p+FpvVee7bC
-g8YCfszTdpVUMlLRLjScimAcovcFLSvtyupinxWg4M8CggEAN9YGEmOsSte7zwXj
-YrfhtumwEBtcFwX/2Ej+F1Tuq4p0xAa0RaoDjumJWhtTsRYQy/raHSuFpzwxbNoi
-QXQ+CIhI6RfXtz/OlQ0B2/rHoJJMFEXgUfuaDfAXW0eqeHYXyezSyIlamKqipPyW
-Pgsf9yue39keKEv1EorfhNTQVaA8rezV4oglXwrxGyNALw2e3UTNI7ai8mFWKDis
-XAg6n9E7UwUYGGnO6DUtCBgRJ0jDOQ6/e8n+LrxiWIKPIgzNCiK6jpMUXqTGv4Fb
-umdNGAdQ9RnHt5tFmRlrczaSwJFtA7uaCpAR2zPpQbiywchZAiAIB2dTwGEXNiZX
-kksg2wKCAQEA6pNad3qhkgPDoK6T+Jkn7M82paoaqtcJWWwEE7oceZNnbWZz9Agl
-CY+vuawXonrv5+0vCq2Tp4zBdBFLC2h3jFrjBVFrUFxifpOIukOSTVqZFON/2bWQ
-9XOcu6UuSz7522Xw+UNPnZXtzcUacD6AP08ZYGvLfrTyDyTzspyED5k48ALEHCkM
-d5WGkFxII4etpF0TDZVnZo/iDbhe49k4yFFEGO6Ho26PESOLBkNAb2V/2bwDxlij
-l9+g21Z6HiZA5SamHPH2mXgeyrcen1cL2QupK9J6vVcqfnboE6qp2zp2c+Yx8MlY
-gfy4EA44YFaSDQVTTgrn8f9Eq+zc130H2QKCAQEAqOKgv68nIPdDSngNyCVyWego
-boFiDaEJoBBg8FrBjTJ6wFLrNAnXmbvfTtgNmNAzF1cUPJZlIIsHgGrMCfpehbXq
-WQQIw+E+yFbTGLxseGRfsLrV0CsgnAoOVeod+yIHmqc3livaUbrWhL1V2f6Ue+sE
-7YLp/iP43NaMfA4kYk2ep7+ZJoEVkCjHJJaHWgAG3RynPJHkTJlSgu7wLYvGc9uE
-ZsEFUM46lX02t7rrtMfasVGrUy1c2xOxFb4v1vG6iEZ7+YWeq5o3AkxUwEGn+mG4
-/3p+k4AaTXJDXgyZ0Sv6CkGuPHenAYG4cswcUUEf/G4Ag77x6LBNMgycJBxUJA==
------END RSA PRIVATE KEY-----
diff --git a/apex/permission/com.android.permission.pk8 b/apex/permission/com.android.permission.pk8
deleted file mode 100644
index d51673dbc2fc..000000000000
--- a/apex/permission/com.android.permission.pk8
+++ /dev/null
Binary files differ
diff --git a/apex/permission/com.android.permission.x509.pem b/apex/permission/com.android.permission.x509.pem
deleted file mode 100644
index 4b146c9edd4f..000000000000
--- a/apex/permission/com.android.permission.x509.pem
+++ /dev/null
@@ -1,35 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIGKzCCBBOgAwIBAgIUezo3fQeVZsmLpm/dkpGWJ/G/MN8wDQYJKoZIhvcNAQEL
-BQAwgaMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
-DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
-b2lkMR8wHQYDVQQDDBZjb20uYW5kcm9pZC5wZXJtaXNzaW9uMSIwIAYJKoZIhvcN
-AQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMCAXDTE5MTAwOTIxMzExOVoYDzQ3NTcw
-OTA0MjEzMTE5WjCBozELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx
-FjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0FuZHJvaWQxEDAOBgNV
-BAsMB0FuZHJvaWQxHzAdBgNVBAMMFmNvbS5hbmRyb2lkLnBlcm1pc3Npb24xIjAg
-BgkqhkiG9w0BCQEWE2FuZHJvaWRAYW5kcm9pZC5jb20wggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQCxefguRJ7E6tBCTEOeU2HJEGs6AQQapLz9hMed0aaJ
-Qr7aTQiYJEk+sG4+jPYbjpxa8JDDzJHp+4g7DjfSb+dvT9n84A8lWaI/yRXTZTQN
-Hu5m/bgHhi0LbySpiaFyodXBKUAnOhZyGPtYjtBFywFylueub8ryc1Z6UxxU7udH
-1mkIr7sE48Qkq5SyjFROE96iFmYA+vS/JXOfS0NBHiMB4GBxx4V7kXpvrTI7hhZG
-HiyhKvNh7wyHIhO9nDEw1rwtAH6CsL3YkQEVBeAU98m+0Au+qStLYkKHh2l8zT4W
-7sVK1VSqfB+VqOUmeIGdzlBfqMsoXD+FJz6KnIdUHIwjFDjL7Xr+hd+7xve+Q3S+
-U3Blk/U6atY8PM09wNfilG+SvwcKk5IgriDcu3rWKgIFxbUUaxLrDW7pLlu6wt/d
-GGtKK+Bc0jF+9Z901Tl33i5xhc5yOktT0btkKs7lSeE6VzP/Nk5g0SuzixmuRoh9
-f5Ge41N2ZCEHNXx3wZeVZwHIIPfYrL7Yql1Xoxbfs4ETFk6ChzVQcvjfDQQuK58J
-uNc+TOCoI/qflXwGCwpuHl0ier8V5Z4tpMUl5rWyVR/QGRtLPvs2lLuxczDw1OXq
-wEVtCMn9aNnd4y7R9PZ52hi53HAvDjpWefrLYi+Q04J6iGFQ1qAFBClK9DquBvmR
-swIDAQABo1MwUTAdBgNVHQ4EFgQULpfus5s5SrqLkoUKyPXA0D1iHPMwHwYDVR0j
-BBgwFoAULpfus5s5SrqLkoUKyPXA0D1iHPMwDwYDVR0TAQH/BAUwAwEB/zANBgkq
-hkiG9w0BAQsFAAOCAgEAjxQG5EFv8V/9yV2glI53VOmlWMjfEgvUjd39s/XLyPlr
-OzPOKSB0NFo8To3l4l+MsManxPK8y0OyfEVKbWVz9onv0ovo5MVokBmV/2G0jmsV
-B4e9yjOq+DmqIvY/Qh63Ywb97sTgcFI8620MhQDbh2IpEGv4ZNV0H6rgXmgdSCBw
-1EjBoYfFpN5aMgZjeyzZcq+d1IapdWqdhuEJQkMvoYS4WIumNIJlEXPQRoq/F5Ih
-nszdbKI/jVyiGFa2oeZ3rja1Y6GCRU8TYEoKx1pjS8uQDOEDTwsG/QnUe9peEj0V
-SsCkIidJWTomAmq9Tub9vpBe1zuTpuRAwxwR0qwgSxozV1Mvow1dJ19oFtHX0yD6
-ZjCpRn5PW9kMvSWSlrcrFs1NJf0j1Cvf7bHpkEDqLqpMnnh9jaFQq3nzDY+MWcIR
-jDcgQpI+AiE2/qtauZnFEVhbce49nCnk9+5bpTTIZJdzqeaExe5KXHwEtZLaEDh4
-atLY9LuEvPsjmDIMOR6hycD9FvwGXhJOQBjESIWFwigtSb1Yud9n6201jw3MLJ4k
-+WhkbmZgWy+xc+Mdm5H3XyB1lvHaHGkxu+QB9KyQuVQKwbUVcbwZIfTFPN6Zr/dS
-ZXJqAbBhG/dBgF0LazuLaPVpibi+a3Y+tb9b8eXGkz4F97PWZIEDkELQ+9KOvhc=
------END CERTIFICATE-----
diff --git a/apex/permission/framework-s/Android.bp b/apex/permission/framework-s/Android.bp
deleted file mode 100644
index e71cc43f13fe..000000000000
--- a/apex/permission/framework-s/Android.bp
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (C) 2021 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.
-
-filegroup {
- name: "framework-permission-s-sources",
- srcs: [
- "java/**/*.java",
- "java/**/*.aidl",
- ],
- path: "java",
- visibility: ["//frameworks/base"],
-}
-
-java_library {
- name: "framework-permission-s-shared",
- srcs: [":framework-permission-s-shared-srcs"],
- libs: [
- "framework-annotations-lib",
- "unsupportedappusage",
- ],
- apex_available: [
- "com.android.permission",
- "test_com.android.permission",
- ],
- installable: false,
- min_sdk_version: "30",
- sdk_version: "module_current",
-}
-
-java_sdk_library {
- name: "framework-permission-s",
- defaults: ["framework-module-defaults"],
- srcs: [
- ":framework-permission-s-sources",
- ],
- libs: [
- "framework-annotations-lib"
- ],
- static_libs: [
- "framework-permission-s-shared",
- ],
- apex_available: [
- "com.android.permission",
- "test_com.android.permission",
- ],
- hostdex: true,
- // Restrict access to implementation library.
- impl_library_visibility: [
- "//frameworks/base/apex/permission:__subpackages__",
- "//packages/modules/Permission:__subpackages__",
- ],
- installable: true,
- jarjar_rules: ":permission-jarjar-rules",
- min_sdk_version: "30",
- permitted_packages: [
- "android.permission",
- "android.app.role",
- // For com.android.permission.jarjar.
- "com.android.permission",
- ],
-}
diff --git a/apex/permission/framework-s/api/current.txt b/apex/permission/framework-s/api/current.txt
deleted file mode 100644
index 4ecc98980c43..000000000000
--- a/apex/permission/framework-s/api/current.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-// Signature format: 2.0
-package android.app.role {
-
- public final class RoleManager {
- method @NonNull public android.content.Intent createRequestRoleIntent(@NonNull String);
- method public boolean isRoleAvailable(@NonNull String);
- method public boolean isRoleHeld(@NonNull String);
- field public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
- field public static final String ROLE_BROWSER = "android.app.role.BROWSER";
- field public static final String ROLE_CALL_REDIRECTION = "android.app.role.CALL_REDIRECTION";
- field public static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING";
- field public static final String ROLE_DIALER = "android.app.role.DIALER";
- field public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
- field public static final String ROLE_HOME = "android.app.role.HOME";
- field public static final String ROLE_SMS = "android.app.role.SMS";
- }
-
-}
-
diff --git a/apex/permission/framework-s/api/module-lib-current.txt b/apex/permission/framework-s/api/module-lib-current.txt
deleted file mode 100644
index d7c9a2395c04..000000000000
--- a/apex/permission/framework-s/api/module-lib-current.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-// Signature format: 2.0
-package android.app.role {
-
- public final class RoleManager {
- method @Nullable public String getBrowserRoleHolder(int);
- method @Nullable public String getSmsRoleHolder(int);
- method @Nullable @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS) public boolean setBrowserRoleHolder(@Nullable String, int);
- }
-
-}
-
diff --git a/apex/permission/framework-s/api/module-lib-removed.txt b/apex/permission/framework-s/api/module-lib-removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework-s/api/module-lib-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework-s/api/removed.txt b/apex/permission/framework-s/api/removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework-s/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework-s/api/system-current.txt b/apex/permission/framework-s/api/system-current.txt
deleted file mode 100644
index 6778d4826841..000000000000
--- a/apex/permission/framework-s/api/system-current.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-// Signature format: 2.0
-package android.app.role {
-
- public interface OnRoleHoldersChangedListener {
- method public void onRoleHoldersChanged(@NonNull String, @NonNull android.os.UserHandle);
- }
-
- @Deprecated public abstract class RoleControllerService extends android.app.Service {
- ctor @Deprecated public RoleControllerService();
- method @Deprecated @WorkerThread public abstract boolean onAddRoleHolder(@NonNull String, @NonNull String, int);
- method @Deprecated @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
- method @Deprecated @WorkerThread public abstract boolean onClearRoleHolders(@NonNull String, int);
- method @Deprecated @WorkerThread public abstract boolean onGrantDefaultRoles();
- method @Deprecated public abstract boolean onIsApplicationQualifiedForRole(@NonNull String, @NonNull String);
- method @Deprecated public boolean onIsApplicationVisibleForRole(@NonNull String, @NonNull String);
- method @Deprecated public abstract boolean onIsRoleVisible(@NonNull String);
- method @Deprecated @WorkerThread public abstract boolean onRemoveRoleHolder(@NonNull String, @NonNull String, int);
- field @Deprecated public static final String SERVICE_INTERFACE = "android.app.role.RoleControllerService";
- }
-
- public class RoleFrameworkInitializer {
- method public static void registerServiceWrappers();
- }
-
- public final class RoleManager {
- method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void addOnRoleHoldersChangedListenerAsUser(@NonNull java.util.concurrent.Executor, @NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @Deprecated @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @Deprecated @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isApplicationVisibleForRole(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isRoleVisible(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @Deprecated @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
- method @Deprecated @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>);
- field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1
- }
-
-}
-
diff --git a/apex/permission/framework-s/api/system-removed.txt b/apex/permission/framework-s/api/system-removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework-s/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework-s/java/android/app/role/IOnRoleHoldersChangedListener.aidl b/apex/permission/framework-s/java/android/app/role/IOnRoleHoldersChangedListener.aidl
deleted file mode 100644
index 6cf961fad2c4..000000000000
--- a/apex/permission/framework-s/java/android/app/role/IOnRoleHoldersChangedListener.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.app.role;
-
-/**
- * @hide
- */
-oneway interface IOnRoleHoldersChangedListener {
-
- void onRoleHoldersChanged(String roleName, int userId);
-}
diff --git a/apex/permission/framework-s/java/android/app/role/IRoleController.aidl b/apex/permission/framework-s/java/android/app/role/IRoleController.aidl
deleted file mode 100644
index 8a43d7fa9036..000000000000
--- a/apex/permission/framework-s/java/android/app/role/IRoleController.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.app.role;
-
-import android.os.RemoteCallback;
-
-/**
- * @hide
- */
-oneway interface IRoleController {
-
- void grantDefaultRoles(in RemoteCallback callback);
-
- void onAddRoleHolder(in String roleName, in String packageName, int flags,
- in RemoteCallback callback);
-
- void onRemoveRoleHolder(in String roleName, in String packageName, int flags,
- in RemoteCallback callback);
-
- void onClearRoleHolders(in String roleName, int flags, in RemoteCallback callback);
-
- void isApplicationQualifiedForRole(in String roleName, in String packageName,
- in RemoteCallback callback);
-
- void isApplicationVisibleForRole(in String roleName, in String packageName,
- in RemoteCallback callback);
-
- void isRoleVisible(in String roleName, in RemoteCallback callback);
-}
diff --git a/apex/permission/framework-s/java/android/app/role/IRoleManager.aidl b/apex/permission/framework-s/java/android/app/role/IRoleManager.aidl
deleted file mode 100644
index 5fc25f0422e2..000000000000
--- a/apex/permission/framework-s/java/android/app/role/IRoleManager.aidl
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.app.role;
-
-import android.app.role.IOnRoleHoldersChangedListener;
-import android.os.Bundle;
-import android.os.RemoteCallback;
-
-/**
- * @hide
- */
-interface IRoleManager {
-
- boolean isRoleAvailable(in String roleName);
-
- boolean isRoleHeld(in String roleName, in String packageName);
-
- List<String> getRoleHoldersAsUser(in String roleName, int userId);
-
- void addRoleHolderAsUser(in String roleName, in String packageName, int flags, int userId,
- in RemoteCallback callback);
-
- void removeRoleHolderAsUser(in String roleName, in String packageName, int flags, int userId,
- in RemoteCallback callback);
-
- void clearRoleHoldersAsUser(in String roleName, int flags, int userId,
- in RemoteCallback callback);
-
- void addOnRoleHoldersChangedListenerAsUser(IOnRoleHoldersChangedListener listener, int userId);
-
- void removeOnRoleHoldersChangedListenerAsUser(IOnRoleHoldersChangedListener listener,
- int userId);
-
- void setRoleNamesFromController(in List<String> roleNames);
-
- boolean addRoleHolderFromController(in String roleName, in String packageName);
-
- boolean removeRoleHolderFromController(in String roleName, in String packageName);
-
- List<String> getHeldRolesFromController(in String packageName);
-
- String getBrowserRoleHolder(int userId);
-
- boolean setBrowserRoleHolder(String packageName, int userId);
-
- String getSmsRoleHolder(int userId);
-}
diff --git a/apex/permission/framework-s/java/android/app/role/OnRoleHoldersChangedListener.java b/apex/permission/framework-s/java/android/app/role/OnRoleHoldersChangedListener.java
deleted file mode 100644
index 5958debc86dd..000000000000
--- a/apex/permission/framework-s/java/android/app/role/OnRoleHoldersChangedListener.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.app.role;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.UserHandle;
-
-/**
- * Listener for role holder changes.
- *
- * @hide
- */
-@SystemApi
-public interface OnRoleHoldersChangedListener {
-
- /**
- * Called when the holders of roles are changed.
- *
- * @param roleName the name of the role whose holders are changed
- * @param user the user for this role holder change
- */
- void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user);
-}
diff --git a/apex/permission/framework-s/java/android/app/role/RoleControllerManager.java b/apex/permission/framework-s/java/android/app/role/RoleControllerManager.java
deleted file mode 100644
index 93a7ae0c82c0..000000000000
--- a/apex/permission/framework-s/java/android/app/role/RoleControllerManager.java
+++ /dev/null
@@ -1,265 +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 android.app.role;
-
-import android.Manifest;
-import android.annotation.CallbackExecutor;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.RemoteCallback;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.AndroidFuture;
-import com.android.internal.infra.ServiceConnector;
-
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-
-/**
- * Interface for communicating with the role controller.
- *
- * @hide
- */
-public class RoleControllerManager {
-
- private static final String LOG_TAG = RoleControllerManager.class.getSimpleName();
-
- private static final long REQUEST_TIMEOUT_MILLIS = 15 * 1000;
-
- private static volatile ComponentName sRemoteServiceComponentName;
-
- private static final Object sRemoteServicesLock = new Object();
-
- /**
- * Global remote services (per user) used by all {@link RoleControllerManager managers}.
- */
- @GuardedBy("sRemoteServicesLock")
- private static final SparseArray<ServiceConnector<IRoleController>> sRemoteServices =
- new SparseArray<>();
-
- @NonNull
- private final ServiceConnector<IRoleController> mRemoteService;
-
- /**
- * Initialize the remote service component name once so that we can avoid acquiring the
- * PackageManagerService lock in constructor.
- *
- * @see #createWithInitializedRemoteServiceComponentName(Handler, Context)
- *
- * @hide
- */
- public static void initializeRemoteServiceComponentName(@NonNull Context context) {
- sRemoteServiceComponentName = getRemoteServiceComponentName(context);
- }
-
- /**
- * Create a {@link RoleControllerManager} instance with the initialized remote service component
- * name so that we can avoid acquiring the PackageManagerService lock in constructor.
- *
- * @see #initializeRemoteServiceComponentName(Context)
- *
- * @hide
- */
- @NonNull
- public static RoleControllerManager createWithInitializedRemoteServiceComponentName(
- @NonNull Handler handler, @NonNull Context context) {
- return new RoleControllerManager(sRemoteServiceComponentName, handler, context);
- }
-
- private RoleControllerManager(@NonNull ComponentName remoteServiceComponentName,
- @NonNull Handler handler, @NonNull Context context) {
- synchronized (sRemoteServicesLock) {
- int userId = context.getUser().getIdentifier();
- ServiceConnector<IRoleController> remoteService = sRemoteServices.get(userId);
- if (remoteService == null) {
- remoteService = new ServiceConnector.Impl<IRoleController>(context,
- new Intent(RoleControllerService.SERVICE_INTERFACE)
- .setComponent(remoteServiceComponentName),
- 0 /* bindingFlags */, userId, IRoleController.Stub::asInterface) {
-
- @Override
- protected Handler getJobHandler() {
- return handler;
- }
- };
- sRemoteServices.put(userId, remoteService);
- }
- mRemoteService = remoteService;
- }
- }
-
- /**
- * @hide
- */
- public RoleControllerManager(@NonNull Context context) {
- this(getRemoteServiceComponentName(context), new Handler(Looper.getMainLooper()), context);
- }
-
- @NonNull
- private static ComponentName getRemoteServiceComponentName(@NonNull Context context) {
- Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE);
- PackageManager packageManager = context.getPackageManager();
- intent.setPackage(packageManager.getPermissionControllerPackageName());
- ServiceInfo serviceInfo = packageManager.resolveService(intent, 0).serviceInfo;
- return new ComponentName(serviceInfo.packageName, serviceInfo.name);
- }
-
- /**
- * @see RoleControllerService#onGrantDefaultRoles()
- *
- * @hide
- */
- public void grantDefaultRoles(@NonNull @CallbackExecutor Executor executor,
- @NonNull Consumer<Boolean> callback) {
- AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
- AndroidFuture<Bundle> future = new AndroidFuture<>();
- service.grantDefaultRoles(new RemoteCallback(future::complete));
- return future;
- });
- propagateCallback(operation, "grantDefaultRoles", executor, callback);
- }
-
- /**
- * @see RoleControllerService#onAddRoleHolder(String, String, int)
- *
- * @hide
- */
- public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
- @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
- AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
- AndroidFuture<Bundle> future = new AndroidFuture<>();
- service.onAddRoleHolder(roleName, packageName, flags,
- new RemoteCallback(future::complete));
- return future;
- });
- propagateCallback(operation, "onAddRoleHolder", callback);
- }
-
- /**
- * @see RoleControllerService#onRemoveRoleHolder(String, String, int)
- *
- * @hide
- */
- public void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
- @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
- AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
- AndroidFuture<Bundle> future = new AndroidFuture<>();
- service.onRemoveRoleHolder(roleName, packageName, flags,
- new RemoteCallback(future::complete));
- return future;
- });
- propagateCallback(operation, "onRemoveRoleHolder", callback);
- }
-
- /**
- * @see RoleControllerService#onClearRoleHolders(String, int)
- *
- * @hide
- */
- public void onClearRoleHolders(@NonNull String roleName,
- @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
- AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
- AndroidFuture<Bundle> future = new AndroidFuture<>();
- service.onClearRoleHolders(roleName, flags,
- new RemoteCallback(future::complete));
- return future;
- });
- propagateCallback(operation, "onClearRoleHolders", callback);
- }
-
- /**
- * @see RoleControllerService#onIsApplicationVisibleForRole(String, String)
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
- public void isApplicationVisibleForRole(@NonNull String roleName, @NonNull String packageName,
- @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
- AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
- AndroidFuture<Bundle> future = new AndroidFuture<>();
- service.isApplicationVisibleForRole(roleName, packageName,
- new RemoteCallback(future::complete));
- return future;
- });
- propagateCallback(operation, "isApplicationVisibleForRole", executor, callback);
- }
-
- /**
- * @see RoleControllerService#onIsRoleVisible(String)
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
- public void isRoleVisible(@NonNull String roleName,
- @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
- AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
- AndroidFuture<Bundle> future = new AndroidFuture<>();
- service.isRoleVisible(roleName, new RemoteCallback(future::complete));
- return future;
- });
- propagateCallback(operation, "isRoleVisible", executor, callback);
- }
-
- private void propagateCallback(AndroidFuture<Bundle> operation, String opName,
- @CallbackExecutor @NonNull Executor executor,
- Consumer<Boolean> destination) {
- operation.orTimeout(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
- .whenComplete((res, err) -> executor.execute(() -> {
- final long token = Binder.clearCallingIdentity();
- try {
- if (err != null) {
- Log.e(LOG_TAG, "Error calling " + opName + "()", err);
- destination.accept(false);
- } else {
- destination.accept(res != null);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }));
- }
-
- private void propagateCallback(AndroidFuture<Bundle> operation, String opName,
- RemoteCallback destination) {
- operation.orTimeout(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
- .whenComplete((res, err) -> {
- final long token = Binder.clearCallingIdentity();
- try {
- if (err != null) {
- Log.e(LOG_TAG, "Error calling " + opName + "()", err);
- destination.sendResult(null);
- } else {
- destination.sendResult(res);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- });
- }
-}
diff --git a/apex/permission/framework-s/java/android/app/role/RoleControllerService.java b/apex/permission/framework-s/java/android/app/role/RoleControllerService.java
deleted file mode 100644
index cf7872913f26..000000000000
--- a/apex/permission/framework-s/java/android/app/role/RoleControllerService.java
+++ /dev/null
@@ -1,304 +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 android.app.role;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.WorkerThread;
-import android.app.Service;
-import android.content.Intent;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteCallback;
-import android.os.UserHandle;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.Objects;
-import java.util.concurrent.Executor;
-
-/**
- * Abstract base class for the role controller service.
- * <p>
- * Subclass should implement the business logic for role management, including enforcing role
- * requirements and granting or revoking relevant privileges of roles. This class can only be
- * implemented by the permission controller app which is registered in {@code PackageManager}.
- *
- * @deprecated The role controller service is an internal implementation detail inside role, and it
- * may be replaced by other mechanisms in the future and no longer be called.
- *
- * @hide
- */
-@Deprecated
-@SystemApi
-public abstract class RoleControllerService extends Service {
-
- /**
- * The {@link Intent} that must be declared as handled by the service.
- */
- public static final String SERVICE_INTERFACE = "android.app.role.RoleControllerService";
-
- private HandlerThread mWorkerThread;
- private Handler mWorkerHandler;
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- mWorkerThread = new HandlerThread(RoleControllerService.class.getSimpleName());
- mWorkerThread.start();
- mWorkerHandler = new Handler(mWorkerThread.getLooper());
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- mWorkerThread.quitSafely();
- }
-
- @Nullable
- @Override
- public final IBinder onBind(@Nullable Intent intent) {
- return new IRoleController.Stub() {
-
- @Override
- public void grantDefaultRoles(RemoteCallback callback) {
- enforceCallerSystemUid("grantDefaultRoles");
-
- Objects.requireNonNull(callback, "callback cannot be null");
-
- mWorkerHandler.post(() -> RoleControllerService.this.grantDefaultRoles(callback));
- }
-
- @Override
- public void onAddRoleHolder(String roleName, String packageName, int flags,
- RemoteCallback callback) {
- enforceCallerSystemUid("onAddRoleHolder");
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName,
- "packageName cannot be null or empty");
- Objects.requireNonNull(callback, "callback cannot be null");
-
- mWorkerHandler.post(() -> RoleControllerService.this.onAddRoleHolder(roleName,
- packageName, flags, callback));
- }
-
- @Override
- public void onRemoveRoleHolder(String roleName, String packageName, int flags,
- RemoteCallback callback) {
- enforceCallerSystemUid("onRemoveRoleHolder");
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName,
- "packageName cannot be null or empty");
- Objects.requireNonNull(callback, "callback cannot be null");
-
- mWorkerHandler.post(() -> RoleControllerService.this.onRemoveRoleHolder(roleName,
- packageName, flags, callback));
- }
-
- @Override
- public void onClearRoleHolders(String roleName, int flags, RemoteCallback callback) {
- enforceCallerSystemUid("onClearRoleHolders");
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Objects.requireNonNull(callback, "callback cannot be null");
-
- mWorkerHandler.post(() -> RoleControllerService.this.onClearRoleHolders(roleName,
- flags, callback));
- }
-
- private void enforceCallerSystemUid(@NonNull String methodName) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the system process can call " + methodName
- + "()");
- }
- }
-
- @Override
- public void isApplicationQualifiedForRole(String roleName, String packageName,
- RemoteCallback callback) {
- enforceCallingPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, null);
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName,
- "packageName cannot be null or empty");
- Objects.requireNonNull(callback, "callback cannot be null");
-
- boolean qualified = onIsApplicationQualifiedForRole(roleName, packageName);
- callback.sendResult(qualified ? Bundle.EMPTY : null);
- }
-
- @Override
- public void isApplicationVisibleForRole(String roleName, String packageName,
- RemoteCallback callback) {
- enforceCallingPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, null);
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName,
- "packageName cannot be null or empty");
- Objects.requireNonNull(callback, "callback cannot be null");
-
- boolean visible = onIsApplicationVisibleForRole(roleName, packageName);
- callback.sendResult(visible ? Bundle.EMPTY : null);
- }
-
- @Override
- public void isRoleVisible(String roleName, RemoteCallback callback) {
- enforceCallingPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, null);
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Objects.requireNonNull(callback, "callback cannot be null");
-
- boolean visible = onIsRoleVisible(roleName);
- callback.sendResult(visible ? Bundle.EMPTY : null);
- }
- };
- }
-
- private void grantDefaultRoles(@NonNull RemoteCallback callback) {
- boolean successful = onGrantDefaultRoles();
- callback.sendResult(successful ? Bundle.EMPTY : null);
- }
-
- private void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
- @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
- boolean successful = onAddRoleHolder(roleName, packageName, flags);
- callback.sendResult(successful ? Bundle.EMPTY : null);
- }
-
- private void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
- @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
- boolean successful = onRemoveRoleHolder(roleName, packageName, flags);
- callback.sendResult(successful ? Bundle.EMPTY : null);
- }
-
- private void onClearRoleHolders(@NonNull String roleName,
- @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
- boolean successful = onClearRoleHolders(roleName, flags);
- callback.sendResult(successful ? Bundle.EMPTY : null);
- }
-
- /**
- * Called by system to grant default permissions and roles.
- * <p>
- * This is typically when creating a new user or upgrading either system or
- * permission controller package
- *
- * @return whether this call was successful
- */
- @WorkerThread
- public abstract boolean onGrantDefaultRoles();
-
- /**
- * Add a specific application to the holders of a role. If the role is exclusive, the previous
- * holder will be replaced.
- * <p>
- * Implementation should enforce the role requirements and grant or revoke the relevant
- * privileges of roles.
- *
- * @param roleName the name of the role to add the role holder for
- * @param packageName the package name of the application to add to the role holders
- * @param flags optional behavior flags
- *
- * @return whether this call was successful
- *
- * @see RoleManager#addRoleHolderAsUser(String, String, int, UserHandle, Executor,
- * RemoteCallback)
- */
- @WorkerThread
- public abstract boolean onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
- @RoleManager.ManageHoldersFlags int flags);
-
- /**
- * Remove a specific application from the holders of a role.
- *
- * @param roleName the name of the role to remove the role holder for
- * @param packageName the package name of the application to remove from the role holders
- * @param flags optional behavior flags
- *
- * @return whether this call was successful
- *
- * @see RoleManager#removeRoleHolderAsUser(String, String, int, UserHandle, Executor,
- * RemoteCallback)
- */
- @WorkerThread
- public abstract boolean onRemoveRoleHolder(@NonNull String roleName,
- @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags);
-
- /**
- * Remove all holders of a role.
- *
- * @param roleName the name of the role to remove role holders for
- * @param flags optional behavior flags
- *
- * @return whether this call was successful
- *
- * @see RoleManager#clearRoleHoldersAsUser(String, int, UserHandle, Executor, RemoteCallback)
- */
- @WorkerThread
- public abstract boolean onClearRoleHolders(@NonNull String roleName,
- @RoleManager.ManageHoldersFlags int flags);
-
- /**
- * Check whether an application is qualified for a role.
- *
- * @param roleName name of the role to check for
- * @param packageName package name of the application to check for
- *
- * @return whether the application is qualified for the role
- *
- * @deprecated Implement {@link #onIsApplicationVisibleForRole(String, String)} instead.
- */
- @Deprecated
- public abstract boolean onIsApplicationQualifiedForRole(@NonNull String roleName,
- @NonNull String packageName);
-
- /**
- * Check whether an application is visible for a role.
- *
- * While an application can be qualified for a role, it can still stay hidden from user (thus
- * not visible). If an application is visible for a role, we may show things related to the role
- * for it, e.g. showing an entry pointing to the role settings in its application info page.
- *
- * @param roleName name of the role to check for
- * @param packageName package name of the application to check for
- *
- * @return whether the application is visible for the role
- */
- public boolean onIsApplicationVisibleForRole(@NonNull String roleName,
- @NonNull String packageName) {
- return onIsApplicationQualifiedForRole(roleName, packageName);
- }
-
- /**
- * Check whether a role should be visible to user.
- *
- * @param roleName name of the role to check for
- *
- * @return whether the role should be visible to user
- */
- public abstract boolean onIsRoleVisible(@NonNull String roleName);
-}
diff --git a/apex/permission/framework-s/java/android/app/role/RoleFrameworkInitializer.java b/apex/permission/framework-s/java/android/app/role/RoleFrameworkInitializer.java
deleted file mode 100644
index 7a97770ecf0f..000000000000
--- a/apex/permission/framework-s/java/android/app/role/RoleFrameworkInitializer.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2021 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.app.role;
-
-import android.annotation.SystemApi;
-import android.app.SystemServiceRegistry;
-import android.content.Context;
-
-/**
- * Class holding initialization code for role in the permission module.
- *
- * @hide
- */
-@SystemApi
-public class RoleFrameworkInitializer {
- private RoleFrameworkInitializer() {}
-
- /**
- * Called by {@link SystemServiceRegistry}'s static initializer and registers
- * {@link RoleManager} to {@link Context}, so that {@link Context#getSystemService} can return
- * it.
- *
- * <p>If this is called from other places, it throws a {@link IllegalStateException).
- */
- public static void registerServiceWrappers() {
- SystemServiceRegistry.registerContextAwareService(Context.ROLE_SERVICE, RoleManager.class,
- (context, serviceBinder) -> new RoleManager(context,
- IRoleManager.Stub.asInterface(serviceBinder)));
- }
-}
diff --git a/apex/permission/framework-s/java/android/app/role/RoleManager.java b/apex/permission/framework-s/java/android/app/role/RoleManager.java
deleted file mode 100644
index ceccc4cfc9f7..000000000000
--- a/apex/permission/framework-s/java/android/app/role/RoleManager.java
+++ /dev/null
@@ -1,773 +0,0 @@
-/*
- * 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.app.role;
-
-import android.Manifest;
-import android.annotation.CallbackExecutor;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.annotation.SystemService;
-import android.annotation.UserIdInt;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Binder;
-import android.os.Process;
-import android.os.RemoteCallback;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.function.Consumer;
-
-/**
- * This class provides information about and manages roles.
- * <p>
- * A role is a unique name within the system associated with certain privileges. The list of
- * available roles might change with a system app update, so apps should not make assumption about
- * the availability of roles. Instead, they should always query if the role is available using
- * {@link #isRoleAvailable(String)} before trying to do anything with it. Some predefined role names
- * are available as constants in this class, and a list of possibly available roles can be found in
- * the <a href="{@docRoot}reference/androidx/core/role/package-summary.html">AndroidX Role
- * library</a>.
- * <p>
- * There can be multiple applications qualifying for a role, but only a subset of them can become
- * role holders. To qualify for a role, an application must meet certain requirements, including
- * defining certain components in its manifest. These requirements can be found in the AndroidX
- * Libraries. Then the application will need user consent to become a role holder, which can be
- * requested using {@link android.app.Activity#startActivityForResult(Intent, int)} with the
- * {@code Intent} obtained from {@link #createRequestRoleIntent(String)}.
- * <p>
- * Upon becoming a role holder, the application may be granted certain privileges that are role
- * specific. When the application loses its role, these privileges will also be revoked.
- */
-@SystemService(Context.ROLE_SERVICE)
-public final class RoleManager {
-
- private static final String LOG_TAG = RoleManager.class.getSimpleName();
-
- /**
- * The name of the assistant app role.
- *
- * @see android.service.voice.VoiceInteractionService
- */
- public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
-
- /**
- * The name of the browser role.
- *
- * @see Intent#CATEGORY_APP_BROWSER
- */
- public static final String ROLE_BROWSER = "android.app.role.BROWSER";
-
- /**
- * The name of the dialer role.
- *
- * @see Intent#ACTION_DIAL
- * @see android.telecom.InCallService
- */
- public static final String ROLE_DIALER = "android.app.role.DIALER";
-
- /**
- * The name of the SMS role.
- *
- * @see Intent#CATEGORY_APP_MESSAGING
- */
- public static final String ROLE_SMS = "android.app.role.SMS";
-
- /**
- * The name of the emergency role
- */
- public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
-
- /**
- * The name of the home role.
- *
- * @see Intent#CATEGORY_HOME
- */
- public static final String ROLE_HOME = "android.app.role.HOME";
-
- /**
- * The name of the call redirection role.
- * <p>
- * A call redirection app provides a means to re-write the phone number for an outgoing call to
- * place the call through a call redirection service.
- *
- * @see android.telecom.CallRedirectionService
- */
- public static final String ROLE_CALL_REDIRECTION = "android.app.role.CALL_REDIRECTION";
-
- /**
- * The name of the call screening and caller id role.
- *
- * @see android.telecom.CallScreeningService
- */
- public static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING";
-
- /**
- * @hide
- */
- @IntDef(flag = true, value = { MANAGE_HOLDERS_FLAG_DONT_KILL_APP })
- public @interface ManageHoldersFlags {}
-
- /**
- * Flag parameter for {@link #addRoleHolderAsUser}, {@link #removeRoleHolderAsUser} and
- * {@link #clearRoleHoldersAsUser} to indicate that apps should not be killed when changing
- * their role holder status.
- *
- * @hide
- */
- @SystemApi
- public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1;
-
- /**
- * The action used to request user approval of a role for an application.
- *
- * @hide
- */
- public static final String ACTION_REQUEST_ROLE = "android.app.role.action.REQUEST_ROLE";
-
- /**
- * The permission required to manage records of role holders in {@link RoleManager} directly.
- *
- * @hide
- */
- public static final String PERMISSION_MANAGE_ROLES_FROM_CONTROLLER =
- "com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER";
-
- @NonNull
- private final Context mContext;
-
- @NonNull
- private final IRoleManager mService;
-
- @GuardedBy("mListenersLock")
- @NonNull
- private final SparseArray<ArrayMap<OnRoleHoldersChangedListener,
- OnRoleHoldersChangedListenerDelegate>> mListeners = new SparseArray<>();
- @NonNull
- private final Object mListenersLock = new Object();
-
- @GuardedBy("mRoleControllerManagerLock")
- @Nullable
- private RoleControllerManager mRoleControllerManager;
- private final Object mRoleControllerManagerLock = new Object();
-
- /**
- * Create a new instance of this class.
- *
- * @param context the {@link Context}
- * @param service the {@link IRoleManager} service
- *
- * @hide
- */
- public RoleManager(@NonNull Context context, @NonNull IRoleManager service) {
- mContext = context;
- mService = service;
- }
-
- /**
- * Returns an {@code Intent} suitable for passing to
- * {@link android.app.Activity#startActivityForResult(Intent, int)} which prompts the user to
- * grant a role to this application.
- * <p>
- * If the role is granted, the {@code resultCode} will be
- * {@link android.app.Activity#RESULT_OK}, otherwise it will be
- * {@link android.app.Activity#RESULT_CANCELED}.
- *
- * @param roleName the name of requested role
- *
- * @return the {@code Intent} to prompt user to grant the role
- */
- @NonNull
- public Intent createRequestRoleIntent(@NonNull String roleName) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Intent intent = new Intent(ACTION_REQUEST_ROLE);
- intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
- intent.putExtra(Intent.EXTRA_ROLE_NAME, roleName);
- return intent;
- }
-
- /**
- * Check whether a role is available in the system.
- *
- * @param roleName the name of role to checking for
- *
- * @return whether the role is available in the system
- */
- public boolean isRoleAvailable(@NonNull String roleName) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- try {
- return mService.isRoleAvailable(roleName);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Check whether the calling application is holding a particular role.
- *
- * @param roleName the name of the role to check for
- *
- * @return whether the calling application is holding the role
- */
- public boolean isRoleHeld(@NonNull String roleName) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- try {
- return mService.isRoleHeld(roleName, mContext.getPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Get package names of the applications holding the role.
- * <p>
- * <strong>Note:</strong> Using this API requires holding
- * {@code android.permission.MANAGE_ROLE_HOLDERS}.
- *
- * @param roleName the name of the role to get the role holder for
- *
- * @return a list of package names of the role holders, or an empty list if none.
- *
- * @see #getRoleHoldersAsUser(String, UserHandle)
- *
- * @hide
- */
- @NonNull
- @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
- @SystemApi
- public List<String> getRoleHolders(@NonNull String roleName) {
- return getRoleHoldersAsUser(roleName, Process.myUserHandle());
- }
-
- /**
- * Get package names of the applications holding the role.
- * <p>
- * <strong>Note:</strong> Using this API requires holding
- * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
- * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
- *
- * @param roleName the name of the role to get the role holder for
- * @param user the user to get the role holder for
- *
- * @return a list of package names of the role holders, or an empty list if none.
- *
- * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
- * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
- * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
- *
- * @hide
- */
- @NonNull
- @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
- @SystemApi
- public List<String> getRoleHoldersAsUser(@NonNull String roleName, @NonNull UserHandle user) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Objects.requireNonNull(user, "user cannot be null");
- try {
- return mService.getRoleHoldersAsUser(roleName, user.getIdentifier());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Add a specific application to the holders of a role. If the role is exclusive, the previous
- * holder will be replaced.
- * <p>
- * <strong>Note:</strong> Using this API requires holding
- * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
- * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
- *
- * @param roleName the name of the role to add the role holder for
- * @param packageName the package name of the application to add to the role holders
- * @param flags optional behavior flags
- * @param user the user to add the role holder for
- * @param executor the {@code Executor} to run the callback on.
- * @param callback the callback for whether this call is successful
- *
- * @see #getRoleHoldersAsUser(String, UserHandle)
- * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
- * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
- @SystemApi
- public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
- @ManageHoldersFlags int flags, @NonNull UserHandle user,
- @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- Objects.requireNonNull(user, "user cannot be null");
- Objects.requireNonNull(executor, "executor cannot be null");
- Objects.requireNonNull(callback, "callback cannot be null");
- try {
- mService.addRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
- createRemoteCallback(executor, callback));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Remove a specific application from the holders of a role.
- * <p>
- * <strong>Note:</strong> Using this API requires holding
- * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
- * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
- *
- * @param roleName the name of the role to remove the role holder for
- * @param packageName the package name of the application to remove from the role holders
- * @param flags optional behavior flags
- * @param user the user to remove the role holder for
- * @param executor the {@code Executor} to run the callback on.
- * @param callback the callback for whether this call is successful
- *
- * @see #getRoleHoldersAsUser(String, UserHandle)
- * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
- * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
- @SystemApi
- public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
- @ManageHoldersFlags int flags, @NonNull UserHandle user,
- @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- Objects.requireNonNull(user, "user cannot be null");
- Objects.requireNonNull(executor, "executor cannot be null");
- Objects.requireNonNull(callback, "callback cannot be null");
- try {
- mService.removeRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
- createRemoteCallback(executor, callback));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Remove all holders of a role.
- * <p>
- * <strong>Note:</strong> Using this API requires holding
- * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
- * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
- *
- * @param roleName the name of the role to remove role holders for
- * @param flags optional behavior flags
- * @param user the user to remove role holders for
- * @param executor the {@code Executor} to run the callback on.
- * @param callback the callback for whether this call is successful
- *
- * @see #getRoleHoldersAsUser(String, UserHandle)
- * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
- * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
- @SystemApi
- public void clearRoleHoldersAsUser(@NonNull String roleName, @ManageHoldersFlags int flags,
- @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor,
- @NonNull Consumer<Boolean> callback) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Objects.requireNonNull(user, "user cannot be null");
- Objects.requireNonNull(executor, "executor cannot be null");
- Objects.requireNonNull(callback, "callback cannot be null");
- try {
- mService.clearRoleHoldersAsUser(roleName, flags, user.getIdentifier(),
- createRemoteCallback(executor, callback));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- @NonNull
- private static RemoteCallback createRemoteCallback(@NonNull Executor executor,
- @NonNull Consumer<Boolean> callback) {
- return new RemoteCallback(result -> executor.execute(() -> {
- boolean successful = result != null;
- final long token = Binder.clearCallingIdentity();
- try {
- callback.accept(successful);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }));
- }
-
- /**
- * Add a listener to observe role holder changes
- * <p>
- * <strong>Note:</strong> Using this API requires holding
- * {@code android.permission.OBSERVE_ROLE_HOLDERS} and if the user id is not the current user
- * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
- *
- * @param executor the {@code Executor} to call the listener on.
- * @param listener the listener to be added
- * @param user the user to add the listener for
- *
- * @see #removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener, UserHandle)
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS)
- @SystemApi
- public void addOnRoleHoldersChangedListenerAsUser(@CallbackExecutor @NonNull Executor executor,
- @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) {
- Objects.requireNonNull(executor, "executor cannot be null");
- Objects.requireNonNull(listener, "listener cannot be null");
- Objects.requireNonNull(user, "user cannot be null");
- int userId = user.getIdentifier();
- synchronized (mListenersLock) {
- ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners =
- mListeners.get(userId);
- if (listeners == null) {
- listeners = new ArrayMap<>();
- mListeners.put(userId, listeners);
- } else {
- if (listeners.containsKey(listener)) {
- return;
- }
- }
- OnRoleHoldersChangedListenerDelegate listenerDelegate =
- new OnRoleHoldersChangedListenerDelegate(executor, listener);
- try {
- mService.addOnRoleHoldersChangedListenerAsUser(listenerDelegate, userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- listeners.put(listener, listenerDelegate);
- }
- }
-
- /**
- * Remove a listener observing role holder changes
- * <p>
- * <strong>Note:</strong> Using this API requires holding
- * {@code android.permission.OBSERVE_ROLE_HOLDERS} and if the user id is not the current user
- * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
- *
- * @param listener the listener to be removed
- * @param user the user to remove the listener for
- *
- * @see #addOnRoleHoldersChangedListenerAsUser(Executor, OnRoleHoldersChangedListener,
- * UserHandle)
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS)
- @SystemApi
- public void removeOnRoleHoldersChangedListenerAsUser(
- @NonNull OnRoleHoldersChangedListener listener, @NonNull UserHandle user) {
- Objects.requireNonNull(listener, "listener cannot be null");
- Objects.requireNonNull(user, "user cannot be null");
- int userId = user.getIdentifier();
- synchronized (mListenersLock) {
- ArrayMap<OnRoleHoldersChangedListener, OnRoleHoldersChangedListenerDelegate> listeners =
- mListeners.get(userId);
- if (listeners == null) {
- return;
- }
- OnRoleHoldersChangedListenerDelegate listenerDelegate = listeners.get(listener);
- if (listenerDelegate == null) {
- return;
- }
- try {
- mService.removeOnRoleHoldersChangedListenerAsUser(listenerDelegate,
- user.getIdentifier());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- listeners.remove(listener);
- if (listeners.isEmpty()) {
- mListeners.remove(userId);
- }
- }
- }
-
- /**
- * Set the names of all the available roles. Should only be called from
- * {@link android.app.role.RoleControllerService}.
- * <p>
- * <strong>Note:</strong> Using this API requires holding
- * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
- *
- * @param roleNames the names of all the available roles
- *
- * @deprecated This is only usable by the role controller service, which is an internal
- * implementation detail inside role.
- *
- * @hide
- */
- @Deprecated
- @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
- @SystemApi
- public void setRoleNamesFromController(@NonNull List<String> roleNames) {
- Objects.requireNonNull(roleNames, "roleNames cannot be null");
- try {
- mService.setRoleNamesFromController(roleNames);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Add a specific application to the holders of a role, only modifying records inside
- * {@link RoleManager}. Should only be called from
- * {@link android.app.role.RoleControllerService}.
- * <p>
- * <strong>Note:</strong> Using this API requires holding
- * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
- *
- * @param roleName the name of the role to add the role holder for
- * @param packageName the package name of the application to add to the role holders
- *
- * @return whether the operation was successful, and will also be {@code true} if a matching
- * role holder is already found.
- *
- * @see #getRoleHolders(String)
- * @see #removeRoleHolderFromController(String, String)
- *
- * @deprecated This is only usable by the role controller service, which is an internal
- * implementation detail inside role.
- *
- * @hide
- */
- @Deprecated
- @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
- @SystemApi
- public boolean addRoleHolderFromController(@NonNull String roleName,
- @NonNull String packageName) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- try {
- return mService.addRoleHolderFromController(roleName, packageName);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Remove a specific application from the holders of a role, only modifying records inside
- * {@link RoleManager}. Should only be called from
- * {@link android.app.role.RoleControllerService}.
- * <p>
- * <strong>Note:</strong> Using this API requires holding
- * {@link #PERMISSION_MANAGE_ROLES_FROM_CONTROLLER}.
- *
- * @param roleName the name of the role to remove the role holder for
- * @param packageName the package name of the application to remove from the role holders
- *
- * @return whether the operation was successful, and will also be {@code true} if no matching
- * role holder was found to remove.
- *
- * @see #getRoleHolders(String)
- * @see #addRoleHolderFromController(String, String)
- *
- * @deprecated This is only usable by the role controller service, which is an internal
- * implementation detail inside role.
- *
- * @hide
- */
- @Deprecated
- @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
- @SystemApi
- public boolean removeRoleHolderFromController(@NonNull String roleName,
- @NonNull String packageName) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- try {
- return mService.removeRoleHolderFromController(roleName, packageName);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns the list of all roles that the given package is currently holding
- *
- * @param packageName the package name
- * @return the list of role names
- *
- * @deprecated This is only usable by the role controller service, which is an internal
- * implementation detail inside role.
- *
- * @hide
- */
- @Deprecated
- @NonNull
- @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
- @SystemApi
- public List<String> getHeldRolesFromController(@NonNull String packageName) {
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- try {
- return mService.getHeldRolesFromController(packageName);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Get the role holder of {@link #ROLE_BROWSER} without requiring
- * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as in
- * {@link android.content.pm.PackageManager#getDefaultBrowserPackageNameAsUser(int)}
- *
- * @param userId the user ID
- * @return the package name of the default browser, or {@code null} if none
- *
- * @hide
- */
- @Nullable
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public String getBrowserRoleHolder(@UserIdInt int userId) {
- try {
- return mService.getBrowserRoleHolder(userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Set the role holder of {@link #ROLE_BROWSER} requiring
- * {@link Manifest.permission.SET_PREFERRED_APPLICATIONS} instead of
- * {@link Manifest.permission#MANAGE_ROLE_HOLDERS}, as in
- * {@link android.content.pm.PackageManager#setDefaultBrowserPackageNameAsUser(String, int)}
- *
- * @param packageName the package name of the default browser, or {@code null} if none
- * @param userId the user ID
- * @return whether the default browser was set successfully
- *
- * @hide
- */
- @Nullable
- @RequiresPermission(Manifest.permission.SET_PREFERRED_APPLICATIONS)
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public boolean setBrowserRoleHolder(@Nullable String packageName, @UserIdInt int userId) {
- try {
- return mService.setBrowserRoleHolder(packageName, userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Allows getting the role holder for {@link #ROLE_SMS} without requiring
- * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as in
- * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}.
- *
- * @param userId the user ID to get the default SMS package for
- * @return the package name of the default SMS app, or {@code null} if none
- *
- * @hide
- */
- @Nullable
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public String getSmsRoleHolder(@UserIdInt int userId) {
- try {
- return mService.getSmsRoleHolder(userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Check whether a role should be visible to user.
- *
- * @param roleName name of the role to check for
- * @param executor the executor to execute callback on
- * @param callback the callback to receive whether the role should be visible to user
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
- @SystemApi
- public void isRoleVisible(@NonNull String roleName,
- @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
- getRoleControllerManager().isRoleVisible(roleName, executor, callback);
- }
-
- /**
- * Check whether an application is visible for a role.
- *
- * While an application can be qualified for a role, it can still stay hidden from user (thus
- * not visible). If an application is visible for a role, we may show things related to the role
- * for it, e.g. showing an entry pointing to the role settings in its application info page.
- *
- * @param roleName the name of the role to check for
- * @param packageName the package name of the application to check for
- * @param executor the executor to execute callback on
- * @param callback the callback to receive whether the application is visible for the role
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
- @SystemApi
- public void isApplicationVisibleForRole(@NonNull String roleName, @NonNull String packageName,
- @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
- getRoleControllerManager().isApplicationVisibleForRole(roleName, packageName, executor,
- callback);
- }
-
- @NonNull
- private RoleControllerManager getRoleControllerManager() {
- synchronized (mRoleControllerManagerLock) {
- if (mRoleControllerManager == null) {
- mRoleControllerManager = new RoleControllerManager(mContext);
- }
- return mRoleControllerManager;
- }
- }
-
- private static class OnRoleHoldersChangedListenerDelegate
- extends IOnRoleHoldersChangedListener.Stub {
-
- @NonNull
- private final Executor mExecutor;
- @NonNull
- private final OnRoleHoldersChangedListener mListener;
-
- OnRoleHoldersChangedListenerDelegate(@NonNull Executor executor,
- @NonNull OnRoleHoldersChangedListener listener) {
- mExecutor = executor;
- mListener = listener;
- }
-
- @Override
- public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
- final long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() ->
- mListener.onRoleHoldersChanged(roleName, UserHandle.of(userId)));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- }
-}
diff --git a/apex/permission/framework-s/java/android/app/role/TEST_MAPPING b/apex/permission/framework-s/java/android/app/role/TEST_MAPPING
deleted file mode 100644
index f8f140dd716e..000000000000
--- a/apex/permission/framework-s/java/android/app/role/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "presubmit": [
- {
- "name": "CtsRoleTestCases",
- "options": [
- {
- "include-filter": "android.app.role.cts.RoleManagerTest"
- }
- ]
- }
- ]
-}
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp
deleted file mode 100644
index 52a61674a596..000000000000
--- a/apex/permission/framework/Android.bp
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (C) 2020 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.
-
-filegroup {
- name: "framework-permission-sources",
- srcs: [
- "java/**/*.java",
- "java/**/*.aidl",
- ],
- path: "java",
- visibility: ["//frameworks/base"],
-}
-
-java_sdk_library {
- name: "framework-permission",
- defaults: ["framework-module-defaults"],
-
- // Restrict access to implementation library.
- impl_library_visibility: [
- "//frameworks/base/apex/permission:__subpackages__",
- "//packages/modules/Permission:__subpackages__",
- ],
-
- srcs: [
- ":framework-permission-sources",
- ],
-
- apex_available: [
- "com.android.permission",
- "test_com.android.permission",
- ],
- min_sdk_version: "30",
- permitted_packages: [
- "android.permission",
- "android.app.role",
- ],
- hostdex: true,
- installable: true,
-}
diff --git a/apex/permission/framework/api/current.txt b/apex/permission/framework/api/current.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/module-lib-current.txt b/apex/permission/framework/api/module-lib-current.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework/api/module-lib-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/module-lib-removed.txt b/apex/permission/framework/api/module-lib-removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework/api/module-lib-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/removed.txt b/apex/permission/framework/api/removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/system-current.txt b/apex/permission/framework/api/system-current.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework/api/system-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/api/system-removed.txt b/apex/permission/framework/api/system-removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/framework/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/framework/java/android/permission/PermissionState.java b/apex/permission/framework/java/android/permission/PermissionState.java
deleted file mode 100644
index e810db8ecbfe..000000000000
--- a/apex/permission/framework/java/android/permission/PermissionState.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2020 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.permission;
-
-/**
- * @hide
- */
-public class PermissionState {}
diff --git a/apex/permission/jarjar-rules.txt b/apex/permission/jarjar-rules.txt
deleted file mode 100644
index 4729ed13dc4c..000000000000
--- a/apex/permission/jarjar-rules.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-rule android.os.HandlerExecutor com.android.permission.jarjar.@0
-rule android.util.IndentingPrintWriter com.android.permission.jarjar.@0
-rule com.android.internal.** com.android.permission.jarjar.@0
-rule com.android.modules.** com.android.permission.jarjar.@0
-rule com.android.role.*Proto com.android.permission.jarjar.@0
diff --git a/apex/permission/service/Android.bp b/apex/permission/service/Android.bp
deleted file mode 100644
index d0fc5b9d7c14..000000000000
--- a/apex/permission/service/Android.bp
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright (C) 2020 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.
-
-filegroup {
- name: "service-permission-sources",
- srcs: [
- "java/**/*.java",
- ],
- path: "java",
- visibility: ["//frameworks/base/services"],
-}
-
-filegroup {
- name: "service-permission-protos",
- srcs: [
- "proto/**/*.proto",
- ],
- visibility: ["//frameworks/base"],
-}
-
-gensrcs {
- name: "service-permission-javastream-protos",
- depfile: true,
-
- tools: [
- "aprotoc",
- "protoc-gen-javastream",
- "soong_zip",
- ],
-
- cmd: "mkdir -p $(genDir)/$(in) " +
- "&& $(location aprotoc) " +
- " --plugin=$(location protoc-gen-javastream) " +
- " --dependency_out=$(depfile) " +
- " --javastream_out=$(genDir)/$(in) " +
- " -Iexternal/protobuf/src " +
- " -I . " +
- " $(in) " +
- "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
-
- srcs: [
- ":service-permission-protos",
- ],
- output_extension: "srcjar",
-}
-
-java_library {
- name: "service-permission-shared",
- srcs: [":service-permission-shared-srcs"],
- libs: [
- "framework-annotations-lib",
- "framework-permission-s-shared",
- ],
- apex_available: [
- "com.android.permission",
- "test_com.android.permission",
- ],
- installable: false,
- min_sdk_version: "30",
- sdk_version: "system_server_current",
-}
-
-java_sdk_library {
- name: "service-permission",
- defaults: ["framework-system-server-module-defaults"],
- impl_library_visibility: [
- "//frameworks/base/apex/permission/tests",
- "//frameworks/base/services/tests/mockingservicestests",
- "//frameworks/base/services/tests/servicestests",
- "//packages/modules/Permission/tests",
- ],
- srcs: [
- ":service-permission-sources",
- ":service-permission-javastream-protos",
- ],
- libs: [
- "framework-permission",
- "framework-permission-s.impl",
- "framework-permission-s-shared",
- ],
- static_libs: [
- "modules-utils-os",
- "service-permission-shared",
- ],
- jarjar_rules: ":permission-jarjar-rules",
- min_sdk_version: "30",
- sdk_version: "system_server_current",
- apex_available: [
- "com.android.permission",
- "test_com.android.permission",
- ],
- installable: true,
- // We don't have last-api tracking files for the public part of this jar's API.
- unsafe_ignore_missing_latest_api: true,
-}
diff --git a/apex/permission/service/api/current.txt b/apex/permission/service/api/current.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/service/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/service/api/removed.txt b/apex/permission/service/api/removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/service/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/service/api/system-server-current.txt b/apex/permission/service/api/system-server-current.txt
deleted file mode 100644
index b1869c2c731d..000000000000
--- a/apex/permission/service/api/system-server-current.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-// Signature format: 2.0
-package com.android.permission.persistence {
-
- public interface RuntimePermissionsPersistence {
- method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance();
- method public void deleteForUser(@NonNull android.os.UserHandle);
- method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle);
- method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
- }
-
- public final class RuntimePermissionsState {
- ctor public RuntimePermissionsState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>);
- method @Nullable public String getFingerprint();
- method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getPackagePermissions();
- method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getSharedUserPermissions();
- method public int getVersion();
- field public static final int NO_VERSION = -1; // 0xffffffff
- }
-
- public static final class RuntimePermissionsState.PermissionState {
- ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int);
- method public int getFlags();
- method @NonNull public String getName();
- method public boolean isGranted();
- }
-
-}
-
-package com.android.role {
-
- public interface RoleManagerLocal {
- method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRolesAndHolders(int);
- }
-
-}
-
-package com.android.role.persistence {
-
- public interface RolesPersistence {
- method @NonNull public static com.android.role.persistence.RolesPersistence createInstance();
- method public void deleteForUser(@NonNull android.os.UserHandle);
- method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle);
- method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
- }
-
- public final class RolesState {
- ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>);
- method @Nullable public String getPackagesHash();
- method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles();
- method public int getVersion();
- }
-
-}
-
diff --git a/apex/permission/service/api/system-server-removed.txt b/apex/permission/service/api/system-server-removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/apex/permission/service/api/system-server-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/permission/service/java/com/android/permission/compat/UserHandleCompat.java b/apex/permission/service/java/com/android/permission/compat/UserHandleCompat.java
deleted file mode 100644
index 7c711d301f00..000000000000
--- a/apex/permission/service/java/com/android/permission/compat/UserHandleCompat.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2021 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.permission.compat;
-
-import android.annotation.UserIdInt;
-import android.os.UserHandle;
-
-/**
- * Helper for accessing features in {@link UserHandle}.
- */
-public final class UserHandleCompat {
- /**
- * A user ID to indicate all users on the device.
- */
- public static final int USER_ALL = UserHandle.ALL.getIdentifier();
-
- /**
- * A user ID to indicate the "system" user of the device.
- */
- public static final int USER_SYSTEM = UserHandle.SYSTEM.getIdentifier();
-
- private UserHandleCompat() {}
-
- /**
- * Get the user ID of a given UID.
- *
- * @param uid the UID
- * @return the user ID
- */
- @UserIdInt
- public static int getUserId(int uid) {
- return UserHandle.getUserHandleForUid(uid).getIdentifier();
- }
-}
diff --git a/apex/permission/service/java/com/android/permission/compat/package-info.java b/apex/permission/service/java/com/android/permission/compat/package-info.java
deleted file mode 100644
index c89cc8eabb92..000000000000
--- a/apex/permission/service/java/com/android/permission/compat/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-/**
- * @hide
- * TODO(b/146466118) remove this javadoc tag
- */
-@android.annotation.Hide
-package com.android.permission.compat;
diff --git a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java b/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
deleted file mode 100644
index 569a78c0ab41..000000000000
--- a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2020 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.permission.persistence;
-
-import android.annotation.NonNull;
-
-/**
- * Utility class for IO.
- *
- * @hide
- */
-public class IoUtils {
-
- private IoUtils() {}
-
- /**
- * Close 'closeable' ignoring any exceptions.
- */
- public static void closeQuietly(@NonNull AutoCloseable closeable) {
- try {
- closeable.close();
- } catch (Exception ignored) {
- // Ignored.
- }
- }
-}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
deleted file mode 100644
index aedba290db1f..000000000000
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2020 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.permission.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-import android.os.UserHandle;
-
-/**
- * Persistence for runtime permissions.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-@SystemApi(client = Client.SYSTEM_SERVER)
-public interface RuntimePermissionsPersistence {
-
- /**
- * Read the runtime permissions from persistence.
- *
- * This will perform I/O operations synchronously.
- *
- * @param user the user to read for
- * @return the runtime permissions read
- */
- @Nullable
- RuntimePermissionsState readForUser(@NonNull UserHandle user);
-
- /**
- * Write the runtime permissions to persistence.
- *
- * This will perform I/O operations synchronously.
- *
- * @param runtimePermissions the runtime permissions to write
- * @param user the user to write for
- */
- void writeForUser(@NonNull RuntimePermissionsState runtimePermissions,
- @NonNull UserHandle user);
-
- /**
- * Delete the runtime permissions from persistence.
- *
- * This will perform I/O operations synchronously.
- *
- * @param user the user to delete for
- */
- void deleteForUser(@NonNull UserHandle user);
-
- /**
- * Create a new instance of {@link RuntimePermissionsPersistence} implementation.
- *
- * @return the new instance.
- */
- @NonNull
- static RuntimePermissionsPersistence createInstance() {
- return new RuntimePermissionsPersistenceImpl();
- }
-}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
deleted file mode 100644
index e43f59a3377a..000000000000
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2020 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.permission.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ApexEnvironment;
-import android.content.pm.PackageManager;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.AtomicFile;
-import android.util.Log;
-import android.util.Xml;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Persistence implementation for runtime permissions.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPersistence {
-
- private static final String LOG_TAG = RuntimePermissionsPersistenceImpl.class.getSimpleName();
-
- private static final String APEX_MODULE_NAME = "com.android.permission";
-
- private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml";
-
- private static final String TAG_PACKAGE = "package";
- private static final String TAG_PERMISSION = "permission";
- private static final String TAG_RUNTIME_PERMISSIONS = "runtime-permissions";
- private static final String TAG_SHARED_USER = "shared-user";
-
- private static final String ATTRIBUTE_FINGERPRINT = "fingerprint";
- private static final String ATTRIBUTE_FLAGS = "flags";
- private static final String ATTRIBUTE_GRANTED = "granted";
- private static final String ATTRIBUTE_NAME = "name";
- private static final String ATTRIBUTE_VERSION = "version";
-
- @Nullable
- @Override
- public RuntimePermissionsState readForUser(@NonNull UserHandle user) {
- File file = getFile(user);
- try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(inputStream, null);
- return parseXml(parser);
- } catch (FileNotFoundException e) {
- Log.i(LOG_TAG, "runtime-permissions.xml not found");
- return null;
- } catch (XmlPullParserException | IOException e) {
- throw new IllegalStateException("Failed to read runtime-permissions.xml: " + file , e);
- }
- }
-
- @NonNull
- private static RuntimePermissionsState parseXml(@NonNull XmlPullParser parser)
- throws IOException, XmlPullParserException {
- int type;
- int depth;
- int innerDepth = parser.getDepth() + 1;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
- if (depth > innerDepth || type != XmlPullParser.START_TAG) {
- continue;
- }
-
- if (parser.getName().equals(TAG_RUNTIME_PERMISSIONS)) {
- return parseRuntimePermissions(parser);
- }
- }
- throw new IllegalStateException("Missing <" + TAG_RUNTIME_PERMISSIONS
- + "> in runtime-permissions.xml");
- }
-
- @NonNull
- private static RuntimePermissionsState parseRuntimePermissions(@NonNull XmlPullParser parser)
- throws IOException, XmlPullParserException {
- String versionValue = parser.getAttributeValue(null, ATTRIBUTE_VERSION);
- int version = versionValue != null ? Integer.parseInt(versionValue)
- : RuntimePermissionsState.NO_VERSION;
- String fingerprint = parser.getAttributeValue(null, ATTRIBUTE_FINGERPRINT);
-
- Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
- new ArrayMap<>();
- Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
- new ArrayMap<>();
- int type;
- int depth;
- int innerDepth = parser.getDepth() + 1;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
- if (depth > innerDepth || type != XmlPullParser.START_TAG) {
- continue;
- }
-
- switch (parser.getName()) {
- case TAG_PACKAGE: {
- String packageName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
- List<RuntimePermissionsState.PermissionState> permissions = parsePermissions(
- parser);
- packagePermissions.put(packageName, permissions);
- break;
- }
- case TAG_SHARED_USER: {
- String sharedUserName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
- List<RuntimePermissionsState.PermissionState> permissions = parsePermissions(
- parser);
- sharedUserPermissions.put(sharedUserName, permissions);
- break;
- }
- }
- }
-
- return new RuntimePermissionsState(version, fingerprint, packagePermissions,
- sharedUserPermissions);
- }
-
- @NonNull
- private static List<RuntimePermissionsState.PermissionState> parsePermissions(
- @NonNull XmlPullParser parser) throws IOException, XmlPullParserException {
- List<RuntimePermissionsState.PermissionState> permissions = new ArrayList<>();
- int type;
- int depth;
- int innerDepth = parser.getDepth() + 1;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
- if (depth > innerDepth || type != XmlPullParser.START_TAG) {
- continue;
- }
-
- if (parser.getName().equals(TAG_PERMISSION)) {
- String name = parser.getAttributeValue(null, ATTRIBUTE_NAME);
- boolean granted = Boolean.parseBoolean(parser.getAttributeValue(null,
- ATTRIBUTE_GRANTED));
- int flags = Integer.parseInt(parser.getAttributeValue(null,
- ATTRIBUTE_FLAGS), 16);
- RuntimePermissionsState.PermissionState permission =
- new RuntimePermissionsState.PermissionState(name, granted, flags);
- permissions.add(permission);
- }
- }
- return permissions;
- }
-
- @Override
- public void writeForUser(@NonNull RuntimePermissionsState runtimePermissions,
- @NonNull UserHandle user) {
- File file = getFile(user);
- AtomicFile atomicFile = new AtomicFile(file);
- FileOutputStream outputStream = null;
- try {
- outputStream = atomicFile.startWrite();
-
- XmlSerializer serializer = Xml.newSerializer();
- serializer.setOutput(outputStream, StandardCharsets.UTF_8.name());
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
- serializer.startDocument(null, true);
-
- serializeRuntimePermissions(serializer, runtimePermissions);
-
- serializer.endDocument();
- atomicFile.finishWrite(outputStream);
- } catch (Exception e) {
- Log.wtf(LOG_TAG, "Failed to write runtime-permissions.xml, restoring backup: " + file,
- e);
- atomicFile.failWrite(outputStream);
- } finally {
- IoUtils.closeQuietly(outputStream);
- }
- }
-
- private static void serializeRuntimePermissions(@NonNull XmlSerializer serializer,
- @NonNull RuntimePermissionsState runtimePermissions) throws IOException {
- serializer.startTag(null, TAG_RUNTIME_PERMISSIONS);
-
- int version = runtimePermissions.getVersion();
- serializer.attribute(null, ATTRIBUTE_VERSION, Integer.toString(version));
- String fingerprint = runtimePermissions.getFingerprint();
- if (fingerprint != null) {
- serializer.attribute(null, ATTRIBUTE_FINGERPRINT, fingerprint);
- }
-
- for (Map.Entry<String, List<RuntimePermissionsState.PermissionState>> entry
- : runtimePermissions.getPackagePermissions().entrySet()) {
- String packageName = entry.getKey();
- List<RuntimePermissionsState.PermissionState> permissions = entry.getValue();
-
- serializer.startTag(null, TAG_PACKAGE);
- serializer.attribute(null, ATTRIBUTE_NAME, packageName);
- serializePermissions(serializer, permissions);
- serializer.endTag(null, TAG_PACKAGE);
- }
-
- for (Map.Entry<String, List<RuntimePermissionsState.PermissionState>> entry
- : runtimePermissions.getSharedUserPermissions().entrySet()) {
- String sharedUserName = entry.getKey();
- List<RuntimePermissionsState.PermissionState> permissions = entry.getValue();
-
- serializer.startTag(null, TAG_SHARED_USER);
- serializer.attribute(null, ATTRIBUTE_NAME, sharedUserName);
- serializePermissions(serializer, permissions);
- serializer.endTag(null, TAG_SHARED_USER);
- }
-
- serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);
- }
-
- private static void serializePermissions(@NonNull XmlSerializer serializer,
- @NonNull List<RuntimePermissionsState.PermissionState> permissions) throws IOException {
- int permissionsSize = permissions.size();
- for (int i = 0; i < permissionsSize; i++) {
- RuntimePermissionsState.PermissionState permissionState = permissions.get(i);
-
- serializer.startTag(null, TAG_PERMISSION);
- serializer.attribute(null, ATTRIBUTE_NAME, permissionState.getName());
- serializer.attribute(null, ATTRIBUTE_GRANTED, Boolean.toString(
- permissionState.isGranted() && (permissionState.getFlags()
- & PackageManager.FLAG_PERMISSION_ONE_TIME) == 0));
- serializer.attribute(null, ATTRIBUTE_FLAGS, Integer.toHexString(
- permissionState.getFlags()));
- serializer.endTag(null, TAG_PERMISSION);
- }
- }
-
- @Override
- public void deleteForUser(@NonNull UserHandle user) {
- getFile(user).delete();
- }
-
- @NonNull
- private static File getFile(@NonNull UserHandle user) {
- ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
- File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
- return new File(dataDirectory, RUNTIME_PERMISSIONS_FILE_NAME);
- }
-}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
deleted file mode 100644
index c6bfc6d32989..000000000000
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2020 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.permission.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * State of all runtime permissions.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-@SystemApi(client = Client.SYSTEM_SERVER)
-public final class RuntimePermissionsState {
-
- /**
- * Special value for {@link #mVersion} to indicate that no version was read.
- */
- public static final int NO_VERSION = -1;
-
- /**
- * The version of the runtime permissions.
- */
- private final int mVersion;
-
- /**
- * The fingerprint of the runtime permissions.
- */
- @Nullable
- private final String mFingerprint;
-
- /**
- * The runtime permissions by packages.
- */
- @NonNull
- private final Map<String, List<PermissionState>> mPackagePermissions;
-
- /**
- * The runtime permissions by shared users.
- */
- @NonNull
- private final Map<String, List<PermissionState>> mSharedUserPermissions;
-
- /**
- * Create a new instance of this class.
- *
- * @param version the version of the runtime permissions
- * @param fingerprint the fingerprint of the runtime permissions
- * @param packagePermissions the runtime permissions by packages
- * @param sharedUserPermissions the runtime permissions by shared users
- */
- public RuntimePermissionsState(int version, @Nullable String fingerprint,
- @NonNull Map<String, List<PermissionState>> packagePermissions,
- @NonNull Map<String, List<PermissionState>> sharedUserPermissions) {
- mVersion = version;
- mFingerprint = fingerprint;
- mPackagePermissions = packagePermissions;
- mSharedUserPermissions = sharedUserPermissions;
- }
-
- /**
- * Get the version of the runtime permissions.
- *
- * @return the version of the runtime permissions
- */
- public int getVersion() {
- return mVersion;
- }
-
- /**
- * Get the fingerprint of the runtime permissions.
- *
- * @return the fingerprint of the runtime permissions
- */
- @Nullable
- public String getFingerprint() {
- return mFingerprint;
- }
-
- /**
- * Get the runtime permissions by packages.
- *
- * @return the runtime permissions by packages
- */
- @NonNull
- public Map<String, List<PermissionState>> getPackagePermissions() {
- return mPackagePermissions;
- }
-
- /**
- * Get the runtime permissions by shared users.
- *
- * @return the runtime permissions by shared users
- */
- @NonNull
- public Map<String, List<PermissionState>> getSharedUserPermissions() {
- return mSharedUserPermissions;
- }
-
- @Override
- public boolean equals(Object object) {
- if (this == object) {
- return true;
- }
- if (object == null || getClass() != object.getClass()) {
- return false;
- }
- RuntimePermissionsState that = (RuntimePermissionsState) object;
- return mVersion == that.mVersion
- && Objects.equals(mFingerprint, that.mFingerprint)
- && Objects.equals(mPackagePermissions, that.mPackagePermissions)
- && Objects.equals(mSharedUserPermissions, that.mSharedUserPermissions);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mVersion, mFingerprint, mPackagePermissions, mSharedUserPermissions);
- }
-
- /**
- * State of a single permission.
- */
- public static final class PermissionState {
-
- /**
- * The name of the permission.
- */
- @NonNull
- private final String mName;
-
- /**
- * Whether the permission is granted.
- */
- private final boolean mGranted;
-
- /**
- * The flags of the permission.
- */
- private final int mFlags;
-
- /**
- * Create a new instance of this class.
- *
- * @param name the name of the permission
- * @param granted whether the permission is granted
- * @param flags the flags of the permission
- */
- public PermissionState(@NonNull String name, boolean granted, int flags) {
- mName = name;
- mGranted = granted;
- mFlags = flags;
- }
-
- /**
- * Get the name of the permission.
- *
- * @return the name of the permission
- */
- @NonNull
- public String getName() {
- return mName;
- }
-
- /**
- * Get whether the permission is granted.
- *
- * @return whether the permission is granted
- */
- public boolean isGranted() {
- return mGranted;
- }
-
- /**
- * Get the flags of the permission.
- *
- * @return the flags of the permission
- */
- public int getFlags() {
- return mFlags;
- }
-
- @Override
- public boolean equals(Object object) {
- if (this == object) {
- return true;
- }
- if (object == null || getClass() != object.getClass()) {
- return false;
- }
- PermissionState that = (PermissionState) object;
- return mGranted == that.mGranted
- && mFlags == that.mFlags
- && Objects.equals(mName, that.mName);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mName, mGranted, mFlags);
- }
- }
-}
diff --git a/apex/permission/service/java/com/android/permission/util/ArrayUtils.java b/apex/permission/service/java/com/android/permission/util/ArrayUtils.java
deleted file mode 100644
index 5d5cd78201bd..000000000000
--- a/apex/permission/service/java/com/android/permission/util/ArrayUtils.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2021 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.permission.util;
-
-import android.annotation.Nullable;
-
-import java.util.Objects;
-
-/**
- * Array utilities.
- */
-public final class ArrayUtils {
- private ArrayUtils() {}
-
- /**
- * @see java.util.List#contains(Object)
- */
- public static <T> boolean contains(@Nullable T[] array, T value) {
- return indexOf(array, value) != -1;
- }
-
- /**
- * Get the first element of an array, or {@code null} if none.
- *
- * @param array the array
- * @param <T> the type of the elements of the array
- * @return first element of an array, or {@code null} if none
- */
- public static <T> T firstOrNull(@Nullable T[] array) {
- return !isEmpty(array) ? array[0] : null;
- }
-
- /**
- * @see java.util.List#indexOf(Object)
- */
- public static <T> int indexOf(@Nullable T[] array, T value) {
- if (array == null) {
- return -1;
- }
- final int length = array.length;
- for (int i = 0; i < length; i++) {
- final T element = array[i];
- if (Objects.equals(element, value)) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * @see java.util.List#isEmpty()
- */
- public static <T> boolean isEmpty(@Nullable T[] array) {
- return array == null || array.length == 0;
- }
-}
diff --git a/apex/permission/service/java/com/android/permission/util/BackgroundThread.java b/apex/permission/service/java/com/android/permission/util/BackgroundThread.java
deleted file mode 100644
index 7308eec98500..000000000000
--- a/apex/permission/service/java/com/android/permission/util/BackgroundThread.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2021 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.permission.util;
-
-import android.annotation.NonNull;
-import android.os.Handler;
-import android.os.HandlerExecutor;
-import android.os.HandlerThread;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.concurrent.Executor;
-
-/**
- * Shared singleton background thread.
- */
-public class BackgroundThread extends HandlerThread {
- private static final Object sLock = new Object();
-
- @GuardedBy("sLock")
- private static BackgroundThread sInstance;
- @GuardedBy("sLock")
- private static Handler sHandler;
- @GuardedBy("sLock")
- private static Executor sExecutor;
-
- private BackgroundThread() {
- super(BackgroundThread.class.getName());
- }
-
- @GuardedBy("sLock")
- private static void ensureInstanceLocked() {
- if (sInstance == null) {
- sInstance = new BackgroundThread();
- sInstance.start();
- sHandler = new Handler(sInstance.getLooper());
- sExecutor = new HandlerExecutor(sHandler);
- }
- }
-
- /**
- * Get the singleton instance of thi class.
- *
- * @return the singleton instance of thi class
- */
- @NonNull
- public static BackgroundThread get() {
- synchronized (sLock) {
- ensureInstanceLocked();
- return sInstance;
- }
- }
-
- /**
- * Get the {@link Handler} for this thread.
- *
- * @return the {@link Handler} for this thread.
- */
- @NonNull
- public static Handler getHandler() {
- synchronized (sLock) {
- ensureInstanceLocked();
- return sHandler;
- }
- }
-
- /**
- * Get the {@link Executor} for this thread.
- *
- * @return the {@link Executor} for this thread.
- */
- @NonNull
- public static Executor getExecutor() {
- synchronized (sLock) {
- ensureInstanceLocked();
- return sExecutor;
- }
- }
-}
diff --git a/apex/permission/service/java/com/android/permission/util/CollectionUtils.java b/apex/permission/service/java/com/android/permission/util/CollectionUtils.java
deleted file mode 100644
index ea4952404179..000000000000
--- a/apex/permission/service/java/com/android/permission/util/CollectionUtils.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2021 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.permission.util;
-
-import android.annotation.Nullable;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-/**
- * {@link Collection} utilities.
- */
-public class CollectionUtils {
- private CollectionUtils() {}
-
- /**
- * Get the first element of a {@link List}, or {@code null} if none.
- *
- * @param list the {@link List}, or {@code null}
- * @param <E> the element type of the {@link List}
- * @return the first element of the {@link List}, or {@code 0} if none
- */
- @Nullable
- public static <E> E firstOrNull(@Nullable List<E> list) {
- return !isEmpty(list) ? list.get(0) : null;
- }
-
- /**
- * Check whether a {@link Collection} is empty or {@code null}.
- *
- * @param collection the {@link Collection}, or {@code null}
- * @return whether the {@link Collection} is empty or {@code null}
- */
- public static boolean isEmpty(@Nullable Collection<?> collection) {
- return collection == null || collection.isEmpty();
- }
-
- /**
- * Get the size of a {@link Collection}, or {@code 0} if {@code null}.
- *
- * @param collection the {@link Collection}, or {@code null}
- * @return the size of the {@link Collection}, or {@code 0} if {@code null}
- */
- public static int size(@Nullable Collection<?> collection) {
- return collection != null ? collection.size() : 0;
- }
-
- /**
- * Get the size of a {@link Map}, or {@code 0} if {@code null}.
- *
- * @param collection the {@link Map}, or {@code null}
- * @return the size of the {@link Map}, or {@code 0} if {@code null}
- */
- public static int size(@Nullable Map<?, ?> collection) {
- return collection != null ? collection.size() : 0;
- }
-}
diff --git a/apex/permission/service/java/com/android/permission/util/ForegroundThread.java b/apex/permission/service/java/com/android/permission/util/ForegroundThread.java
deleted file mode 100644
index cd6f6057030b..000000000000
--- a/apex/permission/service/java/com/android/permission/util/ForegroundThread.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2021 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.permission.util;
-
-import android.annotation.NonNull;
-import android.os.Handler;
-import android.os.HandlerExecutor;
-import android.os.HandlerThread;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.concurrent.Executor;
-
-/**
- * Shared singleton foreground thread.
- */
-public class ForegroundThread extends HandlerThread {
- private static final Object sLock = new Object();
-
- @GuardedBy("sLock")
- private static ForegroundThread sInstance;
- @GuardedBy("sLock")
- private static Handler sHandler;
- @GuardedBy("sLock")
- private static Executor sExecutor;
-
- private ForegroundThread() {
- super(ForegroundThread.class.getName());
- }
-
- @GuardedBy("sLock")
- private static void ensureInstanceLocked() {
- if (sInstance == null) {
- sInstance = new ForegroundThread();
- sInstance.start();
- sHandler = new Handler(sInstance.getLooper());
- sExecutor = new HandlerExecutor(sHandler);
- }
- }
-
- /**
- * Get the singleton instance of thi class.
- *
- * @return the singleton instance of thi class
- */
- @NonNull
- public static ForegroundThread get() {
- synchronized (sLock) {
- ensureInstanceLocked();
- return sInstance;
- }
- }
-
- /**
- * Get the {@link Handler} for this thread.
- *
- * @return the {@link Handler} for this thread.
- */
- @NonNull
- public static Handler getHandler() {
- synchronized (sLock) {
- ensureInstanceLocked();
- return sHandler;
- }
- }
-
- /**
- * Get the {@link Executor} for this thread.
- *
- * @return the {@link Executor} for this thread.
- */
- @NonNull
- public static Executor getExecutor() {
- synchronized (sLock) {
- ensureInstanceLocked();
- return sExecutor;
- }
- }
-}
diff --git a/apex/permission/service/java/com/android/permission/util/ThrottledRunnable.java b/apex/permission/service/java/com/android/permission/util/ThrottledRunnable.java
deleted file mode 100644
index ba1c3939f73e..000000000000
--- a/apex/permission/service/java/com/android/permission/util/ThrottledRunnable.java
+++ /dev/null
@@ -1,75 +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.permission.util;
-
-import android.annotation.NonNull;
-import android.os.Handler;
-import android.os.SystemClock;
-
-import com.android.internal.annotations.GuardedBy;
-
-/**
- * A throttled runnable that can wrap around a runnable and throttle calls to its run().
- *
- * The throttling logic makes sure that the original runnable will be called only after the
- * specified interval passes since the last actual call. The first call in a while (after the
- * specified interval passes since the last actual call) will always result in the original runnable
- * being called immediately, and then subsequent calls will start to be throttled. It is guaranteed
- * that any call to this throttled runnable will always result in the original runnable being called
- * afterwards, within the specified interval.
- */
-public class ThrottledRunnable implements Runnable {
-
- @NonNull
- private final Handler mHandler;
- private final long mIntervalMillis;
- @NonNull
- private final Runnable mRunnable;
-
- @NonNull
- private final Object mLock = new Object();
-
- @GuardedBy("mLock")
- private long mScheduledUptimeMillis;
-
- public ThrottledRunnable(@NonNull Handler handler, long intervalMillis,
- @NonNull Runnable runnable) {
- mHandler = handler;
- mIntervalMillis = intervalMillis;
- mRunnable = runnable;
- }
-
- @Override
- public void run() {
- synchronized (mLock) {
- if (mHandler.hasCallbacks(mRunnable)) {
- // We have a scheduled runnable.
- return;
- }
- long currentUptimeMillis = SystemClock.uptimeMillis();
- if (mScheduledUptimeMillis == 0
- || currentUptimeMillis > mScheduledUptimeMillis + mIntervalMillis) {
- // First time in a while, schedule immediately.
- mScheduledUptimeMillis = currentUptimeMillis;
- } else {
- // We were scheduled not long ago, so schedule with delay for throttling.
- mScheduledUptimeMillis = mScheduledUptimeMillis + mIntervalMillis;
- }
- mHandler.postAtTime(mRunnable, mScheduledUptimeMillis);
- }
- }
-}
diff --git a/apex/permission/service/java/com/android/permission/util/package-info.java b/apex/permission/service/java/com/android/permission/util/package-info.java
deleted file mode 100644
index 18fada534424..000000000000
--- a/apex/permission/service/java/com/android/permission/util/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-/**
- * @hide
- * TODO(b/146466118) remove this javadoc tag
- */
-@android.annotation.Hide
-package com.android.permission.util;
diff --git a/apex/permission/service/java/com/android/role/RoleManagerLocal.java b/apex/permission/service/java/com/android/role/RoleManagerLocal.java
deleted file mode 100644
index e243e2e0db66..000000000000
--- a/apex/permission/service/java/com/android/role/RoleManagerLocal.java
+++ /dev/null
@@ -1,42 +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.role;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.annotation.UserIdInt;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Internal calls into {@link RoleService}.
- *
- * @hide
- */
-@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-public interface RoleManagerLocal {
- /**
- * Get all roles and their holders.
- *
- * @param userId The user to query to roles for
- *
- * @return The roles and their holders
- */
- @NonNull
- Map<String, Set<String>> getRolesAndHolders(@UserIdInt int userId);
-}
diff --git a/apex/permission/service/java/com/android/role/RoleService.java b/apex/permission/service/java/com/android/role/RoleService.java
deleted file mode 100644
index 5f7eb22a42a7..000000000000
--- a/apex/permission/service/java/com/android/role/RoleService.java
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * 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 com.android.role;
-
-import android.Manifest;
-import android.annotation.AnyThread;
-import android.annotation.MainThread;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.annotation.WorkerThread;
-import android.app.AppOpsManager;
-import android.app.role.IOnRoleHoldersChangedListener;
-import android.app.role.IRoleManager;
-import android.app.role.RoleControllerManager;
-import android.app.role.RoleManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.RemoteCallback;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.AndroidFuture;
-import com.android.internal.util.Preconditions;
-import com.android.internal.util.dump.DualDumpOutputStream;
-import com.android.permission.compat.UserHandleCompat;
-import com.android.permission.util.ArrayUtils;
-import com.android.permission.util.CollectionUtils;
-import com.android.permission.util.ForegroundThread;
-import com.android.permission.util.ThrottledRunnable;
-import com.android.server.LocalManagerRegistry;
-import com.android.server.SystemService;
-import com.android.server.role.RoleServicePlatformHelper;
-
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-/**
- * Service for role management.
- *
- * @see RoleManager
- */
-public class RoleService extends SystemService implements RoleUserState.Callback {
- private static final String LOG_TAG = RoleService.class.getSimpleName();
-
- private static final boolean DEBUG = false;
-
- private static final long GRANT_DEFAULT_ROLES_INTERVAL_MILLIS = 1000;
-
- @NonNull
- private final AppOpsManager mAppOpsManager;
- @NonNull
- private final UserManager mUserManager;
-
- @NonNull
- private final Object mLock = new Object();
-
- @NonNull
- private final RoleServicePlatformHelper mPlatformHelper;
-
- /**
- * Maps user id to its state.
- */
- @GuardedBy("mLock")
- @NonNull
- private final SparseArray<RoleUserState> mUserStates = new SparseArray<>();
-
- /**
- * Maps user id to its controller.
- */
- @GuardedBy("mLock")
- @NonNull
- private final SparseArray<RoleControllerManager> mControllers = new SparseArray<>();
-
- /**
- * Maps user id to its list of listeners.
- */
- @GuardedBy("mLock")
- @NonNull
- private final SparseArray<RemoteCallbackList<IOnRoleHoldersChangedListener>> mListeners =
- new SparseArray<>();
-
- @NonNull
- private final Handler mListenerHandler = ForegroundThread.getHandler();
-
- /**
- * Maps user id to its throttled runnable for granting default roles.
- */
- @GuardedBy("mLock")
- @NonNull
- private final SparseArray<ThrottledRunnable> mGrantDefaultRolesThrottledRunnables =
- new SparseArray<>();
-
- public RoleService(@NonNull Context context) {
- super(context);
-
- mPlatformHelper = LocalManagerRegistry.getManager(RoleServicePlatformHelper.class);
-
- RoleControllerManager.initializeRemoteServiceComponentName(context);
-
- mAppOpsManager = context.getSystemService(AppOpsManager.class);
- mUserManager = context.getSystemService(UserManager.class);
-
- LocalManagerRegistry.addManager(RoleManagerLocal.class, new Local());
-
- registerUserRemovedReceiver();
- }
-
- private void registerUserRemovedReceiver() {
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_REMOVED);
- getContext().registerReceiverForAllUsers(new BroadcastReceiver() {
- @Override
- public void onReceive(@NonNull Context context, @NonNull Intent intent) {
- if (TextUtils.equals(intent.getAction(), Intent.ACTION_USER_REMOVED)) {
- int userId = intent.<UserHandle>getParcelableExtra(Intent.EXTRA_USER)
- .getIdentifier();
- onRemoveUser(userId);
- }
- }
- }, intentFilter, null, null);
- }
-
- @Override
- public void onStart() {
- publishBinderService(Context.ROLE_SERVICE, new Stub());
-
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- intentFilter.addDataScheme("package");
- intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- getContext().registerReceiverForAllUsers(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- int userId = UserHandleCompat.getUserId(intent.getIntExtra(Intent.EXTRA_UID, -1));
- if (DEBUG) {
- Log.i(LOG_TAG, "Packages changed - re-running initial grants for user "
- + userId);
- }
- if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
- && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
- // Package is being upgraded - we're about to get ACTION_PACKAGE_ADDED
- return;
- }
- maybeGrantDefaultRolesAsync(userId);
- }
- }, intentFilter, null, null);
- }
-
- @Override
- public void onUserStarting(@NonNull TargetUser user) {
- maybeGrantDefaultRolesSync(user.getUserHandle().getIdentifier());
- }
-
- @MainThread
- private void maybeGrantDefaultRolesSync(@UserIdInt int userId) {
- AndroidFuture<Void> future = maybeGrantDefaultRolesInternal(userId);
- try {
- future.get(30, TimeUnit.SECONDS);
- } catch (InterruptedException | ExecutionException | TimeoutException e) {
- Log.e(LOG_TAG, "Failed to grant default roles for user " + userId, e);
- }
- }
-
- private void maybeGrantDefaultRolesAsync(@UserIdInt int userId) {
- ThrottledRunnable runnable;
- synchronized (mLock) {
- runnable = mGrantDefaultRolesThrottledRunnables.get(userId);
- if (runnable == null) {
- runnable = new ThrottledRunnable(ForegroundThread.getHandler(),
- GRANT_DEFAULT_ROLES_INTERVAL_MILLIS,
- () -> maybeGrantDefaultRolesInternal(userId));
- mGrantDefaultRolesThrottledRunnables.put(userId, runnable);
- }
- }
- runnable.run();
- }
-
- @AnyThread
- @NonNull
- private AndroidFuture<Void> maybeGrantDefaultRolesInternal(@UserIdInt int userId) {
- RoleUserState userState = getOrCreateUserState(userId);
- String oldPackagesHash = userState.getPackagesHash();
- String newPackagesHash = mPlatformHelper.computePackageStateHash(userId);
- if (Objects.equals(oldPackagesHash, newPackagesHash)) {
- if (DEBUG) {
- Log.i(LOG_TAG, "Already granted default roles for packages hash "
- + newPackagesHash);
- }
- return AndroidFuture.completedFuture(null);
- }
-
- // Some package state has changed, so grant default roles again.
- Log.i(LOG_TAG, "Granting default roles...");
- AndroidFuture<Void> future = new AndroidFuture<>();
- getOrCreateController(userId).grantDefaultRoles(ForegroundThread.getExecutor(),
- successful -> {
- if (successful) {
- userState.setPackagesHash(newPackagesHash);
- future.complete(null);
- } else {
- future.completeExceptionally(new RuntimeException());
- }
- });
- return future;
- }
-
- @NonNull
- private RoleUserState getOrCreateUserState(@UserIdInt int userId) {
- synchronized (mLock) {
- RoleUserState userState = mUserStates.get(userId);
- if (userState == null) {
- userState = new RoleUserState(userId, mPlatformHelper, this);
- mUserStates.put(userId, userState);
- }
- return userState;
- }
- }
-
- @NonNull
- private RoleControllerManager getOrCreateController(@UserIdInt int userId) {
- synchronized (mLock) {
- RoleControllerManager controller = mControllers.get(userId);
- if (controller == null) {
- Context systemContext = getContext();
- Context context;
- try {
- context = systemContext.createPackageContextAsUser(
- systemContext.getPackageName(), 0, UserHandle.of(userId));
- } catch (PackageManager.NameNotFoundException e) {
- throw new RuntimeException(e);
- }
- controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName(
- ForegroundThread.getHandler(), context);
- mControllers.put(userId, controller);
- }
- return controller;
- }
- }
-
- @Nullable
- private RemoteCallbackList<IOnRoleHoldersChangedListener> getListeners(@UserIdInt int userId) {
- synchronized (mLock) {
- return mListeners.get(userId);
- }
- }
-
- @NonNull
- private RemoteCallbackList<IOnRoleHoldersChangedListener> getOrCreateListeners(
- @UserIdInt int userId) {
- synchronized (mLock) {
- RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = mListeners.get(userId);
- if (listeners == null) {
- listeners = new RemoteCallbackList<>();
- mListeners.put(userId, listeners);
- }
- return listeners;
- }
- }
-
- private void onRemoveUser(@UserIdInt int userId) {
- RemoteCallbackList<IOnRoleHoldersChangedListener> listeners;
- RoleUserState userState;
- synchronized (mLock) {
- mGrantDefaultRolesThrottledRunnables.remove(userId);
- listeners = mListeners.get(userId);
- mListeners.remove(userId);
- mControllers.remove(userId);
- userState = mUserStates.get(userId);
- mUserStates.remove(userId);
- }
- if (listeners != null) {
- listeners.kill();
- }
- if (userState != null) {
- userState.destroy();
- }
- }
-
- @Override
- public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
- mListenerHandler.post(() -> notifyRoleHoldersChanged(roleName, userId));
- }
-
- @WorkerThread
- private void notifyRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
- RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getListeners(userId);
- if (listeners != null) {
- notifyRoleHoldersChangedForListeners(listeners, roleName, userId);
- }
-
- RemoteCallbackList<IOnRoleHoldersChangedListener> allUsersListeners = getListeners(
- UserHandleCompat.USER_ALL);
- if (allUsersListeners != null) {
- notifyRoleHoldersChangedForListeners(allUsersListeners, roleName, userId);
- }
- }
-
- @WorkerThread
- private void notifyRoleHoldersChangedForListeners(
- @NonNull RemoteCallbackList<IOnRoleHoldersChangedListener> listeners,
- @NonNull String roleName, @UserIdInt int userId) {
- int broadcastCount = listeners.beginBroadcast();
- try {
- for (int i = 0; i < broadcastCount; i++) {
- IOnRoleHoldersChangedListener listener = listeners.getBroadcastItem(i);
- try {
- listener.onRoleHoldersChanged(roleName, userId);
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Error calling OnRoleHoldersChangedListener", e);
- }
- }
- } finally {
- listeners.finishBroadcast();
- }
- }
-
- private class Stub extends IRoleManager.Stub {
-
- @Override
- public boolean isRoleAvailable(@NonNull String roleName) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
-
- int userId = UserHandleCompat.getUserId(getCallingUid());
- return getOrCreateUserState(userId).isRoleAvailable(roleName);
- }
-
- @Override
- public boolean isRoleHeld(@NonNull String roleName, @NonNull String packageName) {
- int callingUid = getCallingUid();
- mAppOpsManager.checkPackage(callingUid, packageName);
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
-
- int userId = UserHandleCompat.getUserId(callingUid);
- ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
- if (roleHolders == null) {
- return false;
- }
- return roleHolders.contains(packageName);
- }
-
- @NonNull
- @Override
- public List<String> getRoleHoldersAsUser(@NonNull String roleName, @UserIdInt int userId) {
- if (!isUserExistent(userId)) {
- Log.e(LOG_TAG, "user " + userId + " does not exist");
- return Collections.emptyList();
- }
- enforceCrossUserPermission(userId, false, "getRoleHoldersAsUser");
- getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
- "getRoleHoldersAsUser");
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
-
- ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
- if (roleHolders == null) {
- return Collections.emptyList();
- }
- return new ArrayList<>(roleHolders);
- }
-
- @Override
- public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
- @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
- @NonNull RemoteCallback callback) {
- if (!isUserExistent(userId)) {
- Log.e(LOG_TAG, "user " + userId + " does not exist");
- return;
- }
- enforceCrossUserPermission(userId, false, "addRoleHolderAsUser");
- getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
- "addRoleHolderAsUser");
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- Objects.requireNonNull(callback, "callback cannot be null");
-
- getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags,
- callback);
- }
-
- @Override
- public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
- @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
- @NonNull RemoteCallback callback) {
- if (!isUserExistent(userId)) {
- Log.e(LOG_TAG, "user " + userId + " does not exist");
- return;
- }
- enforceCrossUserPermission(userId, false, "removeRoleHolderAsUser");
- getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
- "removeRoleHolderAsUser");
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- Objects.requireNonNull(callback, "callback cannot be null");
-
- getOrCreateController(userId).onRemoveRoleHolder(roleName, packageName, flags,
- callback);
- }
-
- @Override
- public void clearRoleHoldersAsUser(@NonNull String roleName,
- @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
- @NonNull RemoteCallback callback) {
- if (!isUserExistent(userId)) {
- Log.e(LOG_TAG, "user " + userId + " does not exist");
- return;
- }
- enforceCrossUserPermission(userId, false, "clearRoleHoldersAsUser");
- getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
- "clearRoleHoldersAsUser");
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Objects.requireNonNull(callback, "callback cannot be null");
-
- getOrCreateController(userId).onClearRoleHolders(roleName, flags, callback);
- }
-
- @Override
- public void addOnRoleHoldersChangedListenerAsUser(
- @NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
- if (userId != UserHandleCompat.USER_ALL && !isUserExistent(userId)) {
- Log.e(LOG_TAG, "user " + userId + " does not exist");
- return;
- }
- enforceCrossUserPermission(userId, true, "addOnRoleHoldersChangedListenerAsUser");
- getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
- "addOnRoleHoldersChangedListenerAsUser");
-
- Objects.requireNonNull(listener, "listener cannot be null");
-
- RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getOrCreateListeners(
- userId);
- listeners.register(listener);
- }
-
- @Override
- public void removeOnRoleHoldersChangedListenerAsUser(
- @NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
- if (userId != UserHandleCompat.USER_ALL && !isUserExistent(userId)) {
- Log.e(LOG_TAG, "user " + userId + " does not exist");
- return;
- }
- enforceCrossUserPermission(userId, true, "removeOnRoleHoldersChangedListenerAsUser");
- getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
- "removeOnRoleHoldersChangedListenerAsUser");
-
- Objects.requireNonNull(listener, "listener cannot be null");
-
- RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getListeners(userId);
- if (listener == null) {
- return;
- }
- listeners.unregister(listener);
- }
-
- @Override
- public void setRoleNamesFromController(@NonNull List<String> roleNames) {
- getContext().enforceCallingOrSelfPermission(
- RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
- "setRoleNamesFromController");
-
- Objects.requireNonNull(roleNames, "roleNames cannot be null");
-
- int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
- getOrCreateUserState(userId).setRoleNames(roleNames);
- }
-
- @Override
- public boolean addRoleHolderFromController(@NonNull String roleName,
- @NonNull String packageName) {
- getContext().enforceCallingOrSelfPermission(
- RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
- "addRoleHolderFromController");
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
-
- int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
- return getOrCreateUserState(userId).addRoleHolder(roleName, packageName);
- }
-
- @Override
- public boolean removeRoleHolderFromController(@NonNull String roleName,
- @NonNull String packageName) {
- getContext().enforceCallingOrSelfPermission(
- RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
- "removeRoleHolderFromController");
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
-
- int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
- return getOrCreateUserState(userId).removeRoleHolder(roleName, packageName);
- }
-
- @Override
- public List<String> getHeldRolesFromController(@NonNull String packageName) {
- getContext().enforceCallingOrSelfPermission(
- RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
- "getRolesHeldFromController");
-
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
-
- int userId = UserHandleCompat.getUserId(Binder.getCallingUid());
- return getOrCreateUserState(userId).getHeldRoles(packageName);
- }
-
- private boolean isUserExistent(@UserIdInt int userId) {
- // FIXME: This checks whether the user is alive, but we should check for whether the
- // user is existent.
- return mUserManager.getUserHandles(true).contains(UserHandle.of(userId));
- }
-
- private void enforceCrossUserPermission(@UserIdInt int userId, boolean allowAll,
- @NonNull String message) {
- final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandleCompat.getUserId(callingUid);
- if (userId == callingUserId) {
- return;
- }
- Preconditions.checkArgument(userId >= UserHandleCompat.USER_SYSTEM
- || (allowAll && userId == UserHandleCompat.USER_ALL), "Invalid user " + userId);
- getContext().enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
- if (callingUid == Process.SHELL_UID && userId >= UserHandleCompat.USER_SYSTEM) {
- if (mUserManager.hasUserRestrictionForUser(UserManager.DISALLOW_DEBUGGING_FEATURES,
- UserHandle.of(userId))) {
- throw new SecurityException("Shell does not have permission to access user "
- + userId);
- }
- }
- }
-
- @Override
- public int handleShellCommand(@NonNull ParcelFileDescriptor in,
- @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
- @NonNull String[] args) {
- return new RoleShellCommand(this).exec(this, in.getFileDescriptor(),
- out.getFileDescriptor(), err.getFileDescriptor(), args);
- }
-
- @Nullable
- @Override
- public String getBrowserRoleHolder(@UserIdInt int userId) {
- final int callingUid = Binder.getCallingUid();
- if (UserHandleCompat.getUserId(callingUid) != userId) {
- getContext().enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
- }
- if (isInstantApp(callingUid)) {
- return null;
- }
-
- final long identity = Binder.clearCallingIdentity();
- try {
- return CollectionUtils.firstOrNull(getRoleHoldersAsUser(RoleManager.ROLE_BROWSER,
- userId));
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- private boolean isInstantApp(int uid) {
- final long identity = Binder.clearCallingIdentity();
- try {
- final UserHandle user = UserHandle.getUserHandleForUid(uid);
- final Context userContext = getContext().createContextAsUser(user, 0);
- final PackageManager userPackageManager = userContext.getPackageManager();
- // Instant apps can not have shared UID, so it's safe to check only the first
- // package name here.
- final String packageName = ArrayUtils.firstOrNull(
- userPackageManager.getPackagesForUid(uid));
- if (packageName == null) {
- return false;
- }
- return userPackageManager.isInstantApp(packageName);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @Override
- public boolean setBrowserRoleHolder(@Nullable String packageName, @UserIdInt int userId) {
- final Context context = getContext();
- context.enforceCallingOrSelfPermission(
- android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
- if (UserHandleCompat.getUserId(Binder.getCallingUid()) != userId) {
- context.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
- }
-
- if (!isUserExistent(userId)) {
- return false;
- }
-
- final AndroidFuture<Void> future = new AndroidFuture<>();
- final RemoteCallback callback = new RemoteCallback(result -> {
- boolean successful = result != null;
- if (successful) {
- future.complete(null);
- } else {
- future.completeExceptionally(new RuntimeException());
- }
- });
- final long identity = Binder.clearCallingIdentity();
- try {
- if (packageName != null) {
- addRoleHolderAsUser(RoleManager.ROLE_BROWSER, packageName, 0, userId, callback);
- } else {
- clearRoleHoldersAsUser(RoleManager.ROLE_BROWSER, 0, userId, callback);
- }
- try {
- future.get(5, TimeUnit.SECONDS);
- } catch (InterruptedException | ExecutionException | TimeoutException e) {
- Log.e(LOG_TAG, "Exception while setting default browser: " + packageName, e);
- return false;
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- return true;
- }
-
- @Override
- public String getSmsRoleHolder(int userId) {
- final long identity = Binder.clearCallingIdentity();
- try {
- return CollectionUtils.firstOrNull(getRoleHoldersAsUser(RoleManager.ROLE_SMS,
- userId));
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @Override
- protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
- @Nullable String[] args) {
- if (!checkDumpPermission("role", fout)) {
- return;
- }
-
- boolean dumpAsProto = args != null && ArrayUtils.contains(args, "--proto");
- DualDumpOutputStream dumpOutputStream;
- if (dumpAsProto) {
- dumpOutputStream = new DualDumpOutputStream(new ProtoOutputStream(
- new FileOutputStream(fd)));
- } else {
- fout.println("ROLE STATE (dumpsys role):");
- dumpOutputStream = new DualDumpOutputStream(new IndentingPrintWriter(fout, " "));
- }
-
- synchronized (mLock) {
- final int userStatesSize = mUserStates.size();
- for (int i = 0; i < userStatesSize; i++) {
- final RoleUserState userState = mUserStates.valueAt(i);
-
- userState.dump(dumpOutputStream, "user_states",
- RoleServiceDumpProto.USER_STATES);
- }
- }
-
- dumpOutputStream.flush();
- }
-
- private boolean checkDumpPermission(@NonNull String serviceName,
- @NonNull PrintWriter writer) {
- if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- writer.println("Permission Denial: can't dump " + serviceName + " from from pid="
- + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
- + " due to missing " + android.Manifest.permission.DUMP + " permission");
- return false;
- } else {
- return true;
- }
- }
- }
-
- private class Local implements RoleManagerLocal {
- @NonNull
- @Override
- public Map<String, Set<String>> getRolesAndHolders(@UserIdInt int userId) {
- // Convert ArrayMap<String, ArraySet<String>> to Map<String, Set<String>> for the API.
- //noinspection unchecked
- return (Map<String, Set<String>>) (Map<String, ?>)
- getOrCreateUserState(userId).getRolesAndHolders();
- }
- }
-}
diff --git a/apex/permission/service/java/com/android/role/RoleShellCommand.java b/apex/permission/service/java/com/android/role/RoleShellCommand.java
deleted file mode 100644
index 03b7c76d2df5..000000000000
--- a/apex/permission/service/java/com/android/role/RoleShellCommand.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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 com.android.role;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.role.IRoleManager;
-import android.os.RemoteCallback;
-import android.os.RemoteException;
-
-import com.android.modules.utils.BasicShellCommandHandler;
-import com.android.permission.compat.UserHandleCompat;
-
-import java.io.PrintWriter;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
-
-class RoleShellCommand extends BasicShellCommandHandler {
- @NonNull
- private final IRoleManager mRoleManager;
-
- RoleShellCommand(@NonNull IRoleManager roleManager) {
- mRoleManager = roleManager;
- }
-
- private class CallbackFuture extends CompletableFuture<Void> {
- @NonNull
- public RemoteCallback createCallback() {
- return new RemoteCallback(result -> {
- boolean successful = result != null;
- if (successful) {
- complete(null);
- } else {
- completeExceptionally(new RuntimeException("Failed"));
- }
- });
- }
-
- public int waitForResult() {
- try {
- get(5, TimeUnit.SECONDS);
- return 0;
- } catch (Exception e) {
- getErrPrintWriter().println("Error: see logcat for details.\n" + e);
- return -1;
- }
- }
- }
-
- @Override
- public int onCommand(@Nullable String cmd) {
- if (cmd == null) {
- return handleDefaultCommands(cmd);
- }
-
- PrintWriter pw = getOutPrintWriter();
- try {
- switch (cmd) {
- case "add-role-holder":
- return runAddRoleHolder();
- case "remove-role-holder":
- return runRemoveRoleHolder();
- case "clear-role-holders":
- return runClearRoleHolders();
- default:
- return handleDefaultCommands(cmd);
- }
- } catch (RemoteException e) {
- pw.println("Remote exception: " + e);
- }
- return -1;
- }
-
- private int getUserIdMaybe() {
- int userId = UserHandleCompat.USER_SYSTEM;
- String option = getNextOption();
- if (option != null && option.equals("--user")) {
- userId = Integer.parseInt(getNextArgRequired());
- }
- return userId;
- }
-
- private int getFlagsMaybe() {
- String flags = getNextArg();
- if (flags == null) {
- return 0;
- }
- return Integer.parseInt(flags);
- }
-
- private int runAddRoleHolder() throws RemoteException {
- int userId = getUserIdMaybe();
- String roleName = getNextArgRequired();
- String packageName = getNextArgRequired();
- int flags = getFlagsMaybe();
-
- CallbackFuture future = new CallbackFuture();
- mRoleManager.addRoleHolderAsUser(roleName, packageName, flags, userId,
- future.createCallback());
- return future.waitForResult();
- }
-
- private int runRemoveRoleHolder() throws RemoteException {
- int userId = getUserIdMaybe();
- String roleName = getNextArgRequired();
- String packageName = getNextArgRequired();
- int flags = getFlagsMaybe();
-
- CallbackFuture future = new CallbackFuture();
- mRoleManager.removeRoleHolderAsUser(roleName, packageName, flags, userId,
- future.createCallback());
- return future.waitForResult();
- }
-
- private int runClearRoleHolders() throws RemoteException {
- int userId = getUserIdMaybe();
- String roleName = getNextArgRequired();
- int flags = getFlagsMaybe();
-
- CallbackFuture future = new CallbackFuture();
- mRoleManager.clearRoleHoldersAsUser(roleName, flags, userId, future.createCallback());
- return future.waitForResult();
- }
-
- @Override
- public void onHelp() {
- PrintWriter pw = getOutPrintWriter();
- pw.println("Role (role) commands:");
- pw.println(" help or -h");
- pw.println(" Print this help text.");
- pw.println();
- pw.println(" add-role-holder [--user USER_ID] ROLE PACKAGE [FLAGS]");
- pw.println(" remove-role-holder [--user USER_ID] ROLE PACKAGE [FLAGS]");
- pw.println(" clear-role-holders [--user USER_ID] ROLE [FLAGS]");
- pw.println();
- }
-}
diff --git a/apex/permission/service/java/com/android/role/RoleUserState.java b/apex/permission/service/java/com/android/role/RoleUserState.java
deleted file mode 100644
index 78d8d15bbe60..000000000000
--- a/apex/permission/service/java/com/android/role/RoleUserState.java
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- * 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 com.android.role;
-
-import android.annotation.CheckResult;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.annotation.WorkerThread;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.dump.DualDumpOutputStream;
-import com.android.permission.util.BackgroundThread;
-import com.android.permission.util.CollectionUtils;
-import com.android.role.persistence.RolesPersistence;
-import com.android.role.persistence.RolesState;
-import com.android.server.role.RoleServicePlatformHelper;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Stores the state of roles for a user.
- */
-class RoleUserState {
- private static final String LOG_TAG = RoleUserState.class.getSimpleName();
-
- public static final int VERSION_UNDEFINED = -1;
-
- private static final long WRITE_DELAY_MILLIS = 200;
-
- private final RolesPersistence mPersistence = RolesPersistence.createInstance();
-
- @UserIdInt
- private final int mUserId;
-
- @NonNull
- private final RoleServicePlatformHelper mPlatformHelper;
-
- @NonNull
- private final Callback mCallback;
-
- @NonNull
- private final Object mLock = new Object();
-
- @GuardedBy("mLock")
- private int mVersion = VERSION_UNDEFINED;
-
- @GuardedBy("mLock")
- @Nullable
- private String mPackagesHash;
-
- /**
- * Maps role names to its holders' package names. The values should never be null.
- */
- @GuardedBy("mLock")
- @NonNull
- private ArrayMap<String, ArraySet<String>> mRoles = new ArrayMap<>();
-
- @GuardedBy("mLock")
- private boolean mWriteScheduled;
-
- @GuardedBy("mLock")
- private boolean mDestroyed;
-
- @NonNull
- private final Handler mWriteHandler = new Handler(BackgroundThread.get().getLooper());
-
- /**
- * Create a new user state, and read its state from disk if previously persisted.
- *
- * @param userId the user id for this user state
- * @param platformHelper the platform helper
- * @param callback the callback for this user state
- */
- public RoleUserState(@UserIdInt int userId, @NonNull RoleServicePlatformHelper platformHelper,
- @NonNull Callback callback) {
- mUserId = userId;
- mPlatformHelper = platformHelper;
- mCallback = callback;
-
- readFile();
- }
-
- /**
- * Get the version of this user state.
- */
- public int getVersion() {
- synchronized (mLock) {
- return mVersion;
- }
- }
-
- /**
- * Set the version of this user state.
- *
- * @param version the version to set
- */
- public void setVersion(int version) {
- synchronized (mLock) {
- if (mVersion == version) {
- return;
- }
- mVersion = version;
- scheduleWriteFileLocked();
- }
- }
-
- /**
- * Get the hash representing the state of packages during the last time initial grants was run.
- *
- * @return the hash representing the state of packages
- */
- @Nullable
- public String getPackagesHash() {
- synchronized (mLock) {
- return mPackagesHash;
- }
- }
-
- /**
- * Set the hash representing the state of packages during the last time initial grants was run.
- *
- * @param packagesHash the hash representing the state of packages
- */
- public void setPackagesHash(@Nullable String packagesHash) {
- synchronized (mLock) {
- if (Objects.equals(mPackagesHash, packagesHash)) {
- return;
- }
- mPackagesHash = packagesHash;
- scheduleWriteFileLocked();
- }
- }
-
- /**
- * Get whether the role is available.
- *
- * @param roleName the name of the role to get the holders for
- *
- * @return whether the role is available
- */
- public boolean isRoleAvailable(@NonNull String roleName) {
- synchronized (mLock) {
- return mRoles.containsKey(roleName);
- }
- }
-
- /**
- * Get the holders of a role.
- *
- * @param roleName the name of the role to query for
- *
- * @return the set of role holders, or {@code null} if and only if the role is not found
- */
- @Nullable
- public ArraySet<String> getRoleHolders(@NonNull String roleName) {
- synchronized (mLock) {
- ArraySet<String> packageNames = mRoles.get(roleName);
- if (packageNames == null) {
- return null;
- }
- return new ArraySet<>(packageNames);
- }
- }
-
- /**
- * Adds the given role, effectively marking it as {@link #isRoleAvailable available}
- *
- * @param roleName the name of the role
- *
- * @return whether any changes were made
- */
- public boolean addRoleName(@NonNull String roleName) {
- synchronized (mLock) {
- if (!mRoles.containsKey(roleName)) {
- mRoles.put(roleName, new ArraySet<>());
- Log.i(LOG_TAG, "Added new role: " + roleName);
- scheduleWriteFileLocked();
- return true;
- } else {
- return false;
- }
- }
- }
-
- /**
- * Set the names of all available roles.
- *
- * @param roleNames the names of all the available roles
- */
- public void setRoleNames(@NonNull List<String> roleNames) {
- synchronized (mLock) {
- boolean changed = false;
-
- for (int i = mRoles.size() - 1; i >= 0; i--) {
- String roleName = mRoles.keyAt(i);
-
- if (!roleNames.contains(roleName)) {
- ArraySet<String> packageNames = mRoles.valueAt(i);
- if (!packageNames.isEmpty()) {
- Log.e(LOG_TAG, "Holders of a removed role should have been cleaned up,"
- + " role: " + roleName + ", holders: " + packageNames);
- }
- mRoles.removeAt(i);
- changed = true;
- }
- }
-
- int roleNamesSize = roleNames.size();
- for (int i = 0; i < roleNamesSize; i++) {
- changed |= addRoleName(roleNames.get(i));
- }
-
- if (changed) {
- scheduleWriteFileLocked();
- }
- }
- }
-
- /**
- * Add a holder to a role.
- *
- * @param roleName the name of the role to add the holder to
- * @param packageName the package name of the new holder
- *
- * @return {@code false} if and only if the role is not found
- */
- @CheckResult
- public boolean addRoleHolder(@NonNull String roleName, @NonNull String packageName) {
- boolean changed;
-
- synchronized (mLock) {
- ArraySet<String> roleHolders = mRoles.get(roleName);
- if (roleHolders == null) {
- Log.e(LOG_TAG, "Cannot add role holder for unknown role, role: " + roleName
- + ", package: " + packageName);
- return false;
- }
- changed = roleHolders.add(packageName);
- if (changed) {
- scheduleWriteFileLocked();
- }
- }
-
- if (changed) {
- mCallback.onRoleHoldersChanged(roleName, mUserId);
- }
- return true;
- }
-
- /**
- * Remove a holder from a role.
- *
- * @param roleName the name of the role to remove the holder from
- * @param packageName the package name of the holder to remove
- *
- * @return {@code false} if and only if the role is not found
- */
- @CheckResult
- public boolean removeRoleHolder(@NonNull String roleName, @NonNull String packageName) {
- boolean changed;
-
- synchronized (mLock) {
- ArraySet<String> roleHolders = mRoles.get(roleName);
- if (roleHolders == null) {
- Log.e(LOG_TAG, "Cannot remove role holder for unknown role, role: " + roleName
- + ", package: " + packageName);
- return false;
- }
-
- changed = roleHolders.remove(packageName);
- if (changed) {
- scheduleWriteFileLocked();
- }
- }
-
- if (changed) {
- mCallback.onRoleHoldersChanged(roleName, mUserId);
- }
- return true;
- }
-
- /**
- * @see android.app.role.RoleManager#getHeldRolesFromController
- */
- @NonNull
- public List<String> getHeldRoles(@NonNull String packageName) {
- synchronized (mLock) {
- List<String> roleNames = new ArrayList<>();
- int size = mRoles.size();
- for (int i = 0; i < size; i++) {
- if (mRoles.valueAt(i).contains(packageName)) {
- roleNames.add(mRoles.keyAt(i));
- }
- }
- return roleNames;
- }
- }
-
- /**
- * Schedule writing the state to file.
- */
- @GuardedBy("mLock")
- private void scheduleWriteFileLocked() {
- if (mDestroyed) {
- return;
- }
-
- if (!mWriteScheduled) {
- mWriteHandler.postDelayed(this::writeFile, WRITE_DELAY_MILLIS);
- mWriteScheduled = true;
- }
- }
-
- @WorkerThread
- private void writeFile() {
- RolesState roles;
- synchronized (mLock) {
- if (mDestroyed) {
- return;
- }
-
- mWriteScheduled = false;
-
- roles = new RolesState(mVersion, mPackagesHash,
- (Map<String, Set<String>>) (Map<String, ?>) snapshotRolesLocked());
- }
-
- mPersistence.writeForUser(roles, UserHandle.of(mUserId));
- }
-
- private void readFile() {
- synchronized (mLock) {
- RolesState roleState = mPersistence.readForUser(UserHandle.of(mUserId));
-
- Map<String, Set<String>> roles;
- if (roleState != null) {
- mVersion = roleState.getVersion();
- mPackagesHash = roleState.getPackagesHash();
- roles = roleState.getRoles();
- } else {
- roles = mPlatformHelper.getLegacyRoleState(mUserId);
- }
- mRoles.clear();
- for (Map.Entry<String, Set<String>> entry : roles.entrySet()) {
- String roleName = entry.getKey();
- ArraySet<String> roleHolders = new ArraySet<>(entry.getValue());
- mRoles.put(roleName, roleHolders);
- }
-
- if (roleState == null) {
- scheduleWriteFileLocked();
- }
- }
- }
-
- /**
- * Dump this user state.
- *
- * @param dumpOutputStream the output stream to dump to
- */
- public void dump(@NonNull DualDumpOutputStream dumpOutputStream, @NonNull String fieldName,
- long fieldId) {
- int version;
- String packagesHash;
- ArrayMap<String, ArraySet<String>> roles;
- synchronized (mLock) {
- version = mVersion;
- packagesHash = mPackagesHash;
- roles = snapshotRolesLocked();
- }
-
- long fieldToken = dumpOutputStream.start(fieldName, fieldId);
- dumpOutputStream.write("user_id", RoleUserStateProto.USER_ID, mUserId);
- dumpOutputStream.write("version", RoleUserStateProto.VERSION, version);
- dumpOutputStream.write("packages_hash", RoleUserStateProto.PACKAGES_HASH, packagesHash);
-
- int rolesSize = roles.size();
- for (int rolesIndex = 0; rolesIndex < rolesSize; rolesIndex++) {
- String roleName = roles.keyAt(rolesIndex);
- ArraySet<String> roleHolders = roles.valueAt(rolesIndex);
-
- long rolesToken = dumpOutputStream.start("roles", RoleUserStateProto.ROLES);
- dumpOutputStream.write("name", RoleProto.NAME, roleName);
-
- int roleHoldersSize = roleHolders.size();
- for (int roleHoldersIndex = 0; roleHoldersIndex < roleHoldersSize; roleHoldersIndex++) {
- String roleHolder = roleHolders.valueAt(roleHoldersIndex);
-
- dumpOutputStream.write("holders", RoleProto.HOLDERS, roleHolder);
- }
-
- dumpOutputStream.end(rolesToken);
- }
-
- dumpOutputStream.end(fieldToken);
- }
-
- /**
- * Get the roles and their holders.
- *
- * @return A copy of the roles and their holders
- */
- @NonNull
- public ArrayMap<String, ArraySet<String>> getRolesAndHolders() {
- synchronized (mLock) {
- return snapshotRolesLocked();
- }
- }
-
- @GuardedBy("mLock")
- @NonNull
- private ArrayMap<String, ArraySet<String>> snapshotRolesLocked() {
- ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>();
- for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) {
- String roleName = mRoles.keyAt(i);
- ArraySet<String> roleHolders = mRoles.valueAt(i);
-
- roleHolders = new ArraySet<>(roleHolders);
- roles.put(roleName, roleHolders);
- }
- return roles;
- }
-
- /**
- * Destroy this user state and delete the corresponding file. Any pending writes to the file
- * will be cancelled, and any future interaction with this state will throw an exception.
- */
- public void destroy() {
- synchronized (mLock) {
- if (mDestroyed) {
- throw new IllegalStateException("This RoleUserState has already been destroyed");
- }
- mWriteHandler.removeCallbacksAndMessages(null);
- mPersistence.deleteForUser(UserHandle.of(mUserId));
- mDestroyed = true;
- }
- }
-
- /**
- * Callback for a user state.
- */
- public interface Callback {
-
- /**
- * Called when the holders of roles are changed.
- *
- * @param roleName the name of the role whose holders are changed
- * @param userId the user id for this role holder change
- */
- void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId);
- }
-}
diff --git a/apex/permission/service/java/com/android/role/TEST_MAPPING b/apex/permission/service/java/com/android/role/TEST_MAPPING
deleted file mode 100644
index 0d7bc1476bd1..000000000000
--- a/apex/permission/service/java/com/android/role/TEST_MAPPING
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "presubmit": [
- {
- "name": "CtsStatsdHostTestCases",
- "options": [
- {
- "include-filter": "android.cts.statsd.atom.UidAtomTests#testRoleHolder"
- }
- ]
- },
- {
- "name": "CtsRoleTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
- }
- ]
-}
diff --git a/apex/permission/service/java/com/android/role/package-info.java b/apex/permission/service/java/com/android/role/package-info.java
deleted file mode 100644
index 8b5b2516105f..000000000000
--- a/apex/permission/service/java/com/android/role/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-/**
- * @hide
- * TODO(b/146466118) remove this javadoc tag
- */
-@android.annotation.Hide
-package com.android.role;
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
deleted file mode 100644
index 2e5a28aa1d6a..000000000000
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2020 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.role.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-import android.os.UserHandle;
-
-/**
- * Persistence for roles.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-@SystemApi(client = Client.SYSTEM_SERVER)
-public interface RolesPersistence {
-
- /**
- * Read the roles from persistence.
- *
- * This will perform I/O operations synchronously.
- *
- * @param user the user to read for
- * @return the roles read
- */
- @Nullable
- RolesState readForUser(@NonNull UserHandle user);
-
- /**
- * Write the roles to persistence.
- *
- * This will perform I/O operations synchronously.
- *
- * @param roles the roles to write
- * @param user the user to write for
- */
- void writeForUser(@NonNull RolesState roles, @NonNull UserHandle user);
-
- /**
- * Delete the roles from persistence.
- *
- * This will perform I/O operations synchronously.
- *
- * @param user the user to delete for
- */
- void deleteForUser(@NonNull UserHandle user);
-
- /**
- * Create a new instance of {@link RolesPersistence} implementation.
- *
- * @return the new instance.
- */
- @NonNull
- static RolesPersistence createInstance() {
- return new RolesPersistenceImpl();
- }
-}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
deleted file mode 100644
index f66257f13ef6..000000000000
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2020 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.role.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ApexEnvironment;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.AtomicFile;
-import android.util.Log;
-import android.util.Xml;
-
-import com.android.permission.persistence.IoUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Persistence implementation for roles.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-public class RolesPersistenceImpl implements RolesPersistence {
-
- private static final String LOG_TAG = RolesPersistenceImpl.class.getSimpleName();
-
- private static final String APEX_MODULE_NAME = "com.android.permission";
-
- private static final String ROLES_FILE_NAME = "roles.xml";
-
- private static final String TAG_ROLES = "roles";
- private static final String TAG_ROLE = "role";
- private static final String TAG_HOLDER = "holder";
-
- private static final String ATTRIBUTE_VERSION = "version";
- private static final String ATTRIBUTE_NAME = "name";
- private static final String ATTRIBUTE_PACKAGES_HASH = "packagesHash";
-
- @Nullable
- @Override
- public RolesState readForUser(@NonNull UserHandle user) {
- File file = getFile(user);
- try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(inputStream, null);
- return parseXml(parser);
- } catch (FileNotFoundException e) {
- Log.i(LOG_TAG, "roles.xml not found");
- return null;
- } catch (XmlPullParserException | IOException e) {
- throw new IllegalStateException("Failed to read roles.xml: " + file , e);
- }
- }
-
- @NonNull
- private static RolesState parseXml(@NonNull XmlPullParser parser)
- throws IOException, XmlPullParserException {
- int type;
- int depth;
- int innerDepth = parser.getDepth() + 1;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
- if (depth > innerDepth || type != XmlPullParser.START_TAG) {
- continue;
- }
-
- if (parser.getName().equals(TAG_ROLES)) {
- return parseRoles(parser);
- }
- }
- throw new IllegalStateException("Missing <" + TAG_ROLES + "> in roles.xml");
- }
-
- @NonNull
- private static RolesState parseRoles(@NonNull XmlPullParser parser)
- throws IOException, XmlPullParserException {
- int version = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION));
- String packagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
-
- Map<String, Set<String>> roles = new ArrayMap<>();
- int type;
- int depth;
- int innerDepth = parser.getDepth() + 1;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
- if (depth > innerDepth || type != XmlPullParser.START_TAG) {
- continue;
- }
-
- if (parser.getName().equals(TAG_ROLE)) {
- String roleName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
- Set<String> roleHolders = parseRoleHolders(parser);
- roles.put(roleName, roleHolders);
- }
- }
-
- return new RolesState(version, packagesHash, roles);
- }
-
- @NonNull
- private static Set<String> parseRoleHolders(@NonNull XmlPullParser parser)
- throws IOException, XmlPullParserException {
- Set<String> roleHolders = new ArraySet<>();
- int type;
- int depth;
- int innerDepth = parser.getDepth() + 1;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
- if (depth > innerDepth || type != XmlPullParser.START_TAG) {
- continue;
- }
-
- if (parser.getName().equals(TAG_HOLDER)) {
- String roleHolder = parser.getAttributeValue(null, ATTRIBUTE_NAME);
- roleHolders.add(roleHolder);
- }
- }
- return roleHolders;
- }
-
- @Override
- public void writeForUser(@NonNull RolesState roles, @NonNull UserHandle user) {
- File file = getFile(user);
- AtomicFile atomicFile = new AtomicFile(file);
- FileOutputStream outputStream = null;
- try {
- outputStream = atomicFile.startWrite();
-
- XmlSerializer serializer = Xml.newSerializer();
- serializer.setOutput(outputStream, StandardCharsets.UTF_8.name());
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
- serializer.startDocument(null, true);
-
- serializeRoles(serializer, roles);
-
- serializer.endDocument();
- atomicFile.finishWrite(outputStream);
- } catch (Exception e) {
- Log.wtf(LOG_TAG, "Failed to write roles.xml, restoring backup: " + file,
- e);
- atomicFile.failWrite(outputStream);
- } finally {
- IoUtils.closeQuietly(outputStream);
- }
- }
-
- private static void serializeRoles(@NonNull XmlSerializer serializer,
- @NonNull RolesState roles) throws IOException {
- serializer.startTag(null, TAG_ROLES);
-
- int version = roles.getVersion();
- serializer.attribute(null, ATTRIBUTE_VERSION, Integer.toString(version));
- String packagesHash = roles.getPackagesHash();
- if (packagesHash != null) {
- serializer.attribute(null, ATTRIBUTE_PACKAGES_HASH, packagesHash);
- }
-
- for (Map.Entry<String, Set<String>> entry : roles.getRoles().entrySet()) {
- String roleName = entry.getKey();
- Set<String> roleHolders = entry.getValue();
-
- serializer.startTag(null, TAG_ROLE);
- serializer.attribute(null, ATTRIBUTE_NAME, roleName);
- serializeRoleHolders(serializer, roleHolders);
- serializer.endTag(null, TAG_ROLE);
- }
-
- serializer.endTag(null, TAG_ROLES);
- }
-
- private static void serializeRoleHolders(@NonNull XmlSerializer serializer,
- @NonNull Set<String> roleHolders) throws IOException {
- for (String roleHolder : roleHolders) {
- serializer.startTag(null, TAG_HOLDER);
- serializer.attribute(null, ATTRIBUTE_NAME, roleHolder);
- serializer.endTag(null, TAG_HOLDER);
- }
- }
-
- @Override
- public void deleteForUser(@NonNull UserHandle user) {
- getFile(user).delete();
- }
-
- @NonNull
- private static File getFile(@NonNull UserHandle user) {
- ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
- File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
- return new File(dataDirectory, ROLES_FILE_NAME);
- }
-}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesState.java b/apex/permission/service/java/com/android/role/persistence/RolesState.java
deleted file mode 100644
index f61efa0e840d..000000000000
--- a/apex/permission/service/java/com/android/role/persistence/RolesState.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2020 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.role.persistence;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * State of all roles.
- *
- * TODO(b/147914847): Remove @hide when it becomes the default.
- * @hide
- */
-@SystemApi(client = Client.SYSTEM_SERVER)
-public final class RolesState {
-
- /**
- * The version of the roles.
- */
- private final int mVersion;
-
- /**
- * The hash of all packages in the system.
- */
- @Nullable
- private final String mPackagesHash;
-
- /**
- * The roles.
- */
- @NonNull
- private final Map<String, Set<String>> mRoles;
-
- /**
- * Create a new instance of this class.
- *
- * @param version the version of the roles
- * @param packagesHash the hash of all packages in the system
- * @param roles the roles
- */
- public RolesState(int version, @Nullable String packagesHash,
- @NonNull Map<String, Set<String>> roles) {
- mVersion = version;
- mPackagesHash = packagesHash;
- mRoles = roles;
- }
-
- /**
- * Get the version of the roles.
- *
- * @return the version of the roles
- */
- public int getVersion() {
- return mVersion;
- }
-
- /**
- * Get the hash of all packages in the system.
- *
- * @return the hash of all packages in the system
- */
- @Nullable
- public String getPackagesHash() {
- return mPackagesHash;
- }
-
- /**
- * Get the roles.
- *
- * @return the roles
- */
- @NonNull
- public Map<String, Set<String>> getRoles() {
- return mRoles;
- }
-
- @Override
- public boolean equals(Object object) {
- if (this == object) {
- return true;
- }
- if (object == null || getClass() != object.getClass()) {
- return false;
- }
- RolesState that = (RolesState) object;
- return mVersion == that.mVersion
- && Objects.equals(mPackagesHash, that.mPackagesHash)
- && Objects.equals(mRoles, that.mRoles);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mVersion, mPackagesHash, mRoles);
- }
-}
diff --git a/apex/permission/service/proto/com/android/role/roleservice.proto b/apex/permission/service/proto/com/android/role/roleservice.proto
deleted file mode 100644
index 79c42299207c..000000000000
--- a/apex/permission/service/proto/com/android/role/roleservice.proto
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.
- */
-
-syntax = "proto2";
-
-package com.android.role;
-
-option java_multiple_files = true;
-
-import "frameworks/base/core/proto/android/privacy.proto";
-
-message RoleServiceDumpProto {
- option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
- // List of per-user states for all users.
- repeated RoleUserStateProto user_states = 1;
-}
-
-message RoleUserStateProto {
- option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
- // The user id of this state.
- optional int32 user_id = 1;
-
- // The version of this state.
- optional int32 version = 2;
-
- // The hash of packages for this state.
- optional string packages_hash = 3;
-
- // The set of roles in this state.
- repeated RoleProto roles = 4;
-}
-
-message RoleProto {
- option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
- // The name of this role, e.g. "android.app.role.DIALER".
- optional string name = 1;
-
- // The package names of the holders of this role.
- repeated string holders = 2;
-}
diff --git a/apex/permission/testing/Android.bp b/apex/permission/testing/Android.bp
deleted file mode 100644
index 63bf0a08e956..000000000000
--- a/apex/permission/testing/Android.bp
+++ /dev/null
@@ -1,25 +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.
-
-apex_test {
- name: "test_com.android.permission",
- visibility: [
- "//system/apex/tests",
- ],
- defaults: ["com.android.permission-defaults"],
- manifest: "test_manifest.json",
- file_contexts: ":com.android.permission-file_contexts",
- // Test APEX, should never be installed
- installable: false,
-}
diff --git a/apex/permission/testing/test_manifest.json b/apex/permission/testing/test_manifest.json
deleted file mode 100644
index bc19a9ea0172..000000000000
--- a/apex/permission/testing/test_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "com.android.permission",
- "version": 2147483647
-}
diff --git a/apex/permission/tests/Android.bp b/apex/permission/tests/Android.bp
deleted file mode 100644
index 271e328c1139..000000000000
--- a/apex/permission/tests/Android.bp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2020 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.
-
-android_test {
- name: "PermissionApexTests",
- sdk_version: "test_current",
- srcs: [
- "java/**/*.kt",
- ],
- static_libs: [
- "service-permission.impl",
- "androidx.test.rules",
- "androidx.test.ext.junit",
- "androidx.test.ext.truth",
- "mockito-target-extended-minus-junit4",
- ],
- jni_libs: [
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
- ],
- compile_multilib: "both",
- test_suites: [
- "general-tests",
- "mts",
- ],
-}
diff --git a/apex/permission/tests/AndroidManifest.xml b/apex/permission/tests/AndroidManifest.xml
deleted file mode 100644
index 57ee6417aeb3..000000000000
--- a/apex/permission/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2020 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.
- -->
-
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.permission.test">
-
- <!-- The application has to be debuggable for static mocking to work. -->
- <application android:debuggable="true">
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation
- android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.permission.test"
- android:label="Permission APEX Tests" />
-</manifest>
diff --git a/apex/permission/tests/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt b/apex/permission/tests/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt
deleted file mode 100644
index 2987da087e51..000000000000
--- a/apex/permission/tests/java/com/android/permission/persistence/RuntimePermissionsPersistenceTest.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2020 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.permission.persistence
-
-import android.content.ApexEnvironment
-import android.content.Context
-import android.os.Process
-import android.os.UserHandle
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.MockitoAnnotations.initMocks
-import org.mockito.MockitoSession
-import org.mockito.quality.Strictness
-import java.io.File
-
-@RunWith(AndroidJUnit4::class)
-class RuntimePermissionsPersistenceTest {
- private val context = InstrumentationRegistry.getInstrumentation().context
-
- private lateinit var mockDataDirectory: File
-
- private lateinit var mockitoSession: MockitoSession
- @Mock
- lateinit var apexEnvironment: ApexEnvironment
-
- private val persistence = RuntimePermissionsPersistence.createInstance()
- private val permissionState = RuntimePermissionsState.PermissionState("permission", true, 3)
- private val state = RuntimePermissionsState(
- 1, "fingerprint", mapOf("package" to listOf(permissionState)),
- mapOf("sharedUser" to listOf(permissionState))
- )
- private val user = Process.myUserHandle()
-
- @Before
- fun createMockDataDirectory() {
- mockDataDirectory = context.getDir("mock_data", Context.MODE_PRIVATE)
- mockDataDirectory.listFiles()!!.forEach { assertThat(it.deleteRecursively()).isTrue() }
- }
-
- @Before
- fun mockApexEnvironment() {
- initMocks(this)
- mockitoSession = mockitoSession()
- .mockStatic(ApexEnvironment::class.java)
- .strictness(Strictness.LENIENT)
- .startMocking()
- `when`(ApexEnvironment.getApexEnvironment(eq(APEX_MODULE_NAME))).thenReturn(apexEnvironment)
- `when`(apexEnvironment.getDeviceProtectedDataDirForUser(any(UserHandle::class.java))).then {
- File(mockDataDirectory, it.arguments[0].toString()).also { it.mkdirs() }
- }
- }
-
- @After
- fun finishMockingApexEnvironment() {
- mockitoSession.finishMocking()
- }
-
- @Test
- fun testReadWrite() {
- persistence.writeForUser(state, user)
- val persistedState = persistence.readForUser(user)
-
- assertThat(persistedState).isEqualTo(state)
- assertThat(persistedState!!.version).isEqualTo(state.version)
- assertThat(persistedState.fingerprint).isEqualTo(state.fingerprint)
- assertThat(persistedState.packagePermissions).isEqualTo(state.packagePermissions)
- val persistedPermissionState = persistedState.packagePermissions.values.first().first()
- assertThat(persistedPermissionState.name).isEqualTo(permissionState.name)
- assertThat(persistedPermissionState.isGranted).isEqualTo(permissionState.isGranted)
- assertThat(persistedPermissionState.flags).isEqualTo(permissionState.flags)
- assertThat(persistedState.sharedUserPermissions).isEqualTo(state.sharedUserPermissions)
- }
-
- @Test
- fun testDelete() {
- persistence.writeForUser(state, user)
- persistence.deleteForUser(user)
- val persistedState = persistence.readForUser(user)
-
- assertThat(persistedState).isNull()
- }
-
- companion object {
- private const val APEX_MODULE_NAME = "com.android.permission"
- }
-}
diff --git a/apex/permission/tests/java/com/android/role/persistence/RolesPersistenceTest.kt b/apex/permission/tests/java/com/android/role/persistence/RolesPersistenceTest.kt
deleted file mode 100644
index f9d9d5afb25d..000000000000
--- a/apex/permission/tests/java/com/android/role/persistence/RolesPersistenceTest.kt
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2020 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.role.persistence
-
-import android.content.ApexEnvironment
-import android.content.Context
-import android.os.Process
-import android.os.UserHandle
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.MockitoAnnotations.initMocks
-import org.mockito.MockitoSession
-import org.mockito.quality.Strictness
-import java.io.File
-
-@RunWith(AndroidJUnit4::class)
-class RolesPersistenceTest {
- private val context = InstrumentationRegistry.getInstrumentation().context
-
- private lateinit var mockDataDirectory: File
-
- private lateinit var mockitoSession: MockitoSession
- @Mock
- lateinit var apexEnvironment: ApexEnvironment
-
- private val persistence = RolesPersistence.createInstance()
- private val state = RolesState(1, "packagesHash", mapOf("role" to setOf("holder1", "holder2")))
- private val user = Process.myUserHandle()
-
- @Before
- fun createMockDataDirectory() {
- mockDataDirectory = context.getDir("mock_data", Context.MODE_PRIVATE)
- mockDataDirectory.listFiles()!!.forEach { assertThat(it.deleteRecursively()).isTrue() }
- }
-
- @Before
- fun mockApexEnvironment() {
- initMocks(this)
- mockitoSession = mockitoSession()
- .mockStatic(ApexEnvironment::class.java)
- .strictness(Strictness.LENIENT)
- .startMocking()
- `when`(ApexEnvironment.getApexEnvironment(eq(APEX_MODULE_NAME))).thenReturn(apexEnvironment)
- `when`(apexEnvironment.getDeviceProtectedDataDirForUser(any(UserHandle::class.java))).then {
- File(mockDataDirectory, it.arguments[0].toString()).also { it.mkdirs() }
- }
- }
-
- @After
- fun finishMockingApexEnvironment() {
- mockitoSession.finishMocking()
- }
-
- @Test
- fun testReadWrite() {
- persistence.writeForUser(state, user)
- val persistedState = persistence.readForUser(user)
-
- assertThat(persistedState).isEqualTo(state)
- assertThat(persistedState!!.version).isEqualTo(state.version)
- assertThat(persistedState.packagesHash).isEqualTo(state.packagesHash)
- assertThat(persistedState.roles).isEqualTo(state.roles)
- }
-
- @Test
- fun testDelete() {
- persistence.writeForUser(state, user)
- persistence.deleteForUser(user)
- val persistedState = persistence.readForUser(user)
-
- assertThat(persistedState).isNull()
- }
-
- companion object {
- private const val APEX_MODULE_NAME = "com.android.permission"
- }
-}
diff --git a/core/api/current.txt b/core/api/current.txt
index 61d7aadce928..ec712d875323 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -36822,9 +36822,10 @@ package android.security.identity {
package android.security.keystore {
public class BackendBusyException extends java.security.ProviderException {
- ctor public BackendBusyException();
- ctor public BackendBusyException(@NonNull String);
- ctor public BackendBusyException(@NonNull String, @NonNull Throwable);
+ ctor public BackendBusyException(long);
+ ctor public BackendBusyException(long, @NonNull String);
+ ctor public BackendBusyException(long, @NonNull String, @NonNull Throwable);
+ method public long getBackOffHintMillis();
}
public class KeyExpiredException extends java.security.InvalidKeyException {
@@ -39714,7 +39715,6 @@ package android.telecom {
field public static final String EXTRA_HAS_PICTURE = "android.telecom.extra.HAS_PICTURE";
field public static final String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS";
field public static final String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS";
- field public static final String EXTRA_INCOMING_PICTURE = "android.telecom.extra.INCOMING_PICTURE";
field public static final String EXTRA_INCOMING_VIDEO_STATE = "android.telecom.extra.INCOMING_VIDEO_STATE";
field public static final String EXTRA_IS_DEFAULT_CALL_SCREENING_APP = "android.telecom.extra.IS_DEFAULT_CALL_SCREENING_APP";
field public static final String EXTRA_LOCATION = "android.telecom.extra.LOCATION";
@@ -39723,6 +39723,7 @@ package android.telecom {
field public static final String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
field public static final String EXTRA_OUTGOING_PICTURE = "android.telecom.extra.OUTGOING_PICTURE";
field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+ field public static final String EXTRA_PICTURE_URI = "android.telecom.extra.PICTURE_URI";
field public static final String EXTRA_PRIORITY = "android.telecom.extra.PRIORITY";
field public static final String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
field public static final String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 7c426be80fa4..0f1296ee01fe 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -12964,11 +12964,100 @@ package android.telephony.ims {
field public static final String RCS_PROFILE_2_3 = "UP_2.3";
}
+ public final class RcsContactPresenceTuple implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.net.Uri getContactUri();
+ method @Nullable public android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities getServiceCapabilities();
+ method @Nullable public String getServiceDescription();
+ method @NonNull public String getServiceId();
+ method @NonNull public String getServiceVersion();
+ method @NonNull public String getStatus();
+ method @Nullable public String getTimestamp();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactPresenceTuple> CREATOR;
+ field public static final String SERVICE_ID_CALL_COMPOSER = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callcomposer";
+ field public static final String SERVICE_ID_CHATBOT = "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.chatbot";
+ field public static final String SERVICE_ID_CHATBOT_ROLE = "org.gsma.rcs.isbot";
+ field public static final String SERVICE_ID_CHATBOT_STANDALONE = " org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.chatbot.sa";
+ field public static final String SERVICE_ID_CHAT_V1 = "org.openmobilealliance:IM-session";
+ field public static final String SERVICE_ID_CHAT_V2 = "org.openmobilealliance:ChatSession";
+ field public static final String SERVICE_ID_FT = "org.openmobilealliance:File-Transfer-HTTP";
+ field public static final String SERVICE_ID_FT_OVER_SMS = "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.ftsms";
+ field public static final String SERVICE_ID_GEO_PUSH = "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.geopush";
+ field public static final String SERVICE_ID_GEO_PUSH_VIA_SMS = "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.geosms";
+ field public static final String SERVICE_ID_MMTEL = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel";
+ field public static final String SERVICE_ID_POST_CALL = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callunanswered";
+ field public static final String SERVICE_ID_SHARED_MAP = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedmap";
+ field public static final String SERVICE_ID_SHARED_SKETCH = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedsketch";
+ field public static final String TUPLE_BASIC_STATUS_CLOSED = "closed";
+ field public static final String TUPLE_BASIC_STATUS_OPEN = "open";
+ }
+
+ public static final class RcsContactPresenceTuple.Builder {
+ ctor public RcsContactPresenceTuple.Builder(@NonNull String, @NonNull String, @NonNull String);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple build();
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setContactUri(@NonNull android.net.Uri);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceCapabilities(@NonNull android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setServiceDescription(@NonNull String);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.Builder setTimestamp(@NonNull String);
+ }
+
+ public static final class RcsContactPresenceTuple.ServiceCapabilities implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<java.lang.String> getSupportedDuplexModes();
+ method @NonNull public java.util.List<java.lang.String> getUnsupportedDuplexModes();
+ method public boolean isAudioCapable();
+ method public boolean isVideoCapable();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities> CREATOR;
+ field public static final String DUPLEX_MODE_FULL = "full";
+ field public static final String DUPLEX_MODE_HALF = "half";
+ field public static final String DUPLEX_MODE_RECEIVE_ONLY = "receive-only";
+ field public static final String DUPLEX_MODE_SEND_ONLY = "send-only";
+ }
+
+ public static final class RcsContactPresenceTuple.ServiceCapabilities.Builder {
+ ctor public RcsContactPresenceTuple.ServiceCapabilities.Builder(boolean, boolean);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities.Builder addSupportedDuplexMode(@NonNull String);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities.Builder addUnsupportedDuplexMode(@NonNull String);
+ method @NonNull public android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities build();
+ }
+
+ public final class RcsContactUceCapability implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getCapabilityMechanism();
+ method @Nullable public android.telephony.ims.RcsContactPresenceTuple getCapabilityTuple(@NonNull String);
+ method @NonNull public java.util.List<android.telephony.ims.RcsContactPresenceTuple> getCapabilityTuples();
+ method @NonNull public android.net.Uri getContactUri();
+ method public int getRequestResult();
+ method public int getSourceType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CAPABILITY_MECHANISM_OPTIONS = 2; // 0x2
+ field public static final int CAPABILITY_MECHANISM_PRESENCE = 1; // 0x1
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR;
+ field public static final int REQUEST_RESULT_FOUND = 3; // 0x3
+ field public static final int REQUEST_RESULT_NOT_FOUND = 2; // 0x2
+ field public static final int REQUEST_RESULT_NOT_ONLINE = 1; // 0x1
+ field public static final int REQUEST_RESULT_UNKNOWN = 0; // 0x0
+ field public static final int SOURCE_TYPE_CACHED = 1; // 0x1
+ field public static final int SOURCE_TYPE_NETWORK = 0; // 0x0
+ }
+
+ public static final class RcsContactUceCapability.PresenceBuilder {
+ ctor public RcsContactUceCapability.PresenceBuilder(@NonNull android.net.Uri, int, int);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.PresenceBuilder addCapabilityTuple(@NonNull android.telephony.ims.RcsContactPresenceTuple);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.PresenceBuilder addCapabilityTuples(@NonNull java.util.List<android.telephony.ims.RcsContactPresenceTuple>);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability build();
+ }
+
public class RcsUceAdapter {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addOnPublishStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.OnPublishStateChangedListener) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getUcePublishState() throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeOnPublishStateChangedListener(@NonNull android.telephony.ims.RcsUceAdapter.OnPublishStateChangedListener) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestAvailability(@NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
+ field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; // 0x1
field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 7; // 0x7
field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 6; // 0x6
@@ -12981,6 +13070,18 @@ package android.telephony.ims {
field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb
field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 8; // 0x8
field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 0; // 0x0
+ field public static final int ERROR_FORBIDDEN = 6; // 0x6
+ field public static final int ERROR_GENERIC_FAILURE = 1; // 0x1
+ field public static final int ERROR_INSUFFICIENT_MEMORY = 10; // 0xa
+ field public static final int ERROR_LOST_NETWORK = 11; // 0xb
+ field public static final int ERROR_NOT_AUTHORIZED = 5; // 0x5
+ field public static final int ERROR_NOT_AVAILABLE = 3; // 0x3
+ field public static final int ERROR_NOT_ENABLED = 2; // 0x2
+ field public static final int ERROR_NOT_FOUND = 7; // 0x7
+ field public static final int ERROR_NOT_REGISTERED = 4; // 0x4
+ field public static final int ERROR_REQUEST_TIMEOUT = 9; // 0x9
+ field public static final int ERROR_REQUEST_TOO_LARGE = 8; // 0x8
+ field public static final int ERROR_SERVER_UNAVAILABLE = 12; // 0xc
field public static final int PUBLISH_STATE_NOT_PUBLISHED = 2; // 0x2
field public static final int PUBLISH_STATE_OK = 1; // 0x1
field public static final int PUBLISH_STATE_OTHER_ERROR = 6; // 0x6
@@ -12989,6 +13090,12 @@ package android.telephony.ims {
field public static final int PUBLISH_STATE_VOICE_PROVISION_ERROR = 3; // 0x3
}
+ public static interface RcsUceAdapter.CapabilitiesCallback {
+ method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>);
+ method public void onComplete();
+ method public void onError(int, long);
+ }
+
public static interface RcsUceAdapter.OnPublishStateChangedListener {
method public void onPublishStateChange(int);
}
@@ -13400,6 +13507,7 @@ package android.telephony.ims.stub {
public class RcsCapabilityExchangeImplBase {
ctor public RcsCapabilityExchangeImplBase(@NonNull java.util.concurrent.Executor);
method public void publishCapabilities(@NonNull String, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback);
+ method public void subscribeForCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback);
field public static final int COMMAND_CODE_FETCH_ERROR = 3; // 0x3
field public static final int COMMAND_CODE_GENERIC_FAILURE = 1; // 0x1
field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 5; // 0x5
@@ -13418,6 +13526,14 @@ package android.telephony.ims.stub {
method public void onNetworkResponse(@IntRange(from=100, to=699) int, @NonNull String) throws android.telephony.ims.ImsException;
}
+ public static interface RcsCapabilityExchangeImplBase.SubscribeResponseCallback {
+ method public void onCommandError(int) throws android.telephony.ims.ImsException;
+ method public void onNetworkResponse(@IntRange(from=100, to=699) int, @NonNull String) throws android.telephony.ims.ImsException;
+ method public void onNotifyCapabilitiesUpdate(@NonNull java.util.List<java.lang.String>) throws android.telephony.ims.ImsException;
+ method public void onResourceTerminated(@NonNull java.util.List<android.util.Pair<android.net.Uri,java.lang.String>>) throws android.telephony.ims.ImsException;
+ method public void onTerminated(@NonNull String, long) throws android.telephony.ims.ImsException;
+ }
+
public interface SipDelegate {
method public void closeDialog(@NonNull String);
method public void notifyMessageReceiveError(@NonNull String, int);
diff --git a/core/java/android/content/integrity/OWNERS b/core/java/android/content/integrity/OWNERS
new file mode 100644
index 000000000000..20c758aedd67
--- /dev/null
+++ b/core/java/android/content/integrity/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 722021
+
+toddke@android.com
+toddke@google.com
+patb@google.com
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 33e33ee5fa02..9bfd75ef2170 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -249,11 +249,13 @@ public class CallLog {
// Nasty casework for the shadow calllog begins...
// First see if we're just inserting for one user. If so, insert into the shadow
// based on whether that user is unlocked.
- if (user != null) {
- Uri baseUri = userManager.isUserUnlocked(user) ? CALL_COMPOSER_PICTURE_URI
+ UserHandle realUser = UserHandle.CURRENT.equals(user)
+ ? android.os.Process.myUserHandle() : user;
+ if (realUser != null) {
+ Uri baseUri = userManager.isUserUnlocked(realUser) ? CALL_COMPOSER_PICTURE_URI
: SHADOW_CALL_COMPOSER_PICTURE_URI;
Uri pictureInsertionUri = ContentProvider.maybeAddUserId(baseUri,
- user.getIdentifier());
+ realUser.getIdentifier());
Log.i(LOG_TAG, "Inserting call composer for single user at "
+ pictureInsertionUri);
diff --git a/core/java/android/view/SyncRtSurfaceTransactionApplier.java b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
index b10370aa5d4c..acbcbfad1a75 100644
--- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java
+++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
@@ -85,12 +85,13 @@ public class SyncRtSurfaceTransactionApplier {
for (int i = params.length - 1; i >= 0; i--) {
SurfaceParams surfaceParams = params[i];
SurfaceControl surface = surfaceParams.surface;
- if (frame > 0) {
- t.deferTransactionUntil(surface, mTargetSc, frame);
- }
applyParams(t, surfaceParams, mTmpFloat9);
}
- t.apply();
+ if (mTargetViewRootImpl != null) {
+ mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
+ } else {
+ t.apply();
+ }
}
public static void applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 844fc267c3cb..52d0062abdf2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -10109,7 +10109,7 @@ public final class ViewRootImpl implements ViewParent,
* Merges the transaction passed in with the next transaction in BLASTBufferQueue. This ensures
* you can add transactions to the upcoming frame.
*/
- void mergeWithNextTransaction(Transaction t, long frameNumber) {
+ public void mergeWithNextTransaction(Transaction t, long frameNumber) {
if (mBlastBufferQueue != null) {
mBlastBufferQueue.mergeWithNextTransaction(t, frameNumber);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index a21c68b4f01a..fcf8bb4e748b 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -41,7 +41,6 @@ import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
-import android.util.SparseLongArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
@@ -379,6 +378,7 @@ public class BatteryStatsHelper {
mMaxDrainedPower = (mStats.getHighDischargeAmountSinceCharge()
* mPowerProfile.getBatteryCapacity()) / 100;
+ // Create list of (almost all) sippers, calculate their usage, and put them in mUsageList.
processAppUsage(asUsers);
Collections.sort(mUsageList);
@@ -556,8 +556,7 @@ public class BatteryStatsHelper {
}
/**
- * Mark the {@link BatterySipper} that we should hide and smear the screen usage based on
- * foreground activity time.
+ * Mark the {@link BatterySipper} that we should hide.
*
* @param sippers sipper list that need to check and remove
* @return the total power of the hidden items of {@link BatterySipper}
@@ -565,7 +564,6 @@ public class BatteryStatsHelper {
*/
public double removeHiddenBatterySippers(List<BatterySipper> sippers) {
double proportionalSmearPowerMah = 0;
- BatterySipper screenSipper = null;
for (int i = sippers.size() - 1; i >= 0; i--) {
final BatterySipper sipper = sippers.get(i);
sipper.shouldHide = shouldHideSipper(sipper);
@@ -581,45 +579,11 @@ public class BatteryStatsHelper {
proportionalSmearPowerMah += sipper.totalPowerMah;
}
}
-
- if (sipper.drainType == BatterySipper.DrainType.SCREEN) {
- screenSipper = sipper;
- }
}
-
- smearScreenBatterySipper(sippers, screenSipper);
-
return proportionalSmearPowerMah;
}
/**
- * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity
- * time.
- */
- public void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper) {
- long totalActivityTimeMs = 0;
- final SparseLongArray activityTimeArray = new SparseLongArray();
- for (int i = 0, size = sippers.size(); i < size; i++) {
- final BatteryStats.Uid uid = sippers.get(i).uidObj;
- if (uid != null) {
- final long timeMs = getProcessForegroundTimeMs(uid,
- BatteryStats.STATS_SINCE_CHARGED);
- activityTimeArray.put(uid.getUid(), timeMs);
- totalActivityTimeMs += timeMs;
- }
- }
-
- if (screenSipper != null && totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) {
- final double screenPowerMah = screenSipper.totalPowerMah;
- for (int i = 0, size = sippers.size(); i < size; i++) {
- final BatterySipper sipper = sippers.get(i);
- sipper.screenPowerMah = screenPowerMah * activityTimeArray.get(sipper.getUid(), 0)
- / totalActivityTimeMs;
- }
- }
- }
-
- /**
* Check whether we should hide the battery sipper.
*/
public boolean shouldHideSipper(BatterySipper sipper) {
@@ -682,33 +646,6 @@ public class BatteryStatsHelper {
}
@VisibleForTesting
- public long getForegroundActivityTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs) {
- final BatteryStats.Timer timer = uid.getForegroundActivityTimer();
- if (timer != null) {
- return timer.getTotalTimeLocked(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
- }
-
- return 0;
- }
-
- @VisibleForTesting
- public long getProcessForegroundTimeMs(BatteryStats.Uid uid, int which) {
- final long rawRealTimeUs = convertMsToUs(SystemClock.elapsedRealtime());
- final int foregroundTypes[] = {BatteryStats.Uid.PROCESS_STATE_TOP};
-
- long timeUs = 0;
- for (int type : foregroundTypes) {
- final long localTime = uid.getProcessStateTime(type, rawRealTimeUs, which);
- timeUs += localTime;
- }
-
- // Return the min value of STATE_TOP time and foreground activity time, since both of these
- // time have some errors.
- return convertUsToMs(
- Math.min(timeUs, getForegroundActivityTotalTimeUs(uid, rawRealTimeUs)));
- }
-
- @VisibleForTesting
public void setPackageManager(PackageManager packageManager) {
mPackageManager = packageManager;
}
diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java
index 25f6b4d16971..9c4a26724ba8 100644
--- a/core/java/com/android/internal/os/ScreenPowerCalculator.java
+++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java
@@ -21,9 +21,14 @@ import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.SystemBatteryConsumer;
+import android.os.SystemClock;
import android.os.UserHandle;
+import android.text.format.DateUtils;
import android.util.Log;
import android.util.SparseArray;
+import android.util.SparseLongArray;
+
+import com.android.internal.annotations.VisibleForTesting;
import java.util.List;
@@ -57,6 +62,7 @@ public class ScreenPowerCalculator extends PowerCalculator {
.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs)
.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah);
}
+ // TODO(b/178140704): Attribute screen usage similar to smearScreenBatterySipper.
}
/**
@@ -73,6 +79,8 @@ public class ScreenPowerCalculator extends PowerCalculator {
bs.usageTimeMs = durationMs;
bs.sumPower();
sippers.add(bs);
+
+ smearScreenBatterySipper(sippers, bs);
}
}
@@ -96,4 +104,60 @@ public class ScreenPowerCalculator extends PowerCalculator {
}
return power;
}
+
+ /**
+ * Smear the screen on power usage among {@code sippers}, based on ratio of foreground activity
+ * time, and store this in the {@link BatterySipper#screenPowerMah} field.
+ */
+ @VisibleForTesting
+ public void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper) {
+
+ long totalActivityTimeMs = 0;
+ final SparseLongArray activityTimeArray = new SparseLongArray();
+ for (int i = sippers.size() - 1; i >= 0; i--) {
+ final BatteryStats.Uid uid = sippers.get(i).uidObj;
+ if (uid != null) {
+ final long timeMs = getProcessForegroundTimeMs(uid);
+ activityTimeArray.put(uid.getUid(), timeMs);
+ totalActivityTimeMs += timeMs;
+ }
+ }
+
+ if (screenSipper != null && totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) {
+ final double screenPowerMah = screenSipper.totalPowerMah;
+ for (int i = sippers.size() - 1; i >= 0; i--) {
+ final BatterySipper sipper = sippers.get(i);
+ sipper.screenPowerMah = screenPowerMah * activityTimeArray.get(sipper.getUid(), 0)
+ / totalActivityTimeMs;
+ }
+ }
+ }
+
+ /** Get the minimum of the uid's ForegroundActivity time and its TOP time. */
+ @VisibleForTesting
+ public long getProcessForegroundTimeMs(BatteryStats.Uid uid) {
+ final long rawRealTimeUs = SystemClock.elapsedRealtime() * 1000;
+ final int[] foregroundTypes = {BatteryStats.Uid.PROCESS_STATE_TOP};
+
+ long timeUs = 0;
+ for (int type : foregroundTypes) {
+ final long localTime = uid.getProcessStateTime(type, rawRealTimeUs,
+ BatteryStats.STATS_SINCE_CHARGED);
+ timeUs += localTime;
+ }
+
+ // Return the min value of STATE_TOP time and foreground activity time, since both of these
+ // time have some errors.
+ return Math.min(timeUs, getForegroundActivityTotalTimeUs(uid, rawRealTimeUs)) / 1000;
+ }
+
+ /** Get the ForegroundActivity time of the given uid. */
+ @VisibleForTesting
+ public long getForegroundActivityTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs) {
+ final BatteryStats.Timer timer = uid.getForegroundActivityTimer();
+ if (timer == null) {
+ return 0;
+ }
+ return timer.getTotalTimeLocked(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
+ }
}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 48094198c2e9..2b665c0fe9fc 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -41,7 +41,6 @@ import "frameworks/base/core/proto/android/server/jobscheduler.proto";
import "frameworks/base/core/proto/android/server/location/context_hub.proto";
import "frameworks/base/core/proto/android/server/powermanagerservice.proto";
import "frameworks/base/core/proto/android/server/powerstatsservice.proto";
-import "frameworks/base/apex/permission/service/proto/com/android/role/roleservice.proto";
import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
import "frameworks/base/core/proto/android/service/appwidget.proto";
import "frameworks/base/core/proto/android/service/battery.proto";
@@ -63,6 +62,7 @@ import "frameworks/base/core/proto/android/privacy.proto";
import "frameworks/base/core/proto/android/section.proto";
import "frameworks/base/proto/src/ipconnectivity.proto";
import "frameworks/proto_logging/stats/enums/service/usb.proto";
+import "packages/modules/Permission/service/proto/com/android/role/roleservice.proto";
package android.os;
diff --git a/core/proto/android/server/powerstatsservice.proto b/core/proto/android/server/powerstatsservice.proto
index ec9bc112c6fb..0c5a36049a29 100644
--- a/core/proto/android/server/powerstatsservice.proto
+++ b/core/proto/android/server/powerstatsservice.proto
@@ -220,6 +220,9 @@ message ChannelProto {
/** Name of the energy meter channel */
optional string name = 2;
+
+ /** Name of the subsystem associated with this Channel. Opaque to framework */
+ optional string subsystem = 3;
}
/**
diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS
index 912db1e835dc..c61a4b538a44 100644
--- a/core/tests/coretests/src/android/content/OWNERS
+++ b/core/tests/coretests/src/android/content/OWNERS
@@ -1,3 +1,4 @@
+per-file AssetTest.java = file:/core/java/android/content/res/OWNERS
per-file ContextTest.java = file:/services/core/java/com/android/server/wm/OWNERS
-per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
+per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
diff --git a/core/tests/coretests/src/android/content/integrity/OWNERS b/core/tests/coretests/src/android/content/integrity/OWNERS
new file mode 100644
index 000000000000..4ffc7041a527
--- /dev/null
+++ b/core/tests/coretests/src/android/content/integrity/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/integrity/OWNERS
diff --git a/core/tests/coretests/src/android/content/pm/OWNERS b/core/tests/coretests/src/android/content/pm/OWNERS
index 7b7670696bfa..867336515ce3 100644
--- a/core/tests/coretests/src/android/content/pm/OWNERS
+++ b/core/tests/coretests/src/android/content/pm/OWNERS
@@ -1,3 +1,5 @@
+include /core/java/android/content/pm/OWNERS
+
per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
-per-file SigningDetailsTest.java = mpgroover@google.com
per-file SigningDetailsTest.java = cbrubaker@google.com
+per-file SigningDetailsTest.java = mpgroover@google.com
diff --git a/core/tests/coretests/src/android/content/res/OWNERS b/core/tests/coretests/src/android/content/res/OWNERS
new file mode 100644
index 000000000000..3e79d8ff0bbe
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/res/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
index fbe16f2c39d1..d2107eaefefc 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
@@ -21,12 +21,10 @@ import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -194,7 +192,6 @@ public class BatteryStatsHelperTest extends TestCase {
sippers.add(mBluetoothBatterySipper);
sippers.add(mIdleBatterySipper);
doReturn(true).when(mBatteryStatsHelper).isTypeSystem(mSystemBatterySipper);
- doNothing().when(mBatteryStatsHelper).smearScreenBatterySipper(any(), any());
final double totalUsage = mBatteryStatsHelper.removeHiddenBatterySippers(sippers);
@@ -208,19 +205,20 @@ public class BatteryStatsHelperTest extends TestCase {
@Test
public void testSmearScreenBatterySipper() {
+ final ScreenPowerCalculator spc = spy(ScreenPowerCalculator.class);
final BatterySipper sipperNull = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
- BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */);
+ BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */, spc);
final BatterySipper sipperBg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
- BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */);
+ BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */, spc);
final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY,
- BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */);
+ BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */, spc);
final List<BatterySipper> sippers = new ArrayList<>();
sippers.add(sipperNull);
sippers.add(sipperBg);
sippers.add(sipperFg);
- mBatteryStatsHelper.smearScreenBatterySipper(sippers, mScreenBatterySipper);
+ spc.smearScreenBatterySipper(sippers, mScreenBatterySipper);
assertThat(sipperNull.screenPowerMah).isWithin(PRECISION).of(0);
assertThat(sipperBg.screenPowerMah).isWithin(PRECISION).of(0);
@@ -249,13 +247,13 @@ public class BatteryStatsHelperTest extends TestCase {
@Test
public void testGetProcessForegroundTimeMs_largerActivityTime_returnMinTime() {
- doReturn(TIME_STATE_FOREGROUND_US + 500).when(mBatteryStatsHelper)
+ final ScreenPowerCalculator spc = spy(ScreenPowerCalculator.class);
+ doReturn(TIME_STATE_FOREGROUND_US + 500).when(spc)
.getForegroundActivityTotalTimeUs(eq(mUid), anyLong());
doReturn(TIME_STATE_FOREGROUND_US).when(mUid).getProcessStateTime(eq(PROCESS_STATE_TOP),
anyLong(), anyInt());
- final long time = mBatteryStatsHelper.getProcessForegroundTimeMs(mUid,
- BatteryStats.STATS_SINCE_CHARGED);
+ final long time = spc.getProcessForegroundTimeMs(mUid);
assertThat(time).isEqualTo(TIME_STATE_FOREGROUND_MS);
}
@@ -291,15 +289,14 @@ public class BatteryStatsHelperTest extends TestCase {
}
private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah,
- int uidCode, boolean isUidNull) {
+ int uidCode, boolean isUidNull, ScreenPowerCalculator spc) {
final BatterySipper sipper = mock(BatterySipper.class);
sipper.drainType = BatterySipper.DrainType.APP;
sipper.totalPowerMah = totalPowerMah;
doReturn(uidCode).when(sipper).getUid();
if (!isUidNull) {
final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS);
- doReturn(activityTime).when(mBatteryStatsHelper).getProcessForegroundTimeMs(eq(uid),
- anyInt());
+ doReturn(activityTime).when(spc).getProcessForegroundTimeMs(eq(uid));
doReturn(uidCode).when(uid).getUid();
sipper.uidObj = uid;
}
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index 92d87aa0fed6..f7477bf92c81 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -23,6 +23,7 @@ import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
+import android.security.keymaster.KeymasterDefs;
import android.system.keystore2.IKeystoreService;
import android.system.keystore2.KeyDescriptor;
import android.system.keystore2.KeyEntryResponse;
@@ -107,7 +108,7 @@ public class KeyStore2 {
return request.execute(service);
} catch (ServiceSpecificException e) {
Log.e(TAG, "KeyStore exception", e);
- throw new KeyStoreException(e.errorCode, "");
+ throw getKeyStoreException(e.errorCode);
} catch (RemoteException e) {
if (firstTry) {
Log.w(TAG, "Looks like we may have lost connection to the Keystore "
@@ -274,4 +275,40 @@ public class KeyStore2 {
}
}
+ static KeyStoreException getKeyStoreException(int errorCode) {
+ if (errorCode > 0) {
+ // KeyStore layer error
+ switch (errorCode) {
+ case ResponseCode.LOCKED:
+ return new KeyStoreException(errorCode, "User authentication required");
+ case ResponseCode.UNINITIALIZED:
+ return new KeyStoreException(errorCode, "Keystore not initialized");
+ case ResponseCode.SYSTEM_ERROR:
+ return new KeyStoreException(errorCode, "System error");
+ case ResponseCode.PERMISSION_DENIED:
+ return new KeyStoreException(errorCode, "Permission denied");
+ case ResponseCode.KEY_NOT_FOUND:
+ return new KeyStoreException(errorCode, "Key not found");
+ case ResponseCode.VALUE_CORRUPTED:
+ return new KeyStoreException(errorCode, "Key blob corrupted");
+ case ResponseCode.KEY_PERMANENTLY_INVALIDATED:
+ return new KeyStoreException(errorCode, "Key permanently invalidated");
+ default:
+ return new KeyStoreException(errorCode, String.valueOf(errorCode));
+ }
+ } else {
+ // Keymaster layer error
+ switch (errorCode) {
+ case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
+ // The name of this parameter significantly differs between Keymaster and
+ // framework APIs. Use the framework wording to make life easier for developers.
+ return new KeyStoreException(errorCode,
+ "Invalid user authentication validity duration");
+ default:
+ return new KeyStoreException(errorCode,
+ KeymasterDefs.getErrorMessage(errorCode));
+ }
+ }
+ }
+
}
diff --git a/keystore/java/android/security/KeyStoreOperation.java b/keystore/java/android/security/KeyStoreOperation.java
index 7ea9e1438845..a6552dddc630 100644
--- a/keystore/java/android/security/KeyStoreOperation.java
+++ b/keystore/java/android/security/KeyStoreOperation.java
@@ -73,8 +73,7 @@ public class KeyStoreOperation {
);
}
default:
- // TODO Human readable string. Use something like KeyStore.getKeyStoreException
- throw new KeyStoreException(e.errorCode, "");
+ throw KeyStore2.getKeyStoreException(e.errorCode);
}
} catch (RemoteException e) {
// Log exception and report invalid operation handle.
diff --git a/keystore/java/android/security/KeyStoreSecurityLevel.java b/keystore/java/android/security/KeyStoreSecurityLevel.java
index 3ef4aa5b7ec3..372add9b7ecb 100644
--- a/keystore/java/android/security/KeyStoreSecurityLevel.java
+++ b/keystore/java/android/security/KeyStoreSecurityLevel.java
@@ -52,7 +52,7 @@ public class KeyStoreSecurityLevel {
try {
return request.execute();
} catch (ServiceSpecificException e) {
- throw new KeyStoreException(e.errorCode, "");
+ throw KeyStore2.getKeyStoreException(e.errorCode);
} catch (RemoteException e) {
// Log exception and report invalid operation handle.
// This should prompt the caller drop the reference to this operation and retry.
@@ -96,25 +96,26 @@ public class KeyStoreSecurityLevel {
} catch (ServiceSpecificException e) {
switch (e.errorCode) {
case ResponseCode.BACKEND_BUSY: {
+ long backOffHint = (long) (Math.random() * 80 + 20);
if (CompatChanges.isChangeEnabled(
KeyStore2.KEYSTORE_OPERATION_CREATION_MAY_FAIL)) {
// Starting with Android S we inform the caller about the
// backend being busy.
- throw new BackendBusyException();
+ throw new BackendBusyException(backOffHint);
} else {
// Before Android S operation creation must always succeed. So we
// just have to retry. We do so with a randomized back-off between
- // 50 and 250ms.
+ // 20 and 100ms.
// It is a little awkward that we cannot break out of this loop
// by interrupting this thread. But that is the expected behavior.
// There is some comfort in the fact that interrupting a thread
// also does not unblock a thread waiting for a binder transaction.
- interruptedPreservingSleep((long) (Math.random() * 200 + 50));
+ interruptedPreservingSleep(backOffHint);
}
break;
}
default:
- throw new KeyStoreException(e.errorCode, "");
+ throw KeyStore2.getKeyStoreException(e.errorCode);
}
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/keystore/java/android/security/keystore/BackendBusyException.java b/keystore/java/android/security/keystore/BackendBusyException.java
index 1a88469d7e54..a813e939a720 100644
--- a/keystore/java/android/security/keystore/BackendBusyException.java
+++ b/keystore/java/android/security/keystore/BackendBusyException.java
@@ -16,37 +16,66 @@
package android.security.keystore;
+import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import java.security.ProviderException;
/**
* Indicates a transient error that prevented a key operation from being created.
- * Callers should try again with a back-off period of 10-30 milliseconds.
+ * Callers should try again with a back-off period of {@link #getBackOffHintMillis()}
+ * milliseconds.
*/
public class BackendBusyException extends ProviderException {
+ private final long mBackOffHintMillis;
+
/**
* Constructs a new {@code BackendBusyException} without detail message and cause.
+ *
*/
- public BackendBusyException() {
+ public BackendBusyException(@DurationMillisLong long backOffHintMillis) {
super("The keystore backend has no operation slots available. Retry later.");
+ if (backOffHintMillis < 0) {
+ throw new IllegalArgumentException("Back-off hint cannot be negative.");
+ }
+ mBackOffHintMillis = backOffHintMillis;
}
/**
* Constructs a new {@code BackendBusyException} with the provided detail message and
* no cause.
*/
- public BackendBusyException(@NonNull String message) {
+ public BackendBusyException(@DurationMillisLong long backOffHintMillis,
+ @NonNull String message) {
super(message);
+ if (backOffHintMillis < 0) {
+ throw new IllegalArgumentException("Back-off hint cannot be negative.");
+ }
+ mBackOffHintMillis = backOffHintMillis;
}
/**
* Constructs a new {@code BackendBusyException} with the provided detail message and
* cause.
*/
- public BackendBusyException(@NonNull String message, @NonNull Throwable cause) {
+ public BackendBusyException(@DurationMillisLong long backOffHintMillis,
+ @NonNull String message, @NonNull Throwable cause) {
super(message, cause);
+ if (backOffHintMillis < 0) {
+ throw new IllegalArgumentException("Back-off hint cannot be negative.");
+ }
+ mBackOffHintMillis = backOffHintMillis;
}
+ /**
+ * When retrying to start a Keystore operation after receiving this exception, this can be
+ * used to determine how long to wait before retrying. It is not guaranteed that the operation
+ * will succeeds after this time. Multiple retries may be necessary if the system is congested.
+ *
+ * @return Number of milliseconds to back off before retrying.
+ */
+ public @DurationMillisLong long getBackOffHintMillis() {
+ return mBackOffHintMillis;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index aeea10d47a67..90992fb92324 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -469,6 +469,11 @@ public class PipAnimationController {
getSurfaceTransactionHelper()
.alpha(tx, leash, 1f)
.round(tx, leash, shouldApplyCornerRadius());
+ // TODO(b/178632364): this is a work around for the black background when
+ // entering PiP in buttion navigation mode.
+ if (isInPipDirection(direction)) {
+ tx.setWindowCrop(leash, getStartValue());
+ }
tx.show(leash);
tx.apply();
}
diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml
new file mode 100644
index 000000000000..fc68a64ac9bd
--- /dev/null
+++ b/packages/SystemUI/res/layout/long_screenshot.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:background="?android:colorBackgroundFloating"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:id="@+id/preview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginVertical="8dp"
+ android:layout_marginHorizontal="48dp"
+ android:adjustViewBounds="true"
+ app:layout_constrainedHeight="true"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintBottom_toBottomOf="@id/guideline"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:background="?android:colorBackground"
+ tools:minHeight="100dp"
+ tools:minWidth="100dp" />
+
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/guideline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ app:layout_constraintGuide_percent="0.9" />
+
+ <Button
+ android:id="@+id/close"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:text="Close"
+ app:layout_constraintEnd_toStartOf="@+id/edit"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintHorizontal_chainStyle="packed"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/guideline" />
+
+ <Button
+ android:id="@+id/edit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:text="Edit"
+ app:layout_constraintEnd_toStartOf="@+id/share"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toEndOf="@+id/close"
+ app:layout_constraintTop_toTopOf="@+id/guideline" />
+
+ <Button
+ android:id="@+id/share"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:text="Share"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toEndOf="@+id/edit"
+ app:layout_constraintTop_toTopOf="@+id/guideline" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
+
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java
index c3815e4cee78..42bc1d0ea0ff 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java
@@ -37,4 +37,9 @@ public interface PluginInitializer {
* Called from {@link PluginManagerImpl#handleWtfs()}.
*/
void handleWtfs();
+
+ /**
+ * Returns if pluging manager should run in debug mode.
+ */
+ boolean isDebuggable();
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
index ee7030a8cf5f..1a4e2d1665f6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
@@ -28,7 +28,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.net.Uri;
-import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -72,7 +71,7 @@ public class PluginInstanceManager<T extends Plugin> {
PluginInstanceManager(Context context, String action, PluginListener<T> listener,
boolean allowMultiple, Looper looper, VersionInfo version, PluginManagerImpl manager) {
this(context, context.getPackageManager(), action, listener, allowMultiple, looper, version,
- manager, Build.IS_DEBUGGABLE, manager.getWhitelistedPlugins());
+ manager, manager.isDebuggable(), manager.getWhitelistedPlugins());
}
@VisibleForTesting
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index 6d67f2147d37..f5ed9da15fa3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -64,8 +64,6 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
private static final String TAG = PluginManagerImpl.class.getSimpleName();
static final String DISABLE_PLUGIN = "com.android.systemui.action.DISABLE_PLUGIN";
- private static PluginManager sInstance;
-
private final ArrayMap<PluginListener<?>, PluginInstanceManager> mPluginMap
= new ArrayMap<>();
private final Map<String, ClassLoader> mClassLoaders = new ArrayMap<>();
@@ -73,7 +71,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
private final ArraySet<String> mWhitelistedPlugins = new ArraySet<>();
private final Context mContext;
private final PluginInstanceManagerFactory mFactory;
- private final boolean isDebuggable;
+ private final boolean mIsDebuggable;
private final PluginPrefs mPluginPrefs;
private final PluginEnabler mPluginEnabler;
private final PluginInitializer mPluginInitializer;
@@ -83,7 +81,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
private Looper mLooper;
public PluginManagerImpl(Context context, PluginInitializer initializer) {
- this(context, new PluginInstanceManagerFactory(), Build.IS_DEBUGGABLE,
+ this(context, new PluginInstanceManagerFactory(), initializer.isDebuggable(),
Thread.getUncaughtExceptionPreHandler(), initializer);
}
@@ -93,7 +91,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
mContext = context;
mFactory = factory;
mLooper = initializer.getBgLooper();
- isDebuggable = debuggable;
+ mIsDebuggable = debuggable;
mWhitelistedPlugins.addAll(Arrays.asList(initializer.getWhitelistedPlugins(mContext)));
mPluginPrefs = new PluginPrefs(mContext);
mPluginEnabler = initializer.getPluginEnabler(mContext);
@@ -111,6 +109,10 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
});
}
+ public boolean isDebuggable() {
+ return mIsDebuggable;
+ }
+
public String[] getWhitelistedPlugins() {
return mWhitelistedPlugins.toArray(new String[0]);
}
@@ -297,7 +299,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
/** Returns class loader specific for the given plugin. */
public ClassLoader getClassLoader(ApplicationInfo appInfo) {
- if (!isDebuggable && !isPluginPackageWhitelisted(appInfo.packageName)) {
+ if (!mIsDebuggable && !isPluginPackageWhitelisted(appInfo.packageName)) {
Log.w(TAG, "Cannot get class loader for non-whitelisted plugin. Src:"
+ appInfo.sourceDir + ", pkg: " + appInfo.packageName);
return null;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index 70021b6f3d45..fbabaa489d74 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -114,10 +114,13 @@ public class SyncRtSurfaceTransactionApplierCompat {
for (int i = params.length - 1; i >= 0; i--) {
SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams =
params[i];
- t.deferTransactionUntil(surfaceParams.surface, mBarrierSurfaceControl, frame);
surfaceParams.applyTo(t);
}
- t.apply();
+ if (mTargetViewRootImpl != null) {
+ mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
+ } else {
+ t.apply();
+ }
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
.sendToTarget();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
index 4a28d56a41e1..89c60f1d3f06 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
@@ -56,4 +56,12 @@ public class ViewRootImplCompat {
});
}
}
+
+ public void mergeWithNextTransaction(SurfaceControl.Transaction t, long frame) {
+ if (mViewRoot != null) {
+ mViewRoot.mergeWithNextTransaction(t, frame);
+ } else {
+ t.apply();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
index 95029c013ab6..7f01d6f1ffa3 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
@@ -15,6 +15,7 @@
package com.android.systemui.plugins;
import android.content.Context;
+import android.os.Build;
import android.os.Looper;
import android.util.Log;
@@ -67,4 +68,9 @@ public class PluginInitializerImpl implements PluginInitializer {
});
}
}
+
+ @Override
+ public boolean isDebuggable() {
+ return Build.IS_DEBUGGABLE;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTile.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTile.java
index 143121af9f2c..212e6c86e9da 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTile.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTile.java
@@ -19,6 +19,7 @@ import static android.graphics.ColorSpace.Named.SRGB;
import static java.util.Objects.requireNonNull;
+import android.annotation.NonNull;
import android.graphics.Bitmap;
import android.graphics.ColorSpace;
import android.graphics.RecordingCanvas;
@@ -50,14 +51,13 @@ class ImageTile implements AutoCloseable {
* @param image an image containing a hardware buffer
* @param location the captured area represented by image tile (virtual coordinates)
*/
- ImageTile(Image image, Rect location) {
+ ImageTile(@NonNull Image image, @NonNull Rect location) {
mImage = requireNonNull(image, "image");
- mLocation = location;
-
+ mLocation = requireNonNull(location);
requireNonNull(mImage.getHardwareBuffer(), "image must be a hardware image");
}
- RenderNode getDisplayList() {
+ synchronized RenderNode getDisplayList() {
if (mNode == null) {
mNode = new RenderNode("Tile{" + Integer.toHexString(mImage.hashCode()) + "}");
}
@@ -69,7 +69,6 @@ class ImageTile implements AutoCloseable {
mNode.setPosition(0, 0, w, h);
RecordingCanvas canvas = mNode.beginRecording(w, h);
- Rect rect = new Rect(0, 0, w, h);
canvas.save();
canvas.clipRect(0, 0, mLocation.right, mLocation.bottom);
canvas.drawBitmap(Bitmap.wrapHardwareBuffer(mImage.getHardwareBuffer(), COLOR_SPACE),
@@ -100,9 +99,11 @@ class ImageTile implements AutoCloseable {
}
@Override
- public void close() {
+ public synchronized void close() {
mImage.close();
- mNode.discardDisplayList();
+ if (mNode != null) {
+ mNode.discardDisplayList();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 4431b6974b7b..d6413ed63e6e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -603,7 +603,18 @@ public class ScreenshotController {
cancelTimeout();
ScrollCaptureController controller = new ScrollCaptureController(mContext, connection,
mMainExecutor, mBgExecutor, mImageExporter);
- controller.start(/* onDismiss */ () -> dismissScreenshot(false));
+ controller.attach(mWindow);
+ controller.start(new TakeScreenshotService.RequestCallback() {
+ @Override
+ public void reportError() {
+ }
+
+ @Override
+ public void onFinish() {
+ Log.d(TAG, "onFinish from ScrollCaptureController");
+ finishDismiss();
+ }
+ });
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 825c85769e03..c2c67903da86 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -16,16 +16,24 @@
package com.android.systemui.screenshot;
+import android.annotation.IdRes;
+import android.annotation.UiThread;
import android.content.Context;
import android.content.Intent;
-import android.graphics.Bitmap;
import android.net.Uri;
import android.os.UserHandle;
import android.util.Log;
-import android.widget.Toast;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewTreeObserver.InternalInsetsInfo;
+import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
+import android.view.Window;
+import android.widget.ImageView;
+import com.android.systemui.R;
import com.android.systemui.screenshot.ScrollCaptureClient.Connection;
import com.android.systemui.screenshot.ScrollCaptureClient.Session;
+import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback;
import com.google.common.util.concurrent.ListenableFuture;
@@ -38,11 +46,9 @@ import java.util.function.Consumer;
/**
* Interaction controller between the UI and ScrollCaptureClient.
*/
-public class ScrollCaptureController {
+public class ScrollCaptureController implements OnComputeInternalInsetsListener {
private static final String TAG = "ScrollCaptureController";
- private static final boolean USE_TILED_IMAGE = false;
-
public static final int MAX_PAGES = 5;
public static final int MAX_HEIGHT = 12000;
@@ -53,9 +59,19 @@ public class ScrollCaptureController {
private final Executor mBgExecutor;
private final ImageExporter mImageExporter;
private final ImageTileSet mImageTileSet;
+ private final LayoutInflater mLayoutInflater;
private ZonedDateTime mCaptureTime;
private UUID mRequestId;
+ private RequestCallback mCallback;
+ private Window mWindow;
+ private ImageView mPreview;
+ private View mClose;
+ private View mEdit;
+ private View mShare;
+
+ private ListenableFuture<ImageExporter.Result> mExportFuture;
+ private Runnable mPendingAction;
public ScrollCaptureController(Context context, Connection connection, Executor uiExecutor,
Executor bgExecutor, ImageExporter exporter) {
@@ -65,20 +81,126 @@ public class ScrollCaptureController {
mBgExecutor = bgExecutor;
mImageExporter = exporter;
mImageTileSet = new ImageTileSet();
+ mLayoutInflater = mContext.getSystemService(LayoutInflater.class);
+ }
+
+ /**
+ * @param window the window to display the preview
+ */
+ public void attach(Window window) {
+ mWindow = window;
}
/**
* Run scroll capture!
*
- * @param after action to take after the flow is complete
+ * @param callback request callback to report back to the service
*/
- public void start(final Runnable after) {
+ public void start(RequestCallback callback) {
mCaptureTime = ZonedDateTime.now();
mRequestId = UUID.randomUUID();
- mConnection.start((session) -> startCapture(session, after));
+ mCallback = callback;
+
+ setContentView(R.layout.long_screenshot);
+ mWindow.getDecorView().getViewTreeObserver()
+ .addOnComputeInternalInsetsListener(this);
+ mPreview = findViewById(R.id.preview);
+
+ mClose = findViewById(R.id.close);
+ mEdit = findViewById(R.id.edit);
+ mShare = findViewById(R.id.share);
+
+ mClose.setOnClickListener(this::onClicked);
+ mEdit.setOnClickListener(this::onClicked);
+ mShare.setOnClickListener(this::onClicked);
+
+ mPreview.setImageDrawable(mImageTileSet.getDrawable());
+ mConnection.start(this::startCapture);
+ }
+
+
+ /** Ensure the entire window is touchable */
+ public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) {
+ inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
+ }
+
+ void disableButtons() {
+ mClose.setEnabled(false);
+ mEdit.setEnabled(false);
+ mShare.setEnabled(false);
+ }
+
+ private void onClicked(View v) {
+ Log.d(TAG, "button clicked!");
+
+ int id = v.getId();
+ if (id == R.id.close) {
+ v.setPressed(true);
+ disableButtons();
+ finish();
+ } else if (id == R.id.edit) {
+ v.setPressed(true);
+ disableButtons();
+ edit();
+ } else if (id == R.id.share) {
+ v.setPressed(true);
+ disableButtons();
+ share();
+ }
}
- private void startCapture(Session session, final Runnable onDismiss) {
+ private void finish() {
+ if (mExportFuture == null) {
+ doFinish();
+ } else {
+ mExportFuture.addListener(this::doFinish, mUiExecutor);
+ }
+ }
+
+ private void doFinish() {
+ mPreview.setImageDrawable(null);
+ mImageTileSet.clear();
+ mCallback.onFinish();
+ mWindow.getDecorView().getViewTreeObserver()
+ .removeOnComputeInternalInsetsListener(this);
+ }
+
+ private void edit() {
+ sendIntentWhenReady(Intent.ACTION_EDIT);
+ }
+
+ private void share() {
+ sendIntentWhenReady(Intent.ACTION_SEND);
+ }
+
+ void sendIntentWhenReady(String action) {
+ if (mExportFuture != null) {
+ mExportFuture.addListener(() -> {
+ try {
+ ImageExporter.Result result = mExportFuture.get();
+ sendIntent(action, result.uri);
+ mCallback.onFinish();
+ } catch (InterruptedException | ExecutionException e) {
+ Log.e(TAG, "failed to export", e);
+ mCallback.onFinish();
+ }
+
+ }, mUiExecutor);
+ } else {
+ mPendingAction = this::edit;
+ }
+ }
+
+ private void setContentView(@IdRes int id) {
+ mWindow.setContentView(id);
+ }
+
+ <T extends View> T findViewById(@IdRes int res) {
+ return mWindow.findViewById(res);
+ }
+
+ private void startCapture(Session session) {
+ Log.d(TAG, "startCapture");
Consumer<ScrollCaptureClient.CaptureResult> consumer =
new Consumer<ScrollCaptureClient.CaptureResult>() {
@@ -91,17 +213,17 @@ public class ScrollCaptureController {
boolean emptyFrame = result.captured.height() == 0;
if (!emptyFrame) {
- mImageTileSet.addTile(new ImageTile(result.image, result.captured));
+ ImageTile tile = new ImageTile(result.image, result.captured);
+ Log.d(TAG, "Adding tile: " + tile);
+ mImageTileSet.addTile(tile);
+ Log.d(TAG, "New dimens: w=" + mImageTileSet.getWidth() + ", "
+ + "h=" + mImageTileSet.getHeight());
}
if (emptyFrame || mFrameCount >= MAX_PAGES
|| mTop + session.getTileHeight() > MAX_HEIGHT) {
- if (!mImageTileSet.isEmpty()) {
- exportToFile(mImageTileSet.toBitmap(), session, onDismiss);
- mImageTileSet.clear();
- } else {
- session.end(onDismiss);
- }
+
+ mUiExecutor.execute(() -> afterCaptureComplete(session));
return;
}
mTop += result.captured.height();
@@ -113,25 +235,24 @@ public class ScrollCaptureController {
session.requestTile(0, consumer);
};
- void exportToFile(Bitmap bitmap, Session session, Runnable afterEnd) {
- mImageExporter.setFormat(Bitmap.CompressFormat.PNG);
- mImageExporter.setQuality(6);
- ListenableFuture<ImageExporter.Result> future =
- mImageExporter.export(mBgExecutor, mRequestId, bitmap, mCaptureTime);
- future.addListener(() -> {
- try {
- ImageExporter.Result result = future.get();
- launchViewer(result.uri);
- } catch (InterruptedException | ExecutionException e) {
- Toast.makeText(mContext, "Failed to write image", Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Error storing screenshot to media store", e.getCause());
+ @UiThread
+ void afterCaptureComplete(Session session) {
+ Log.d(TAG, "afterCaptureComplete");
+
+ if (mImageTileSet.isEmpty()) {
+ session.end(mCallback::onFinish);
+ } else {
+ mExportFuture = mImageExporter.export(
+ mBgExecutor, mRequestId, mImageTileSet.toBitmap(), mCaptureTime);
+ // The user chose an action already, link it to the result
+ if (mPendingAction != null) {
+ mExportFuture.addListener(mPendingAction, mUiExecutor);
}
- session.end(afterEnd); // end session, close connection, afterEnd.run()
- }, mUiExecutor);
+ }
}
- void launchViewer(Uri uri) {
- Intent editIntent = new Intent(Intent.ACTION_VIEW);
+ void sendIntent(String action, Uri uri) {
+ Intent editIntent = new Intent(action);
editIntent.setType("image/png");
editIntent.setData(uri);
editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
diff --git a/services/core/java/com/android/server/am/PhantomProcessList.java b/services/core/java/com/android/server/am/PhantomProcessList.java
index 5167c5719955..37b17411dac5 100644
--- a/services/core/java/com/android/server/am/PhantomProcessList.java
+++ b/services/core/java/com/android/server/am/PhantomProcessList.java
@@ -38,6 +38,7 @@ import com.android.internal.os.ProcessCpuTracker;
import libcore.io.IoUtils;
+import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -109,10 +110,23 @@ public final class PhantomProcessList {
private final ActivityManagerService mService;
private final Handler mKillHandler;
+ private static final int CGROUP_V1 = 0;
+ private static final int CGROUP_V2 = 1;
+ private static final String[] CGROUP_PATH_PREFIXES = {
+ "/acct/uid_" /* cgroup v1 */,
+ "/sys/fs/cgroup/uid_" /* cgroup v2 */
+ };
+ private static final String CGROUP_PID_PREFIX = "/pid_";
+ private static final String CGROUP_PROCS = "/cgroup.procs";
+
+ @VisibleForTesting
+ int mCgroupVersion = CGROUP_V1;
+
PhantomProcessList(final ActivityManagerService service) {
mService = service;
mKillHandler = service.mProcessList.sKillHandler;
mInjector = new Injector();
+ probeCgroupVersion();
}
@VisibleForTesting
@@ -190,9 +204,18 @@ public final class PhantomProcessList {
}
}
+ private void probeCgroupVersion() {
+ for (int i = CGROUP_PATH_PREFIXES.length - 1; i >= 0; i--) {
+ if ((new File(CGROUP_PATH_PREFIXES[i] + Process.SYSTEM_UID)).exists()) {
+ mCgroupVersion = i;
+ break;
+ }
+ }
+ }
+
@VisibleForTesting
- static String getCgroupFilePath(int uid, int pid) {
- return "/acct/uid_" + uid + "/pid_" + pid + "/cgroup.procs";
+ String getCgroupFilePath(int uid, int pid) {
+ return CGROUP_PATH_PREFIXES[mCgroupVersion] + uid + CGROUP_PID_PREFIX + pid + CGROUP_PROCS;
}
static String getProcessName(int pid) {
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
index 3e39b4bbe1d0..eb9df756dd0e 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
@@ -295,14 +295,14 @@ public final class PowerStatsHALWrapper {
@Override
public android.hardware.power.stats.EnergyConsumer[] getEnergyConsumerInfo() {
if (DEBUG) Slog.d(TAG, "Energy consumer info is not supported");
- return null;
+ return new android.hardware.power.stats.EnergyConsumer[0];
}
@Override
public android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed(
int[] energyConsumerIds) {
if (DEBUG) Slog.d(TAG, "Energy consumer results are not supported");
- return null;
+ return new android.hardware.power.stats.EnergyConsumerResult[0];
}
@Override
diff --git a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
index e71b962baef7..766cf9c1b678 100644
--- a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
+++ b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
@@ -266,6 +266,7 @@ public class ProtoStreamUtils {
long token = pos.start(PowerStatsServiceMeterProto.CHANNEL);
pos.write(ChannelProto.ID, channel[i].id);
pos.write(ChannelProto.NAME, channel[i].name);
+ pos.write(ChannelProto.SUBSYSTEM, channel[i].subsystem);
pos.end(token);
}
}
@@ -275,7 +276,8 @@ public class ProtoStreamUtils {
for (int i = 0; i < channel.length; i++) {
Slog.d(TAG, "ChannelId: " + channel[i].id
- + ", ChannelName: " + channel[i].name);
+ + ", ChannelName: " + channel[i].name
+ + ", ChannelSubsystem: " + channel[i].subsystem);
}
}
@@ -284,7 +286,8 @@ public class ProtoStreamUtils {
for (int i = 0; i < channel.length; i++) {
pw.println("ChannelId: " + channel[i].id
- + ", ChannelName: " + channel[i].name);
+ + ", ChannelName: " + channel[i].name
+ + ", ChannelSubsystem: " + channel[i].subsystem);
}
}
}
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 8805fa2f4dbb..703bfab6d868 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -638,6 +638,22 @@ public class VcnGatewayConnection extends StateMachine {
protected abstract void processStateMsg(Message msg) throws Exception;
+ @Override
+ public void exit() {
+ try {
+ exitState();
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Uncaught exception", e);
+ sendMessage(
+ EVENT_DISCONNECT_REQUESTED,
+ TOKEN_ALL,
+ new EventDisconnectRequestedInfo(
+ DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+ }
+ }
+
+ protected void exitState() throws Exception {}
+
protected void logUnhandledMessage(Message msg) {
// Log as unexpected all known messages, and log all else as unknown.
switch (msg.what) {
@@ -664,18 +680,11 @@ public class VcnGatewayConnection extends StateMachine {
}
}
- protected void teardownIke() {
- if (mIkeSession != null) {
- mIkeSession.close();
- }
- }
-
protected void handleDisconnectRequested(String msg) {
Slog.v(TAG, "Tearing down. Cause: " + msg);
mIsRunning = false;
teardownNetwork();
- teardownIke();
if (mIkeSession == null) {
// Already disconnected, go straight to DisconnectedState
@@ -768,6 +777,20 @@ public class VcnGatewayConnection extends StateMachine {
* does not complete teardown in a timely fashion, it will be killed (forcibly closed).
*/
private class DisconnectingState extends ActiveBaseState {
+ /**
+ * Whether to skip the RetryTimeoutState and go straight to the ConnectingState.
+ *
+ * <p>This is used when an underlying network change triggered a restart on a new network.
+ *
+ * <p>Reset (to false) upon exit of the DisconnectingState.
+ */
+ private boolean mSkipRetryTimeout = false;
+
+ // TODO(b/178441390): Remove this in favor of resetting retry timers on UND_NET change.
+ public void setSkipRetryTimeout(boolean shouldSkip) {
+ mSkipRetryTimeout = shouldSkip;
+ }
+
@Override
protected void enterState() throws Exception {
if (mIkeSession == null) {
@@ -783,6 +806,7 @@ public class VcnGatewayConnection extends StateMachine {
return;
}
+ mIkeSession.close();
sendMessageDelayed(
EVENT_TEARDOWN_TIMEOUT_EXPIRED,
mCurrentToken,
@@ -822,7 +846,7 @@ public class VcnGatewayConnection extends StateMachine {
mIkeSession = null;
if (mIsRunning && mUnderlying != null) {
- transitionTo(mRetryTimeoutState);
+ transitionTo(mSkipRetryTimeout ? mConnectingState : mRetryTimeoutState);
} else {
teardownNetwork();
transitionTo(mDisconnectedState);
@@ -833,6 +857,11 @@ public class VcnGatewayConnection extends StateMachine {
break;
}
}
+
+ @Override
+ protected void exitState() throws Exception {
+ mSkipRetryTimeout = false;
+ }
}
/**
@@ -843,7 +872,69 @@ public class VcnGatewayConnection extends StateMachine {
*/
private class ConnectingState extends ActiveBaseState {
@Override
- protected void processStateMsg(Message msg) {}
+ protected void enterState() {
+ if (mIkeSession != null) {
+ Slog.wtf(TAG, "ConnectingState entered with active session");
+
+ // Attempt to recover.
+ mIkeSession.kill();
+ mIkeSession = null;
+ }
+
+ mIkeSession = buildIkeSession();
+ }
+
+ @Override
+ protected void processStateMsg(Message msg) {
+ switch (msg.what) {
+ case EVENT_UNDERLYING_NETWORK_CHANGED:
+ final UnderlyingNetworkRecord oldUnderlying = mUnderlying;
+ mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
+
+ if (oldUnderlying == null) {
+ // This should never happen, but if it does, there's likely a nasty bug.
+ Slog.wtf(TAG, "Old underlying network was null in connected state. Bug?");
+ }
+
+ // If new underlying is null, all underlying networks have been lost; disconnect
+ if (mUnderlying == null) {
+ transitionTo(mDisconnectingState);
+ break;
+ }
+
+ if (oldUnderlying != null
+ && mUnderlying.network.equals(oldUnderlying.network)) {
+ break; // Only network properties have changed; continue connecting.
+ }
+ // Else, retry on the new network.
+
+ // Immediately come back to the ConnectingState (skip RetryTimeout, since this
+ // isn't a failure)
+ mDisconnectingState.setSkipRetryTimeout(true);
+
+ // fallthrough - disconnect, and retry on new network.
+ case EVENT_SESSION_LOST:
+ transitionTo(mDisconnectingState);
+ break;
+ case EVENT_SESSION_CLOSED:
+ deferMessage(msg);
+
+ transitionTo(mDisconnectingState);
+ break;
+ case EVENT_SETUP_COMPLETED: // fallthrough
+ case EVENT_TRANSFORM_CREATED:
+ // Child setup complete; move to ConnectedState for NetworkAgent registration
+ deferMessage(msg);
+ transitionTo(mConnectedState);
+ break;
+ case EVENT_DISCONNECT_REQUESTED:
+ handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
+ break;
+ default:
+ logUnhandledMessage(msg);
+ break;
+ }
+ }
}
private abstract class ConnectedStateBase extends ActiveBaseState {}
@@ -1015,12 +1106,12 @@ public class VcnGatewayConnection extends StateMachine {
}
private IkeSessionParams buildIkeParams() {
- // TODO: Implement this with ConnectingState
+ // TODO: Implement this once IkeSessionParams is persisted
return null;
}
private ChildSessionParams buildChildParams() {
- // TODO: Implement this with ConnectingState
+ // TODO: Implement this once IkeSessionParams is persisted
return null;
}
diff --git a/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp b/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp
index ec2549c5991c..1208354899d5 100644
--- a/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp
+++ b/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp
@@ -33,6 +33,7 @@ static jclass class_C;
static jmethodID method_C_init;
static jfieldID field_C_id;
static jfieldID field_C_name;
+static jfieldID field_C_subsystem;
// EnergyMeasurement
static jclass class_EM;
@@ -277,11 +278,14 @@ static jobjectArray nativeGetEnergyMeterInfo(JNIEnv *env, jclass clazz) {
channelArray = env->NewObjectArray(railInfo.size(), class_C, nullptr);
for (int i = 0; i < railInfo.size(); i++) {
jstring name = env->NewStringUTF(railInfo[i].railName.c_str());
+ jstring subsystem = env->NewStringUTF(railInfo[i].subsysName.c_str());
jobject channel = env->NewObject(class_C, method_C_init);
env->SetIntField(channel, field_C_id, railInfo[i].index);
env->SetObjectField(channel, field_C_name, name);
+ env->SetObjectField(channel, field_C_subsystem, subsystem);
env->SetObjectArrayElement(channelArray, i, channel);
env->DeleteLocalRef(name);
+ env->DeleteLocalRef(subsystem);
env->DeleteLocalRef(channel);
}
}
@@ -359,6 +363,7 @@ static jboolean nativeInit(JNIEnv *env, jclass clazz) {
method_C_init = env->GetMethodID(class_C, "<init>", "()V");
field_C_id = env->GetFieldID(class_C, "id", "I");
field_C_name = env->GetFieldID(class_C, "name", "Ljava/lang/String;");
+ field_C_subsystem = env->GetFieldID(class_C, "subsystem", "Ljava/lang/String;");
// EnergyMeasurement
temp = env->FindClass("android/hardware/power/stats/EnergyMeasurement");
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index fd8dfc32e5d3..d28c3cc8e2b8 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1705,15 +1705,6 @@ public final class SystemServer implements Dumpable {
}
t.traceEnd();
- t.traceBegin("StartVcnManagementService");
- try {
- vcnManagement = VcnManagementService.create(context);
- ServiceManager.addService(Context.VCN_MANAGEMENT_SERVICE, vcnManagement);
- } catch (Throwable e) {
- reportWtf("starting VCN Management Service", e);
- }
- t.traceEnd();
-
t.traceBegin("StartFontManagerService");
mSystemServiceManager.startService(FontManagerService.Lifecycle.class);
t.traceEnd();
@@ -1815,6 +1806,15 @@ public final class SystemServer implements Dumpable {
networkPolicy.bindConnectivityManager(connectivity);
t.traceEnd();
+ t.traceBegin("StartVcnManagementService");
+ try {
+ vcnManagement = VcnManagementService.create(context);
+ ServiceManager.addService(Context.VCN_MANAGEMENT_SERVICE, vcnManagement);
+ } catch (Throwable e) {
+ reportWtf("starting VCN Management Service", e);
+ }
+ t.traceEnd();
+
t.traceBegin("StartNsdService");
try {
serviceDiscovery = NsdService.create(context);
@@ -2632,15 +2632,6 @@ public final class SystemServer implements Dumpable {
reportWtf("making IpSec Service ready", e);
}
t.traceEnd();
- t.traceBegin("MakeVcnManagementServiceReady");
- try {
- if (vcnManagementF != null) {
- vcnManagementF.systemReady();
- }
- } catch (Throwable e) {
- reportWtf("making VcnManagementService ready", e);
- }
- t.traceEnd();
t.traceBegin("MakeNetworkStatsServiceReady");
try {
if (networkStatsF != null) {
@@ -2659,6 +2650,15 @@ public final class SystemServer implements Dumpable {
reportWtf("making Connectivity Service ready", e);
}
t.traceEnd();
+ t.traceBegin("MakeVcnManagementServiceReady");
+ try {
+ if (vcnManagementF != null) {
+ vcnManagementF.systemReady();
+ }
+ } catch (Throwable e) {
+ reportWtf("making VcnManagementService ready", e);
+ }
+ t.traceEnd();
t.traceBegin("MakeNetworkPolicyServiceReady");
try {
if (networkPolicyF != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
index b85da9460476..17f326fbdbce 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AppChildProcessTest.java
@@ -298,7 +298,7 @@ public class AppChildProcessTest {
}
void addToProcess(int uid, int pid, int newPid) {
- final String path = PhantomProcessList.getCgroupFilePath(uid, pid);
+ final String path = mPhantomProcessList.getCgroupFilePath(uid, pid);
StringBuffer sb = mPathToData.get(path);
if (sb == null) {
sb = new StringBuffer();
diff --git a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
index b6ae8555b02e..84b690f01b02 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
@@ -67,6 +67,7 @@ public class PowerStatsServiceTest {
private static final String RESIDENCY_FILENAME = "residencytest";
private static final String PROTO_OUTPUT_FILENAME = "powerstats.proto";
private static final String CHANNEL_NAME = "channelname";
+ private static final String CHANNEL_SUBSYSTEM = "channelsubsystem";
private static final String POWER_ENTITY_NAME = "powerentityinfo";
private static final String STATE_NAME = "stateinfo";
private static final String ENERGY_CONSUMER_NAME = "energyconsumer";
@@ -214,6 +215,7 @@ public class PowerStatsServiceTest {
energyMeterList[i] = new Channel();
energyMeterList[i].id = i;
energyMeterList[i].name = new String(CHANNEL_NAME + i);
+ energyMeterList[i].subsystem = new String(CHANNEL_SUBSYSTEM + i);
}
return energyMeterList;
}
@@ -272,6 +274,7 @@ public class PowerStatsServiceTest {
for (int i = 0; i < pssProto.channel.length; i++) {
assertTrue(pssProto.channel[i].id == i);
assertTrue(pssProto.channel[i].name.equals(CHANNEL_NAME + i));
+ assertTrue(pssProto.channel[i].subsystem.equals(CHANNEL_SUBSYSTEM + i));
}
// Validate the energyMeasurement array matches what was written to on-device storage.
@@ -414,6 +417,7 @@ public class PowerStatsServiceTest {
for (int i = 0; i < pssProto.channel.length; i++) {
assertTrue(pssProto.channel[i].id == i);
assertTrue(pssProto.channel[i].name.equals(CHANNEL_NAME + i));
+ assertTrue(pssProto.channel[i].subsystem.equals(CHANNEL_SUBSYSTEM + i));
}
// No energyMeasurements should be written to the incident report since it
@@ -547,6 +551,7 @@ public class PowerStatsServiceTest {
for (int i = 0; i < pssProto.channel.length; i++) {
assertTrue(pssProto.channel[i].id == i);
assertTrue(pssProto.channel[i].name.equals(CHANNEL_NAME + i));
+ assertTrue(pssProto.channel[i].subsystem.equals(CHANNEL_SUBSYSTEM + i));
}
// No energyMeasurements should be written to the incident report since the
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 5b03863efc7d..472d63946ebc 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -314,20 +314,22 @@ public class TelecomManager {
public static final String EXTRA_HAS_PICTURE = "android.telecom.extra.HAS_PICTURE";
/**
- * A URI representing the picture that was downloaded when a call is received.
+ * A URI representing the picture that was downloaded when a call is received or uploaded
+ * when a call is placed.
+ *
* This is a content URI within the call log provider which can be used to open a file
* descriptor. This could be set a short time after a call is added to the Dialer app if the
- * download is delayed for some reason. The Dialer app will receive a callback via
+ * download/upload is delayed for some reason. The Dialer app will receive a callback via
* {@link Call.Callback#onDetailsChanged} when this value has changed.
*
* Reference: RCC.20 Section 2.4.3.2
*/
- public static final String EXTRA_INCOMING_PICTURE = "android.telecom.extra.INCOMING_PICTURE";
+ public static final String EXTRA_PICTURE_URI = "android.telecom.extra.PICTURE_URI";
- // TODO(hallliu), This UUID is obtained from TelephonyManager#uploadCallComposerPicture.
/**
* A ParcelUuid used as a token to represent a picture that was uploaded prior to the call
- * being placed.
+ * being placed. The value of this extra should be set using the {@link android.os.ParcelUuid}
+ * obtained from the callback in {@link TelephonyManager#uploadCallComposerPicture}.
*/
public static final String EXTRA_OUTGOING_PICTURE = "android.telecom.extra.OUTGOING_PICTURE";
diff --git a/telephony/java/android/telephony/TelephonyLocalConnection.java b/telephony/java/android/telephony/TelephonyLocalConnection.java
new file mode 100644
index 000000000000..1cab267cc817
--- /dev/null
+++ b/telephony/java/android/telephony/TelephonyLocalConnection.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 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.telephony;
+
+import java.util.UUID;
+
+/**
+ * Shim used for code in frameworks/opt/telephony to be able to call code in
+ * packages/services/Telephony. A singleton instance of this class is set when the phone process
+ * is brought up.
+ * @hide
+ */
+public class TelephonyLocalConnection {
+ public interface ConnectionImpl {
+ String getCallComposerServerUrlForHandle(int subscriptionId, UUID uuid);
+ }
+ private static ConnectionImpl sInstance;
+
+ public static String getCallComposerServerUrlForHandle(int subscriptionId, UUID uuid) {
+ checkInstance();
+ return sInstance.getCallComposerServerUrlForHandle(subscriptionId, uuid);
+ }
+
+ private static void checkInstance() {
+ if (sInstance == null) {
+ throw new IllegalStateException("Connection impl is null!");
+ }
+ }
+
+ public static void setInstance(ConnectionImpl impl) {
+ sInstance = impl;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
index 519d0164b0d6..5eb75e762fc9 100644
--- a/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
+++ b/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java
@@ -19,6 +19,7 @@ package android.telephony.ims;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
+import android.annotation.SystemApi;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -34,14 +35,135 @@ import java.util.List;
* network during a SUBSCRIBE request. See RFC3863 for more information.
* @hide
*/
+@SystemApi
public final class RcsContactPresenceTuple implements Parcelable {
- /** The service id of the MMTEL */
+ /**
+ * The service ID used to indicate that MMTEL service is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
public static final String SERVICE_ID_MMTEL = "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel";
- /** The service id of the Call Composer */
+ /**
+ * The service ID used to indicate that the chat(v1.0) is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_CHAT_V1 = "org.openmobilealliance:IM-session";
+
+ /**
+ * The service ID used to indicate that the chat(v2.0) is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_CHAT_V2 = "org.openmobilealliance:ChatSession";
+
+ /**
+ * The service ID used to indicate that the File Transfer is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_FT = "org.openmobilealliance:File-Transfer-HTTP";
+
+ /**
+ * The service ID used to indicate that the File Transfer over SMS is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_FT_OVER_SMS =
+ "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.ftsms";
+
+ /**
+ * The service ID used to indicate that the Geolocation Push is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_GEO_PUSH =
+ "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.geopush";
+
+ /**
+ * The service ID used to indicate that the Geolocation Push via SMS is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_GEO_PUSH_VIA_SMS =
+ "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.geosms";
+
+ /**
+ * The service ID used to indicate that the Call Composer is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
public static final String SERVICE_ID_CALL_COMPOSER =
- "org.3gpp.urn:urn-7:3gppservice.ims.icsi.gsma.callcomposer";
+ "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callcomposer";
+
+ /**
+ * The service ID used to indicate that the Post Call is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_POST_CALL =
+ "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.callunanswered";
+
+ /**
+ * The service ID used to indicate that the Shared Map is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_SHARED_MAP =
+ "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedmap";
+
+ /**
+ * The service ID used to indicate that the Shared Sketch is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_SHARED_SKETCH =
+ "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.gsma.sharedsketch";
+
+ /**
+ * The service ID used to indicate that the Chatbot using Session is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_CHATBOT =
+ "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.chatbot";
+
+ /**
+ * The service ID used to indicate that the Standalone Messaging is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_CHATBOT_STANDALONE =
+ " org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcs.chatbot.sa";
+
+ /**
+ * The service ID used to indicate that the Chatbot Role is available.
+ * <p>
+ * See the GSMA RCC.07 specification for more information.
+ */
+ public static final String SERVICE_ID_CHATBOT_ROLE = "org.gsma.rcs.isbot";
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef(prefix = "SERVICE_ID_", value = {
+ SERVICE_ID_MMTEL,
+ SERVICE_ID_CHAT_V1,
+ SERVICE_ID_CHAT_V2,
+ SERVICE_ID_FT,
+ SERVICE_ID_FT_OVER_SMS,
+ SERVICE_ID_GEO_PUSH,
+ SERVICE_ID_GEO_PUSH_VIA_SMS,
+ SERVICE_ID_CALL_COMPOSER,
+ SERVICE_ID_POST_CALL,
+ SERVICE_ID_SHARED_MAP,
+ SERVICE_ID_SHARED_SKETCH,
+ SERVICE_ID_CHATBOT,
+ SERVICE_ID_CHATBOT_STANDALONE,
+ SERVICE_ID_CHATBOT_ROLE
+ })
+ public @interface ServiceId {}
/** The service capabilities is available. */
public static final String TUPLE_BASIC_STATUS_OPEN = "open";
@@ -149,6 +271,7 @@ public final class RcsContactPresenceTuple implements Parcelable {
in.readStringList(mSupportedDuplexModeList);
in.readStringList(mUnsupportedDuplexModeList);
}
+
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeBoolean(mIsAudioCapable);
@@ -217,12 +340,14 @@ public final class RcsContactPresenceTuple implements Parcelable {
/**
* Builds a RcsContactPresenceTuple instance.
+ * @param status The status associated with the service capability. See RFC3865 for more
+ * information.
* @param serviceId The OMA Presence service-id associated with this capability. See the
* OMA Presence SIMPLE specification v1.1, section 10.5.1.
* @param serviceVersion The OMA Presence version associated with the service capability.
* See the OMA Presence SIMPLE specification v1.1, section 10.5.1.
*/
- public Builder(@NonNull @BasicStatus String status, @NonNull String serviceId,
+ public Builder(@NonNull @BasicStatus String status, @NonNull @ServiceId String serviceId,
@NonNull String serviceVersion) {
mPresenceTuple = new RcsContactPresenceTuple(status, serviceId, serviceVersion);
}
@@ -230,16 +355,17 @@ public final class RcsContactPresenceTuple implements Parcelable {
/**
* The optional SIP Contact URI associated with the PIDF tuple element.
*/
- public @NonNull Builder addContactUri(@NonNull Uri contactUri) {
+ public @NonNull Builder setContactUri(@NonNull Uri contactUri) {
mPresenceTuple.mContactUri = contactUri;
return this;
}
/**
* The optional timestamp indicating the data and time of the status change of this tuple.
- * See RFC3863, section 4.1.7 for more information on the expected format.
+ * Per RFC3863 section 4.1.7, the timestamp is formatted as an IMPP datetime format
+ * string per RFC3339.
*/
- public @NonNull Builder addTimeStamp(@NonNull String timestamp) {
+ public @NonNull Builder setTimestamp(@NonNull String timestamp) {
mPresenceTuple.mTimestamp = timestamp;
return this;
}
@@ -248,7 +374,7 @@ public final class RcsContactPresenceTuple implements Parcelable {
* An optional parameter containing the description element of the service-description. See
* OMA Presence SIMPLE specification v1.1
*/
- public @NonNull Builder addDescription(@NonNull String description) {
+ public @NonNull Builder setServiceDescription(@NonNull String description) {
mPresenceTuple.mServiceDescription = description;
return this;
}
@@ -257,7 +383,7 @@ public final class RcsContactPresenceTuple implements Parcelable {
* An optional parameter containing the service capabilities of the presence tuple if they
* are present in the servcaps element.
*/
- public @NonNull Builder addServiceCapabilities(@NonNull ServiceCapabilities caps) {
+ public @NonNull Builder setServiceCapabilities(@NonNull ServiceCapabilities caps) {
mPresenceTuple.mServiceCapabilities = caps;
return this;
}
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index d4715bfeeb3e..fe855023f5d0 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -19,6 +19,7 @@ package android.telephony.ims;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -33,6 +34,7 @@ import java.util.List;
* Contains the User Capability Exchange capabilities corresponding to a contact's URI.
* @hide
*/
+@SystemApi
public final class RcsContactUceCapability implements Parcelable {
/** Contains presence information associated with the contact */
@@ -70,52 +72,46 @@ public final class RcsContactUceCapability implements Parcelable {
public @interface SourceType {}
/**
+ * Capability information for the requested contact has expired and can not be refreshed due to
+ * a temporary network error. This is a temporary error and the capabilities of the contact
+ * should be queried again at a later time.
+ */
+ public static final int REQUEST_RESULT_UNKNOWN = 0;
+
+ /**
* The requested contact was found to be offline when queried. This is only applicable to
* contact capabilities that were queried via OPTIONS requests and the network returned a
* 408/480 response.
*/
- public static final int REQUEST_RESULT_NOT_ONLINE = 0;
+ public static final int REQUEST_RESULT_NOT_ONLINE = 1;
/**
* Capability information for the requested contact was not found. The contact should not be
* considered an RCS user.
*/
- public static final int REQUEST_RESULT_NOT_FOUND = 1;
+ public static final int REQUEST_RESULT_NOT_FOUND = 2;
/**
* Capability information for the requested contact was found successfully.
*/
- public static final int REQUEST_RESULT_FOUND = 2;
-
- /**
- * Capability information for the requested contact has expired and can not be refreshed due to
- * a temporary network error. This is a temporary error and the capabilities of the contact
- * should be queried again at a later time.
- */
- public static final int REQUEST_RESULT_UNKNOWN = 3;
+ public static final int REQUEST_RESULT_FOUND = 3;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "REQUEST_RESULT_", value = {
+ REQUEST_RESULT_UNKNOWN,
REQUEST_RESULT_NOT_ONLINE,
REQUEST_RESULT_NOT_FOUND,
- REQUEST_RESULT_FOUND,
- REQUEST_RESULT_UNKNOWN
+ REQUEST_RESULT_FOUND
})
public @interface RequestResult {}
/**
- * The base class of {@link OptionsBuilder} and {@link PresenceBuilder}
- */
- public static abstract class RcsUcsCapabilityBuilder {
- public abstract @NonNull RcsContactUceCapability build();
- }
-
- /**
* Builder to help construct {@link RcsContactUceCapability} instances when capabilities were
* queried through SIP OPTIONS.
+ * @hide
*/
- public static class OptionsBuilder extends RcsUcsCapabilityBuilder {
+ public static final class OptionsBuilder {
private final RcsContactUceCapability mCapabilities;
@@ -162,7 +158,6 @@ public final class RcsContactUceCapability implements Parcelable {
/**
* @return the constructed instance.
*/
- @Override
public @NonNull RcsContactUceCapability build() {
return mCapabilities;
}
@@ -172,7 +167,7 @@ public final class RcsContactUceCapability implements Parcelable {
* Builder to help construct {@link RcsContactUceCapability} instances when capabilities were
* queried through a presence server.
*/
- public static class PresenceBuilder extends RcsUcsCapabilityBuilder {
+ public static final class PresenceBuilder {
private final RcsContactUceCapability mCapabilities;
@@ -214,7 +209,6 @@ public final class RcsContactUceCapability implements Parcelable {
/**
* @return the RcsContactUceCapability instance.
*/
- @Override
public @NonNull RcsContactUceCapability build() {
return mCapabilities;
}
@@ -284,6 +278,7 @@ public final class RcsContactUceCapability implements Parcelable {
* <p>
* Note: this is only populated if {@link #getCapabilityMechanism} is
* {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS}
+ * @hide
*/
public @NonNull List<String> getOptionsFeatureTags() {
if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) {
@@ -299,7 +294,7 @@ public final class RcsContactUceCapability implements Parcelable {
* Note: this is only populated if {@link #getCapabilityMechanism} is
* {@link RcsContactUceCapability#CAPABILITY_MECHANISM_PRESENCE}
*/
- public @NonNull List<RcsContactPresenceTuple> getPresenceTuples() {
+ public @NonNull List<RcsContactPresenceTuple> getCapabilityTuples() {
if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) {
return Collections.emptyList();
}
@@ -309,13 +304,14 @@ public final class RcsContactUceCapability implements Parcelable {
/**
* Get the RcsContactPresenceTuple associated with the given service id.
* @param serviceId The service id to get the presence tuple.
- * @return The RcsContactPresenceTuple which has the given service id.
+ * @return The RcsContactPresenceTuple which has the given service id or {@code null} if the
+ * service id does not exist in the list of presence tuples returned from the network.
*
* <p>
* Note: this is only populated if {@link #getCapabilityMechanism} is
* {@link RcsContactUceCapability#CAPABILITY_MECHANISM_PRESENCE}
*/
- public @Nullable RcsContactPresenceTuple getPresenceTuple(@NonNull String serviceId) {
+ public @Nullable RcsContactPresenceTuple getCapabilityTuple(@NonNull String serviceId) {
if (mCapabilityMechanism != CAPABILITY_MECHANISM_PRESENCE) {
return null;
}
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 6c31466c2a89..070fd799d6cc 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -63,6 +63,7 @@ public class RcsUceAdapter {
* RcsFeature should not publish capabilities or service capability requests.
* @hide
*/
+ @SystemApi
public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1;
/**@hide*/
@@ -77,12 +78,14 @@ public class RcsUceAdapter {
* An unknown error has caused the request to fail.
* @hide
*/
+ @SystemApi
public static final int ERROR_GENERIC_FAILURE = 1;
/**
* The carrier network does not have UCE support enabled for this subscriber.
* @hide
*/
+ @SystemApi
public static final int ERROR_NOT_ENABLED = 2;
/**
@@ -90,12 +93,14 @@ public class RcsUceAdapter {
* 1x only currently).
* @hide
*/
+ @SystemApi
public static final int ERROR_NOT_AVAILABLE = 3;
/**
* The network has responded with SIP 403 error and a reason "User not registered."
* @hide
*/
+ @SystemApi
public static final int ERROR_NOT_REGISTERED = 4;
/**
@@ -103,12 +108,14 @@ public class RcsUceAdapter {
* presence" for this subscriber.
* @hide
*/
+ @SystemApi
public static final int ERROR_NOT_AUTHORIZED = 5;
/**
* The network has responded to this request with a SIP 403 error and no reason.
* @hide
*/
+ @SystemApi
public static final int ERROR_FORBIDDEN = 6;
/**
@@ -116,6 +123,7 @@ public class RcsUceAdapter {
* subscriber to the carrier network.
* @hide
*/
+ @SystemApi
public static final int ERROR_NOT_FOUND = 7;
/**
@@ -123,6 +131,7 @@ public class RcsUceAdapter {
* with a lower number of contact numbers. The number varies per carrier.
* @hide
*/
+ @SystemApi
// TODO: Try to integrate this into the API so that the service will split based on carrier.
public static final int ERROR_REQUEST_TOO_LARGE = 8;
@@ -130,18 +139,21 @@ public class RcsUceAdapter {
* The network did not respond to the capabilities request before the request timed out.
* @hide
*/
+ @SystemApi
public static final int ERROR_REQUEST_TIMEOUT = 9;
/**
* The request failed due to the service having insufficient memory.
* @hide
*/
+ @SystemApi
public static final int ERROR_INSUFFICIENT_MEMORY = 10;
/**
* The network was lost while trying to complete the request.
* @hide
*/
+ @SystemApi
public static final int ERROR_LOST_NETWORK = 11;
/**
@@ -149,6 +161,7 @@ public class RcsUceAdapter {
* time returned in {@link CapabilitiesCallback#onError} has elapsed.
* @hide
*/
+ @SystemApi
public static final int ERROR_SERVER_UNAVAILABLE = 12;
/**@hide*/
@@ -405,6 +418,7 @@ public class RcsUceAdapter {
* @see #requestCapabilities(Executor, List, CapabilitiesCallback)
* @hide
*/
+ @SystemApi
public interface CapabilitiesCallback {
/**
@@ -424,10 +438,10 @@ public class RcsUceAdapter {
* The pending request has resulted in an error and may need to be retried, depending on the
* error code.
* @param errorCode The reason for the framework being unable to process the request.
- * @param retryAfterMilliseconds The time in milliseconds the requesting application should
+ * @param retryIntervalMillis The time in milliseconds the requesting application should
* wait before retrying, if non-zero.
*/
- void onError(@ErrorCode int errorCode, long retryAfterMilliseconds);
+ void onError(@ErrorCode int errorCode, long retryIntervalMillis);
}
private final Context mContext;
@@ -458,9 +472,9 @@ public class RcsUceAdapter {
* {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is enabled or else
* this operation will fail with {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}.
*
+ * @param contactNumbers A list of numbers that the capabilities are being requested for.
* @param executor The executor that will be used when the request is completed and the
* {@link CapabilitiesCallback} is called.
- * @param contactNumbers A list of numbers that the capabilities are being requested for.
* @param c A one-time callback for when the request for capabilities completes or there is an
* error processing the request.
* @throws ImsException if the subscription associated with this instance of
@@ -469,9 +483,10 @@ public class RcsUceAdapter {
* becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void requestCapabilities(@NonNull @CallbackExecutor Executor executor,
- @NonNull List<Uri> contactNumbers,
+ public void requestCapabilities(@NonNull List<Uri> contactNumbers,
+ @NonNull @CallbackExecutor Executor executor,
@NonNull CapabilitiesCallback c) throws ImsException {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null CapabilitiesCallback.");
@@ -495,8 +510,7 @@ public class RcsUceAdapter {
public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
final long callingIdentity = Binder.clearCallingIdentity();
try {
- executor.execute(() ->
- c.onCapabilitiesReceived(contactCapabilities));
+ executor.execute(() -> c.onCapabilitiesReceived(contactCapabilities));
} finally {
restoreCallingIdentity(callingIdentity);
}
@@ -550,13 +564,17 @@ public class RcsUceAdapter {
* {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}.
*
* @param contactNumber The contact of the capabilities is being requested for.
+ * @param executor The executor that will be used when the request is completed and the
+ * {@link CapabilitiesCallback} is called.
* @param c A one-time callback for when the request for capabilities completes or there is
* an error processing the request.
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
- public void requestNetworkAvailability(@NonNull @CallbackExecutor Executor executor,
- @NonNull Uri contactNumber, @NonNull CapabilitiesCallback c) throws ImsException {
+ public void requestAvailability(@NonNull Uri contactNumber,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull CapabilitiesCallback c) throws ImsException {
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
@@ -569,7 +587,7 @@ public class RcsUceAdapter {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "requestNetworkAvailability: IImsRcsController is null");
+ Log.e(TAG, "requestAvailability: IImsRcsController is null");
throw new ImsException("Cannot find remote IMS service",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
@@ -579,8 +597,7 @@ public class RcsUceAdapter {
public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
final long callingIdentity = Binder.clearCallingIdentity();
try {
- executor.execute(() ->
- c.onCapabilitiesReceived(contactCapabilities));
+ executor.execute(() -> c.onCapabilitiesReceived(contactCapabilities));
} finally {
restoreCallingIdentity(callingIdentity);
}
@@ -606,12 +623,12 @@ public class RcsUceAdapter {
};
try {
- imsRcsController.requestNetworkAvailability(mSubId, mContext.getOpPackageName(),
+ imsRcsController.requestAvailability(mSubId, mContext.getOpPackageName(),
mContext.getAttributionTag(), contactNumber, internalCallback);
} catch (ServiceSpecificException e) {
throw new ImsException(e.toString(), e.errorCode);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling IImsRcsController#requestNetworkAvailability", e);
+ Log.e(TAG, "Error calling IImsRcsController#requestAvailability", e);
throw new ImsException("Remote IMS Service is not available",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
@@ -683,7 +700,7 @@ public class RcsUceAdapter {
if (imsRcsController == null) {
Log.e(TAG, "addOnPublishStateChangedListener : IImsRcsController is null");
throw new ImsException("Cannot find remote IMS service",
- ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
PublishStateCallbackAdapter stateCallback = addPublishStateCallback(executor, listener);
@@ -694,7 +711,7 @@ public class RcsUceAdapter {
} catch (RemoteException e) {
Log.e(TAG, "Error calling IImsRcsController#registerUcePublishStateCallback", e);
throw new ImsException("Remote IMS Service is not available",
- ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
index 36349895c35b..7a6c28bddd09 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -52,7 +52,7 @@ interface IImsRcsController {
// ImsUceAdapter specific
void requestCapabilities(int subId, String callingPackage, String callingFeatureId,
in List<Uri> contactNumbers, IRcsUceControllerCallback c);
- void requestNetworkAvailability(int subId, String callingPackage,
+ void requestAvailability(int subId, String callingPackage,
String callingFeatureId, in Uri contactNumber,
IRcsUceControllerCallback c);
int getUcePublishState(int subId);
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index c84e23c38e97..7eba709a11da 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -24,6 +24,7 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.net.Uri;
import android.telephony.ims.ImsException;
+import android.telephony.ims.RcsUceAdapter;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.RcsFeature;
import android.util.Log;
@@ -139,18 +140,19 @@ public class RcsCapabilityExchangeImplBase {
* Provide the framework with a subsequent network response update to
* {@link #publishCapabilities(String, PublishResponseCallback)}.
*
- * @param code The SIP response code sent from the network for the operation
+ * @param sipCode The SIP response code sent from the network for the operation
* token specified.
* @param reason The optional reason response from the network. If there is a reason header
* included in the response, that should take precedence over the reason provided in the
- * status line. If the network provided no reason with the code, the string should be empty.
+ * status line. If the network provided no reason with the sip code, the string should be
+ * empty.
* @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
* not currently connected to the framework. This can happen if the {@link RcsFeature}
* is not {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received
* the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases
* when the Telephony stack has crashed.
*/
- void onNetworkResponse(@IntRange(from = 100, to = 699) int code,
+ void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode,
@NonNull String reason) throws ImsException;
}
@@ -173,7 +175,7 @@ public class RcsCapabilityExchangeImplBase {
/**
* Send the response of a SIP OPTIONS capability exchange to the framework.
- * @param code The SIP response code that was sent by the network in response
+ * @param sipCode The SIP response code that was sent by the network in response
* to the request sent by {@link #sendOptionsCapabilityRequest}.
* @param reason The optional SIP response reason sent by the network.
* If none was sent, this should be an empty string.
@@ -186,17 +188,20 @@ public class RcsCapabilityExchangeImplBase {
* {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare
* cases when the Telephony stack has crashed.
*/
- void onNetworkResponse(int code, @NonNull String reason,
+ void onNetworkResponse(int sipCode, @NonNull String reason,
@Nullable List<String> theirCaps) throws ImsException;
}
/**
* Interface used by the framework to receive the response of the subscribe request.
- * @hide
*/
public interface SubscribeResponseCallback {
/**
* Notify the framework that the command associated with this callback has failed.
+ * <p>
+ * Must only be called when there was an error generating a SUBSCRIBE request due to an
+ * IMS stack error. This is a terminating event, so no other callback event will be
+ * expected after this callback.
*
* @param code The reason why the associated command has failed.
* @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
@@ -211,27 +216,38 @@ public class RcsCapabilityExchangeImplBase {
/**
* Notify the framework of the response to the SUBSCRIBE request from
* {@link #subscribeForCapabilities(List<Uri>, SubscribeResponseCallback)}.
+ * <p>
+ * If the carrier network responds to the SUBSCRIBE request with a 2XX response, then the
+ * framework will expect the IMS stack to call {@link #onNotifyCapabilitiesUpdate},
+ * {@link #onResourceTerminated}, and {@link #onTerminated} as required for the
+ * subsequent NOTIFY responses to the subscription.
*
- * @param code The SIP response code sent from the network for the operation
+ * @param sipCode The SIP response code sent from the network for the operation
* token specified.
* @param reason The optional reason response from the network. If the network
- * provided no reason with the code, the string should be empty.
+ * provided no reason with the sip code, the string should be empty.
* @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
* not currently connected to the framework. This can happen if the
* {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the
* {@link RcsFeature} has not received the {@link ImsFeature#onFeatureReady()} callback.
* This may also happen in rare cases when the Telephony stack has crashed.
*/
- void onNetworkResponse(@IntRange(from = 100, to = 699) int code,
+ void onNetworkResponse(@IntRange(from = 100, to = 699) int sipCode,
@NonNull String reason) throws ImsException;
/**
- * Provides the framework with latest XML PIDF documents included in the
- * network response for the requested contacts' capabilities requested by the
- * Framework using {@link #requestCapabilities(List, int)}. This should be
- * called every time a new NOTIFY event is received with new capability
- * information.
+ * Notify the framework of the latest XML PIDF documents included in the network response
+ * for the requested contacts' capabilities requested by the Framework using
+ * {@link RcsUceAdapter#requestCapabilities(Executor, List<Uri>, CapabilitiesCallback)}.
+ * <p>
+ * The expected format for the PIDF XML is defined in RFC3861. Each XML document must be a
+ * "application/pidf+xml" object and start with a root <presence> element. For NOTIFY
+ * responses that contain RLMI information and potentially multiple PIDF XMLs, each
+ * PIDF XML should be separated and added as a separate item in the List. This should be
+ * called every time a new NOTIFY event is received with new capability information.
*
+ * @param pidfXmls The list of the PIDF XML data for the contact URIs that it subscribed
+ * for.
* @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
* not currently connected to the framework.
* This can happen if the {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the
@@ -242,21 +258,42 @@ public class RcsCapabilityExchangeImplBase {
void onNotifyCapabilitiesUpdate(@NonNull List<String> pidfXmls) throws ImsException;
/**
- * A resource in the resource list for the presence subscribe event has been terminated.
+ * Notify the framework that a resource in the RLMI XML contained in the NOTIFY response
+ * for the ongoing SUBSCRIBE dialog has been terminated.
* <p>
- * This allows the framework to know that there will not be any capability information for
- * a specific contact URI that they subscribed for.
+ * This will be used to notify the framework that a contact URI that the IMS stack has
+ * subscribed to on the Resource List Server has been terminated as well as the reason why.
+ * Usually this means that there will not be any capability information for the contact URI
+ * that they subscribed for. See RFC 4662 for more information.
+ *
+ * @param uriTerminatedReason The contact URIs which have been terminated. Each pair in the
+ * list is the contact URI and its terminated reason.
+ * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
+ * not currently connected to the framework.
+ * This can happen if the {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the
+ * {@link RcsFeature} {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not
+ * received the {@link ImsFeature#onFeatureReady()} callback. This may also happen in
+ * rare cases when the Telephony stack has crashed.
*/
void onResourceTerminated(
@NonNull List<Pair<Uri, String>> uriTerminatedReason) throws ImsException;
/**
- * The subscription associated with a previous #requestCapabilities operation
- * has been terminated. This will mostly be due to the subscription expiring,
- * but may also happen due to an error.
- * <p>
- * This allows the framework to know that there will no longer be any
- * capability updates for the requested operationToken.
+ * The subscription associated with a previous
+ * {@link RcsUceAdapter#requestCapabilities(Executor, List<Uri>, CapabilitiesCallback)}
+ * operation has been terminated. This will mostly be due to the network sending a final
+ * NOTIFY response due to the subscription expiring, but this may also happen due to a
+ * network error.
+ *
+ * @param reason The reason for the request being unable to process.
+ * @param retryAfterMilliseconds The time in milliseconds the requesting application should
+ * wait before retrying, if non-zero.
+ * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is
+ * not currently connected to the framework.
+ * This can happen if the {@link RcsFeature} is not {@link ImsFeature#STATE_READY} and the
+ * {@link RcsFeature} {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not
+ * received the {@link ImsFeature#onFeatureReady()} callback. This may also happen in
+ * rare cases when the Telephony stack has crashed.
*/
void onTerminated(@NonNull String reason, long retryAfterMilliseconds) throws ImsException;
}
@@ -278,18 +315,23 @@ public class RcsCapabilityExchangeImplBase {
/**
* The user capabilities of one or multiple contacts have been requested by the framework.
* <p>
+ * The implementer must follow up this call with an
+ * {@link SubscribeResponseCallback#onCommandError} call to indicate this operation has failed.
* The response from the network to the SUBSCRIBE request must be sent back to the framework
- * using {@link #onSubscribeNetworkResponse(int, String, int)}. As NOTIFY requests come in from
- * the network, the requested contact’s capabilities should be sent back to the framework using
- * {@link #onSubscribeNotifyRequest} and {@link onSubscribeResourceTerminated}
+ * using {@link SubscribeResponseCallback#onNetworkResponse(int, String)}.
+ * As NOTIFY requests come in from the network, the requested contact’s capabilities should be
+ * sent back to the framework using
+ * {@link SubscribeResponseCallback#onNotifyCapabilitiesUpdate(List<String>}) and
+ * {@link SubscribeResponseCallback#onResourceTerminated(List<Pair<Uri, String>>)}
* should be called with the presence information for the contacts specified.
* <p>
- * Once the subscription is terminated, {@link #onSubscriptionTerminated} must be called for
- * the framework to finish listening for NOTIFY responses.
+ * Once the subscription is terminated,
+ * {@link SubscribeResponseCallback#onTerminated(String, long)} must be called for the
+ * framework to finish listening for NOTIFY responses.
+ *
* @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE
* capabilities for.
* @param cb The callback of the subscribe request.
- * @hide
*/
// executor used is defined in the constructor.
@SuppressLint("ExecutorRegistration")
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 2d3c8f29ec9c..ee6c36ca6b76 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2350,6 +2350,11 @@ interface ITelephony {
*/
String getMobileProvisioningUrl();
+ /*
+ * Remove the EAB contacts from the EAB database.
+ */
+ int removeContactFromEab(int subId, String contacts);
+
/**
* Set a SignalStrengthUpdateRequest to receive notification when Signal Strength breach the
* specified thresholds.
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
new file mode 100644
index 000000000000..d936183e5a0b
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 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.vcn;
+
+import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for VcnGatewayConnection.ConnectingState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectionTestBase {
+ private VcnIkeSession mIkeSession;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mGatewayConnection.transitionTo(mGatewayConnection.mConnectingState);
+ mTestLooper.dispatchAll();
+
+ mIkeSession = mGatewayConnection.getIkeSession();
+ }
+
+ @Test
+ public void testEnterStateCreatesNewIkeSession() throws Exception {
+ verify(mDeps).newIkeSession(any(), any(), any(), any(), any());
+ }
+
+ @Test
+ public void testNullNetworkTriggersDisconnect() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).kill();
+ }
+
+ @Test
+ public void testNewNetworkTriggersReconnect() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).close();
+ verify(mIkeSession, never()).kill();
+ }
+
+ @Test
+ public void testSameNetworkDoesNotTriggerReconnect() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testChildSessionClosedTriggersDisconnect() throws Exception {
+ getChildSessionCallback().onClosed();
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).close();
+ }
+
+ @Test
+ public void testIkeSessionClosedTriggersDisconnect() throws Exception {
+ getIkeSessionCallback().onClosed();
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).close();
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 346785907fcf..b4d39bf74a4b 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -32,6 +32,7 @@ import android.net.IpSecTunnelInterfaceResponse;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.IkeSessionCallback;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnGatewayConnectionConfigTest;
@@ -117,4 +118,11 @@ public class VcnGatewayConnectionTestBase {
verify(mDeps).newIkeSession(any(), any(), any(), captor.capture(), any());
return captor.getValue();
}
+
+ protected ChildSessionCallback getChildSessionCallback() {
+ ArgumentCaptor<ChildSessionCallback> captor =
+ ArgumentCaptor.forClass(ChildSessionCallback.class);
+ verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture());
+ return captor.getValue();
+ }
}
diff --git a/tools/powerstats/PowerStatsServiceProtoParser.java b/tools/powerstats/PowerStatsServiceProtoParser.java
index e4135b5584e4..21409542714d 100644
--- a/tools/powerstats/PowerStatsServiceProtoParser.java
+++ b/tools/powerstats/PowerStatsServiceProtoParser.java
@@ -30,7 +30,7 @@ public class PowerStatsServiceProtoParser {
for (int i = 0; i < proto.getChannelCount(); i++) {
ChannelProto energyMeterInfo = proto.getChannel(i);
csvHeader += "Index,Timestamp,Duration," + energyMeterInfo.getId()
- + "/" + energyMeterInfo.getName() + ",";
+ + "/" + energyMeterInfo.getName() + "/" + energyMeterInfo.getSubsystem() + ",";
}
System.out.println(csvHeader);
}