Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1739114d authored by Josh Hou's avatar Josh Hou Committed by Android (Google) Code Review
Browse files

Merge "Fix the security vulnerability issue in AppLocalePickerActivity" into tm-qpr-dev

parents 31406c04 5d7d1665
Loading
Loading
Loading
Loading
+16 −3
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.settings.localepicker;
import android.app.FragmentTransaction;
import android.app.LocaleManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.LocaleList;
@@ -34,6 +35,7 @@ import com.android.internal.app.LocalePickerWithRegion;
import com.android.internal.app.LocaleStore;
import com.android.settings.R;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.AppLocaleUtil;
import com.android.settings.applications.appinfo.AppLocaleDetails;
import com.android.settings.core.SettingsBaseActivity;

@@ -64,12 +66,17 @@ public class AppLocalePickerActivity extends SettingsBaseActivity
        }
        mContextAsUser = this;
        if (getIntent().hasExtra(AppInfoBase.ARG_PACKAGE_UID)) {
            int userId = getIntent().getIntExtra(AppInfoBase.ARG_PACKAGE_UID, -1);
            if (userId != -1) {
                UserHandle userHandle = UserHandle.getUserHandleForUid(userId);
            int uid = getIntent().getIntExtra(AppInfoBase.ARG_PACKAGE_UID, -1);
            if (uid != -1) {
                UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
                mContextAsUser = createContextAsUser(userHandle, 0);
            }
        }
        if (!canDisplayLocaleUi() || mContextAsUser.getUserId() != UserHandle.myUserId()) {
            Log.w(TAG, "Not allow to display Locale Settings UI.");
            finish();
            return;
        }

        setTitle(R.string.app_locale_picker_title);
        getActionBar().setDisplayHomeAsUpEnabled(true);
@@ -160,4 +167,10 @@ public class AppLocalePickerActivity extends SettingsBaseActivity
                .replace(R.id.content_frame, mLocalePickerWithRegion)
                .commit();
    }

    private boolean canDisplayLocaleUi() {
        return AppLocaleUtil.canDisplayLocaleUi(mContextAsUser, mPackageName,
                mContextAsUser.getPackageManager().queryIntentActivities(
                        AppLocaleUtil.LAUNCHER_ENTRY_INTENT, PackageManager.GET_META_DATA));
    }
}
+167 −5
Original line number Diff line number Diff line
@@ -18,25 +18,35 @@ package com.android.settings.localepicker;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.annotation.Nullable;
import android.app.Activity;
import android.app.ApplicationPackageManager;
import android.app.LocaleConfig;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.net.Uri;
import android.os.LocaleList;
import android.os.Process;
import android.os.UserHandle;
import android.telephony.TelephonyManager;

import androidx.annotation.ArrayRes;

import com.android.internal.app.LocaleStore;
import com.android.settings.applications.AppInfoBase;

import java.util.Locale;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,17 +55,26 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowPackageManager;
import org.robolectric.shadows.ShadowTelephonyManager;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

@RunWith(RobolectricTestRunner.class)
@Config(
        shadows = {
                AppLocalePickerActivityTest.ShadowApplicationPackageManager.class,
                AppLocalePickerActivityTest.ShadowResources.class,
                AppLocalePickerActivityTest.ShadowUserHandle.class,
                AppLocalePickerActivityTest.ShadowLocaleConfig.class,
        })
