diff --git a/core/java/com/android/internal/config/appcloning/AppCloningDeviceConfigHelper.java b/core/java/com/android/internal/config/appcloning/AppCloningDeviceConfigHelper.java new file mode 100644 index 0000000000000..ddd3d2cf3aed0 --- /dev/null +++ b/core/java/com/android/internal/config/appcloning/AppCloningDeviceConfigHelper.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2023 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.internal.config.appcloning; + +import android.content.Context; +import android.provider.DeviceConfig; + +import com.android.internal.annotations.GuardedBy; + +/** + * Helper class that holds the flags related to the app_cloning namespace in {@link DeviceConfig}. + * + * @hide + */ +public class AppCloningDeviceConfigHelper { + + @GuardedBy("sLock") + private static AppCloningDeviceConfigHelper sInstance; + + private static final Object sLock = new Object(); + + private DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangeListener; + + /** + * This flag is defined inside {@link DeviceConfig#NAMESPACE_APP_CLONING}. Please check + * {@link #mEnableAppCloningBuildingBlocks} for details. + */ + public static final String ENABLE_APP_CLONING_BUILDING_BLOCKS = + "enable_app_cloning_building_blocks"; + + /** + * Checks whether the support for app-cloning building blocks (like contacts + * sharing/intent redirection), which are available starting from the U release, is turned on. + * The default value is true to ensure the features are always enabled going forward. + * + * TODO:(b/253449368) Add information about the app-cloning config and mention that the devices + * that do not support app-cloning should use the app-cloning config to disable all app-cloning + * features. + */ + private volatile boolean mEnableAppCloningBuildingBlocks = true; + + private AppCloningDeviceConfigHelper() {} + + /** + * @hide + */ + public static AppCloningDeviceConfigHelper getInstance(Context context) { + synchronized (sLock) { + if (sInstance == null) { + sInstance = new AppCloningDeviceConfigHelper(); + sInstance.init(context); + } + return sInstance; + } + } + + private void init(Context context) { + initializeDeviceConfigChangeListener(); + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APP_CLONING, + context.getMainExecutor(), + mDeviceConfigChangeListener); + } + + private void initializeDeviceConfigChangeListener() { + mDeviceConfigChangeListener = properties -> { + if (!DeviceConfig.NAMESPACE_APP_CLONING.equals(properties.getNamespace())) { + return; + } + for (String name : properties.getKeyset()) { + if (name == null) { + return; + } + if (ENABLE_APP_CLONING_BUILDING_BLOCKS.equals(name)) { + updateEnableAppCloningBuildingBlocks(); + } + } + }; + } + + private void updateEnableAppCloningBuildingBlocks() { + mEnableAppCloningBuildingBlocks = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_APP_CLONING, ENABLE_APP_CLONING_BUILDING_BLOCKS, true); + } + + /** + * Fetch the feature flag to check whether the support for the app-cloning building blocks + * (like contacts sharing/intent redirection) is enabled on the device. + * @hide + */ + public boolean getEnableAppCloningBuildingBlocks() { + return mEnableAppCloningBuildingBlocks; + } +} diff --git a/core/java/com/android/internal/config/appcloning/OWNERS b/core/java/com/android/internal/config/appcloning/OWNERS new file mode 100644 index 0000000000000..0645a8c544142 --- /dev/null +++ b/core/java/com/android/internal/config/appcloning/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 1207885 +jigarthakkar@google.com +saumyap@google.com \ No newline at end of file diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index a339756c5ccbb..3e31bd1e820f1 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -104,6 +104,7 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; +import com.android.internal.config.appcloning.AppCloningDeviceConfigHelper; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.BackgroundThread; @@ -256,6 +257,8 @@ public class SyncManager { private final SyncLogger mLogger; + private final AppCloningDeviceConfigHelper mAppCloningDeviceConfigHelper; + private boolean isJobIdInUseLockedH(int jobId, List pendingJobs) { for (int i = 0, size = pendingJobs.size(); i < size; i++) { JobInfo job = pendingJobs.get(i); @@ -681,6 +684,7 @@ public class SyncManager { }, mSyncHandler); mConstants = new SyncManagerConstants(context); + mAppCloningDeviceConfigHelper = AppCloningDeviceConfigHelper.getInstance(context); IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); context.registerReceiver(mConnectivityIntentReceiver, intentFilter); @@ -888,7 +892,8 @@ public class SyncManager { * @return true/false if contact sharing is enabled/disabled */ protected boolean isContactSharingAllowedForCloneProfile() { - return mContext.getResources().getBoolean(R.bool.config_enableAppCloningBuildingBlocks); + return mContext.getResources().getBoolean(R.bool.config_enableAppCloningBuildingBlocks) + && mAppCloningDeviceConfigHelper.getEnableAppCloningBuildingBlocks(); } /** diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java index e149b04a3e4b9..b5c04171e3127 100644 --- a/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java +++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolverEngine.java @@ -37,6 +37,7 @@ import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import com.android.internal.config.appcloning.AppCloningDeviceConfigHelper; import com.android.server.LocalServices; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; @@ -61,6 +62,8 @@ public class CrossProfileIntentResolverEngine { private final Context mContext; private final UserManagerInternal mUserManagerInternal; + private AppCloningDeviceConfigHelper mAppCloningDeviceConfigHelper; + public CrossProfileIntentResolverEngine(UserManagerService userManager, DomainVerificationManagerInternal domainVerificationManager, DefaultAppProvider defaultAppProvider, Context context) { @@ -250,7 +253,12 @@ public class CrossProfileIntentResolverEngine { * We would return NoFilteringResolver only if it is allowed(feature flag is set). */ if (shouldUseNoFilteringResolver(sourceUserId, targetUserId)) { - if (NoFilteringResolver.isIntentRedirectionAllowed(mContext, resolveForStart, flags)) { + if (mAppCloningDeviceConfigHelper == null) { + //lazy initialization of helper till required, to improve performance. + mAppCloningDeviceConfigHelper = AppCloningDeviceConfigHelper.getInstance(mContext); + } + if (NoFilteringResolver.isIntentRedirectionAllowed(mContext, + mAppCloningDeviceConfigHelper, resolveForStart, flags)) { return new NoFilteringResolver(computer.getComponentResolver(), mUserManager); } else { diff --git a/services/core/java/com/android/server/pm/NoFilteringResolver.java b/services/core/java/com/android/server/pm/NoFilteringResolver.java index 817e1f6e2e5a1..b87256dbbd9a6 100644 --- a/services/core/java/com/android/server/pm/NoFilteringResolver.java +++ b/services/core/java/com/android/server/pm/NoFilteringResolver.java @@ -24,6 +24,7 @@ import android.content.pm.ResolveInfo; import android.os.Binder; import com.android.internal.R; +import com.android.internal.config.appcloning.AppCloningDeviceConfigHelper; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.resolution.ComponentResolverApi; import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; @@ -56,9 +57,10 @@ public class NoFilteringResolver extends CrossProfileResolver { * (PackageManager.MATCH_CLONE_PROFILE) bit set. * @return true if resolver would be used for cross profile resolution. */ - public static boolean isIntentRedirectionAllowed(Context context, boolean resolveForStart, + public static boolean isIntentRedirectionAllowed(Context context, + AppCloningDeviceConfigHelper appCloningDeviceConfigHelper, boolean resolveForStart, long flags) { - return isAppCloningBuildingBlocksEnabled(context) + return isAppCloningBuildingBlocksEnabled(context, appCloningDeviceConfigHelper) && (resolveForStart || (((flags & PackageManager.MATCH_CLONE_PROFILE) != 0) && hasPermission(context, Manifest.permission.QUERY_CLONED_APPS))); } @@ -140,12 +142,14 @@ public class NoFilteringResolver extends CrossProfileResolver { } /** - * Checks if the AppCloningBuildingBlocks config is enabled. + * Checks if the AppCloningBuildingBlocks flag is enabled. */ - private static boolean isAppCloningBuildingBlocksEnabled(Context context) { + private static boolean isAppCloningBuildingBlocksEnabled(Context context, + AppCloningDeviceConfigHelper appCloningDeviceConfigHelper) { final long token = Binder.clearCallingIdentity(); try { - return context.getResources().getBoolean(R.bool.config_enableAppCloningBuildingBlocks); + return context.getResources().getBoolean(R.bool.config_enableAppCloningBuildingBlocks) + && appCloningDeviceConfigHelper.getEnableAppCloningBuildingBlocks(); } finally { Binder.restoreCallingIdentity(token); }