diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java index 8e14c5a44ea..ddc1d775d7c 100644 --- a/src/com/android/settings/homepage/SettingsHomepageActivity.java +++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java @@ -27,9 +27,13 @@ import android.app.ActivityManager; import android.app.settings.SettingsEnums; import android.content.ComponentName; import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.os.Bundle; +import android.os.Process; +import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; @@ -43,6 +47,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.Toolbar; +import androidx.annotation.VisibleForTesting; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowCompat; @@ -65,6 +70,7 @@ import com.android.settings.core.CategoryMixin; import com.android.settings.core.FeatureFlags; import com.android.settings.homepage.contextualcards.ContextualCardsFragment; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.password.PasswordUtils; import com.android.settingslib.Utils; import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; @@ -431,6 +437,31 @@ public class SettingsHomepageActivity extends FragmentActivity implements finish(); return; } + + ActivityInfo targetActivityInfo = null; + try { + targetActivityInfo = getPackageManager().getActivityInfo(targetComponentName, + /* flags= */ 0); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Failed to get target ActivityInfo: " + e); + finish(); + return; + } + + if (!hasPrivilegedAccess(targetActivityInfo)) { + if (!targetActivityInfo.exported) { + Log.e(TAG, "Target Activity is not exported"); + finish(); + return; + } + + if (!isCallingAppPermitted(targetActivityInfo.permission)) { + Log.e(TAG, "Calling app must have the permission of deep link Activity"); + finish(); + return; + } + } + targetIntent.setComponent(targetComponentName); // To prevent launchDeepLinkIntentToRight again for configuration change. @@ -472,6 +503,52 @@ public class SettingsHomepageActivity extends FragmentActivity implements } } + // Check if calling app has privileged access to launch Activity of activityInfo. + private boolean hasPrivilegedAccess(ActivityInfo activityInfo) { + if (TextUtils.equals(PasswordUtils.getCallingAppPackageName(getActivityToken()), + getPackageName())) { + return true; + } + + int callingUid = -1; + try { + callingUid = ActivityManager.getService().getLaunchedFromUid(getActivityToken()); + } catch (RemoteException re) { + Log.e(TAG, "Not able to get callingUid: " + re); + return false; + } + + int targetUid = -1; + try { + targetUid = getPackageManager().getApplicationInfo(activityInfo.packageName, + /* flags= */ 0).uid; + } catch (PackageManager.NameNotFoundException nnfe) { + Log.e(TAG, "Not able to get targetUid: " + nnfe); + return false; + } + + // When activityInfo.exported is false, Activity still can be launched if applications have + // the same user ID. + if (UserHandle.isSameApp(callingUid, targetUid)) { + return true; + } + + // When activityInfo.exported is false, Activity still can be launched if calling app has + // root or system privilege. + int callingAppId = UserHandle.getAppId(callingUid); + if (callingAppId == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID) { + return true; + } + + return false; + } + + @VisibleForTesting + boolean isCallingAppPermitted(String permission) { + return TextUtils.isEmpty(permission) || PasswordUtils.isCallingAppPermitted( + this, getActivityToken(), permission); + } + private String getHighlightMenuKey() { final Intent intent = getIntent(); if (intent != null && TextUtils.equals(intent.getAction(),