public class AppLocalePickerActivityTest {
    private static final String TEST_PACKAGE_NAME = "com.android.settings";
@@ -67,21 +86,99 @@ public class AppLocalePickerActivityTest {
    @Rule
    public MockitoRule rule = MockitoJUnit.rule();

    private Context mContext;
    private ShadowPackageManager mPackageManager;

    @Before
    public void setUp() {
        mContext = spy(RuntimeEnvironment.application);
        mPackageManager = Shadows.shadowOf(mContext.getPackageManager());
    }

    @After
    public void tearDown() {
        mPackageManager.removePackage(TEST_PACKAGE_NAME);
        ShadowResources.setDisAllowPackage(false);
        ShadowApplicationPackageManager.setNoLaunchEntry(false);
        ShadowUserHandle.setUserId(0);
        ShadowLocaleConfig.setStatus(LocaleConfig.STATUS_SUCCESS);
    }

    @Test
    public void launchAppLocalePickerActivity_hasPackageName_success() {
        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(true);

        controller.create();

        assertThat(controller.get().isFinishing()).isFalse();
    }

    @Test
    public void launchAppLocalePickerActivity_appNoLocaleConfig_failed() {
        ShadowLocaleConfig.setStatus(LocaleConfig.STATUS_NOT_SPECIFIED);

        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(true);
        controller.create();

        assertThat(controller.get().isFinishing()).isTrue();
    }

    @Test
    public void launchAppLocalePickerActivity_appSignPlatformKey_failed() {
        final ApplicationInfo applicationInfo = new ApplicationInfo();
        applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
        applicationInfo.packageName = TEST_PACKAGE_NAME;

        final PackageInfo packageInfo = new PackageInfo();
        packageInfo.packageName = TEST_PACKAGE_NAME;
        packageInfo.applicationInfo = applicationInfo;
        mPackageManager.installPackage(packageInfo);

        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(true);
        controller.create();

        assertThat(controller.get().isFinishing()).isTrue();
    }

    @Test
    public void launchAppLocalePickerActivity_appMatchDisallowedPackage_failed() {
        ShadowResources.setDisAllowPackage(true);

        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(true);
        controller.create();

        assertThat(controller.get().isFinishing()).isTrue();
    }

    @Test
    public void launchAppLocalePickerActivity_appNoLaunchEntry_failed() {
        ShadowApplicationPackageManager.setNoLaunchEntry(true);

        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(true);
        controller.create();

        assertThat(controller.get().isFinishing()).isTrue();
    }

    @Test
    public void launchAppLocalePickerActivity_modifyAppLocalesOfAnotherUser_failed() {
        ShadowUserHandle.setUserId(10);

        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(true);
        controller.create();

        assertThat(controller.get().isFinishing()).isTrue();
    }

    @Test
    public void launchAppLocalePickerActivity_intentWithoutPackageName_failed() {
        ActivityController<TestAppLocalePickerActivity> controller =
                initActivityController(false);

        controller.create();

        assertThat(controller.get().isFinishing()).isTrue();
@@ -125,7 +222,7 @@ public class AppLocalePickerActivityTest {
        if (hasPackageName) {
            data.setData(TEST_PACKAGE_URI);
        }
        data.putExtra(AppInfoBase.ARG_PACKAGE_UID, UserHandle.getUserId(Process.myUid()));
        data.putExtra(AppInfoBase.ARG_PACKAGE_UID, Process.myUid());
        ActivityController<TestAppLocalePickerActivity> activityController =
                Robolectric.buildActivity(TestAppLocalePickerActivity.class, data);
        Activity activity = activityController.get();
@@ -149,10 +246,75 @@ public class AppLocalePickerActivityTest {
    @Implements(ApplicationPackageManager.class)
    public static class ShadowApplicationPackageManager extends
            org.robolectric.shadows.ShadowApplicationPackageManager {
        private static boolean sNoLaunchEntry = false;

        @Implementation
        protected Object getInstallSourceInfo(String packageName) {
            return new InstallSourceInfo("", null, null, "");
        }

        @Implementation
        protected List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
            if (sNoLaunchEntry) {
                return new ArrayList();
            } else {
                return super.queryIntentActivities(intent, flags);
            }
        }

        private static void setNoLaunchEntry(boolean noLaunchEntry) {
            sNoLaunchEntry = noLaunchEntry;
        }
    }

    @Implements(Resources.class)
    public static class ShadowResources extends
            org.robolectric.shadows.ShadowResources {
        private static boolean sDisAllowPackage = false;

        @Implementation
        public String[] getStringArray(@ArrayRes int id) {
            if (sDisAllowPackage) {
                return new String[]{TEST_PACKAGE_NAME};
            } else {
                return new String[0];
            }
        }

        private static void setDisAllowPackage(boolean disAllowPackage) {
            sDisAllowPackage = disAllowPackage;
        }
    }

    @Implements(UserHandle.class)
    public static class ShadowUserHandle {
        private static int sUserId = 0;
        private static void setUserId(int userId) {
            sUserId = userId;
        }

        @Implementation
        public static int getUserId(int userId) {
            return sUserId;
        }
    }

    @Implements(LocaleConfig.class)
    public static class ShadowLocaleConfig {
        private static int sStatus = 0;

        @Implementation
        public @Nullable LocaleList getSupportedLocales() {
            return LocaleList.forLanguageTags("en-US");
        }

        private static void setStatus(@LocaleConfig.Status int status) {
            sStatus = status;
        }

        @Implementation
        public @LocaleConfig.Status int getStatus() {
            return sStatus;
        }
    }
}