Merge "Settings 2-pane deep link vulnerabilities" into tm-qpr-dev
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index 6739084..b79a64c 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -27,6 +27,8 @@
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;
@@ -66,6 +68,7 @@
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.settings.safetycenter.SafetyCenterManagerWrapper;
import com.android.settingslib.Utils;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
@@ -444,6 +447,32 @@
finish();
return;
}
+
+ if (!TextUtils.equals(PasswordUtils.getCallingAppPackageName(getActivityToken()),
+ getPackageName())) {
+ 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 (!targetActivityInfo.exported) {
+ Log.e(TAG, "Must not launch an unexported Actvity for deep link");
+ 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.
@@ -485,6 +514,12 @@
}
}
+ @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(),
diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
index 7387407..337b659 100644
--- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
@@ -20,6 +20,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -40,9 +42,11 @@
import com.android.settings.R;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl;
import com.android.settings.testutils.shadow.ShadowActivityEmbeddingUtils;
+import com.android.settings.testutils.shadow.ShadowPasswordUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -69,6 +73,11 @@
MockitoAnnotations.initMocks(this);
}
+ @After
+ public void tearDown() {
+ ShadowPasswordUtils.reset();
+ }
+
@Test
public void launch_shouldHaveAnimationForIaFragment() {
final SettingsHomepageActivity activity = Robolectric.buildActivity(
@@ -208,6 +217,32 @@
verify(activity).initSplitPairRules();
}
+ @Test
+ @Config(shadows = {ShadowPasswordUtils.class})
+ public void isCallingAppPermitted_emptyPermission_returnTrue() {
+ SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
+
+ assertTrue(homepageActivity.isCallingAppPermitted(""));
+ }
+
+ @Test
+ @Config(shadows = {ShadowPasswordUtils.class})
+ public void isCallingAppPermitted_noGrantedPermission_returnFalse() {
+ SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
+
+ assertFalse(homepageActivity.isCallingAppPermitted("android.permission.TEST"));
+ }
+
+ @Test
+ @Config(shadows = {ShadowPasswordUtils.class})
+ public void isCallingAppPermitted_grantedPermission_returnTrue() {
+ SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
+ String permission = "android.permission.TEST";
+ ShadowPasswordUtils.addGrantedPermission(permission);
+
+ assertTrue(homepageActivity.isCallingAppPermitted(permission));
+ }
+
@Implements(SuggestionFeatureProviderImpl.class)
public static class ShadowSuggestionFeatureProviderImpl {