Merge "Remove StartingWindow or cancel the request to add StartingWindow after all activities have been drawn" into main
diff --git a/MULTIUSER_OWNERS b/MULTIUSER_OWNERS
index b8857ec..1738a35 100644
--- a/MULTIUSER_OWNERS
+++ b/MULTIUSER_OWNERS
@@ -3,7 +3,5 @@
bookatz@google.com
nykkumar@google.com
olilan@google.com
-omakoto@google.com
tetianameronyk@google.com
tyk@google.com
-yamasani@google.com
diff --git a/OWNERS b/OWNERS
index afa60be..eb2bfcf 100644
--- a/OWNERS
+++ b/OWNERS
@@ -7,8 +7,6 @@
hackbod@android.com #{LAST_RESORT_SUGGESTION}
hackbod@google.com #{LAST_RESORT_SUGGESTION}
jjaggi@google.com #{LAST_RESORT_SUGGESTION}
-jsharkey@android.com #{LAST_RESORT_SUGGESTION}
-jsharkey@google.com #{LAST_RESORT_SUGGESTION}
lorenzo@google.com #{LAST_RESORT_SUGGESTION}
michaelwr@google.com #{LAST_RESORT_SUGGESTION}
nandana@google.com #{LAST_RESORT_SUGGESTION}
@@ -33,19 +31,19 @@
per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS
per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS
-per-file INPUT_OWNERS = file:/INPUT_OWNERS
-per-file ZYGOTE_OWNERS = file:/ZYGOTE_OWNERS
-per-file SQLITE_OWNERS = file:/SQLITE_OWNERS
-
per-file *ravenwood* = file:ravenwood/OWNERS
per-file *Ravenwood* = file:ravenwood/OWNERS
+per-file INPUT_OWNERS = file:/INPUT_OWNERS
+per-file ZYGOTE_OWNERS = file:/ZYGOTE_OWNERS
+per-file SQLITE_OWNERS = file:/SQLITE_OWNERS
per-file PERFORMANCE_OWNERS = file:/PERFORMANCE_OWNERS
-
per-file PACKAGE_MANAGER_OWNERS = file:/PACKAGE_MANAGER_OWNERS
-
per-file WEAR_OWNERS = file:/WEAR_OWNERS
-
+per-file ACTIVITY_MANAGER_OWNERS = file:/ACTIVITY_MANAGER_OWNERS
+per-file BATTERY_STATS_OWNERS = file:/BATTERY_STATS_OWNERS
+per-file OOM_ADJUSTER_OWNERS = file:/OOM_ADJUSTER_OWNERS
+per-file MULTIUSER_OWNERS = file:/MULTIUSER_OWNERS
+per-file BROADCASTS_OWNERS = file:/BROADCASTS_OWNERS
per-file ADPF_OWNERS = file:/ADPF_OWNERS
-
per-file GAME_MANAGER_OWNERS = file:/GAME_MANAGER_OWNERS
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index c1894f0..a37779e 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -3568,7 +3568,7 @@
Slog.i(TAG, "becomeActiveLocked, reason=" + activeReason
+ ", changeLightIdle=" + changeLightIdle);
}
- if (mState != STATE_ACTIVE || mLightState != STATE_ACTIVE) {
+ if (mState != STATE_ACTIVE || mLightState != LIGHT_STATE_ACTIVE) {
moveToStateLocked(STATE_ACTIVE, activeReason);
mInactiveTimeout = newInactiveTimeout;
resetIdleManagementLocked();
diff --git a/core/api/current.txt b/core/api/current.txt
index e2feb20..2c4c146 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10740,6 +10740,7 @@
field public static final String IPSEC_SERVICE = "ipsec";
field public static final String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final String KEYGUARD_SERVICE = "keyguard";
+ field @FlaggedApi("android.security.keystore_grant_api") public static final String KEYSTORE_SERVICE = "keystore";
field public static final String LAUNCHER_APPS_SERVICE = "launcherapps";
field @UiContext public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
field public static final String LOCALE_SERVICE = "locale";
@@ -39946,6 +39947,14 @@
method @NonNull public android.security.keystore.KeyProtection.Builder setUserPresenceRequired(boolean);
}
+ @FlaggedApi("android.security.keystore_grant_api") public class KeyStoreManager {
+ method @NonNull public java.util.List<java.security.cert.X509Certificate> getGrantedCertificateChainFromId(long) throws android.security.keystore.KeyPermanentlyInvalidatedException, java.security.UnrecoverableKeyException;
+ method @NonNull public java.security.Key getGrantedKeyFromId(long) throws android.security.keystore.KeyPermanentlyInvalidatedException, java.security.UnrecoverableKeyException;
+ method @NonNull public java.security.KeyPair getGrantedKeyPairFromId(long) throws android.security.keystore.KeyPermanentlyInvalidatedException, java.security.UnrecoverableKeyException;
+ method public long grantKeyAccess(@NonNull String, int) throws android.security.KeyStoreException, java.security.UnrecoverableKeyException;
+ method public void revokeKeyAccess(@NonNull String, int) throws android.security.KeyStoreException, java.security.UnrecoverableKeyException;
+ }
+
public class SecureKeyImportUnavailableException extends java.security.ProviderException {
ctor public SecureKeyImportUnavailableException();
ctor public SecureKeyImportUnavailableException(String);
diff --git a/core/java/Android.bp b/core/java/Android.bp
index ce9dedc..7e8a309 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -19,6 +19,7 @@
srcs: [
"**/*.java",
"**/*.aidl",
+ ":systemfeatures-gen-srcs",
":framework-nfc-non-updatable-sources",
":ranging_stack_mock_initializer",
],
@@ -637,3 +638,29 @@
}
// protolog end
+
+// Whether to enable read-only system feature codegen.
+gen_readonly_feature_apis = select(release_flag("RELEASE_USE_SYSTEM_FEATURE_BUILD_FLAGS"), {
+ true: "true",
+ false: "false",
+ default: "false",
+})
+
+// Generates com.android.internal.pm.RoSystemFeatures, optionally compiling in
+// details about fixed system features defined by build flags. When disabled,
+// the APIs are simply passthrough stubs with no meaningful side effects.
+genrule {
+ name: "systemfeatures-gen-srcs",
+ cmd: "$(location systemfeatures-gen-tool) com.android.internal.pm.RoSystemFeatures " +
+ // --readonly=false (default) makes the codegen an effective no-op passthrough API.
+ " --readonly=" + gen_readonly_feature_apis +
+ // For now, only export "android.hardware.type.*" system features APIs.
+ // TODO(b/203143243): Use an intermediate soong var that aggregates all declared
+ // RELEASE_SYSTEM_FEATURE_* declarations into a single arg.
+ " --feature-apis=AUTOMOTIVE,WATCH,TELEVISION,EMBEDDED,PC" +
+ " > $(out)",
+ out: [
+ "RoSystemFeatures.java",
+ ],
+ tools: ["systemfeatures-gen-tool"],
+}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index eb742fa..5e69ec1 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -7236,6 +7236,8 @@
}
}
+ VMDebug.setUserId(UserHandle.myUserId());
+ VMDebug.addApplication(data.appInfo.packageName);
// send up app name; do this *before* waiting for debugger
Process.setArgV0(data.processName);
android.ddm.DdmHandleAppName.setAppName(data.processName,
@@ -7758,9 +7760,20 @@
file.getParentFile().mkdirs();
Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
}
+
+ if (ii.packageName != null) {
+ VMDebug.addApplication(ii.packageName);
+ }
}
private void handleFinishInstrumentationWithoutRestart() {
+ LoadedApk loadedApk = getApplication().mLoadedApk;
+ // Only remove instrumentation app if this was not a self-testing app.
+ if (mInstrumentationPackageName != null && loadedApk != null && !mInstrumentationPackageName
+ .equals(loadedApk.mPackageName)) {
+ VMDebug.removeApplication(mInstrumentationPackageName);
+ }
+
mInstrumentation.onDestroy();
mInstrumentationPackageName = null;
mInstrumentationAppDir = null;
@@ -8794,6 +8807,11 @@
return false;
}
+ void addApplication(@NonNull Application app) {
+ mAllApplications.add(app);
+ VMDebug.addApplication(app.mLoadedApk.mPackageName);
+ }
+
@Override
public boolean isInDensityCompatMode() {
return mDensityCompatMode;
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 1df8f63..1e45d6f 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1478,7 +1478,7 @@
+ " package " + mPackageName + ": " + e.toString(), e);
}
}
- mActivityThread.mAllApplications.add(app);
+ mActivityThread.addApplication(app);
mApplication = app;
if (!allowDuplicateInstances) {
synchronized (sApplications) {
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index d363e19..6e4c28f 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -3,50 +3,54 @@
per-file ContextImpl.java = *
# ActivityManager
-per-file ActivityManager* = file:/services/core/java/com/android/server/am/OWNERS
-per-file *ApplicationStartInfo* = file:/services/core/java/com/android/server/am/OWNERS
-per-file ApplicationErrorReport* = file:/services/core/java/com/android/server/am/OWNERS
-per-file ApplicationExitInfo* = file:/services/core/java/com/android/server/am/OWNERS
-per-file Application.java = file:/services/core/java/com/android/server/am/OWNERS
-per-file ApplicationLoaders.java = file:/services/core/java/com/android/server/am/OWNERS
-per-file ApplicationThreadConstants.java = file:/services/core/java/com/android/server/am/OWNERS
-per-file ContentProviderHolder* = file:/services/core/java/com/android/server/am/OWNERS
-per-file *ForegroundService* = file:/services/core/java/com/android/server/am/OWNERS
-per-file IActivityController.aidl = file:/services/core/java/com/android/server/am/OWNERS
-per-file IActivityManager.aidl = file:/services/core/java/com/android/server/am/OWNERS
-per-file IApplicationThread.aidl = file:/services/core/java/com/android/server/am/OWNERS
-per-file IAppTraceRetriever.aidl = file:/services/core/java/com/android/server/am/OWNERS
-per-file IForegroundServiceObserver.aidl = file:/services/core/java/com/android/server/am/OWNERS
-per-file IInstrumentationWatcher.aidl = file:/services/core/java/com/android/server/am/OWNERS
-per-file IntentService.aidl = file:/services/core/java/com/android/server/am/OWNERS
-per-file IServiceConnection.aidl = file:/services/core/java/com/android/server/am/OWNERS
-per-file IStopUserCallback.aidl = file:/services/core/java/com/android/server/am/OWNERS
-per-file IUidObserver.aidl = file:/services/core/java/com/android/server/am/OWNERS
-per-file LoadedApk.java = file:/services/core/java/com/android/server/am/OWNERS
-per-file LocalActivityManager.java = file:/services/core/java/com/android/server/am/OWNERS
-per-file PendingIntent* = file:/services/core/java/com/android/server/am/OWNERS
-per-file *Process* = file:/services/core/java/com/android/server/am/OWNERS
-per-file ProfilerInfo* = file:/services/core/java/com/android/server/am/OWNERS
-per-file Service* = file:/services/core/java/com/android/server/am/OWNERS
-per-file SystemServiceRegistry.java = file:/services/core/java/com/android/server/am/OWNERS
-per-file *UserSwitchObserver* = file:/services/core/java/com/android/server/am/OWNERS
+per-file ActivityManager* = file:/ACTIVITY_MANAGER_OWNERS
+per-file Application.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file ApplicationErrorReport* = file:/ACTIVITY_MANAGER_OWNERS
+per-file ApplicationLoaders.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file ApplicationThreadConstants.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file ContentProviderHolder* = file:/ACTIVITY_MANAGER_OWNERS
+per-file *ForegroundService* = file:/ACTIVITY_MANAGER_OWNERS
+per-file IActivityController.aidl = file:/ACTIVITY_MANAGER_OWNERS
+per-file IActivityManager.aidl = file:/ACTIVITY_MANAGER_OWNERS
+per-file IApplicationThread.aidl = file:/ACTIVITY_MANAGER_OWNERS
+per-file IAppTraceRetriever.aidl = file:/ACTIVITY_MANAGER_OWNERS
+per-file IForegroundServiceObserver.aidl = file:/ACTIVITY_MANAGER_OWNERS
+per-file IInstrumentationWatcher.aidl = file:/ACTIVITY_MANAGER_OWNERS
+per-file IntentService.aidl = file:/ACTIVITY_MANAGER_OWNERS
+per-file IServiceConnection.aidl = file:/ACTIVITY_MANAGER_OWNERS
+per-file IStopUserCallback.aidl = file:/ACTIVITY_MANAGER_OWNERS
+per-file IUidObserver.aidl = file:/ACTIVITY_MANAGER_OWNERS
+per-file LoadedApk.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file LocalActivityManager.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file PendingIntent* = file:/ACTIVITY_MANAGER_OWNERS
+per-file *Process* = file:/ACTIVITY_MANAGER_OWNERS
+per-file ProfilerInfo* = file:/ACTIVITY_MANAGER_OWNERS
+per-file Service* = file:/ACTIVITY_MANAGER_OWNERS
+per-file SystemServiceRegistry.java = file:/ACTIVITY_MANAGER_OWNERS
+per-file *UserSwitchObserver* = file:/ACTIVITY_MANAGER_OWNERS
+
+# UI Automation
per-file *UiAutomation* = file:/services/accessibility/OWNERS
per-file *UiAutomation* = file:/core/java/android/permission/OWNERS
+
+# Game Manager
per-file GameManager* = file:/GAME_MANAGER_OWNERS
per-file GameMode* = file:/GAME_MANAGER_OWNERS
per-file GameState* = file:/GAME_MANAGER_OWNERS
per-file IGameManager* = file:/GAME_MANAGER_OWNERS
per-file IGameMode* = file:/GAME_MANAGER_OWNERS
+
+# Background Starts
per-file BackgroundStartPrivileges.java = file:/BAL_OWNERS
per-file activity_manager.aconfig = file:/ACTIVITY_MANAGER_OWNERS
# ActivityThread
-per-file ActivityThread.java = file:/services/core/java/com/android/server/am/OWNERS
+per-file ActivityThread.java = file:/ACTIVITY_MANAGER_OWNERS
per-file ActivityThread.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file ActivityThread.java = file:RESOURCES_OWNERS
# Alarm
-per-file *Alarm* = file:/apex/jobscheduler/OWNERS
+per-file *Alarm* = file:/apex/jobscheduler/ALARM_OWNERS
# AppOps
per-file *AppOp* = file:/core/java/android/permission/OWNERS
@@ -97,6 +101,9 @@
# Performance
per-file PropertyInvalidatedCache.java = file:/PERFORMANCE_OWNERS
+per-file *ApplicationStartInfo* = file:/PERFORMANCE_OWNERS
+per-file ApplicationExitInfo* = file:/PERFORMANCE_OWNERS
+per-file performance.aconfig = file:/PERFORMANCE_OWNERS
# Pinner
per-file pinner-client.aconfig = file:/core/java/android/app/pinner/OWNERS
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 8f298db..093dad6 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -66,8 +66,6 @@
import android.companion.virtual.IVirtualDeviceManager;
import android.companion.virtual.VirtualDeviceManager;
import android.compat.Compatibility;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledSince;
import android.content.ClipboardManager;
import android.content.ContentCaptureOptions;
import android.content.Context;
@@ -162,8 +160,7 @@
import android.net.PacProxyManager;
import android.net.TetheringManager;
import android.net.VpnManager;
-import android.net.vcn.IVcnManagementService;
-import android.net.vcn.VcnManager;
+import android.net.vcn.VcnFrameworkInitializer;
import android.net.wifi.WifiFrameworkInitializer;
import android.net.wifi.nl80211.WifiNl80211Manager;
import android.net.wifi.sharedconnectivity.app.SharedConnectivityManager;
@@ -198,7 +195,6 @@
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.StatsFrameworkInitializer;
import android.os.SystemConfigManager;
-import android.os.SystemProperties;
import android.os.SystemUpdateManager;
import android.os.SystemVibrator;
import android.os.SystemVibratorManager;
@@ -227,6 +223,7 @@
import android.security.IFileIntegrityService;
import android.security.attestationverification.AttestationVerificationManager;
import android.security.attestationverification.IAttestationVerificationManagerService;
+import android.security.keystore.KeyStoreManager;
import android.service.oemlock.IOemLockService;
import android.service.oemlock.OemLockManager;
import android.service.persistentdata.IPersistentDataBlockService;
@@ -289,28 +286,6 @@
/** @hide */
public static boolean sEnableServiceNotFoundWtf = false;
- /**
- * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags
- * (e.g. {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before
- * returning managers that depend on them. If the feature is missing,
- * {@link Context#getSystemService} will return null.
- *
- * This change is specific to VcnManager.
- */
- @ChangeId
- @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
- static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016;
-
- /**
- * The corresponding vendor API for Android V
- *
- * <p>Starting with Android V, the vendor API format has switched to YYYYMM.
- *
- * @see <a href="https://preview.source.android.com/docs/core/architecture/api-flags">Vendor API
- * level</a>
- */
- private static final int VENDOR_API_FOR_ANDROID_V = 202404;
-
// Service registry information.
// This information is never changed once static initialization has completed.
private static final Map<Class<?>, String> SYSTEM_SERVICE_NAMES =
@@ -472,22 +447,6 @@
return new VpnManager(ctx, service);
}});
- registerService(Context.VCN_MANAGEMENT_SERVICE, VcnManager.class,
- new CachedServiceFetcher<VcnManager>() {
- @Override
- public VcnManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- final String telephonyFeatureToCheck = getVcnFeatureDependency();
-
- if (telephonyFeatureToCheck != null
- && !ctx.getPackageManager().hasSystemFeature(telephonyFeatureToCheck)) {
- return null;
- }
-
- IBinder b = ServiceManager.getService(Context.VCN_MANAGEMENT_SERVICE);
- IVcnManagementService service = IVcnManagementService.Stub.asInterface(b);
- return new VcnManager(ctx, service);
- }});
-
registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
new StaticServiceFetcher<CountryDetector>() {
@Override
@@ -1668,6 +1627,17 @@
}
});
+ registerService(Context.KEYSTORE_SERVICE, KeyStoreManager.class,
+ new StaticServiceFetcher<KeyStoreManager>() {
+ @Override
+ public KeyStoreManager createService()
+ throws ServiceNotFoundException {
+ if (!android.security.Flags.keystoreGrantApi()) {
+ throw new ServiceNotFoundException("KeyStoreManager is not supported");
+ }
+ return KeyStoreManager.getInstance();
+ }});
+
registerService(Context.CONTACT_KEYS_SERVICE, E2eeContactKeysManager.class,
new CachedServiceFetcher<E2eeContactKeysManager>() {
@Override
@@ -1721,6 +1691,8 @@
OnDevicePersonalizationFrameworkInitializer.registerServiceWrappers();
DeviceLockFrameworkInitializer.registerServiceWrappers();
VirtualizationFrameworkInitializer.registerServiceWrappers();
+ VcnFrameworkInitializer.registerServiceWrappers();
+
if (com.android.server.telecom.flags.Flags.telecomMainlineBlockedNumbersManager()) {
ProviderFrameworkInitializer.registerServiceWrappers();
}
@@ -1782,30 +1754,6 @@
return manager.hasSystemFeature(featureName);
}
- // Suppressing AndroidFrameworkCompatChange because we're querying vendor
- // partition SDK level, not application's target SDK version (which BTW we
- // also check through Compatibility framework a few lines below).
- @SuppressWarnings("AndroidFrameworkCompatChange")
- @Nullable
- private static String getVcnFeatureDependency() {
- // Check SDK version of the client app. Apps targeting pre-V SDK might
- // have not checked for existence of these features.
- if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN)) {
- return null;
- }
-
- // Check SDK version of the vendor partition. Pre-V devices might have
- // incorrectly under-declared telephony features.
- final int vendorApiLevel = SystemProperties.getInt(
- "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
- if (vendorApiLevel < VENDOR_API_FOR_ANDROID_V) {
- return PackageManager.FEATURE_TELEPHONY;
- } else {
- return PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION;
- }
-
- }
-
/**
* Gets a system service from a given context.
* @hide
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 4050b82..36bdf73 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4753,6 +4753,18 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a {@link
+ * android.security.keystore.KeyStoreManager} for accessing
+ * <a href="/privacy-and-security/keystore">Android Keystore</a>
+ * functions.
+ *
+ * @see #getSystemService(String)
+ * @see android.security.keystore.KeyStoreManager
+ */
+ @FlaggedApi(android.security.Flags.FLAG_KEYSTORE_GRANT_API)
+ public static final String KEYSTORE_SERVICE = "keystore";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a {@link
* android.os.storage.StorageManager} for accessing system storage
* functions.
*
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
index a37408b..743623f 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -1,11 +1,11 @@
# Remain no owner because multiple modules may touch this file.
per-file Context.java = *
per-file ContextWrapper.java = *
-per-file *Content* = file:/services/core/java/com/android/server/am/OWNERS
-per-file *Sync* = file:/services/core/java/com/android/server/am/OWNERS
+per-file *Content* = varunshah@google.com, yamasani@google.com
+per-file *Sync* = file:/apex/jobscheduler/JOB_OWNERS
per-file IntentFilter.java = file:/PACKAGE_MANAGER_OWNERS
per-file UriRelativeFilter* = file:/PACKAGE_MANAGER_OWNERS
-per-file IntentFilter.java = file:/services/core/java/com/android/server/am/OWNERS
+per-file IntentFilter.java = file:/INTENT_OWNERS
per-file Intent.java = file:/INTENT_OWNERS
per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS
per-file ContentCaptureOptions* = file:/core/java/android/service/contentcapture/OWNERS
diff --git a/core/java/android/net/vcn/VcnFrameworkInitializer.java b/core/java/android/net/vcn/VcnFrameworkInitializer.java
new file mode 100644
index 0000000..8cb213b
--- /dev/null
+++ b/core/java/android/net/vcn/VcnFrameworkInitializer.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+import android.annotation.Nullable;
+import android.app.SystemServiceRegistry;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.SystemProperties;
+
+/**
+ * Class for performing registration for VCN service.
+ *
+ * @hide
+ */
+// TODO: Expose it as @SystemApi(client = MODULE_LIBRARIES)
+public final class VcnFrameworkInitializer {
+ /**
+ * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags (e.g. {@link
+ * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before returning managers
+ * that depend on them. If the feature is missing, {@link Context#getSystemService} will return
+ * null.
+ *
+ * <p>This change is specific to VcnManager.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ private static final long ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN = 330902016;
+
+ /**
+ * The corresponding vendor API for Android V
+ *
+ * <p>Starting with Android V, the vendor API format has switched to YYYYMM.
+ *
+ * @see <a href="https://preview.source.android.com/docs/core/architecture/api-flags">Vendor API
+ * level</a>
+ */
+ private static final int VENDOR_API_FOR_ANDROID_V = 202404;
+
+ private VcnFrameworkInitializer() {}
+
+ // Suppressing AndroidFrameworkCompatChange because we're querying vendor
+ // partition SDK level, not application's target SDK version (which BTW we
+ // also check through Compatibility framework a few lines below).
+ @Nullable
+ private static String getVcnFeatureDependency() {
+ // Check SDK version of the client app. Apps targeting pre-V SDK might
+ // have not checked for existence of these features.
+ if (!Compatibility.isChangeEnabled(ENABLE_CHECKING_TELEPHONY_FEATURES_FOR_VCN)) {
+ return null;
+ }
+
+ // Check SDK version of the vendor partition. Pre-V devices might have
+ // incorrectly under-declared telephony features.
+ final int vendorApiLevel =
+ SystemProperties.getInt(
+ "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
+ if (vendorApiLevel < VENDOR_API_FOR_ANDROID_V) {
+ return PackageManager.FEATURE_TELEPHONY;
+ } else {
+ return PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION;
+ }
+ }
+
+ /**
+ * Register VCN service to {@link Context}, so that {@link Context#getSystemService} can return
+ * a VcnManager.
+ *
+ * @throws IllegalStateException if this is called anywhere besides {@link
+ * SystemServiceRegistry}.
+ */
+ public static void registerServiceWrappers() {
+ SystemServiceRegistry.registerContextAwareService(
+ VcnManager.VCN_MANAGEMENT_SERVICE_STRING,
+ VcnManager.class,
+ (context, serviceBinder) -> {
+ final String telephonyFeatureToCheck = getVcnFeatureDependency();
+ if (telephonyFeatureToCheck != null
+ && !context.getPackageManager()
+ .hasSystemFeature(telephonyFeatureToCheck)) {
+ return null;
+ }
+ IVcnManagementService service =
+ IVcnManagementService.Stub.asInterface(serviceBinder);
+ return new VcnManager(context, service);
+ });
+ }
+}
diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig
index efddd1f..5b30624 100644
--- a/core/java/android/net/vcn/flags.aconfig
+++ b/core/java/android/net/vcn/flags.aconfig
@@ -14,11 +14,4 @@
namespace: "vcn"
description: "Feature flag for adjustable safe mode timeout"
bug: "317406085"
-}
-
-flag{
- name: "network_metric_monitor"
- namespace: "vcn"
- description: "Feature flag for enabling network metric monitor"
- bug: "282996138"
}
\ No newline at end of file
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index a55398a..ef1e6c94 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -114,6 +114,7 @@
"opengl-tracing",
"view-hierarchy",
"support_boot_stages",
+ "app_info",
};
/**
@@ -1016,14 +1017,14 @@
// send VM_START.
System.out.println("Waiting for debugger first packet");
- mWaiting = true;
+ setWaitingForDebugger(true);
while (!isDebuggerConnected()) {
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
}
}
- mWaiting = false;
+ setWaitingForDebugger(false);
System.out.println("Debug.suspendAllAndSentVmStart");
VMDebug.suspendAllAndSendVmStart();
@@ -1049,12 +1050,12 @@
Chunk waitChunk = new Chunk(ChunkHandler.type("WAIT"), data, 0, 1);
DdmServer.sendChunk(waitChunk);
- mWaiting = true;
+ setWaitingForDebugger(true);
while (!isDebuggerConnected()) {
try { Thread.sleep(SPIN_DELAY); }
catch (InterruptedException ie) {}
}
- mWaiting = false;
+ setWaitingForDebugger(false);
System.out.println("Debugger has connected");
@@ -1112,6 +1113,16 @@
}
/**
+ * Set whether the app is waiting for a debugger to connect
+ *
+ * @hide
+ */
+ private static void setWaitingForDebugger(boolean waiting) {
+ mWaiting = waiting;
+ VMDebug.setWaitingForDebugger(waiting);
+ }
+
+ /**
* Returns an array of strings that identify Framework features. This is
* used by DDMS to determine what sorts of operations the Framework can
* perform.
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index a1b75034..590ddb4 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -122,3 +122,6 @@
per-file StatsBootstrapAtomValue.aidl = file:/services/core/java/com/android/server/stats/OWNERS
per-file StatsBootstrapAtomService.java = file:/services/core/java/com/android/server/stats/OWNERS
per-file StatsServiceManager.java = file:/services/core/java/com/android/server/stats/OWNERS
+
+# Dropbox
+per-file DropBoxManager* = mwachens@google.com
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index df6ece4..cd8788d 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -41,6 +41,7 @@
import com.android.internal.util.Preconditions;
import com.android.sdksandbox.flags.Flags;
+import dalvik.system.VMDebug;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
@@ -1411,6 +1412,7 @@
public static void setArgV0(@NonNull String text) {
sArgV0 = text;
setArgV0Native(text);
+ VMDebug.setCurrentProcessName(text);
}
private static native void setArgV0Native(String text);
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index b1ef05a..6c99bd1 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -73,6 +73,9 @@
private static final int ZYGOTE_CONNECT_TIMEOUT_MS = 60000;
+ // How long we wait for an AppZygote to complete pre-loading; this is a pretty conservative
+ // value that we can probably decrease over time, but we want to be careful here.
+ public static volatile int sAppZygotePreloadTimeoutMs = 15000;
/**
* Use a relatively short delay, because for app zygote, this is in the critical path of
* service launch.
@@ -1100,6 +1103,17 @@
}
/**
+ * Updates the timeout used when preloading code in the app-zygote
+ *
+ * @param timeoutMs timeout in milliseconds
+ */
+ public static void setAppZygotePreloadTimeout(int timeoutMs) {
+ Slog.i(LOG_TAG, "Changing app-zygote preload timeout to " + timeoutMs + " ms.");
+
+ sAppZygotePreloadTimeoutMs = timeoutMs;
+ }
+
+ /**
* Instructs the zygote to pre-load the application code for the given Application.
* Only the app zygote supports this function.
* TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
@@ -1107,25 +1121,35 @@
public boolean preloadApp(ApplicationInfo appInfo, String abi)
throws ZygoteStartFailedEx, IOException {
synchronized (mLock) {
+ int ret;
ZygoteState state = openZygoteSocketIfNeeded(abi);
- state.mZygoteOutputWriter.write("2");
- state.mZygoteOutputWriter.newLine();
+ int previousSocketTimeout = state.mZygoteSessionSocket.getSoTimeout();
- state.mZygoteOutputWriter.write("--preload-app");
- state.mZygoteOutputWriter.newLine();
+ try {
+ state.mZygoteSessionSocket.setSoTimeout(sAppZygotePreloadTimeoutMs);
- // Zygote args needs to be strings, so in order to pass ApplicationInfo,
- // write it to a Parcel, and base64 the raw Parcel bytes to the other side.
- Parcel parcel = Parcel.obtain();
- appInfo.writeToParcel(parcel, 0 /* flags */);
- String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall());
- parcel.recycle();
- state.mZygoteOutputWriter.write(encodedParcelData);
- state.mZygoteOutputWriter.newLine();
+ state.mZygoteOutputWriter.write("2");
+ state.mZygoteOutputWriter.newLine();
- state.mZygoteOutputWriter.flush();
+ state.mZygoteOutputWriter.write("--preload-app");
+ state.mZygoteOutputWriter.newLine();
- return (state.mZygoteInputStream.readInt() == 0);
+ // Zygote args needs to be strings, so in order to pass ApplicationInfo,
+ // write it to a Parcel, and base64 the raw Parcel bytes to the other side.
+ Parcel parcel = Parcel.obtain();
+ appInfo.writeToParcel(parcel, 0 /* flags */);
+ String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall());
+ parcel.recycle();
+ state.mZygoteOutputWriter.write(encodedParcelData);
+ state.mZygoteOutputWriter.newLine();
+
+ state.mZygoteOutputWriter.flush();
+
+ ret = state.mZygoteInputStream.readInt();
+ } finally {
+ state.mZygoteSessionSocket.setSoTimeout(previousSocketTimeout);
+ }
+ return ret == 0;
}
}
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index aedf8e0..1d35344 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -113,3 +113,10 @@
description: "AFL feature"
bug: "365994454"
}
+
+flag {
+ name: "keystore_grant_api"
+ namespace: "hardware_backed_security"
+ description: "Feature flag for exposing KeyStore grant APIs"
+ bug: "351158708"
+}
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index b8b84d9..c6ee497 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -33,6 +33,7 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.WeaklyReferencedCallback;
import com.android.internal.telephony.IPhoneStateListener;
import com.android.internal.telephony.flags.Flags;
@@ -69,6 +70,7 @@
* its manifest file. Where permissions apply, they are noted in the
* appropriate sub-interfaces.
*/
+@WeaklyReferencedCallback
public class TelephonyCallback {
private static final String LOG_TAG = "TelephonyCallback";
/**
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index 9f54d9f..3adbd68 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -24,7 +24,7 @@
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.Network;
-import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
import android.net.SntpClient;
import android.os.Build;
import android.os.SystemClock;
@@ -687,16 +687,8 @@
if (connectivityManager == null) {
return false;
}
- final NetworkCapabilities networkCapabilities =
- connectivityManager.getNetworkCapabilities(network);
- if (networkCapabilities == null) {
- if (LOGD) Log.d(TAG, "getNetwork: failed to get network capabilities");
- return false;
- }
- final boolean isConnectedToInternet = networkCapabilities.hasCapability(
- NetworkCapabilities.NET_CAPABILITY_INTERNET)
- && networkCapabilities.hasCapability(
- NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+ final NetworkInfo ni = connectivityManager.getNetworkInfo(network);
+
// This connectivity check is to avoid performing a DNS lookup for the time server on a
// unconnected network. There are races to obtain time in Android when connectivity
// changes, which means that forceRefresh() can be called by various components before
@@ -706,8 +698,8 @@
// A side effect of check is that tests that run a fake NTP server on the device itself
// will only be able to use it if the active network is connected, even though loopback
// addresses are actually reachable.
- if (!isConnectedToInternet) {
- if (LOGD) Log.d(TAG, "getNetwork: no internet connectivity");
+ if (ni == null || !ni.isConnected()) {
+ if (LOGD) Log.d(TAG, "getNetwork: no connectivity");
return false;
}
return true;
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 18080e4..fc7a65d 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -24,6 +24,7 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.WeaklyReferencedCallback;
import dalvik.annotation.optimization.FastNative;
@@ -40,6 +41,7 @@
*
* @hide
*/
+@WeaklyReferencedCallback
public abstract class DisplayEventReceiver {
/**
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index 31a8dfa..3b69f1d 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -87,6 +87,7 @@
per-file OnReceiveContentListener.java = file:/core/java/android/widget/OWNERS
per-file ContentInfo.java = file:/core/java/android/service/autofill/OWNERS
per-file ContentInfo.java = file:/core/java/android/widget/OWNERS
+per-file view_flags.aconfig = file:/services/core/java/com/android/server/wm/OWNERS
# WindowManager
per-file ContentRecordingSession.aidl = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/proto/android/app/OWNERS b/core/proto/android/app/OWNERS
index a137ea9..519bf9a 100644
--- a/core/proto/android/app/OWNERS
+++ b/core/proto/android/app/OWNERS
@@ -1,3 +1,3 @@
-per-file appstartinfo.proto = file:/services/core/java/com/android/server/am/OWNERS
+per-file appstartinfo.proto = file:/PERFORMANCE_OWNERS
per-file location_time_zone_manager.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
per-file time_zone_detector.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/core/res/OWNERS b/core/res/OWNERS
index d109cee..faed4d8 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -53,7 +53,7 @@
per-file res/values/dimens_car.xml = file:/platform/packages/services/Car:/OWNERS
# Device Idle
-per-file res/values/config_device_idle.xml = file:/apex/jobscheduler/OWNERS
+per-file res/values/config_device_idle.xml = file:/apex/jobscheduler/DEVICE_IDLE_OWNERS
# Display Manager
per-file res/values/config_display.xml = file:/services/core/java/com/android/server/display/OWNERS
diff --git a/core/tests/coretests/src/android/app/OWNERS b/core/tests/coretests/src/android/app/OWNERS
index 5636f9b..6d14ccb 100644
--- a/core/tests/coretests/src/android/app/OWNERS
+++ b/core/tests/coretests/src/android/app/OWNERS
@@ -14,3 +14,5 @@
# Files related to background activity launches
per-file Background*Start* = file:/BAL_OWNERS
+# Files related to caching
+per-file PropertyInvalidatedCache* = file:/PERFORMANCE_OWNERS
diff --git a/core/tests/coretests/src/android/os/OWNERS b/core/tests/coretests/src/android/os/OWNERS
index 1c00734..6149382 100644
--- a/core/tests/coretests/src/android/os/OWNERS
+++ b/core/tests/coretests/src/android/os/OWNERS
@@ -9,3 +9,6 @@
# PerformanceHintManager
per-file PerformanceHintManagerTest.java = file:/ADPF_OWNERS
+
+# Caching
+per-file IpcDataCache* = file:/PERFORMANCE_OWNERS
diff --git a/errorprone/Android.bp b/errorprone/Android.bp
index c1d2235..b559a15 100644
--- a/errorprone/Android.bp
+++ b/errorprone/Android.bp
@@ -22,6 +22,7 @@
static_libs: [
"annotations",
+ "jsr305",
"framework-annotations-lib",
"//external/error_prone:error_prone_core",
],
diff --git a/errorprone/OWNERS b/errorprone/OWNERS
index bddbdb3..aa8c126 100644
--- a/errorprone/OWNERS
+++ b/errorprone/OWNERS
@@ -1,2 +1 @@
-jsharkey@android.com
-jsharkey@google.com
+colefaust@google.com
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/HideInCommentsChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/HideInCommentsChecker.java
index 8dc9579..6d5e4484 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/HideInCommentsChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/HideInCommentsChecker.java
@@ -29,6 +29,7 @@
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.util.ASTHelpers;
+import com.google.errorprone.util.ErrorProneComment;
import com.google.errorprone.util.ErrorProneToken;
import com.google.errorprone.util.ErrorProneTokens;
import com.sun.source.tree.ClassTree;
@@ -37,7 +38,6 @@
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
-import com.sun.tools.javac.parser.Tokens;
import java.util.HashMap;
import java.util.Map;
@@ -66,7 +66,7 @@
final Map<Integer, Tree> javadocableTrees = findJavadocableTrees(tree, state);
final String sourceCode = state.getSourceCode().toString();
for (ErrorProneToken token : ErrorProneTokens.getTokens(sourceCode, state.context)) {
- for (Tokens.Comment comment : token.comments()) {
+ for (ErrorProneComment comment : token.comments()) {
if (!javadocableTrees.containsKey(token.pos())) {
continue;
}
@@ -81,7 +81,7 @@
return NO_MATCH;
}
- private static Optional<SuggestedFix> generateFix(Tokens.Comment comment) {
+ private static Optional<SuggestedFix> generateFix(ErrorProneComment comment) {
final String text = comment.getText();
if (text.startsWith("/**")) {
return Optional.empty();
diff --git a/keystore/java/android/security/OWNERS b/keystore/java/android/security/OWNERS
index ed30587..32759b2 100644
--- a/keystore/java/android/security/OWNERS
+++ b/keystore/java/android/security/OWNERS
@@ -1 +1,2 @@
per-file *.java,*.aidl = eranm@google.com,pgrafov@google.com,rubinxu@google.com
+per-file KeyStoreManager.java = mpgroover@google.com
diff --git a/keystore/java/android/security/keystore/KeyStoreManager.java b/keystore/java/android/security/keystore/KeyStoreManager.java
new file mode 100644
index 0000000..197aaba
--- /dev/null
+++ b/keystore/java/android/security/keystore/KeyStoreManager.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2024 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.security.keystore;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.security.KeyStore2;
+import android.security.KeyStoreException;
+import android.security.keystore2.AndroidKeyStoreProvider;
+import android.security.keystore2.AndroidKeyStorePublicKey;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyPermission;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.ByteArrayInputStream;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This class provides methods for interacting with keys stored within the
+ * <a href="/privacy-and-security/keystore">Android Keystore</a>.
+ */
+@FlaggedApi(android.security.Flags.FLAG_KEYSTORE_GRANT_API)
+@SystemService(Context.KEYSTORE_SERVICE)
+public class KeyStoreManager {
+ private static final String TAG = "KeyStoreManager";
+
+ private static final Object sInstanceLock = new Object();
+ @GuardedBy("sInstanceLock")
+ private static KeyStoreManager sInstance;
+
+ private final KeyStore2 mKeyStore2;
+
+ /**
+ * Private constructor to ensure only a single instance is created.
+ */
+ private KeyStoreManager() {
+ mKeyStore2 = KeyStore2.getInstance();
+ }
+
+ /**
+ * Returns the single instance of the {@code KeyStoreManager}.
+ *
+ * @hide
+ */
+ public static KeyStoreManager getInstance() {
+ synchronized (sInstanceLock) {
+ if (sInstance == null) {
+ sInstance = new KeyStoreManager();
+ }
+ return sInstance;
+ }
+ }
+
+ /**
+ * Grants access to the key owned by the calling app stored under the specified {@code alias}
+ * to another app on the device with the provided {@code uid}.
+ *
+ * <p>This method supports granting access to instances of both {@link javax.crypto.SecretKey}
+ * and {@link java.security.PrivateKey}. The resulting ID will persist across reboots and can be
+ * used by the grantee app for the life of the key or until access is revoked with {@link
+ * #revokeKeyAccess(String, int)}.
+ *
+ * <p>If the provided {@code alias} does not correspond to a key in the Android KeyStore, then
+ * an {@link UnrecoverableKeyException} is thrown.
+ *
+ * @param alias the alias of the key to be granted to another app
+ * @param uid the uid of the app to which the key should be granted
+ * @return the ID of the granted key; this can be shared with the specified app, and that
+ * app can use {@link #getGrantedKeyFromId(long)} to access the key
+ * @throws UnrecoverableKeyException if the specified key cannot be recovered
+ * @throws KeyStoreException if an error is encountered when attempting to grant access to
+ * the key
+ * @see #getGrantedKeyFromId(long)
+ */
+ public long grantKeyAccess(@NonNull String alias, int uid)
+ throws KeyStoreException, UnrecoverableKeyException {
+ KeyDescriptor keyDescriptor = createKeyDescriptorFromAlias(alias);
+ final int grantAccessVector = KeyPermission.USE | KeyPermission.GET_INFO;
+ // When a key is in the GRANT domain, the nspace field of the KeyDescriptor contains its ID.
+ KeyDescriptor result = null;
+ try {
+ result = mKeyStore2.grant(keyDescriptor, uid, grantAccessVector);
+ } catch (KeyStoreException e) {
+ // If the provided alias does not correspond to a valid key in the KeyStore, then throw
+ // an UnrecoverableKeyException to remain consistent with other APIs in this class.
+ if (e.getNumericErrorCode() == KeyStoreException.ERROR_KEY_DOES_NOT_EXIST) {
+ throw new UnrecoverableKeyException("No key found by the given alias");
+ }
+ throw e;
+ }
+ if (result == null) {
+ Log.e(TAG, "Received a null KeyDescriptor from grant");
+ throw new KeyStoreException(KeyStoreException.ERROR_INTERNAL_SYSTEM_ERROR,
+ "No ID was returned for the grant request for alias " + alias + " to uid "
+ + uid);
+ } else if (result.domain != Domain.GRANT) {
+ Log.e(TAG, "Received a result outside the grant domain: " + result.domain);
+ throw new KeyStoreException(KeyStoreException.ERROR_INTERNAL_SYSTEM_ERROR,
+ "Unable to obtain a grant ID for alias " + alias + " to uid " + uid);
+ }
+ return result.nspace;
+ }
+
+ /**
+ * Revokes access to the key in the app's namespace stored under the specified {@code
+ * alias} that was previously granted to another app on the device with the provided
+ * {@code uid}.
+ *
+ * <p>If the provided {@code alias} does not correspond to a key in the Android KeyStore, then
+ * an {@link UnrecoverableKeyException} is thrown.
+ *
+ * @param alias the alias of the key to be revoked from another app
+ * @param uid the uid of the app from which the key access should be revoked
+ * @throws UnrecoverableKeyException if the specified key cannot be recovered
+ * @throws KeyStoreException if an error is encountered when attempting to revoke access
+ * to the key
+ */
+ public void revokeKeyAccess(@NonNull String alias, int uid)
+ throws KeyStoreException, UnrecoverableKeyException {
+ KeyDescriptor keyDescriptor = createKeyDescriptorFromAlias(alias);
+ try {
+ mKeyStore2.ungrant(keyDescriptor, uid);
+ } catch (KeyStoreException e) {
+ // If the provided alias does not correspond to a valid key in the KeyStore, then throw
+ // an UnrecoverableKeyException to remain consistent with other APIs in this class.
+ if (e.getNumericErrorCode() == KeyStoreException.ERROR_KEY_DOES_NOT_EXIST) {
+ throw new UnrecoverableKeyException("No key found by the given alias");
+ }
+ throw e;
+ }
+ }
+
+ /**
+ * Returns the key with the specified {@code id} that was previously shared with the
+ * app.
+ *
+ * <p>This method can return instances of both {@link javax.crypto.SecretKey} and {@link
+ * java.security.PrivateKey}. If a key with the provide {@code id} has not been granted to the
+ * caller, then an {@link UnrecoverableKeyException} is thrown.
+ *
+ * @param id the ID of the key that was shared with the app
+ * @return the {@link Key} that was shared with the app
+ * @throws UnrecoverableKeyException if the specified key cannot be recovered
+ * @throws KeyPermanentlyInvalidatedException if the specified key was authorized to only
+ * be used if the user has been authenticated and a
+ * change has been made to the users
+ * lockscreen or biometric enrollment that
+ * permanently invalidates the key
+ * @see #grantKeyAccess(String, int)
+ */
+ public @NonNull Key getGrantedKeyFromId(long id)
+ throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
+ Key result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(mKeyStore2, null,
+ id, Domain.GRANT);
+ if (result == null) {
+ throw new UnrecoverableKeyException("No key found by the given alias");
+ }
+ return result;
+ }
+
+ /**
+ * Returns a {@link KeyPair} containing the public and private key associated with
+ * the key that was previously shared with the app under the provided {@code id}.
+ *
+ * <p>If a {@link java.security.PrivateKey} has not been granted to the caller with the
+ * specified {@code id}, then an {@link UnrecoverableKeyException} is thrown.
+ *
+ * @param id the ID of the private key that was shared with the app
+ * @return a KeyPair containing the public and private key shared with the app
+ * @throws UnrecoverableKeyException if the specified key cannot be recovered
+ * @throws KeyPermanentlyInvalidatedException if the specified key was authorized to only
+ * be used if the user has been authenticated and a
+ * change has been made to the users
+ * lockscreen or biometric enrollment that
+ * permanently invalidates the key
+ */
+ public @NonNull KeyPair getGrantedKeyPairFromId(long id)
+ throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
+ KeyDescriptor keyDescriptor = createKeyDescriptorFromId(id, Domain.GRANT);
+ return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(mKeyStore2,
+ keyDescriptor);
+ }
+
+ /**
+ * Returns a {@link List} of {@link X509Certificate} instances representing the certificate
+ * chain for the key that was previously shared with the app under the provided {@code id}.
+ *
+ * <p>If a {@link java.security.PrivateKey} has not been granted to the caller with the
+ * specified {@code id}, then an {@link UnrecoverableKeyException} is thrown.
+ *
+ * @param id the ID of the asymmetric key that was shared with the app
+ * @return a List of X509Certificates with the certificate at index 0 corresponding to
+ * the private key shared with the app
+ * @throws UnrecoverableKeyException if the specified key cannot be recovered
+ * @throws KeyPermanentlyInvalidatedException if the specified key was authorized to only
+ * be used if the user has been authenticated and a
+ * change has been made to the users
+ * lockscreen or biometric enrollment that
+ * permanently invalidates the key
+ * @see #grantKeyAccess(String, int)
+ */
+ // Java APIs should prefer mutable collection return types with the exception being
+ // Collection.empty return types.
+ @SuppressWarnings("MixedMutabilityReturnType")
+ public @NonNull List<X509Certificate> getGrantedCertificateChainFromId(long id)
+ throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
+ KeyDescriptor keyDescriptor = createKeyDescriptorFromId(id, Domain.GRANT);
+ KeyPair keyPair = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(mKeyStore2,
+ keyDescriptor);
+ PublicKey keyStoreKey = keyPair.getPublic();
+ if (keyStoreKey instanceof AndroidKeyStorePublicKey) {
+ AndroidKeyStorePublicKey androidKeyStorePublicKey =
+ (AndroidKeyStorePublicKey) keyStoreKey;
+ byte[] certBytes = androidKeyStorePublicKey.getCertificate();
+ X509Certificate cert = getCertificate(certBytes);
+ // If the leaf certificate is null, then a chain should not exist either
+ if (cert == null) {
+ return Collections.emptyList();
+ }
+ List<X509Certificate> result = new ArrayList<>();
+ result.add(cert);
+ byte[] certificateChain = androidKeyStorePublicKey.getCertificateChain();
+ Collection<X509Certificate> certificates = getCertificates(certificateChain);
+ result.addAll(certificates);
+ return result;
+ } else {
+ Log.e(TAG, "keyStoreKey is not of the expected type: " + keyStoreKey);
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * Returns an {@link X509Certificate} instance from the provided {@code certificate} byte
+ * encoding of the certificate, or null if the provided encoding is null.
+ */
+ private static X509Certificate getCertificate(byte[] certificate) {
+ X509Certificate result = null;
+ if (certificate != null) {
+ try {
+ CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
+ result = (X509Certificate) certificateFactory.generateCertificate(
+ new ByteArrayInputStream(certificate));
+ } catch (Exception e) {
+ Log.e(TAG, "Caught an exception parsing the certificate: ", e);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns a {@link Collection} of {@link X509Certificate} instances from the provided
+ * {@code certificateChain} byte encoding of the certificates, or null if the provided
+ * encoding is null.
+ */
+ private static Collection<X509Certificate> getCertificates(byte[] certificateChain) {
+ if (certificateChain != null) {
+ try {
+ CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
+ Collection<X509Certificate> certificates =
+ (Collection<X509Certificate>) certificateFactory.generateCertificates(
+ new ByteArrayInputStream(certificateChain));
+ if (certificates == null) {
+ Log.e(TAG, "Received null certificates from a non-null certificateChain");
+ return Collections.emptyList();
+ }
+ return certificates;
+ } catch (Exception e) {
+ Log.e(TAG, "Caught an exception parsing the certs: ", e);
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * Returns a new {@link KeyDescriptor} instance in the app domain / namespace with the {@code
+ * alias} set to the provided value.
+ */
+ private static KeyDescriptor createKeyDescriptorFromAlias(String alias) {
+ KeyDescriptor keyDescriptor = new KeyDescriptor();
+ keyDescriptor.domain = Domain.APP;
+ keyDescriptor.nspace = KeyProperties.NAMESPACE_APPLICATION;
+ keyDescriptor.alias = alias;
+ keyDescriptor.blob = null;
+ return keyDescriptor;
+ }
+
+ /**
+ * Returns a new {@link KeyDescriptor} instance in the provided {@code domain} with the nspace
+ * field set to the provided {@code id}.
+ */
+ private static KeyDescriptor createKeyDescriptorFromId(long id, int domain) {
+ KeyDescriptor keyDescriptor = new KeyDescriptor();
+ keyDescriptor.domain = domain;
+ keyDescriptor.nspace = id;
+ keyDescriptor.alias = null;
+ keyDescriptor.blob = null;
+ return keyDescriptor;
+ }
+}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 99100de..dcc8844 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -17,6 +17,7 @@
package android.security.keystore2;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.security.KeyStore2;
import android.security.KeyStoreSecurityLevel;
import android.security.keymaster.KeymasterDefs;
@@ -335,11 +336,11 @@
}
/**
- * Loads an an AndroidKeyStoreKey from the AndroidKeyStore backend.
+ * Loads an AndroidKeyStoreKey from the AndroidKeyStore backend.
*
* @param keyStore The keystore2 backend.
* @param alias The alias of the key in the Keystore database.
- * @param namespace The a Keystore namespace. This is used by system api only to request
+ * @param namespace The Keystore namespace. This is used by system api only to request
* Android system specific keystore namespace, which can be configured
* in the device's SEPolicy. Third party apps and most system components
* set this parameter to -1 to indicate their application specific namespace.
@@ -351,14 +352,40 @@
public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore(
@NonNull KeyStore2 keyStore, @NonNull String alias, int namespace)
throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- KeyDescriptor descriptor = new KeyDescriptor();
+ int descriptorNamespace;
+ int descriptorDomain;
if (namespace == KeyProperties.NAMESPACE_APPLICATION) {
- descriptor.nspace = KeyProperties.NAMESPACE_APPLICATION; // ignored;
- descriptor.domain = Domain.APP;
+ descriptorNamespace = KeyProperties.NAMESPACE_APPLICATION; // ignored;
+ descriptorDomain = Domain.APP;
} else {
- descriptor.nspace = namespace;
- descriptor.domain = Domain.SELINUX;
+ descriptorNamespace = namespace;
+ descriptorDomain = Domain.SELINUX;
}
+ return loadAndroidKeyStoreKeyFromKeystore(keyStore, alias, descriptorNamespace,
+ descriptorDomain);
+ }
+
+ /**
+ * Loads an AndroidKeyStoreKey from the AndroidKeyStore backend.
+ *
+ * @param keyStore The keystore2 backend
+ * @param alias The alias of the key in the Keystore database
+ * @param namespace The Keystore namespace. This is used by system api only to request
+ * Android system specific keystore namespace, which can be configured
+ * in the device's SEPolicy. Third party apps and most system components
+ * set this parameter to -1 to indicate their application specific namespace.
+ * See <a href="https://source.android.com/security/keystore#access-control">
+ * Keystore 2.0 access control</a>
+ * @param domain The Keystore domain
+ * @return an AndroidKeyStoreKey corresponding to the provided values for the KeyDescriptor
+ * @hide
+ */
+ public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore(@NonNull KeyStore2 keyStore,
+ @Nullable String alias, long namespace, int domain)
+ throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
+ KeyDescriptor descriptor = new KeyDescriptor();
+ descriptor.nspace = namespace;
+ descriptor.domain = domain;
descriptor.alias = alias;
descriptor.blob = null;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
index 0b3be32..bcf619b 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
@@ -44,6 +44,22 @@
mEncoded = x509EncodedForm;
}
+ /**
+ * Returns the byte array encoding of the certificate corresponding to this public key.
+ * @hide
+ */
+ public byte[] getCertificate() {
+ return mCertificate;
+ }
+
+ /**
+ * Returns the byte array encoding of the certificate chain for this public key.
+ * @hide
+ */
+ public byte[] getCertificateChain() {
+ return mCertificateChain;
+ }
+
abstract AndroidKeyStorePrivateKey getPrivateKey();
@Override
diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp
index cbb1e8f..5e645cc 100644
--- a/libs/androidfw/CursorWindow.cpp
+++ b/libs/androidfw/CursorWindow.cpp
@@ -18,11 +18,10 @@
#include <androidfw/CursorWindow.h>
-#include "android-base/logging.h"
-#include "android-base/mapped_file.h"
-#include "cutils/ashmem.h"
+#include <sys/mman.h>
-using android::base::MappedFile;
+#include "android-base/logging.h"
+#include "cutils/ashmem.h"
namespace android {
@@ -40,7 +39,7 @@
CursorWindow::~CursorWindow() {
if (mAshmemFd != -1) {
- mMappedFile.reset();
+ ::munmap(mData, mSize);
::close(mAshmemFd);
} else {
free(mData);
@@ -76,7 +75,6 @@
status_t CursorWindow::maybeInflate() {
int ashmemFd = 0;
void* newData = nullptr;
- std::unique_ptr<MappedFile> mappedFile;
// Bail early when we can't expand any further
if (mReadOnly || mSize == mInflatedSize) {
@@ -97,12 +95,11 @@
goto fail_silent;
}
- mappedFile = MappedFile::FromFd(ashmemFd, 0, mInflatedSize, PROT_READ | PROT_WRITE);
- if (mappedFile == nullptr) {
+ newData = ::mmap(nullptr, mInflatedSize, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);
+ if (newData == MAP_FAILED) {
PLOG(ERROR) << "Failed mmap";
goto fail_silent;
}
- newData = mappedFile->data();
if (ashmem_set_prot_region(ashmemFd, PROT_READ) < 0) {
PLOG(ERROR) << "Failed ashmem_set_prot_region";
@@ -123,7 +120,6 @@
mData = newData;
mSize = mInflatedSize;
mSlotsOffset = newSlotsOffset;
- mMappedFile = std::move(mappedFile);
updateSlotsData();
}
@@ -134,7 +130,7 @@
fail:
LOG(ERROR) << "Failed maybeInflate";
fail_silent:
- mappedFile.reset();
+ ::munmap(newData, mInflatedSize);
::close(ashmemFd);
return UNKNOWN_ERROR;
}
@@ -171,12 +167,11 @@
goto fail_silent;
}
- window->mMappedFile = MappedFile::FromFd(window->mAshmemFd, 0, window->mSize, PROT_READ);
- if (window->mMappedFile == nullptr) {
+ window->mData = ::mmap(nullptr, window->mSize, PROT_READ, MAP_SHARED, window->mAshmemFd, 0);
+ if (window->mData == MAP_FAILED) {
PLOG(ERROR) << "Failed mmap";
goto fail_silent;
}
- window->mData = window->mMappedFile->data();
} else {
window->mAshmemFd = -1;
diff --git a/libs/androidfw/include/androidfw/CursorWindow.h b/libs/androidfw/include/androidfw/CursorWindow.h
index c2eac12..9ec026a 100644
--- a/libs/androidfw/include/androidfw/CursorWindow.h
+++ b/libs/androidfw/include/androidfw/CursorWindow.h
@@ -26,8 +26,6 @@
#include "binder/Parcel.h"
#include "utils/String8.h"
-#include "android-base/mapped_file.h"
-
#define LOG_WINDOW(...)
namespace android {
@@ -151,8 +149,6 @@
String8 mName;
int mAshmemFd = -1;
void* mData = nullptr;
- std::unique_ptr<android::base::MappedFile> mMappedFile;
-
/**
* Pointer to the first FieldSlot, used to optimize the extremely
* hot code path of getFieldSlot().
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index 951702c..d9fd42f 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -1150,8 +1150,9 @@
}
/**
- * Pauses polling for a {@code timeoutInMs} millis. If polling must be resumed before timeout,
- * use {@link #resumePolling()}.
+ * Pauses NFC tag reader mode polling for a {@code timeoutInMs} millisecond.
+ * In case of {@code timeoutInMs} is zero or invalid polling will be stopped indefinitely
+ * use {@link #resumePolling() to resume the polling.
* @hide
*/
public void pausePolling(int timeoutInMs) {
@@ -1210,9 +1211,8 @@
}
/**
- * Resumes default polling for the current device state if polling is paused. Calling
- * this while polling is not paused is a no-op.
- *
+ * Resumes default NFC tag reader mode polling for the current device state if polling is
+ * paused. Calling this while already in polling is a no-op.
* @hide
*/
public void resumePolling() {
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index bc410c7..905d6f6 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -569,8 +569,9 @@
}
/**
- * Pauses NFC tag reader mode polling for a {@code timeoutInMs} millisecond. If polling must be
- * resumed before timeout, use {@link #resumePolling()}.
+ * Pauses NFC tag reader mode polling for a {@code timeoutInMs} millisecond.
+ * In case of {@code timeoutInMs} is zero or invalid polling will be stopped indefinitely
+ * use {@link #resumePolling() to resume the polling.
* @param timeoutInMs the pause polling duration in millisecond
*/
@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
@@ -581,7 +582,7 @@
/**
* Resumes default NFC tag reader mode polling for the current device state if polling is
- * paused. Calling this while polling is not paused is a no-op.
+ * paused. Calling this while already in polling is a no-op.
*/
@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index 3cf0a4d..5727f99 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -301,7 +301,7 @@
mOffHostName = sa.getString(
com.android.internal.R.styleable.OffHostApduService_secureElementName);
mShouldDefaultToObserveMode = sa.getBoolean(
- R.styleable.HostApduService_shouldDefaultToObserveMode,
+ R.styleable.OffHostApduService_shouldDefaultToObserveMode,
false);
if (mOffHostName != null) {
if (mOffHostName.equals("eSE")) {
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 363045e..c440a07 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -819,6 +819,11 @@
<!-- Summary of checkbox setting that enables the terminal app. [CHAR LIMIT=64] -->
<string name="enable_terminal_summary">Enable terminal app that offers local shell access</string>
+ <!-- Title of checkbox setting that enables the Linux terminal app. [CHAR LIMIT=32] -->
+ <string name="enable_linux_terminal_title">Linux development environment</string>
+ <!-- Summary of checkbox setting that enables the Linux terminal app. [CHAR LIMIT=64] -->
+ <string name="enable_linux_terminal_summary">Run Linux terminal on Android</string>
+
<!-- HDCP checking title, used for debug purposes only. [CHAR LIMIT=25] -->
<string name="hdcp_checking_title">HDCP checking</string>
<!-- HDCP checking dialog title, used for debug purposes only. [CHAR LIMIT=25] -->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
index 65b42e6..fcf486b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
@@ -23,6 +23,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler.Companion.handleAction
import com.android.systemui.media.controls.util.MediaSessionLegacyHelperWrapper
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.shade.ShadeController
@@ -105,7 +106,15 @@
(statusBarStateController.state != StatusBarState.SHADE) &&
statusBarKeyguardViewManager.shouldDismissOnMenuPressed()
if (shouldUnlockOnMenuPressed) {
- shadeController.animateCollapseShadeForced()
+ statusBarKeyguardViewManager.dismissWithAction(
+ object : OnDismissAction {
+ override fun onDismiss(): Boolean {
+ return false
+ }
+ },
+ null,
+ false,
+ )
return true
}
return false
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
index 13f30f5..945e44a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
@@ -46,6 +46,7 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.isNull
@ExperimentalCoroutinesApi
@SmallTest
@@ -96,7 +97,7 @@
.sendVolumeKeyEvent(
eq(actionDownVolumeDownKeyEvent),
eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
- eq(true)
+ eq(true),
)
assertThat(underTest.dispatchKeyEvent(actionDownVolumeUpKeyEvent)).isTrue()
@@ -104,7 +105,7 @@
.sendVolumeKeyEvent(
eq(actionDownVolumeUpKeyEvent),
eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
- eq(true)
+ eq(true),
)
}
@@ -117,7 +118,7 @@
.sendVolumeKeyEvent(
eq(actionDownVolumeDownKeyEvent),
eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
- eq(true)
+ eq(true),
)
assertThat(underTest.dispatchKeyEvent(actionDownVolumeUpKeyEvent)).isFalse()
@@ -125,7 +126,7 @@
.sendVolumeKeyEvent(
eq(actionDownVolumeUpKeyEvent),
eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
- eq(true)
+ eq(true),
)
}
@@ -135,7 +136,9 @@
whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
- verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_MENU)
+ val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)
+ assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
+ verify(statusBarKeyguardViewManager).dismissWithAction(any(), isNull(), eq(false))
}
@Test
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 8e884bc..d918201 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -124,6 +124,7 @@
],
libs: [
"framework-minus-apex.ravenwood",
+ "framework-configinfrastructure.ravenwood",
"ravenwood-helper-libcore-runtime",
],
sdk_version: "core_current",
@@ -395,6 +396,9 @@
"icu4j-icudata-jarjar",
"icu4j-icutzdata-jarjar",
+ // DeviceConfig
+ "framework-configinfrastructure.ravenwood",
+
// Provide runtime versions of utils linked in below
"junit",
"truth",
diff --git a/ravenwood/Framework.bp b/ravenwood/Framework.bp
index 5cb1479..1bea434 100644
--- a/ravenwood/Framework.bp
+++ b/ravenwood/Framework.bp
@@ -290,3 +290,57 @@
"core-icu4j-for-host.ravenwood.jar",
],
}
+
+///////////////////////////////////
+// framework-configinfrastructure
+///////////////////////////////////
+
+java_genrule {
+ name: "framework-configinfrastructure.ravenwood-base",
+ tools: ["hoststubgen"],
+ cmd: "$(location hoststubgen) " +
+ "@$(location :ravenwood-standard-options) " +
+
+ "--debug-log $(location framework-configinfrastructure.log) " +
+ "--stats-file $(location framework-configinfrastructure_stats.csv) " +
+ "--supported-api-list-file $(location framework-configinfrastructure_apis.csv) " +
+ "--gen-keep-all-file $(location framework-configinfrastructure_keep_all.txt) " +
+ "--gen-input-dump-file $(location framework-configinfrastructure_dump.txt) " +
+
+ "--out-impl-jar $(location ravenwood.jar) " +
+ "--in-jar $(location :framework-configinfrastructure.impl{.jar}) " +
+
+ "--policy-override-file $(location :ravenwood-common-policies) " +
+ "--policy-override-file $(location :framework-configinfrastructure-ravenwood-policies) ",
+ srcs: [
+ ":framework-configinfrastructure.impl{.jar}",
+
+ ":ravenwood-common-policies",
+ ":framework-configinfrastructure-ravenwood-policies",
+ ":ravenwood-standard-options",
+ ],
+ out: [
+ "ravenwood.jar",
+
+ // Following files are created just as FYI.
+ "framework-configinfrastructure_keep_all.txt",
+ "framework-configinfrastructure_dump.txt",
+
+ "framework-configinfrastructure.log",
+ "framework-configinfrastructure_stats.csv",
+ "framework-configinfrastructure_apis.csv",
+ ],
+ visibility: ["//visibility:private"],
+}
+
+java_genrule {
+ name: "framework-configinfrastructure.ravenwood",
+ defaults: ["ravenwood-internal-only-visibility-genrule"],
+ cmd: "cp $(in) $(out)",
+ srcs: [
+ ":framework-configinfrastructure.ravenwood-base{ravenwood.jar}",
+ ],
+ out: [
+ "framework-configinfrastructure.ravenwood.jar",
+ ],
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 24950e6..9a145cb 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -40,6 +40,7 @@
import android.os.Looper;
import android.os.ServiceManager;
import android.os.SystemProperties;
+import android.provider.DeviceConfig_host;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
@@ -136,9 +137,6 @@
private static RavenwoodConfig sConfig;
private static RavenwoodSystemProperties sProps;
- // TODO: use the real UiAutomation class instead of a mock
- private static UiAutomation sMockUiAutomation;
- private static Set<String> sAdoptedPermissions = Collections.emptySet();
private static boolean sInitialized = false;
/**
@@ -186,7 +184,6 @@
"androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner");
assertMockitoVersion();
- sMockUiAutomation = createMockUiAutomation();
}
/**
@@ -225,14 +222,9 @@
ActivityManager.init$ravenwood(config.mCurrentUser);
- final HandlerThread main;
- if (config.mProvideMainThread) {
- main = new HandlerThread(MAIN_THREAD_NAME);
- main.start();
- Looper.setMainLooperForTest(main.getLooper());
- } else {
- main = null;
- }
+ final var main = new HandlerThread(MAIN_THREAD_NAME);
+ main.start();
+ Looper.setMainLooperForTest(main.getLooper());
final boolean isSelfInstrumenting =
Objects.equals(config.mTestPackageName, config.mTargetPackageName);
@@ -277,7 +269,7 @@
// Prepare other fields.
config.mInstrumentation = new Instrumentation();
- config.mInstrumentation.basicInit(instContext, targetContext, sMockUiAutomation);
+ config.mInstrumentation.basicInit(instContext, targetContext, createMockUiAutomation());
InstrumentationRegistry.registerInstance(config.mInstrumentation, Bundle.EMPTY);
RavenwoodSystemServer.init(config);
@@ -322,12 +314,9 @@
((RavenwoodContext) config.mTargetContext).cleanUp();
config.mTargetContext = null;
}
- sMockUiAutomation.dropShellPermissionIdentity();
- if (config.mProvideMainThread) {
- Looper.getMainLooper().quit();
- Looper.clearMainLooperForTest();
- }
+ Looper.getMainLooper().quit();
+ Looper.clearMainLooperForTest();
ActivityManager.reset$ravenwood();
@@ -340,6 +329,8 @@
}
android.os.Process.reset$ravenwood();
+ DeviceConfig_host.reset();
+
try {
ResourcesManager.setInstance(null); // Better structure needed.
} catch (Exception e) {
@@ -425,28 +416,30 @@
() -> Class.forName("org.mockito.Matchers"));
}
+ // TODO: use the real UiAutomation class instead of a mock
private static UiAutomation createMockUiAutomation() {
+ final Set[] adoptedPermission = { Collections.emptySet() };
var mock = mock(UiAutomation.class, inv -> {
HostTestUtils.onThrowMethodCalled();
return null;
});
doAnswer(inv -> {
- sAdoptedPermissions = UiAutomation.ALL_PERMISSIONS;
+ adoptedPermission[0] = UiAutomation.ALL_PERMISSIONS;
return null;
}).when(mock).adoptShellPermissionIdentity();
doAnswer(inv -> {
if (inv.getArgument(0) == null) {
- sAdoptedPermissions = UiAutomation.ALL_PERMISSIONS;
+ adoptedPermission[0] = UiAutomation.ALL_PERMISSIONS;
} else {
- sAdoptedPermissions = (Set) Set.of(inv.getArguments());
+ adoptedPermission[0] = Set.of(inv.getArguments());
}
return null;
}).when(mock).adoptShellPermissionIdentity(any());
doAnswer(inv -> {
- sAdoptedPermissions = Collections.emptySet();
+ adoptedPermission[0] = Collections.emptySet();
return null;
}).when(mock).dropShellPermissionIdentity();
- doAnswer(inv -> sAdoptedPermissions).when(mock).getAdoptedShellPermissions();
+ doAnswer(inv -> adoptedPermission[0]).when(mock).getAdoptedShellPermissions();
return mock;
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
index 446f819..1f6e11d 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
@@ -152,7 +152,10 @@
/**
* Configure a "main" thread to be available for the duration of the test, as defined
* by {@code Looper.getMainLooper()}. Has no effect on non-Ravenwood environments.
+ *
+ * @deprecated
*/
+ @Deprecated
public Builder setProvideMainThread(boolean provideMainThread) {
mConfig.mProvideMainThread = provideMainThread;
return this;
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 4196d8e..93a6806 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -139,7 +139,10 @@
/**
* Configure a "main" thread to be available for the duration of the test, as defined
* by {@code Looper.getMainLooper()}. Has no effect on non-Ravenwood environments.
+ *
+ * @deprecated
*/
+ @Deprecated
public Builder setProvideMainThread(boolean provideMainThread) {
mBuilder.setProvideMainThread(provideMainThread);
return this;
diff --git a/ravenwood/runtime-helper-src/framework/android/provider/DeviceConfig_host.java b/ravenwood/runtime-helper-src/framework/android/provider/DeviceConfig_host.java
new file mode 100644
index 0000000..9c2188f
--- /dev/null
+++ b/ravenwood/runtime-helper-src/framework/android/provider/DeviceConfig_host.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 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.provider;
+
+public class DeviceConfig_host {
+
+ /**
+ * Called by Ravenwood runtime to reset all local changes.
+ */
+ public static void reset() {
+ RavenwoodConfigDataStore.getInstance().clearAll();
+ }
+
+ /**
+ * Called by {@link DeviceConfig#newDataStore()}
+ */
+ public static DeviceConfigDataStore newDataStore() {
+ return RavenwoodConfigDataStore.getInstance();
+ }
+}
diff --git a/ravenwood/runtime-helper-src/framework/android/provider/RavenwoodConfigDataStore.java b/ravenwood/runtime-helper-src/framework/android/provider/RavenwoodConfigDataStore.java
new file mode 100644
index 0000000..4bc3de7
--- /dev/null
+++ b/ravenwood/runtime-helper-src/framework/android/provider/RavenwoodConfigDataStore.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2024 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.provider;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.DeviceConfig.BadConfigException;
+import android.provider.DeviceConfig.MonitorCallback;
+import android.provider.DeviceConfig.Properties;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * {@link DeviceConfigDataStore} used only on Ravenwood.
+ *
+ * TODO(b/368591527) Support monitor callback related features
+ * TODO(b/368591527) Support "default" related features
+ */
+final class RavenwoodConfigDataStore implements DeviceConfigDataStore {
+ private static final RavenwoodConfigDataStore sInstance = new RavenwoodConfigDataStore();
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private int mSyncDisabledMode = DeviceConfig.SYNC_DISABLED_MODE_NONE;
+
+ @GuardedBy("mLock")
+ private final HashMap<String, HashMap<String, String>> mStore = new HashMap<>();
+
+ private record ObserverInfo(String namespace, ContentObserver observer) {
+ }
+
+ @GuardedBy("mLock")
+ private final ArrayList<ObserverInfo> mObservers = new ArrayList<>();
+
+ static RavenwoodConfigDataStore getInstance() {
+ return sInstance;
+ }
+
+ private static void shouldNotBeCalled() {
+ throw new RuntimeException("shouldNotBeCalled");
+ }
+
+ void clearAll() {
+ synchronized (mLock) {
+ mSyncDisabledMode = DeviceConfig.SYNC_DISABLED_MODE_NONE;
+ mStore.clear();
+ }
+ }
+
+ @GuardedBy("mLock")
+ private HashMap<String, String> getNamespaceLocked(@NonNull String namespace) {
+ Objects.requireNonNull(namespace);
+ return mStore.computeIfAbsent(namespace, k -> new HashMap<>());
+ }
+
+ /** {@inheritDoc} */
+ @NonNull
+ @Override
+ public Map<String, String> getAllProperties() {
+ synchronized (mLock) {
+ var ret = new HashMap<String, String>();
+
+ for (var namespaceAndMap : mStore.entrySet()) {
+ for (var nameAndValue : namespaceAndMap.getValue().entrySet()) {
+ ret.put(namespaceAndMap.getKey() + "/" + nameAndValue.getKey(),
+ nameAndValue.getValue());
+ }
+ }
+ return ret;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @NonNull
+ @Override
+ public Properties getProperties(@NonNull String namespace, @NonNull String... names) {
+ Objects.requireNonNull(namespace);
+
+ synchronized (mLock) {
+ var namespaceMap = getNamespaceLocked(namespace);
+
+ if (names.length == 0) {
+ return new Properties(namespace, Map.copyOf(namespaceMap));
+ } else {
+ var map = new HashMap<String, String>();
+ for (var name : names) {
+ Objects.requireNonNull(name);
+ map.put(name, namespaceMap.get(name));
+ }
+ return new Properties(namespace, map);
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean setProperties(@NonNull Properties properties) throws BadConfigException {
+ Objects.requireNonNull(properties);
+
+ synchronized (mLock) {
+ var namespaceMap = getNamespaceLocked(properties.getNamespace());
+ for (var kv : properties.getPropertyValues().entrySet()) {
+ namespaceMap.put(
+ Objects.requireNonNull(kv.getKey()),
+ Objects.requireNonNull(kv.getValue())
+ );
+ }
+ notifyObserversLock(properties.getNamespace(),
+ properties.getKeyset().toArray(new String[0]));
+ }
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean setProperty(@NonNull String namespace, @NonNull String name,
+ @Nullable String value, boolean makeDefault) {
+ Objects.requireNonNull(namespace);
+ Objects.requireNonNull(name);
+
+ synchronized (mLock) {
+ var namespaceMap = getNamespaceLocked(namespace);
+ namespaceMap.put(name, value);
+
+ // makeDefault not supported.
+ notifyObserversLock(namespace, new String[]{name});
+ }
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean deleteProperty(@NonNull String namespace, @NonNull String name) {
+ Objects.requireNonNull(namespace);
+ Objects.requireNonNull(name);
+
+ synchronized (mLock) {
+ var namespaceMap = getNamespaceLocked(namespace);
+ if (namespaceMap.remove(name) != null) {
+ notifyObserversLock(namespace, new String[]{name});
+ }
+ }
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void resetToDefaults(int resetMode, @Nullable String namespace) {
+ // not supported in DeviceConfig.java
+ shouldNotBeCalled();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setSyncDisabledMode(int syncDisabledMode) {
+ synchronized (mLock) {
+ mSyncDisabledMode = syncDisabledMode;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int getSyncDisabledMode() {
+ synchronized (mLock) {
+ return mSyncDisabledMode;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setMonitorCallback(@NonNull ContentResolver resolver, @NonNull Executor executor,
+ @NonNull MonitorCallback callback) {
+ // not supported in DeviceConfig.java
+ shouldNotBeCalled();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void clearMonitorCallback(@NonNull ContentResolver resolver) {
+ // not supported in DeviceConfig.java
+ shouldNotBeCalled();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void registerContentObserver(@NonNull String namespace, boolean notifyForescendants,
+ ContentObserver contentObserver) {
+ synchronized (mLock) {
+ mObservers.add(new ObserverInfo(
+ Objects.requireNonNull(namespace),
+ Objects.requireNonNull(contentObserver)
+ ));
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void unregisterContentObserver(@NonNull ContentObserver contentObserver) {
+ synchronized (mLock) {
+ for (int i = mObservers.size() - 1; i >= 0; i--) {
+ if (mObservers.get(i).observer == contentObserver) {
+ mObservers.remove(i);
+ }
+ }
+ }
+ }
+
+ private static final Uri CONTENT_URI = Uri.parse("content://settings/config");
+
+ @GuardedBy("mLock")
+ private void notifyObserversLock(@NonNull String namespace, String[] keys) {
+ var urib = CONTENT_URI.buildUpon().appendPath(namespace);
+ for (var key : keys) {
+ urib.appendEncodedPath(key);
+ }
+ var uri = urib.build();
+
+ final var copy = List.copyOf(mObservers);
+ new Handler(Looper.getMainLooper()).post(() -> {
+ for (int i = copy.size() - 1; i >= 0; i--) {
+ if (copy.get(i).namespace.equals(namespace)) {
+ copy.get(i).observer.dispatchChange(false, uri);
+ }
+ }
+ });
+ }
+}
diff --git a/ravenwood/tests/bivalenttest/Android.bp b/ravenwood/tests/bivalenttest/Android.bp
index ac499b9..d7f4b3e 100644
--- a/ravenwood/tests/bivalenttest/Android.bp
+++ b/ravenwood/tests/bivalenttest/Android.bp
@@ -54,34 +54,36 @@
auto_gen_config: true,
}
-// TODO(b/371215487): migrate bivalenttest.ravenizer tests to another architecture
+android_test {
+ name: "RavenwoodBivalentTest_device",
-// android_test {
-// name: "RavenwoodBivalentTest_device",
-//
-// srcs: [
-// "test/**/*.java",
-// ],
-// static_libs: [
-// "junit",
-// "truth",
-//
-// "androidx.annotation_annotation",
-// "androidx.test.ext.junit",
-// "androidx.test.rules",
-//
-// "junit-params",
-// "platform-parametric-runner-lib",
-//
-// "ravenwood-junit",
-// ],
-// jni_libs: [
-// "libravenwoodbivalenttest_jni",
-// ],
-// test_suites: [
-// "device-tests",
-// ],
-// optimize: {
-// enabled: false,
-// },
-// }
+ srcs: [
+ "test/**/*.java",
+ ],
+ // TODO(b/371215487): migrate bivalenttest.ravenizer tests to another architecture
+ exclude_srcs: [
+ "test/**/ravenizer/*.java",
+ ],
+ static_libs: [
+ "junit",
+ "truth",
+
+ "androidx.annotation_annotation",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+
+ "junit-params",
+ "platform-parametric-runner-lib",
+
+ "ravenwood-junit",
+ ],
+ jni_libs: [
+ "libravenwoodbivalenttest_jni",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/services/Android.bp b/services/Android.bp
index a679341..e8d6630 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -186,6 +186,11 @@
},
}
+vintf_fragment {
+ name: "manifest_services.xml",
+ src: "manifest_services.xml",
+}
+
// merge all required services into one jar
// ============================================================
java_library {
@@ -250,7 +255,7 @@
"service-sdksandbox.stubs.system_server",
],
- vintf_fragments: [
+ vintf_fragment_modules: [
"manifest_services.xml",
],
diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS
index 0e35a40..4e11750 100644
--- a/services/accessibility/OWNERS
+++ b/services/accessibility/OWNERS
@@ -2,10 +2,11 @@
# Android Accessibility Framework owners
danielnorman@google.com
-aarmaly@google.com
chunkulin@google.com
fuego@google.com
sallyyuen@google.com
+yingleiw@google.com
+caseyburkhardt@google.com
# Android Accessibility members who have OWNERS but should not be sent
# day-to-day changes for code review:
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index d80e40c..8b619a4 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -46,6 +46,7 @@
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.RoSystemFeatures;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.build.UnboundedSdkLevel;
import com.android.server.pm.permission.PermissionAllowlist;
@@ -212,6 +213,30 @@
}
}
+ /**
+ * Utility class for testing interaction with compile-time defined system features.
+ * @hide
+ */
+ @VisibleForTesting
+ public static class Injector {
+ /** Whether a system feature is defined as enabled and available at compile-time. */
+ public boolean isReadOnlySystemEnabledFeature(String featureName, int version) {
+ return Boolean.TRUE.equals(RoSystemFeatures.maybeHasFeature(featureName, version));
+ }
+
+ /** Whether a system feature is defined as disabled and unavailable at compile-time. */
+ public boolean isReadOnlySystemDisabledFeature(String featureName, int version) {
+ return Boolean.FALSE.equals(RoSystemFeatures.maybeHasFeature(featureName, version));
+ }
+
+ /** The full set of system features defined as compile-time enabled and available. */
+ public ArrayMap<String, FeatureInfo> getReadOnlySystemEnabledFeatures() {
+ return RoSystemFeatures.getReadOnlySystemEnabledFeatures();
+ }
+ }
+
+ private final Injector mInjector;
+
// These are the built-in shared libraries that were read from the
// system configuration files. Keys are the library names; values are
// the individual entries that contain information such as filename
@@ -220,7 +245,7 @@
// These are the features this devices supports that were read from the
// system configuration files.
- final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();
+ final ArrayMap<String, FeatureInfo> mAvailableFeatures;
// These are the features which this device doesn't support; the OEM
// partition uses these to opt-out of features from the system image.
@@ -602,12 +627,26 @@
public ArrayMap<String, Integer> getOemDefinedUids() {
return mOemDefinedUids;
}
+
/**
* Only use for testing. Do NOT use in production code.
* @param readPermissions false to create an empty SystemConfig; true to read the permissions.
*/
@VisibleForTesting
public SystemConfig(boolean readPermissions) {
+ this(readPermissions, new Injector());
+ }
+
+ /**
+ * Only use for testing. Do NOT use in production code.
+ * @param readPermissions false to create an empty SystemConfig; true to read the permissions.
+ * @param injector Additional dependency injection for testing.
+ */
+ @VisibleForTesting
+ public SystemConfig(boolean readPermissions, Injector injector) {
+ mInjector = injector;
+ mAvailableFeatures = mInjector.getReadOnlySystemEnabledFeatures();
+
if (readPermissions) {
Slog.w(TAG, "Constructing a test SystemConfig");
readAllPermissions();
@@ -617,6 +656,9 @@
}
SystemConfig() {
+ mInjector = new Injector();
+ mAvailableFeatures = mInjector.getReadOnlySystemEnabledFeatures();
+
TimingsTraceLog log = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
log.traceBegin("readAllPermissions");
try {
@@ -1777,6 +1819,10 @@
}
private void addFeature(String name, int version) {
+ if (mInjector.isReadOnlySystemDisabledFeature(name, version)) {
+ Slog.w(TAG, "Skipping feature addition for compile-time disabled feature: " + name);
+ return;
+ }
FeatureInfo fi = mAvailableFeatures.get(name);
if (fi == null) {
fi = new FeatureInfo();
@@ -1789,6 +1835,10 @@
}
private void removeFeature(String name) {
+ if (mInjector.isReadOnlySystemEnabledFeature(name, /*version=*/0)) {
+ Slog.w(TAG, "Skipping feature removal for compile-time enabled feature: " + name);
+ return;
+ }
if (mAvailableFeatures.remove(name) != null) {
Slog.d(TAG, "Removed unavailable feature " + name);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d7c43b5..4efe62c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2859,8 +2859,11 @@
if (isolated) {
if (mIsolatedAppBindArgs == null) {
mIsolatedAppBindArgs = new ArrayMap<>(1);
+ // See b/79378449 about the following exemption.
addServiceToMap(mIsolatedAppBindArgs, "package");
- addServiceToMap(mIsolatedAppBindArgs, "permissionmgr");
+ if (!android.server.Flags.removeJavaServiceManagerCache()) {
+ addServiceToMap(mIsolatedAppBindArgs, "permissionmgr");
+ }
}
return mIsolatedAppBindArgs;
}
@@ -2871,27 +2874,33 @@
// Add common services.
// IMPORTANT: Before adding services here, make sure ephemeral apps can access them too.
// Enable the check in ApplicationThread.bindApplication() to make sure.
+ if (!android.server.Flags.removeJavaServiceManagerCache()) {
+ addServiceToMap(mAppBindArgs, "permissionmgr");
+ addServiceToMap(mAppBindArgs, Context.ALARM_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.DISPLAY_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.NETWORKMANAGEMENT_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.CONNECTIVITY_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.ACCESSIBILITY_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.INPUT_METHOD_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.INPUT_SERVICE);
+ addServiceToMap(mAppBindArgs, "graphicsstats");
+ addServiceToMap(mAppBindArgs, Context.APP_OPS_SERVICE);
+ addServiceToMap(mAppBindArgs, "content");
+ addServiceToMap(mAppBindArgs, Context.JOB_SCHEDULER_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.NOTIFICATION_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.VIBRATOR_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.ACCOUNT_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.POWER_SERVICE);
+ addServiceToMap(mAppBindArgs, Context.USER_SERVICE);
+ addServiceToMap(mAppBindArgs, "mount");
+ addServiceToMap(mAppBindArgs, Context.PLATFORM_COMPAT_SERVICE);
+ }
+ // See b/79378449
+ // Getting the window service and package service binder from servicemanager
+ // is blocked for Apps. However they are necessary for apps.
+ // TODO: remove exception
addServiceToMap(mAppBindArgs, "package");
- addServiceToMap(mAppBindArgs, "permissionmgr");
addServiceToMap(mAppBindArgs, Context.WINDOW_SERVICE);
- addServiceToMap(mAppBindArgs, Context.ALARM_SERVICE);
- addServiceToMap(mAppBindArgs, Context.DISPLAY_SERVICE);
- addServiceToMap(mAppBindArgs, Context.NETWORKMANAGEMENT_SERVICE);
- addServiceToMap(mAppBindArgs, Context.CONNECTIVITY_SERVICE);
- addServiceToMap(mAppBindArgs, Context.ACCESSIBILITY_SERVICE);
- addServiceToMap(mAppBindArgs, Context.INPUT_METHOD_SERVICE);
- addServiceToMap(mAppBindArgs, Context.INPUT_SERVICE);
- addServiceToMap(mAppBindArgs, "graphicsstats");
- addServiceToMap(mAppBindArgs, Context.APP_OPS_SERVICE);
- addServiceToMap(mAppBindArgs, "content");
- addServiceToMap(mAppBindArgs, Context.JOB_SCHEDULER_SERVICE);
- addServiceToMap(mAppBindArgs, Context.NOTIFICATION_SERVICE);
- addServiceToMap(mAppBindArgs, Context.VIBRATOR_SERVICE);
- addServiceToMap(mAppBindArgs, Context.ACCOUNT_SERVICE);
- addServiceToMap(mAppBindArgs, Context.POWER_SERVICE);
- addServiceToMap(mAppBindArgs, Context.USER_SERVICE);
- addServiceToMap(mAppBindArgs, "mount");
- addServiceToMap(mAppBindArgs, Context.PLATFORM_COMPAT_SERVICE);
}
return mAppBindArgs;
}
@@ -12689,7 +12698,7 @@
continue;
}
endTime = SystemClock.currentThreadTimeMillis();
- hasSwapPss = mi.hasSwappedOutPss;
+ hasSwapPss = hasSwapPss || mi.hasSwappedOutPss;
memtrackGraphics = mi.getOtherPrivate(Debug.MemoryInfo.OTHER_GRAPHICS);
memtrackGl = mi.getOtherPrivate(Debug.MemoryInfo.OTHER_GL);
} else {
@@ -13367,7 +13376,7 @@
continue;
}
endTime = SystemClock.currentThreadTimeMillis();
- hasSwapPss = mi.hasSwappedOutPss;
+ hasSwapPss = hasSwapPss || mi.hasSwappedOutPss;
} else {
reportType = ProcessStats.ADD_PSS_EXTERNAL;
startTime = SystemClock.currentThreadTimeMillis();
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index bbd4323..3a3f041 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -110,6 +110,7 @@
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.ZygoteProcess;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -439,6 +440,8 @@
return runSetForegroundServiceDelegate(pw);
case "capabilities":
return runCapabilities(pw);
+ case "set-app-zygote-preload-timeout":
+ return runSetAppZygotePreloadTimeout(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -448,6 +451,15 @@
return -1;
}
+ int runSetAppZygotePreloadTimeout(PrintWriter pw) throws RemoteException {
+ final String timeout = getNextArgRequired();
+ final int timeoutMs = Integer.parseInt(timeout);
+
+ ZygoteProcess.setAppZygotePreloadTimeout(timeoutMs);
+
+ return 0;
+ }
+
int runCapabilities(PrintWriter pw) throws RemoteException {
final PrintWriter err = getErrPrintWriter();
boolean outputAsProtobuf = false;
@@ -4603,6 +4615,8 @@
pw.println(" capabilities [--protobuf]");
pw.println(" Output am supported features (text format). Options are:");
pw.println(" --protobuf: format output using protobuffer");
+ pw.println(" set-app-zygote-preload-timeout <TIMEOUT_IN_MS>");
+ pw.println(" Set the timeout for preloading code in the app-zygote");
Intent.printIntentArgsHelp(pw, "");
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index a7af80f..554265a 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -5146,6 +5146,7 @@
if (ai != null) {
if (ai.packageName.equals(app.info.packageName)) {
app.info = ai;
+ app.getWindowProcessController().updateApplicationInfo(ai);
PlatformCompatCache.getInstance()
.onApplicationInfoChanged(ai);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index daaafcb..c38ad60 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -115,7 +115,7 @@
}
@LockoutTracker.LockoutMode
- public int handleFailedAttempt(int userId) {
+ private int handleFailedAttempt(int userId) {
if (mLockoutTracker != null) {
mLockoutTracker.addFailedAttemptForUser(getTargetUserId());
}
diff --git a/services/core/java/com/android/server/content/OWNERS b/services/core/java/com/android/server/content/OWNERS
index b6a9fe86..5642382 100644
--- a/services/core/java/com/android/server/content/OWNERS
+++ b/services/core/java/com/android/server/content/OWNERS
@@ -1 +1,3 @@
-include /services/core/java/com/android/server/am/OWNERS
\ No newline at end of file
+include /services/core/java/com/android/server/am/OWNERS
+
+per-file Sync* = file:/apex/jobscheduler/JOB_OWNERS
\ No newline at end of file
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 3883604..d23e76f 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -74,6 +74,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.WeaklyReferencedCallback;
import com.android.internal.util.DumpUtils;
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
@@ -1730,6 +1731,7 @@
/**
* Interface for applying transforms to a given AppWindow.
*/
+ @WeaklyReferencedCallback
public interface ColorTransformController {
/**
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 636854b..d1576c5 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -17,118 +17,63 @@
package com.android.server.integrity;
import static android.content.Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION;
-import static android.content.Intent.EXTRA_LONG_VERSION_CODE;
-import static android.content.Intent.EXTRA_ORIGINATING_UID;
-import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.integrity.AppIntegrityManager.EXTRA_STATUS;
import static android.content.integrity.AppIntegrityManager.STATUS_FAILURE;
import static android.content.integrity.AppIntegrityManager.STATUS_SUCCESS;
-import static android.content.integrity.InstallerAllowedByManifestFormula.INSTALLER_CERTIFICATE_NOT_EVALUATED;
import static android.content.integrity.IntegrityUtils.getHexDigest;
import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
import android.annotation.BinderThread;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
-import android.content.integrity.AppInstallMetadata;
import android.content.integrity.IAppIntegrityManager;
import android.content.integrity.Rule;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
-import android.content.pm.Signature;
-import android.content.pm.SigningDetails;
-import android.content.pm.parsing.result.ParseResult;
-import android.content.pm.parsing.result.ParseTypeImpl;
import android.net.Uri;
import android.os.Binder;
-import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.provider.Settings;
import android.util.Pair;
import android.util.Slog;
-import android.util.apk.SourceStampVerificationResult;
-import android.util.apk.SourceStampVerifier;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.parsing.PackageParser2;
-import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
-import com.android.server.integrity.model.IntegrityCheckResult;
import com.android.server.integrity.model.RuleMetadata;
-import com.android.server.pm.PackageManagerServiceUtils;
-import com.android.server.pm.parsing.PackageParserUtils;
-import java.io.ByteArrayInputStream;
import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
-import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
/** Implementation of {@link AppIntegrityManagerService}. */
public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
- /**
- * This string will be used as the "installer" for formula evaluation when the app's installer
- * cannot be determined.
- *
- * <p>This may happen for various reasons. e.g., the installing app's package name may not match
- * its UID.
- */
- private static final String UNKNOWN_INSTALLER = "";
- /**
- * This string will be used as the "installer" for formula evaluation when the app is being
- * installed via ADB.
- */
- public static final String ADB_INSTALLER = "adb";
private static final String TAG = "AppIntegrityManagerServiceImpl";
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
- private static final String BASE_APK_FILE = "base.apk";
- private static final String ALLOWED_INSTALLERS_METADATA_NAME = "allowed-installers";
- private static final String ALLOWED_INSTALLER_DELIMITER = ",";
- private static final String INSTALLER_PACKAGE_CERT_DELIMITER = "\\|";
public static final boolean DEBUG_INTEGRITY_COMPONENT = false;
- private static final Set<String> PACKAGE_INSTALLER =
- new HashSet<>(
- Arrays.asList(
- "com.google.android.packageinstaller", "com.android.packageinstaller"));
-
// Access to files inside mRulesDir is protected by mRulesLock;
private final Context mContext;
private final Handler mHandler;
private final PackageManagerInternal mPackageManagerInternal;
- private final Supplier<PackageParser2> mParserSupplier;
private final IntegrityFileManager mIntegrityFileManager;
/** Create an instance of {@link AppIntegrityManagerServiceImpl}. */
@@ -139,7 +84,6 @@
return new AppIntegrityManagerServiceImpl(
context,
LocalServices.getService(PackageManagerInternal.class),
- PackageParserUtils::forParsingFileWithDefaults,
IntegrityFileManager.getInstance(),
handlerThread.getThreadHandler());
}
@@ -148,12 +92,10 @@
AppIntegrityManagerServiceImpl(
Context context,
PackageManagerInternal packageManagerInternal,
- Supplier<PackageParser2> parserSupplier,
IntegrityFileManager integrityFileManager,
Handler handler) {
mContext = context;
mPackageManagerInternal = packageManagerInternal;
- mParserSupplier = parserSupplier;
mIntegrityFileManager = integrityFileManager;
mHandler = handler;
@@ -263,148 +205,8 @@
private void handleIntegrityVerification(Intent intent) {
int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1);
-
- try {
- if (DEBUG_INTEGRITY_COMPONENT) {
- Slog.d(TAG, "Received integrity verification intent " + intent.toString());
- Slog.d(TAG, "Extras " + intent.getExtras());
- }
-
- String installerPackageName = getInstallerPackageName(intent);
-
- // Skip integrity verification if the verifier is doing the install.
- if (!integrityCheckIncludesRuleProvider() && isRuleProvider(installerPackageName)) {
- if (DEBUG_INTEGRITY_COMPONENT) {
- Slog.i(TAG, "Verifier doing the install. Skipping integrity check.");
- }
- mPackageManagerInternal.setIntegrityVerificationResult(
- verificationId, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
- return;
- }
-
- String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
-
- Pair<SigningDetails, Bundle> packageSigningAndMetadata =
- getPackageSigningAndMetadata(intent.getData());
- if (packageSigningAndMetadata == null) {
- Slog.w(TAG, "Cannot parse package " + packageName);
- // We can't parse the package.
- mPackageManagerInternal.setIntegrityVerificationResult(
- verificationId, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
- return;
- }
-
- var signingDetails = packageSigningAndMetadata.first;
- List<String> appCertificates = getCertificateFingerprint(packageName, signingDetails);
- List<String> appCertificateLineage = getCertificateLineage(packageName, signingDetails);
- List<String> installerCertificates =
- getInstallerCertificateFingerprint(installerPackageName);
-
- AppInstallMetadata.Builder builder = new AppInstallMetadata.Builder();
-
- builder.setPackageName(getPackageNameNormalized(packageName));
- builder.setAppCertificates(appCertificates);
- builder.setAppCertificateLineage(appCertificateLineage);
- builder.setVersionCode(intent.getLongExtra(EXTRA_LONG_VERSION_CODE, -1));
- builder.setInstallerName(getPackageNameNormalized(installerPackageName));
- builder.setInstallerCertificates(installerCertificates);
- builder.setIsPreInstalled(isSystemApp(packageName));
-
- Map<String, String> allowedInstallers =
- getAllowedInstallers(packageSigningAndMetadata.second);
- builder.setAllowedInstallersAndCert(allowedInstallers);
- extractSourceStamp(intent.getData(), builder);
-
- AppInstallMetadata appInstallMetadata = builder.build();
-
- if (DEBUG_INTEGRITY_COMPONENT) {
- Slog.i(
- TAG,
- "To be verified: "
- + appInstallMetadata
- + " installers "
- + allowedInstallers);
- }
- IntegrityCheckResult result = IntegrityCheckResult.allow();
- if (!result.getMatchedRules().isEmpty() || DEBUG_INTEGRITY_COMPONENT) {
- Slog.i(
- TAG,
- String.format(
- "Integrity check of %s result: %s due to %s",
- packageName, result.getEffect(), result.getMatchedRules()));
- }
-
- mPackageManagerInternal.setIntegrityVerificationResult(
- verificationId,
- result.getEffect() == IntegrityCheckResult.Effect.ALLOW
- ? PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW
- : PackageManagerInternal.INTEGRITY_VERIFICATION_REJECT);
- } catch (IllegalArgumentException e) {
- // This exception indicates something is wrong with the input passed by package manager.
- // e.g., someone trying to trick the system. We block installs in this case.
- Slog.e(TAG, "Invalid input to integrity verification", e);
- mPackageManagerInternal.setIntegrityVerificationResult(
- verificationId, PackageManagerInternal.INTEGRITY_VERIFICATION_REJECT);
- } catch (Exception e) {
- // Other exceptions indicate an error within the integrity component implementation and
- // we allow them.
- Slog.e(TAG, "Error handling integrity verification", e);
- mPackageManagerInternal.setIntegrityVerificationResult(
- verificationId, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
- }
- }
-
- /**
- * Verify the UID and return the installer package name.
- *
- * @return the package name of the installer, or null if it cannot be determined or it is
- * installed via adb.
- */
- @Nullable
- private String getInstallerPackageName(Intent intent) {
- String installer =
- intent.getStringExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE);
- if (PackageManagerServiceUtils.isInstalledByAdb(installer)) {
- return ADB_INSTALLER;
- }
- int installerUid = intent.getIntExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID, -1);
- if (installerUid < 0) {
- Slog.e(
- TAG,
- "Installer cannot be determined: installer: "
- + installer
- + " installer UID: "
- + installerUid);
- return UNKNOWN_INSTALLER;
- }
-
- // Verify that the installer UID actually contains the package. Note that comparing UIDs
- // is not safe since context's uid can change in different settings; e.g. Android Auto.
- if (!getPackageListForUid(installerUid).contains(installer)) {
- return UNKNOWN_INSTALLER;
- }
-
- // At this time we can trust "installer".
-
- // A common way for apps to install packages is to send an intent to PackageInstaller. In
- // that case, the installer will always show up as PackageInstaller which is not what we
- // want.
- if (PACKAGE_INSTALLER.contains(installer)) {
- int originatingUid = intent.getIntExtra(EXTRA_ORIGINATING_UID, -1);
- if (originatingUid < 0) {
- Slog.e(TAG, "Installer is package installer but originating UID not found.");
- return UNKNOWN_INSTALLER;
- }
- List<String> installerPackages = getPackageListForUid(originatingUid);
- if (installerPackages.isEmpty()) {
- Slog.e(TAG, "No package found associated with originating UID " + originatingUid);
- return UNKNOWN_INSTALLER;
- }
- // In the case of multiple package sharing a UID, we just return the first one.
- return installerPackages.get(0);
- }
-
- return installer;
+ mPackageManagerInternal.setIntegrityVerificationResult(
+ verificationId, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
}
/** We will use the SHA256 digest of a package name if it is more than 32 bytes long. */
@@ -422,264 +224,6 @@
}
}
- private List<String> getInstallerCertificateFingerprint(String installer) {
- if (installer.equals(ADB_INSTALLER) || installer.equals(UNKNOWN_INSTALLER)) {
- return Collections.emptyList();
- }
- var installerPkg = mPackageManagerInternal.getPackage(installer);
- if (installerPkg == null) {
- Slog.w(TAG, "Installer package " + installer + " not found.");
- return Collections.emptyList();
- }
- return getCertificateFingerprint(installerPkg.getPackageName(),
- installerPkg.getSigningDetails());
- }
-
- private List<String> getCertificateFingerprint(@NonNull String packageName,
- @NonNull SigningDetails signingDetails) {
- ArrayList<String> certificateFingerprints = new ArrayList();
- for (Signature signature : getSignatures(packageName, signingDetails)) {
- certificateFingerprints.add(getFingerprint(signature));
- }
- return certificateFingerprints;
- }
-
- private List<String> getCertificateLineage(@NonNull String packageName,
- @NonNull SigningDetails signingDetails) {
- ArrayList<String> certificateLineage = new ArrayList();
- for (Signature signature : getSignatureLineage(packageName, signingDetails)) {
- certificateLineage.add(getFingerprint(signature));
- }
- return certificateLineage;
- }
-
- /** Get the allowed installers and their associated certificate hashes from <meta-data> tag. */
- private Map<String, String> getAllowedInstallers(@Nullable Bundle metaData) {
- Map<String, String> packageCertMap = new HashMap<>();
- if (metaData != null) {
- String allowedInstallers = metaData.getString(ALLOWED_INSTALLERS_METADATA_NAME);
- if (allowedInstallers != null) {
- // parse the metadata for certs.
- String[] installerCertPairs = allowedInstallers.split(ALLOWED_INSTALLER_DELIMITER);
- for (String packageCertPair : installerCertPairs) {
- String[] packageAndCert =
- packageCertPair.split(INSTALLER_PACKAGE_CERT_DELIMITER);
- if (packageAndCert.length == 2) {
- String packageName = getPackageNameNormalized(packageAndCert[0]);
- String cert = packageAndCert[1];
- packageCertMap.put(packageName, cert);
- } else if (packageAndCert.length == 1) {
- packageCertMap.put(
- getPackageNameNormalized(packageAndCert[0]),
- INSTALLER_CERTIFICATE_NOT_EVALUATED);
- }
- }
- }
- }
-
- return packageCertMap;
- }
-
- /** Extract the source stamp embedded in the APK, if present. */
- private void extractSourceStamp(Uri dataUri, AppInstallMetadata.Builder appInstallMetadata) {
- File installationPath = getInstallationPath(dataUri);
- if (installationPath == null) {
- throw new IllegalArgumentException("Installation path is null, package not found");
- }
-
- SourceStampVerificationResult sourceStampVerificationResult;
- if (installationPath.isDirectory()) {
- try (Stream<Path> filesList = Files.list(installationPath.toPath())) {
- List<String> apkFiles =
- filesList
- .map(path -> path.toAbsolutePath().toString())
- .filter(str -> str.endsWith(".apk"))
- .collect(Collectors.toList());
- sourceStampVerificationResult = SourceStampVerifier.verify(apkFiles);
- } catch (IOException e) {
- throw new IllegalArgumentException("Could not read APK directory");
- }
- } else {
- sourceStampVerificationResult =
- SourceStampVerifier.verify(installationPath.getAbsolutePath());
- }
-
- appInstallMetadata.setIsStampPresent(sourceStampVerificationResult.isPresent());
- appInstallMetadata.setIsStampVerified(sourceStampVerificationResult.isVerified());
- // A verified stamp is set to be trusted.
- appInstallMetadata.setIsStampTrusted(sourceStampVerificationResult.isVerified());
- if (sourceStampVerificationResult.isVerified()) {
- X509Certificate sourceStampCertificate =
- (X509Certificate) sourceStampVerificationResult.getCertificate();
- // Sets source stamp certificate digest.
- try {
- MessageDigest digest = MessageDigest.getInstance("SHA-256");
- byte[] certificateDigest = digest.digest(sourceStampCertificate.getEncoded());
- appInstallMetadata.setStampCertificateHash(getHexDigest(certificateDigest));
- } catch (NoSuchAlgorithmException | CertificateEncodingException e) {
- throw new IllegalArgumentException(
- "Error computing source stamp certificate digest", e);
- }
- }
- }
-
- private static Signature[] getSignatures(@NonNull String packageName,
- @NonNull SigningDetails signingDetails) {
- Signature[] signatures = signingDetails.getSignatures();
- if (signatures == null || signatures.length < 1) {
- throw new IllegalArgumentException("Package signature not found in " + packageName);
- }
-
- // We are only interested in evaluating the active signatures.
- return signatures;
- }
-
- private static Signature[] getSignatureLineage(@NonNull String packageName,
- @NonNull SigningDetails signingDetails) {
- // Obtain the active signatures of the package.
- Signature[] signatureLineage = getSignatures(packageName, signingDetails);
-
- var pastSignatures = signingDetails.getPastSigningCertificates();
- // Obtain the past signatures of the package.
- if (signatureLineage.length == 1 && !ArrayUtils.isEmpty(pastSignatures)) {
- // Merge the signatures and return.
- Signature[] allSignatures =
- new Signature[signatureLineage.length + pastSignatures.length];
- int i;
- for (i = 0; i < signatureLineage.length; i++) {
- allSignatures[i] = signatureLineage[i];
- }
- for (int j = 0; j < pastSignatures.length; j++) {
- allSignatures[i] = pastSignatures[j];
- i++;
- }
- signatureLineage = allSignatures;
- }
-
- return signatureLineage;
- }
-
- private static String getFingerprint(Signature cert) {
- InputStream input = new ByteArrayInputStream(cert.toByteArray());
-
- CertificateFactory factory;
- try {
- factory = CertificateFactory.getInstance("X509");
- } catch (CertificateException e) {
- throw new RuntimeException("Error getting CertificateFactory", e);
- }
- X509Certificate certificate = null;
- try {
- if (factory != null) {
- certificate = (X509Certificate) factory.generateCertificate(input);
- }
- } catch (CertificateException e) {
- throw new RuntimeException("Error getting X509Certificate", e);
- }
-
- if (certificate == null) {
- throw new RuntimeException("X509 Certificate not found");
- }
-
- try {
- MessageDigest digest = MessageDigest.getInstance("SHA-256");
- byte[] publicKey = digest.digest(certificate.getEncoded());
- return getHexDigest(publicKey);
- } catch (NoSuchAlgorithmException | CertificateEncodingException e) {
- throw new IllegalArgumentException("Error error computing fingerprint", e);
- }
- }
-
- @Nullable
- private Pair<SigningDetails, Bundle> getPackageSigningAndMetadata(Uri dataUri) {
- File installationPath = getInstallationPath(dataUri);
- if (installationPath == null) {
- throw new IllegalArgumentException("Installation path is null, package not found");
- }
-
- try (PackageParser2 parser = mParserSupplier.get()) {
- var pkg = parser.parsePackage(installationPath, 0, false);
- // APK signatures is already verified elsewhere in PackageManager. We do not need to
- // verify it again since it could cause a timeout for large APKs.
- final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
- final ParseResult<SigningDetails> result = ParsingPackageUtils.getSigningDetails(
- input, pkg, /* skipVerify= */ true);
- if (result.isError()) {
- Slog.w(TAG, result.getErrorMessage(), result.getException());
- return null;
- }
- return Pair.create(result.getResult(), pkg.getMetaData());
- } catch (Exception e) {
- Slog.w(TAG, "Exception reading " + dataUri, e);
- return null;
- }
- }
-
- private PackageInfo getMultiApkInfo(File multiApkDirectory) {
- // The base apk will normally be called base.apk
- File baseFile = new File(multiApkDirectory, BASE_APK_FILE);
- PackageInfo basePackageInfo =
- mContext.getPackageManager()
- .getPackageArchiveInfo(
- baseFile.getAbsolutePath(),
- PackageManager.GET_SIGNING_CERTIFICATES
- | PackageManager.GET_META_DATA);
-
- if (basePackageInfo == null) {
- for (File apkFile : multiApkDirectory.listFiles()) {
- if (apkFile.isDirectory()) {
- continue;
- }
-
- // If we didn't find a base.apk, then try to parse each apk until we find the one
- // that succeeds.
- try {
- basePackageInfo =
- mContext.getPackageManager()
- .getPackageArchiveInfo(
- apkFile.getAbsolutePath(),
- PackageManager.GET_SIGNING_CERTIFICATES
- | PackageManager.GET_META_DATA);
- } catch (Exception e) {
- // Some of the splits may not contain a valid android manifest. It is an
- // expected exception. We still log it nonetheless but we should keep looking.
- Slog.w(TAG, "Exception reading " + apkFile, e);
- }
- if (basePackageInfo != null) {
- Slog.i(TAG, "Found package info from " + apkFile);
- break;
- }
- }
- }
-
- if (basePackageInfo == null) {
- throw new IllegalArgumentException(
- "Base package info cannot be found from installation directory");
- }
-
- return basePackageInfo;
- }
-
- private File getInstallationPath(Uri dataUri) {
- if (dataUri == null) {
- throw new IllegalArgumentException("Null data uri");
- }
-
- String scheme = dataUri.getScheme();
- if (!"file".equalsIgnoreCase(scheme)) {
- throw new IllegalArgumentException("Unsupported scheme for " + dataUri);
- }
-
- File installationPath = new File(dataUri.getPath());
- if (!installationPath.exists()) {
- throw new IllegalArgumentException("Cannot find file for " + dataUri);
- }
- if (!installationPath.canRead()) {
- throw new IllegalArgumentException("Cannot read file for " + dataUri);
- }
- return installationPath;
- }
-
private String getCallerPackageNameOrThrow(int callingUid) {
String callerPackageName = getCallingRulePusherPackageName(callingUid);
if (callerPackageName == null) {
@@ -715,15 +259,6 @@
return allowedCallingPackages.isEmpty() ? null : allowedCallingPackages.get(0);
}
- private boolean isRuleProvider(String installerPackageName) {
- for (String ruleProvider : getAllowedRuleProviderSystemApps()) {
- if (ruleProvider.matches(installerPackageName)) {
- return true;
- }
- }
- return false;
- }
-
private List<String> getAllowedRuleProviderSystemApps() {
List<String> integrityRuleProviders =
Arrays.asList(
@@ -751,14 +286,6 @@
}
}
- private boolean integrityCheckIncludesRuleProvider() {
- return Settings.Global.getInt(
- mContext.getContentResolver(),
- Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
- 0)
- == 1;
- }
-
private List<String> getPackageListForUid(int uid) {
try {
return Arrays.asList(mContext.getPackageManager().getPackagesForUid(uid));
diff --git a/services/core/java/com/android/server/net/OWNERS b/services/core/java/com/android/server/net/OWNERS
index bbc7c01..4596a44 100644
--- a/services/core/java/com/android/server/net/OWNERS
+++ b/services/core/java/com/android/server/net/OWNERS
@@ -2,7 +2,5 @@
file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
per-file NetworkPolicyManagerService.java=jackyu@google.com, sarahchin@google.com
-jsharkey@android.com
sudheersai@google.com
-yamasani@google.com
suprabh@google.com
diff --git a/services/core/java/com/android/server/security/advancedprotection/OWNERS b/services/core/java/com/android/server/security/advancedprotection/OWNERS
new file mode 100644
index 0000000..9bf5e58
--- /dev/null
+++ b/services/core/java/com/android/server/security/advancedprotection/OWNERS
@@ -0,0 +1 @@
+file:platform/frameworks/base:main:/core/java/android/security/advancedprotection/OWNERS
diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java
index 6a4c9c2..a492a72 100644
--- a/services/core/java/com/android/server/vcn/VcnContext.java
+++ b/services/core/java/com/android/server/vcn/VcnContext.java
@@ -70,10 +70,6 @@
return mIsInTestMode;
}
- public boolean isFlagNetworkMetricMonitorEnabled() {
- return mFeatureFlags.networkMetricMonitor();
- }
-
public boolean isFlagIpSecTransformStateEnabled() {
// TODO: b/328844044: Ideally this code should gate the behavior by checking the
// android.net.platform.flags.ipsec_transform_state flag but that flag is not accessible
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index b574782..a81ad22 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -1913,7 +1913,6 @@
mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform);
if (direction == IpSecManager.DIRECTION_IN
- && mVcnContext.isFlagNetworkMetricMonitorEnabled()
&& mVcnContext.isFlagIpSecTransformStateEnabled()) {
mUnderlyingNetworkController.updateInboundTransform(mUnderlying, transform);
}
diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
index b9b1060..0d4c373 100644
--- a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
+++ b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
@@ -62,12 +62,6 @@
@Nullable PersistableBundleWrapper carrierConfig,
@NonNull NetworkMetricMonitorCallback callback)
throws IllegalAccessException {
- if (!vcnContext.isFlagNetworkMetricMonitorEnabled()) {
- // Caller error
- logWtf("networkMetricMonitor flag disabled");
- throw new IllegalAccessException("networkMetricMonitor flag disabled");
- }
-
mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext");
mNetwork = Objects.requireNonNull(network, "Missing network");
mCallback = Objects.requireNonNull(callback, "Missing callback");
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
index 2b0ca08..ad5bc72 100644
--- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
@@ -204,8 +204,7 @@
List<NetworkCallback> oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks);
mCellBringupCallbacks.clear();
- if (mVcnContext.isFlagNetworkMetricMonitorEnabled()
- && mVcnContext.isFlagIpSecTransformStateEnabled()) {
+ if (mVcnContext.isFlagIpSecTransformStateEnabled()) {
for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) {
evaluator.close();
}
@@ -431,8 +430,7 @@
.getAllSubIdsInGroup(mSubscriptionGroup)
.equals(newSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))) {
- if (mVcnContext.isFlagNetworkMetricMonitorEnabled()
- && mVcnContext.isFlagIpSecTransformStateEnabled()) {
+ if (mVcnContext.isFlagIpSecTransformStateEnabled()) {
reevaluateNetworks();
}
return;
@@ -447,8 +445,7 @@
*/
public void updateInboundTransform(
@NonNull UnderlyingNetworkRecord currentNetwork, @NonNull IpSecTransform transform) {
- if (!mVcnContext.isFlagNetworkMetricMonitorEnabled()
- || !mVcnContext.isFlagIpSecTransformStateEnabled()) {
+ if (!mVcnContext.isFlagIpSecTransformStateEnabled()) {
logWtf("#updateInboundTransform: unexpected call; flags missing");
return;
}
@@ -575,8 +572,7 @@
@Override
public void onLost(@NonNull Network network) {
- if (mVcnContext.isFlagNetworkMetricMonitorEnabled()
- && mVcnContext.isFlagIpSecTransformStateEnabled()) {
+ if (mVcnContext.isFlagIpSecTransformStateEnabled()) {
mUnderlyingNetworkRecords.get(network).close();
}
@@ -652,8 +648,7 @@
class NetworkEvaluatorCallbackImpl implements NetworkEvaluatorCallback {
@Override
public void onEvaluationResultChanged() {
- if (!mVcnContext.isFlagNetworkMetricMonitorEnabled()
- || !mVcnContext.isFlagIpSecTransformStateEnabled()) {
+ if (!mVcnContext.isFlagIpSecTransformStateEnabled()) {
logWtf("#onEvaluationResultChanged: unexpected call; flags missing");
return;
}
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java
index c852fb4..53b0751 100644
--- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java
@@ -193,8 +193,7 @@
}
private static boolean isIpSecPacketLossDetectorEnabled(VcnContext vcnContext) {
- return vcnContext.isFlagIpSecTransformStateEnabled()
- && vcnContext.isFlagNetworkMetricMonitorEnabled();
+ return vcnContext.isFlagIpSecTransformStateEnabled();
}
/** Get the comparator for UnderlyingNetworkEvaluator */
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7b27084..cbf6c5a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5807,9 +5807,9 @@
}
private boolean canMoveTaskToBack(Task task) {
- // Checks whether a task is a child of this task because it can be reparetned when
+ // Checks whether a task is a child of this task because it can be reparented when
// transition is deferred.
- if (task != this && task.getParent() != this) {
+ if (task != this && !task.isDescendantOf(this)) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 5e9fdd8..a64bab1 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -122,7 +122,7 @@
private int mRapidActivityLaunchCount;
// all about the first app in the process
- final ApplicationInfo mInfo;
+ volatile ApplicationInfo mInfo;
final String mName;
final int mUid;
@@ -1789,12 +1789,17 @@
Configuration overrideConfig = new Configuration(r.getRequestedOverrideConfiguration());
overrideConfig.assetsSeq = assetSeq;
r.onRequestedOverrideConfigurationChanged(overrideConfig);
+ r.updateApplicationInfo(mInfo);
if (r.isVisibleRequested()) {
r.ensureActivityConfiguration();
}
}
}
+ public void updateApplicationInfo(ApplicationInfo aInfo) {
+ mInfo = aInfo;
+ }
+
/**
* This is called for sending {@link android.app.servertransaction.LaunchActivityItem}.
* The caller must call {@link #setLastReportedConfiguration} if the delivered configuration
diff --git a/services/java/com/android/server/flags.aconfig b/services/java/com/android/server/flags.aconfig
index 38354e8..41a9646 100644
--- a/services/java/com/android/server/flags.aconfig
+++ b/services/java/com/android/server/flags.aconfig
@@ -10,6 +10,14 @@
}
flag {
+ name: "remove_java_service_manager_cache"
+ namespace: "system_performance"
+ description: "This flag turns off Java's Service Manager caching mechanism."
+ bug: "333854840"
+ is_fixed_read_only: true
+}
+
+flag {
name: "remove_text_service"
namespace: "wear_frameworks"
description: "Remove TextServiceManagerService on Wear"
diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
index 8b65337..32135f1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
@@ -22,9 +22,10 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
@@ -36,6 +37,7 @@
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.os.Process;
+import android.os.RemoteException;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
@@ -137,9 +139,17 @@
mSensitiveContentProtectionManagerService.mNotificationListener =
spy(mSensitiveContentProtectionManagerService.mNotificationListener);
- doCallRealMethod()
- .when(mSensitiveContentProtectionManagerService.mNotificationListener)
- .onListenerConnected();
+
+ // Unexpected NLS interactions when registered cause test flakes. For purposes of this test,
+ // the test will control any NLS calls.
+ try {
+ doNothing().when(mSensitiveContentProtectionManagerService.mNotificationListener)
+ .registerAsSystemService(any(), any(), anyInt());
+ doNothing().when(mSensitiveContentProtectionManagerService.mNotificationListener)
+ .unregisterAsSystemService();
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
// Setup RankingMap and two possilbe rankings
when(mSensitiveRanking.hasSensitiveContent()).thenReturn(true);
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/OWNERS b/services/tests/mockingservicestests/src/com/android/server/alarm/OWNERS
index 6f207fb1..6eb986b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/OWNERS
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/OWNERS
@@ -1 +1 @@
-include /apex/jobscheduler/OWNERS
+include /apex/jobscheduler/ALARM_OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/OWNERS b/services/tests/mockingservicestests/src/com/android/server/job/OWNERS
index 6f207fb1..c8345f7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/OWNERS
+++ b/services/tests/mockingservicestests/src/com/android/server/job/OWNERS
@@ -1 +1 @@
-include /apex/jobscheduler/OWNERS
+include /apex/jobscheduler/JOB_OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/OWNERS b/services/tests/servicestests/src/com/android/server/OWNERS
index d49bc43..d8a9400 100644
--- a/services/tests/servicestests/src/com/android/server/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/OWNERS
@@ -1,4 +1,4 @@
-per-file *Alarm* = file:/apex/jobscheduler/OWNERS
+per-file *Alarm* = file:/apex/jobscheduler/ALARM_OWNERS
per-file *AppOp* = file:/core/java/android/permission/OWNERS
per-file *BinaryTransparency* = file:/core/java/android/transparency/OWNERS
per-file *Bluetooth* = file:platform/packages/modules/Bluetooth:master:/framework/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index d1f6c2f..9c6412b 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -67,10 +67,8 @@
import androidx.test.InstrumentationRegistry;
import com.android.internal.R;
-import com.android.internal.pm.parsing.PackageParser2;
import com.android.server.compat.PlatformCompat;
import com.android.server.integrity.model.IntegrityCheckResult;
-import com.android.server.pm.parsing.TestPackageParser2;
import com.android.server.testutils.TestUtils;
import org.junit.After;
@@ -140,8 +138,6 @@
@Mock IntegrityFileManager mIntegrityFileManager;
@Mock Handler mHandler;
- private Supplier<PackageParser2> mParserSupplier = TestPackageParser2::new;
-
private final Context mRealContext = InstrumentationRegistry.getTargetContext();
private PackageManager mSpyPackageManager;
@@ -173,7 +169,6 @@
new AppIntegrityManagerServiceImpl(
mMockContext,
mPackageManagerInternal,
- mParserSupplier,
mIntegrityFileManager,
mHandler);
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigReadOnlyFeaturesTest.kt b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigReadOnlyFeaturesTest.kt
new file mode 100644
index 0000000..22d894a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigReadOnlyFeaturesTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2024 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.systemconfig
+
+import android.content.Context
+import android.content.pm.FeatureInfo
+import android.util.ArrayMap
+import android.util.Xml
+
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.SystemConfig
+import com.google.common.truth.Truth.assertThat
+import org.junit.runner.RunWith
+import org.junit.Rule
+
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class SystemConfigReadOnlyFeaturesTest {
+
+ companion object {
+ private const val FEATURE_ONE = "feature.test.1"
+ private const val FEATURE_TWO = "feature.test.2"
+ private const val FEATURE_RUNTIME_AVAILABLE_TEMPLATE =
+ """
+ <permissions>
+ <feature name="%s" />
+ </permissions>
+ """
+ private const val FEATURE_RUNTIME_DISABLED_TEMPLATE =
+ """
+ <permissions>
+ <Disabled-feature name="%s" />
+ </permissions>
+ """
+
+ fun featureInfo(featureName: String) = FeatureInfo().apply { name = featureName }
+ }
+
+ private val context: Context = InstrumentationRegistry.getInstrumentation().context
+
+ @get:Rule
+ val tempFolder = TemporaryFolder(context.filesDir)
+
+ private val injector = TestInjector()
+
+ private var uniqueCounter = 0
+
+ @Test
+ fun empty() {
+ assertFeatures().isEmpty()
+ }
+
+ @Test
+ fun readOnlyEnabled() {
+ addReadOnlyEnabledFeature(FEATURE_ONE)
+ addReadOnlyEnabledFeature(FEATURE_TWO)
+
+ assertFeatures().containsAtLeast(FEATURE_ONE, FEATURE_TWO)
+ }
+
+ @Test
+ fun readOnlyAndRuntimeEnabled() {
+ addReadOnlyEnabledFeature(FEATURE_ONE)
+ addRuntimeEnabledFeature(FEATURE_TWO)
+
+ // No issues with matching availability.
+ assertFeatures().containsAtLeast(FEATURE_ONE, FEATURE_TWO)
+ }
+
+ @Test
+ fun readOnlyEnabledRuntimeDisabled() {
+ addReadOnlyEnabledFeature(FEATURE_ONE)
+ addRuntimeDisabledFeature(FEATURE_ONE)
+
+ // Read-only feature availability should take precedence.
+ assertFeatures().contains(FEATURE_ONE)
+ }
+
+ @Test
+ fun readOnlyDisabled() {
+ addReadOnlyDisabledFeature(FEATURE_ONE)
+
+ assertFeatures().doesNotContain(FEATURE_ONE)
+ }
+
+ @Test
+ fun readOnlyAndRuntimeDisabled() {
+ addReadOnlyDisabledFeature(FEATURE_ONE)
+ addRuntimeDisabledFeature(FEATURE_ONE)
+
+ // No issues with matching (un)availability.
+ assertFeatures().doesNotContain(FEATURE_ONE)
+ }
+
+ @Test
+ fun readOnlyDisabledRuntimeEnabled() {
+ addReadOnlyDisabledFeature(FEATURE_ONE)
+ addRuntimeEnabledFeature(FEATURE_ONE)
+ addRuntimeEnabledFeature(FEATURE_TWO)
+
+ // Read-only feature (un)availability should take precedence.
+ assertFeatures().doesNotContain(FEATURE_ONE)
+ assertFeatures().contains(FEATURE_TWO)
+ }
+
+ fun addReadOnlyEnabledFeature(featureName: String) {
+ injector.readOnlyEnabledFeatures[featureName] = featureInfo(featureName)
+ }
+
+ fun addReadOnlyDisabledFeature(featureName: String) {
+ injector.readOnlyDisabledFeatures.add(featureName)
+ }
+
+ fun addRuntimeEnabledFeature(featureName: String) {
+ FEATURE_RUNTIME_AVAILABLE_TEMPLATE.format(featureName).write()
+ }
+
+ fun addRuntimeDisabledFeature(featureName: String) {
+ FEATURE_RUNTIME_DISABLED_TEMPLATE.format(featureName).write()
+ }
+
+ private fun String.write() = tempFolder.root.resolve("${uniqueCounter++}.xml")
+ .writeText(this.trimIndent())
+
+ private fun assertFeatures() = assertThat(availableFeatures().keys)
+
+ private fun availableFeatures() = SystemConfig(false, injector).apply {
+ val parser = Xml.newPullParser()
+ readPermissions(parser, tempFolder.root, /*Grant all permission flags*/ 0.inv())
+ }.let { it.availableFeatures }
+
+ internal class TestInjector() : SystemConfig.Injector() {
+ val readOnlyEnabledFeatures = ArrayMap<String, FeatureInfo>()
+ val readOnlyDisabledFeatures = mutableSetOf<String>()
+
+ override fun isReadOnlySystemEnabledFeature(featureName: String, version: Int): Boolean {
+ return readOnlyEnabledFeatures.containsKey(featureName)
+ }
+
+ override fun isReadOnlySystemDisabledFeature(featureName: String, version: Int): Boolean {
+ return readOnlyDisabledFeatures.contains(featureName)
+ }
+
+ override fun getReadOnlySystemEnabledFeatures(): ArrayMap<String, FeatureInfo> {
+ return readOnlyEnabledFeatures
+ }
+ }
+}
diff --git a/services/usage/OWNERS b/services/usage/OWNERS
index f825f55..678c7ac 100644
--- a/services/usage/OWNERS
+++ b/services/usage/OWNERS
@@ -3,7 +3,6 @@
mwachens@google.com
varunshah@google.com
-yamasani@google.com
guanxin@google.com
per-file *StorageStats* = file:/core/java/android/os/storage/OWNERS
diff --git a/tests/JobSchedulerPerfTests/OWNERS b/tests/JobSchedulerPerfTests/OWNERS
index 6f207fb1..c8345f7 100644
--- a/tests/JobSchedulerPerfTests/OWNERS
+++ b/tests/JobSchedulerPerfTests/OWNERS
@@ -1 +1 @@
-include /apex/jobscheduler/OWNERS
+include /apex/jobscheduler/JOB_OWNERS
diff --git a/tests/JobSchedulerTestApp/OWNERS b/tests/JobSchedulerTestApp/OWNERS
index 6f207fb1..c8345f7 100644
--- a/tests/JobSchedulerTestApp/OWNERS
+++ b/tests/JobSchedulerTestApp/OWNERS
@@ -1 +1 @@
-include /apex/jobscheduler/OWNERS
+include /apex/jobscheduler/JOB_OWNERS
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index e29e462..e045f10 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -224,7 +224,6 @@
doReturn(mFeatureFlags).when(mVcnContext).getFeatureFlags();
doReturn(true).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled();
doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled();
- doReturn(true).when(mVcnContext).isFlagNetworkMetricMonitorEnabled();
doReturn(mUnderlyingNetworkController)
.when(mDeps)
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
index 421e1ad..bc7ff47 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
@@ -127,7 +127,6 @@
false /* isInTestMode */));
doNothing().when(mVcnContext).ensureRunningOnLooperThread();
- doReturn(true).when(mVcnContext).isFlagNetworkMetricMonitorEnabled();
doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled();
setupSystemService(
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
index 588624b..6f31d8d 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
@@ -226,7 +226,6 @@
private void resetVcnContext(VcnContext vcnContext) {
reset(vcnContext);
doNothing().when(vcnContext).ensureRunningOnLooperThread();
- doReturn(true).when(vcnContext).isFlagNetworkMetricMonitorEnabled();
doReturn(true).when(vcnContext).isFlagIpSecTransformStateEnabled();
}
diff --git a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
index cba521e..196b5e7 100644
--- a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
+++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
@@ -22,8 +22,6 @@
import com.squareup.javapoet.MethodSpec
import com.squareup.javapoet.ParameterizedTypeName
import com.squareup.javapoet.TypeSpec
-import java.util.HashMap
-import java.util.Map
import javax.lang.model.element.Modifier
/*
@@ -52,7 +50,7 @@
* public static boolean hasFeatureAutomotive(Context context);
* public static boolean hasFeatureLeanback(Context context);
* public static Boolean maybeHasFeature(String feature, int version);
- * public static ArrayMap<String, FeatureInfo> getCompileTimeAvailableFeatures();
+ * public static ArrayMap<String, FeatureInfo> getReadOnlySystemEnabledFeatures();
* }
* </pre>
*/
@@ -63,6 +61,7 @@
private val PACKAGEMANAGER_CLASS = ClassName.get("android.content.pm", "PackageManager")
private val CONTEXT_CLASS = ClassName.get("android.content", "Context")
private val FEATUREINFO_CLASS = ClassName.get("android.content.pm", "FeatureInfo")
+ private val ARRAYMAP_CLASS = ClassName.get("android.util", "ArrayMap")
private val ASSUME_TRUE_CLASS =
ClassName.get("com.android.aconfig.annotations", "AssumeTrueForR8")
private val ASSUME_FALSE_CLASS =
@@ -291,19 +290,19 @@
features: Collection<FeatureInfo>,
) {
val methodBuilder =
- MethodSpec.methodBuilder("getCompileTimeAvailableFeatures")
+ MethodSpec.methodBuilder("getReadOnlySystemEnabledFeatures")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addAnnotation(ClassName.get("android.annotation", "NonNull"))
.addJavadoc("Gets features marked as available at compile-time, keyed by name." +
"\n\n@hide")
.returns(ParameterizedTypeName.get(
- ClassName.get(Map::class.java),
+ ARRAYMAP_CLASS,
ClassName.get(String::class.java),
FEATUREINFO_CLASS))
val availableFeatures = features.filter { it.readonly && it.version != null }
- methodBuilder.addStatement("Map<String, FeatureInfo> features = new \$T<>(\$L)",
- HashMap::class.java, availableFeatures.size)
+ methodBuilder.addStatement("\$T<String, FeatureInfo> features = new \$T<>(\$L)",
+ ARRAYMAP_CLASS, ARRAYMAP_CLASS, availableFeatures.size)
if (!availableFeatures.isEmpty()) {
methodBuilder.addStatement("FeatureInfo fi = new FeatureInfo()")
}
diff --git a/tools/systemfeatures/tests/golden/RoFeatures.java.gen b/tools/systemfeatures/tests/golden/RoFeatures.java.gen
index edbfc42..ee97b26 100644
--- a/tools/systemfeatures/tests/golden/RoFeatures.java.gen
+++ b/tools/systemfeatures/tests/golden/RoFeatures.java.gen
@@ -13,10 +13,9 @@
import android.content.Context;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
+import android.util.ArrayMap;
import com.android.aconfig.annotations.AssumeFalseForR8;
import com.android.aconfig.annotations.AssumeTrueForR8;
-import java.util.HashMap;
-import java.util.Map;
/**
* @hide
@@ -94,8 +93,8 @@
* @hide
*/
@NonNull
- public static Map<String, FeatureInfo> getCompileTimeAvailableFeatures() {
- Map<String, FeatureInfo> features = new HashMap<>(2);
+ public static ArrayMap<String, FeatureInfo> getReadOnlySystemEnabledFeatures() {
+ ArrayMap<String, FeatureInfo> features = new ArrayMap<>(2);
FeatureInfo fi = new FeatureInfo();
fi.name = PackageManager.FEATURE_WATCH;
fi.version = 1;
diff --git a/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen b/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen
index bf7a006..40c7db7 100644
--- a/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen
+++ b/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen
@@ -9,8 +9,7 @@
import android.content.Context;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
-import java.util.HashMap;
-import java.util.Map;
+import android.util.ArrayMap;
/**
* @hide
@@ -43,8 +42,8 @@
* @hide
*/
@NonNull
- public static Map<String, FeatureInfo> getCompileTimeAvailableFeatures() {
- Map<String, FeatureInfo> features = new HashMap<>(0);
+ public static ArrayMap<String, FeatureInfo> getReadOnlySystemEnabledFeatures() {
+ ArrayMap<String, FeatureInfo> features = new ArrayMap<>(0);
return features;
}
}
diff --git a/tools/systemfeatures/tests/golden/RwFeatures.java.gen b/tools/systemfeatures/tests/golden/RwFeatures.java.gen
index b20b228..7bf8961 100644
--- a/tools/systemfeatures/tests/golden/RwFeatures.java.gen
+++ b/tools/systemfeatures/tests/golden/RwFeatures.java.gen
@@ -12,8 +12,7 @@
import android.content.Context;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
-import java.util.HashMap;
-import java.util.Map;
+import android.util.ArrayMap;
/**
* @hide
@@ -73,8 +72,8 @@
* @hide
*/
@NonNull
- public static Map<String, FeatureInfo> getCompileTimeAvailableFeatures() {
- Map<String, FeatureInfo> features = new HashMap<>(0);
+ public static ArrayMap<String, FeatureInfo> getReadOnlySystemEnabledFeatures() {
+ ArrayMap<String, FeatureInfo> features = new ArrayMap<>(0);
return features;
}
}
diff --git a/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen b/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen
index d91f5b6..eb7ec63 100644
--- a/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen
+++ b/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen
@@ -7,8 +7,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.FeatureInfo;
-import java.util.HashMap;
-import java.util.Map;
+import android.util.ArrayMap;
/**
* @hide
@@ -32,8 +31,8 @@
* @hide
*/
@NonNull
- public static Map<String, FeatureInfo> getCompileTimeAvailableFeatures() {
- Map<String, FeatureInfo> features = new HashMap<>(0);
+ public static ArrayMap<String, FeatureInfo> getReadOnlySystemEnabledFeatures() {
+ ArrayMap<String, FeatureInfo> features = new ArrayMap<>(0);
return features;
}
}
diff --git a/tools/systemfeatures/tests/src/ArrayMap.java b/tools/systemfeatures/tests/src/ArrayMap.java
new file mode 100644
index 0000000..a5ed9b0
--- /dev/null
+++ b/tools/systemfeatures/tests/src/ArrayMap.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.util;
+
+import java.util.HashMap;
+
+/** Stub for testing. */
+public final class ArrayMap<K, V> extends HashMap<K, V> {
+ public ArrayMap(int capacity) {
+ super(capacity);
+ }
+}
diff --git a/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java
index 39f8fc4..ed3f5c9 100644
--- a/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java
+++ b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java
@@ -60,7 +60,7 @@
assertThat(RwNoFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, 0)).isNull();
assertThat(RwNoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 0)).isNull();
assertThat(RwNoFeatures.maybeHasFeature("com.arbitrary.feature", 0)).isNull();
- assertThat(RwNoFeatures.getCompileTimeAvailableFeatures()).isEmpty();
+ assertThat(RwNoFeatures.getReadOnlySystemEnabledFeatures()).isEmpty();
}
@Test
@@ -72,7 +72,7 @@
assertThat(RoNoFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, 0)).isNull();
assertThat(RoNoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 0)).isNull();
assertThat(RoNoFeatures.maybeHasFeature("com.arbitrary.feature", 0)).isNull();
- assertThat(RoNoFeatures.getCompileTimeAvailableFeatures()).isEmpty();
+ assertThat(RoNoFeatures.getReadOnlySystemEnabledFeatures()).isEmpty();
// Also ensure we fall back to the PackageManager for feature APIs without an accompanying
// versioned feature definition.
@@ -106,7 +106,7 @@
assertThat(RwFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, 0)).isNull();
assertThat(RwFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 0)).isNull();
assertThat(RwFeatures.maybeHasFeature("com.arbitrary.feature", 0)).isNull();
- assertThat(RwFeatures.getCompileTimeAvailableFeatures()).isEmpty();
+ assertThat(RwFeatures.getReadOnlySystemEnabledFeatures()).isEmpty();
}
@Test
@@ -163,7 +163,7 @@
assertThat(RoFeatures.maybeHasFeature("com.arbitrary.feature", 100)).isNull();
assertThat(RoFeatures.maybeHasFeature("", 0)).isNull();
- Map<String, FeatureInfo> compiledFeatures = RoFeatures.getCompileTimeAvailableFeatures();
+ Map<String, FeatureInfo> compiledFeatures = RoFeatures.getReadOnlySystemEnabledFeatures();
assertThat(compiledFeatures.keySet())
.containsExactly(PackageManager.FEATURE_WATCH, PackageManager.FEATURE_WIFI);
assertThat(compiledFeatures.get(PackageManager.FEATURE_WATCH).version).isEqualTo(1);