Added support for dynamic RRO
Also added overlayable.xml file
Remaining task:
Convert overlay from seahwak, cuttlefish and emulator into static RRO.
Bug: 198516172
Test: Checked the following manually:
1. config_car_bugreport_application value updated correctly for emulator for both user and user debug build
2. userDebug build
overlay package name: com.android.car.resources.vendor
targetPackageName: com.android.car.updatable
3. user build
overlay package name: com.google.android.car.resources.vendor
targetPackageName: com.google.android.car.updatable
Change-Id: Ifa70ba0249dd3c703051276572b851dde203d235
diff --git a/car-builtin-lib/api/module-lib-current.txt b/car-builtin-lib/api/module-lib-current.txt
index 5607976..91de6ab 100644
--- a/car-builtin-lib/api/module-lib-current.txt
+++ b/car-builtin-lib/api/module-lib-current.txt
@@ -78,7 +78,7 @@
method public static boolean isUpdatedSystemApp(@NonNull android.content.pm.ApplicationInfo);
method public static boolean isVendorApp(@NonNull android.content.pm.ApplicationInfo);
method public static void setApplicationEnabledSettingForUser(@NonNull String, int, int, int, @NonNull String) throws android.os.RemoteException;
- field public static final String PROPERTY_CAR_SERVICE_OVERLAY_PACKAGE_NAME = "ro.android.car.service.overlay.package";
+ field public static final String PROPERTY_CAR_SERVICE_OVERLAY_PACKAGES = "ro.android.car.service.overlay.packages";
}
}
diff --git a/car-builtin-lib/src/android/car/builtin/content/pm/PackageManagerHelper.java b/car-builtin-lib/src/android/car/builtin/content/pm/PackageManagerHelper.java
index 5f07e7b..0c3222da 100644
--- a/car-builtin-lib/src/android/car/builtin/content/pm/PackageManagerHelper.java
+++ b/car-builtin-lib/src/android/car/builtin/content/pm/PackageManagerHelper.java
@@ -39,8 +39,17 @@
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class PackageManagerHelper {
- public static final String PROPERTY_CAR_SERVICE_OVERLAY_PACKAGE_NAME =
- "ro.android.car.service.overlay.package";
+ /**
+ * Read only property which contains semicolon (;) separated list of RRO packages.
+ *
+ * <p>
+ * RRO packages would be enabled if they are overlaying {@code CarServiceUpdatable}.
+ * {@code CarServiceUpdatable} can have different package names and this property may include
+ * all RROs to cover different {@code CarServiceUpdatable} package names but only those
+ * overriding the current {@code CarServiceUpdatable} package name will be selected.
+ */
+ public static final String PROPERTY_CAR_SERVICE_OVERLAY_PACKAGES =
+ "ro.android.car.service.overlay.packages";
private PackageManagerHelper() {
throw new UnsupportedOperationException("provides only static methods");
diff --git a/car_product/build/car.mk b/car_product/build/car.mk
index e672d06..61e3cdf 100644
--- a/car_product/build/car.mk
+++ b/car_product/build/car.mk
@@ -119,6 +119,11 @@
PRODUCT_SYSTEM_PROPERTIES += \
persist.wm.enable_remote_keyguard_animation=0
+# TODO(b/198516172): Find a better location to add this read only property
+# It is added here to check the functionality, will be updated in next CL
+PRODUCT_SYSTEM_PROPERTIES += \
+ ro.android.car.service.overlay.packages=com.android.car.resources.vendor;com.google.android.car.resources.vendor;
+
# Automotive specific packages
PRODUCT_PACKAGES += \
CarFrameworkPackageStubs \
diff --git a/car_product/build/preinstalled-packages-product-car-base.xml b/car_product/build/preinstalled-packages-product-car-base.xml
index a04f61c..c9cfd77 100644
--- a/car_product/build/preinstalled-packages-product-car-base.xml
+++ b/car_product/build/preinstalled-packages-product-car-base.xml
@@ -243,6 +243,12 @@
<install-in user-type="SYSTEM" />
</install-in-user-type>
+ <!-- CarService updatable resources -->
+ <install-in-user-type package="com.android.car.resources.vendor">
+ <install-in user-type="FULL" />
+ <install-in user-type="SYSTEM" />
+ </install-in-user-type>
+
<!--
Apps that do need to run on SYSTEM and evaluated by package owner.
Here the apps will have FULL only.
diff --git a/service-builtin/src/com/android/car/UpdatablePackageContext.java b/service-builtin/src/com/android/car/UpdatablePackageContext.java
index 3d247f7..883024c 100644
--- a/service-builtin/src/com/android/car/UpdatablePackageContext.java
+++ b/service-builtin/src/com/android/car/UpdatablePackageContext.java
@@ -16,11 +16,13 @@
package com.android.car;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.car.builtin.content.pm.PackageManagerHelper;
import android.car.builtin.util.Slogf;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.om.OverlayInfo;
import android.content.om.OverlayManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -30,6 +32,11 @@
import android.os.UserHandle;
import android.text.TextUtils;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
/** Context for updatable package */
public class UpdatablePackageContext extends ContextWrapper {
@@ -85,49 +92,124 @@
return info;
}
+ // TODO(b/198516172): Add detailed description for the priority of RROs, who will replace whom.
private static void enableRROForCarServiceUpdatable(Context baseContext) {
- String packageName = SystemProperties.get(
- PackageManagerHelper.PROPERTY_CAR_SERVICE_OVERLAY_PACKAGE_NAME,
- /* default= */ null);
- if (TextUtils.isEmpty(packageName)) {
- // read only property not defined. No need to dynamically overlay resources.
- Slogf.i(TAG, " %s is not set. No need to dynamically overlay resources.",
- PackageManagerHelper.PROPERTY_CAR_SERVICE_OVERLAY_PACKAGE_NAME);
+ List<String> packages = getEligibleRROPackages(baseContext);
+ if (packages.isEmpty()) {
+ Slogf.d(TAG, "No eligible RRO package to enable.");
return;
}
- // check package
- try {
- PackageInfo info = baseContext.getPackageManager().getPackageInfo(packageName, 0);
- if (info == null || info.applicationInfo == null
- || !(PackageManagerHelper.isSystemApp(info.applicationInfo)
- || PackageManagerHelper.isUpdatedSystemApp(info.applicationInfo)
- || PackageManagerHelper.isOemApp(info.applicationInfo)
- || PackageManagerHelper.isOdmApp(info.applicationInfo)
- || PackageManagerHelper.isVendorApp(info.applicationInfo)
- || PackageManagerHelper.isProductApp(info.applicationInfo)
- || PackageManagerHelper.isSystemExtApp(info.applicationInfo))) {
- Slogf.i(TAG, "%s is not usable: %s", packageName, ((info == null)
- ? "package do not exist" : info.applicationInfo));
- return;
- }
- } catch (Exception e) {
- Slogf.w(TAG, e, "couldn't find package: %s", packageName);
- return;
- }
-
- // package is valid. Enable RRO. This class is called for each user, so need to enable RRO
- // for system and current user separately.
+ OverlayManager manager = baseContext.getSystemService(OverlayManager.class);
UserHandle user = baseContext.getUser();
- try {
- OverlayManager manager = baseContext.getSystemService(OverlayManager.class);
- manager.setEnabled(packageName, true, user);
- Slogf.i(TAG, "RRO package %s is enabled for User %s", packageName, user);
- } catch (Exception e) {
- Slogf.w(TAG, e, "RRO package %s is NOT enabled for User %s", packageName, user);
+ for (int i = 0; i < packages.size(); i++) {
+ // This class is called for each user, so need to enable RRO for system and current user
+ // separately.
+ String rroPackageName = packages.get(i);
+ try {
+ manager.setEnabled(rroPackageName, /* enable= */true, user);
+ Slogf.d(TAG, "RRO package %s is enabled for User %s", rroPackageName, user);
+ } catch (Exception e) {
+ Slogf.w(TAG, e, "RRO package %s is NOT enabled for User %s", rroPackageName, user);
+ }
}
}
+ @NonNull
+ private static List<String> getEligibleRROPackages(Context baseContext) {
+ List<String> eligiblePackages = new ArrayList<>();
+
+ String packageNames = SystemProperties.get(
+ PackageManagerHelper.PROPERTY_CAR_SERVICE_OVERLAY_PACKAGES,
+ /* default= */ null);
+ if (TextUtils.isEmpty(packageNames)) {
+ // read only property not defined. No need to dynamically overlay resources.
+ Slogf.d(TAG, " %s is not set. No need to dynamically overlay resources.",
+ PackageManagerHelper.PROPERTY_CAR_SERVICE_OVERLAY_PACKAGES);
+ return eligiblePackages;
+ }
+
+ Set<String> installedRROPackages = getInstalledRROPackages(baseContext);
+
+ if (installedRROPackages.isEmpty()) {
+ return eligiblePackages;
+ }
+
+ String[] packages = packageNames.split(";");
+ String rroPackageName;
+ for (int i = 0; i < packages.length; i++) {
+ rroPackageName = packages[i].trim();
+
+ if (rroPackageName.isEmpty()) {
+ continue;
+ }
+
+ if (!installedRROPackages.contains(rroPackageName)) {
+ Slogf.d(TAG, "RRO package %s is not installed.", rroPackageName);
+ continue;
+ }
+
+ // Check that package is part of the original image. A third party RRO
+ // should not be enabled using this.
+ try {
+ PackageInfo info = baseContext.getPackageManager().getPackageInfo(
+ rroPackageName, 0);
+ // TODO(b/198516172): Move following logic to separate class and test it.
+ if (info == null || info.applicationInfo == null
+ || !(PackageManagerHelper.isSystemApp(info.applicationInfo)
+ || PackageManagerHelper.isUpdatedSystemApp(info.applicationInfo)
+ || PackageManagerHelper.isOemApp(info.applicationInfo)
+ || PackageManagerHelper.isOdmApp(info.applicationInfo)
+ || PackageManagerHelper.isVendorApp(info.applicationInfo)
+ || PackageManagerHelper.isProductApp(info.applicationInfo)
+ || PackageManagerHelper.isSystemExtApp(info.applicationInfo))) {
+ Slogf.d(TAG, "%s is not usable: %s", rroPackageName, ((info == null)
+ ? "package do not exist"
+ : info.applicationInfo));
+ continue;
+ }
+ } catch (Exception e) {
+ Slogf.w(TAG, e, "couldn't find package: %s", rroPackageName);
+ continue;
+ }
+
+ // Add RRO package to the list.
+ Slogf.d(TAG, "RRO package %s is eligible for enabling.", rroPackageName);
+ eligiblePackages.add(rroPackageName);
+ }
+ return eligiblePackages;
+ }
+
+ @NonNull
+ private static Set<String> getInstalledRROPackages(Context baseContext) {
+ Set<String> installedOverlayPackages = new HashSet<>();
+ PackageInfo packageInfo = findUpdatableServicePackage(baseContext);
+ if (packageInfo == null) {
+ return installedOverlayPackages;
+ }
+ String updatablePackageName = packageInfo.packageName;
+
+ OverlayManager manager = baseContext.getSystemService(OverlayManager.class);
+ UserHandle user = baseContext.getUser();
+
+ List<OverlayInfo> installedOverlays = manager.getOverlayInfosForTarget(updatablePackageName,
+ user);
+
+ if (installedOverlays == null || installedOverlays.isEmpty()) {
+ return installedOverlayPackages;
+ }
+
+ for (int i = 0; i < installedOverlays.size(); i++) {
+ OverlayInfo overlayInfo = installedOverlays.get(i);
+ installedOverlayPackages.add(overlayInfo.getPackageName());
+ }
+
+ Slogf.d(TAG, "Total RROs packages for target package %s are %d.", updatablePackageName,
+ installedOverlayPackages.size());
+
+ return installedOverlayPackages;
+ }
+
private UpdatablePackageContext(Context baseContext, Context packageContext) {
super(baseContext);
mPackageContext = packageContext;
diff --git a/service/res/values/overlayable.xml b/service/res/values/overlayable.xml
new file mode 100644
index 0000000..5c11eab
--- /dev/null
+++ b/service/res/values/overlayable.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+
+<!-- These values can be used to control CarService stack behavior/features on individual devices.
+ These can be overridden by OEM's by using an RRO overlay app.
+ See <update APP location> for a sample overlay app. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <overlayable name="CarServiceCustomization">
+ <!-- START VENDOR CUSTOMIZATION -->
+ <policy type="product|system|vendor">
+ <!-- Params from config.xml that can be overlaid -->
+ <item type="bool" name="audioUseDynamicRouting"/>
+ <item type="bool" name="audioUseCarVolumeGroupMuting"/>
+ <item type="bool" name="audioUseHalDuckingSignals"/>
+ <item type="integer" name="audioVolumeAdjustmentContextsVersion"/>
+ <item type="bool" name="audioPersistMasterMuteState"/>
+ <item type="integer" name="audioVolumeKeyEventTimeoutMs"/>
+ <item type="bool" name="displayOffMuteLockAllAudio"/>
+ <item type="bool" name="useDefaultBluetoothConnectionPolicy"/>
+ <item type="string" name="instrumentClusterRendererService" translatable="false"/>
+ <item type="string" name="config_clusterHomeActivity" translatable="false"/>
+ <item type="string" name="rotaryService" translatable="false"/>
+ <item type="bool" name="enableActivityBlockingForSafety"/>
+ <item type="string" name="activityBlockingActivity" translatable="false"/>
+ <item type="string" name="continuousBlankActivity" translatable="false"/>
+ <item type="string" name="activityAllowlist" translatable="false"/>
+ <item type="string" name="systemActivityAllowlist" translatable="false"/>
+ <item type="string" name="activityDenylist" translatable="false"/>
+ <item type="array" name="allowedAppInstallSources" translatable="false"/>
+ <item type="string" name="defaultHomeActivity" translatable="false"/>
+ <item type="integer" name="vmsHalClientMetricsProperty"/>
+ <item type="array" name="vmsPublisherSystemClients" translatable="false"/>
+ <item type="array" name="vmsPublisherUserClients" translatable="false"/>
+ <item type="integer" name="millisecondsBeforeRebindToVmsPublisher"/>
+ <item type="integer" name="acceptableHoursPerOnePercentFlashWear"/>
+ <item type="integer" name="uptimeHoursIntervalBetweenUptimeDataWrite"/>
+ <item type="string" name="activityHandlerForFlashWearChanges" translatable="false"/>
+ <item type="integer" name="ioStatsRefreshRateSeconds"/>
+ <item type="integer" name="ioStatsNumSamplesToStore"/>
+ <item type="integer" name="acceptableWrittenKBytesPerSample"/>
+ <item type="integer" name="acceptableFsyncCallsPerSample"/>
+ <item type="integer" name="maxExcessiveIoSamplesInWindow"/>
+ <item type="integer" name="recurringResourceOverusePeriodInDays"/>
+ <item type="integer" name="recurringResourceOveruseTimes"/>
+ <item type="integer" name="uidIoUsageSummaryTopCount"/>
+ <item type="integer" name="ioUsageSummaryMinSystemTotalWrittenBytes"/>
+ <item type="string" name="intentReceiverForUnacceptableIoMetrics" translatable="false"/>
+ <item type="string" name="eMmcLifetimeFilePath" translatable="false"/>
+ <item type="string" name="eMmcEolFilePath" translatable="false"/>
+ <item type="integer" name="fastPairModelId"/>
+ <item type="string" name="fastPairAntiSpoofKey" translatable="false"/>
+ <item type="bool" name="fastPairAutomaticAcceptance"/>
+ <item type="integer" name="maxGarageModeRunningDurationInSecs"/>
+ <item type="array" name="config_earlyStartupServices" translatable="false"/>
+ <item type="string" name="config_projectionConsentActivity" translatable="false"/>
+ <item type="integer" name="config_projectionActivityDisplayId"/>
+ <item type="array" name="config_projectionActivityLaunchBounds"/>
+ <item type="integer" name="config_projectionUiMode"/>
+ <item type="bool" name="config_projectionAccessPointTethering"/>
+ <item type="bool" name="config_stableLocalOnlyHotspotConfig"/>
+ <item type="string" name="serviceMediaConnection" translatable="false"/>
+ <item type="string" name="config_car_bugreport_application" translatable="false"/>
+ <item type="array" name="config_occupant_zones" translatable="false"/>
+ <item type="array" name="config_occupant_display_mapping" translatable="false"/>
+ <item type="array" name="config_sourcePreferredComponents" translatable="false"/>
+ <item type="string" name="config_userNoticeUiService" translatable="false"/>
+ <item type="integer" name="config_mediaSourceChangedAutoplay"/>
+ <item type="integer" name="config_mediaBootAutoplay"/>
+ <item type="bool" name="config_mediaSourceIndependentPlayback"/>
+ <item type="array" name="config_allowed_optional_car_features" translatable="false"/>
+ <item type="bool" name="enablePassengerSupport"/>
+ <item type="string" name="config_customCountryDetector" translatable="false"/>
+ <item type="bool" name="enableLongPressBluetoothVoiceRecognition"/>
+ <item type="bool" name="config_switchGuestUserBeforeGoingSleep"/>
+ <item type="bool" name="enableProfileUserAssignmentForMultiDisplay"/>
+ <item type="string" name="config_defaultMediaSource" translatable="false"/>
+ <item type="bool" name="config_callButtonEndsOngoingCall"/>
+ <item type="integer" name="config_maxSuspendWaitDuration"/>
+ <item type="integer" name="config_preShutdownPrepareTimeout"/>
+ <item type="integer" name="config_shutdownEnterTimeout"/>
+ <item type="integer" name="config_postShutdownEnterTimeout"/>
+ <item type="string" name="config_evsRearviewCameraId" translatable="false"/>
+ <item type="string" name="config_evsCameraActivity" translatable="false"/>
+ <item type="bool" name="config_wifiAdjustmentForSuspend"/>
+ <item type="bool" name="config_enableCarLocationServiceGnssControlsForPowerManagement"/>
+ <item type="bool" name="config_preventTemplatedAppsFromShowingDialog"/>
+ <item type="string" name="config_template_activity_class_name" translatable="false"/>
+ <item type="bool" name="config_enableExternalCarTimeToExternalTimeSuggestion"/>
+ <!-- Params from config.xml that can be overlaid -->
+ </policy>
+ <!-- END VENDOR CUSTOMIZATION -->
+ </overlayable>
+</resources>
\ No newline at end of file
diff --git a/service/src/com/android/car/pm/CarPackageManagerService.java b/service/src/com/android/car/pm/CarPackageManagerService.java
index bd8948b..e1df7d9 100644
--- a/service/src/com/android/car/pm/CarPackageManagerService.java
+++ b/service/src/com/android/car/pm/CarPackageManagerService.java
@@ -1212,9 +1212,11 @@
writer.println(mCurrentDrivingSafetyRegion);
writer.print("mTempAllowedActivities:");
writer.println(mTempAllowedActivities);
- writer.println("Car service overlay package name: "
+ writer.println("Car service overlay packages property name: "
+ + PackageManagerHelper.PROPERTY_CAR_SERVICE_OVERLAY_PACKAGES);
+ writer.println("Car service overlay packages: "
+ SystemProperties.get(
- PackageManagerHelper.PROPERTY_CAR_SERVICE_OVERLAY_PACKAGE_NAME,
+ PackageManagerHelper.PROPERTY_CAR_SERVICE_OVERLAY_PACKAGES,
/* default= */ null));
}
}