Merge "Intercepting activites that could cause lock task mode violation in ActivityStartInterceptor."
This commit is contained in:
@@ -7140,6 +7140,7 @@ package android.app.admin {
|
||||
field public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 8; // 0x8
|
||||
field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1
|
||||
field public static final int LEAVE_ALL_SYSTEM_APPS_ENABLED = 16; // 0x10
|
||||
field public static final int LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK = 64; // 0x40
|
||||
field public static final int LOCK_TASK_FEATURE_GLOBAL_ACTIONS = 16; // 0x10
|
||||
field public static final int LOCK_TASK_FEATURE_HOME = 4; // 0x4
|
||||
field public static final int LOCK_TASK_FEATURE_KEYGUARD = 32; // 0x20
|
||||
|
||||
@@ -2089,6 +2089,13 @@ public class DevicePolicyManager {
|
||||
*/
|
||||
public static final int LOCK_TASK_FEATURE_KEYGUARD = 1 << 5;
|
||||
|
||||
/**
|
||||
* Enable blocking of non-whitelisted activities from being started into a locked task.
|
||||
*
|
||||
* @see #setLockTaskFeatures(ComponentName, int)
|
||||
*/
|
||||
public static final int LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK = 1 << 6;
|
||||
|
||||
/**
|
||||
* Flags supplied to {@link #setLockTaskFeatures(ComponentName, int)}.
|
||||
*
|
||||
@@ -2102,7 +2109,8 @@ public class DevicePolicyManager {
|
||||
LOCK_TASK_FEATURE_HOME,
|
||||
LOCK_TASK_FEATURE_OVERVIEW,
|
||||
LOCK_TASK_FEATURE_GLOBAL_ACTIONS,
|
||||
LOCK_TASK_FEATURE_KEYGUARD
|
||||
LOCK_TASK_FEATURE_KEYGUARD,
|
||||
LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK
|
||||
})
|
||||
public @interface LockTaskFeature {}
|
||||
|
||||
|
||||
86
core/java/com/android/internal/app/BlockedAppActivity.java
Normal file
86
core/java/com/android/internal/app/BlockedAppActivity.java
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.app;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
/**
|
||||
* A dialog shown to the user when they try to launch an app that is not allowed in lock task
|
||||
* mode. The intent to start this activity must be created with the static factory method provided
|
||||
* below.
|
||||
*/
|
||||
public class BlockedAppActivity extends AlertActivity {
|
||||
|
||||
private static final String TAG = "BlockedAppActivity";
|
||||
private static final String PACKAGE_NAME = "com.android.internal.app";
|
||||
private static final String EXTRA_BLOCKED_PACKAGE = PACKAGE_NAME + ".extra.BLOCKED_PACKAGE";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Intent intent = getIntent();
|
||||
int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, /* defaultValue= */ -1);
|
||||
if (userId < 0) {
|
||||
Slog.wtf(TAG, "Invalid user: " + userId);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
String packageName = intent.getStringExtra(EXTRA_BLOCKED_PACKAGE);
|
||||
if (TextUtils.isEmpty(packageName)) {
|
||||
Slog.wtf(TAG, "Invalid package: " + packageName);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
CharSequence appLabel = getAppLabel(userId, packageName);
|
||||
|
||||
mAlertParams.mTitle = getString(R.string.app_blocked_title);
|
||||
mAlertParams.mMessage = getString(R.string.app_blocked_message, appLabel);
|
||||
mAlertParams.mPositiveButtonText = getString(android.R.string.ok);
|
||||
setupAlert();
|
||||
}
|
||||
|
||||
private CharSequence getAppLabel(int userId, String packageName) {
|
||||
PackageManager pm = getPackageManager();
|
||||
try {
|
||||
ApplicationInfo aInfo =
|
||||
pm.getApplicationInfoAsUser(packageName, /* flags= */ 0, userId);
|
||||
return aInfo.loadLabel(pm);
|
||||
} catch (PackageManager.NameNotFoundException ne) {
|
||||
Slog.e(TAG, "Package " + packageName + " not found", ne);
|
||||
}
|
||||
return packageName;
|
||||
}
|
||||
|
||||
|
||||
/** Creates an intent that launches {@link BlockedAppActivity}. */
|
||||
public static Intent createIntent(int userId, String packageName) {
|
||||
return new Intent()
|
||||
.setClassName("android", BlockedAppActivity.class.getName())
|
||||
.putExtra(Intent.EXTRA_USER_ID, userId)
|
||||
.putExtra(EXTRA_BLOCKED_PACKAGE, packageName);
|
||||
}
|
||||
}
|
||||
@@ -5075,6 +5075,12 @@
|
||||
android:process=":ui">
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.android.internal.app.BlockedAppActivity"
|
||||
android:theme="@style/Theme.Dialog.Confirmation"
|
||||
android:excludeFromRecents="true"
|
||||
android:process=":ui">
|
||||
</activity>
|
||||
|
||||
<activity android:name="com.android.settings.notification.NotificationAccessConfirmationActivity"
|
||||
android:theme="@style/Theme.Dialog.Confirmation"
|
||||
android:excludeFromRecents="true">
|
||||
|
||||
@@ -4936,6 +4936,13 @@
|
||||
<!-- Title for button to turn on work profile. [CHAR LIMIT=NONE] -->
|
||||
<string name="work_mode_turn_on">Turn on</string>
|
||||
|
||||
<!-- Title of the dialog that is shown when the user tries to launch a blocked application [CHAR LIMIT=50] -->
|
||||
<string name="app_blocked_title">App is not available</string>
|
||||
<!-- Default message shown in the dialog that is shown when the user tries to launch a blocked application [CHAR LIMIT=NONE] -->
|
||||
<string name="app_blocked_message">
|
||||
<xliff:g id="app_name" example="Gmail">%1$s</xliff:g> is not available right now.
|
||||
</string>
|
||||
|
||||
<!-- Message displayed in dialog when app is too old to run on this verison of android. [CHAR LIMIT=NONE] -->
|
||||
<string name="deprecated_target_sdk_message">This app was built for an older version of Android and may not work properly. Try checking for updates, or contact the developer.</string>
|
||||
<!-- Title for button to see application detail in app store which it came from - it may allow user to update to newer version. [CHAR LIMIT=50] -->
|
||||
|
||||
@@ -3048,6 +3048,9 @@
|
||||
<java-symbol type="string" name="app_suspended_unsuspend_message" />
|
||||
<java-symbol type="string" name="app_suspended_default_message" />
|
||||
|
||||
<java-symbol type="string" name="app_blocked_title" />
|
||||
<java-symbol type="string" name="app_blocked_message" />
|
||||
|
||||
<!-- Used internally for assistant to launch activity transitions -->
|
||||
<java-symbol type="id" name="cross_task_transition" />
|
||||
|
||||
|
||||
@@ -1629,12 +1629,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
requestedVrComponent = (aInfo.requestedVrComponent == null) ?
|
||||
null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
|
||||
|
||||
lockTaskLaunchMode = aInfo.lockTaskLaunchMode;
|
||||
if (info.applicationInfo.isPrivilegedApp()
|
||||
&& (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS
|
||||
|| lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
|
||||
lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
|
||||
}
|
||||
lockTaskLaunchMode = getLockTaskLaunchMode(aInfo, options);
|
||||
|
||||
if (options != null) {
|
||||
pendingOptions = options;
|
||||
@@ -1642,15 +1637,27 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
if (usageReport != null) {
|
||||
appTimeTracker = new AppTimeTracker(usageReport);
|
||||
}
|
||||
final boolean useLockTask = pendingOptions.getLockTaskMode();
|
||||
if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) {
|
||||
lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
|
||||
}
|
||||
// Gets launch display id from options. It returns INVALID_DISPLAY if not set.
|
||||
mHandoverLaunchDisplayId = options.getLaunchDisplayId();
|
||||
}
|
||||
}
|
||||
|
||||
static int getLockTaskLaunchMode(ActivityInfo aInfo, @Nullable ActivityOptions options) {
|
||||
int lockTaskLaunchMode = aInfo.lockTaskLaunchMode;
|
||||
if (aInfo.applicationInfo.isPrivilegedApp()
|
||||
&& (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS
|
||||
|| lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
|
||||
lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
|
||||
}
|
||||
if (options != null) {
|
||||
final boolean useLockTask = options.getLockTaskMode();
|
||||
if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) {
|
||||
lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
|
||||
}
|
||||
}
|
||||
return lockTaskLaunchMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
ActivityRecord asActivityRecord() {
|
||||
// I am an activity record!
|
||||
|
||||
@@ -52,6 +52,7 @@ import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.app.BlockedAppActivity;
|
||||
import com.android.internal.app.HarmfulAppWarningActivity;
|
||||
import com.android.internal.app.SuspendedAppActivity;
|
||||
import com.android.internal.app.UnlaunchableAppActivity;
|
||||
@@ -166,6 +167,9 @@ class ActivityStartInterceptor {
|
||||
// no user action can undo this.
|
||||
return true;
|
||||
}
|
||||
if (interceptLockTaskModeViolationPackageIfNeeded()) {
|
||||
return true;
|
||||
}
|
||||
if (interceptHarmfulAppIfNeeded()) {
|
||||
// If the app has a "harmful app" warning associated with it, we should ask to uninstall
|
||||
// before issuing the work challenge.
|
||||
@@ -270,6 +274,25 @@ class ActivityStartInterceptor {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean interceptLockTaskModeViolationPackageIfNeeded() {
|
||||
if (mAInfo == null || mAInfo.applicationInfo == null) {
|
||||
return false;
|
||||
}
|
||||
LockTaskController controller = mService.getLockTaskController();
|
||||
String packageName = mAInfo.applicationInfo.packageName;
|
||||
int lockTaskLaunchMode = ActivityRecord.getLockTaskLaunchMode(mAInfo, mActivityOptions);
|
||||
if (controller.isActivityAllowed(mUserId, packageName, lockTaskLaunchMode)) {
|
||||
return false;
|
||||
}
|
||||
mIntent = BlockedAppActivity.createIntent(mUserId, mAInfo.applicationInfo.packageName);
|
||||
mCallingPid = mRealCallingPid;
|
||||
mCallingUid = mRealCallingUid;
|
||||
mResolvedType = null;
|
||||
mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid);
|
||||
mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean interceptWorkProfileChallengeIfNeeded() {
|
||||
final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mAInfo, mUserId);
|
||||
if (interceptingIntent == null) {
|
||||
|
||||
@@ -23,6 +23,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
import static android.content.Context.DEVICE_POLICY_SERVICE;
|
||||
import static android.content.Context.STATUS_BAR_SERVICE;
|
||||
import static android.content.Intent.ACTION_CALL_EMERGENCY;
|
||||
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
|
||||
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
|
||||
import static android.os.UserHandle.USER_ALL;
|
||||
import static android.os.UserHandle.USER_CURRENT;
|
||||
import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT;
|
||||
@@ -339,6 +341,25 @@ public class LockTaskController {
|
||||
& DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD) != 0;
|
||||
}
|
||||
|
||||
private boolean isBlockingInTaskEnabled(int userId) {
|
||||
return (getLockTaskFeaturesForUser(userId)
|
||||
& DevicePolicyManager.LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK) != 0;
|
||||
}
|
||||
|
||||
boolean isActivityAllowed(int userId, String packageName, int lockTaskLaunchMode) {
|
||||
if (mLockTaskModeState != LOCK_TASK_MODE_LOCKED || !isBlockingInTaskEnabled(userId)) {
|
||||
return true;
|
||||
}
|
||||
switch (lockTaskLaunchMode) {
|
||||
case LOCK_TASK_LAUNCH_MODE_ALWAYS:
|
||||
return true;
|
||||
case LOCK_TASK_LAUNCH_MODE_NEVER:
|
||||
return false;
|
||||
default:
|
||||
}
|
||||
return isPackageWhitelisted(userId, packageName);
|
||||
}
|
||||
|
||||
private boolean isEmergencyCallTask(Task task) {
|
||||
final Intent intent = task.intent;
|
||||
if (intent == null) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
|
||||
import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
|
||||
@@ -44,6 +45,7 @@ import android.testing.DexmakerShareClassLoaderRule;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.app.BlockedAppActivity;
|
||||
import com.android.internal.app.HarmfulAppWarningActivity;
|
||||
import com.android.internal.app.SuspendedAppActivity;
|
||||
import com.android.internal.app.UnlaunchableAppActivity;
|
||||
@@ -105,6 +107,8 @@ public class ActivityStartInterceptorTest {
|
||||
private PackageManagerService mPackageManager;
|
||||
@Mock
|
||||
private ActivityManagerInternal mAmInternal;
|
||||
@Mock
|
||||
private LockTaskController mLockTaskController;
|
||||
|
||||
private ActivityStartInterceptor mInterceptor;
|
||||
private ActivityInfo mAInfo = new ActivityInfo();
|
||||
@@ -145,6 +149,13 @@ public class ActivityStartInterceptorTest {
|
||||
when(mPackageManager.getHarmfulAppWarning(TEST_PACKAGE_NAME, TEST_USER_ID))
|
||||
.thenReturn(null);
|
||||
|
||||
// Mock LockTaskController
|
||||
mAInfo.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
|
||||
when(mService.getLockTaskController()).thenReturn(mLockTaskController);
|
||||
when(mLockTaskController.isActivityAllowed(
|
||||
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT))
|
||||
.thenReturn(true);
|
||||
|
||||
// Initialise activity info
|
||||
mAInfo.applicationInfo = new ApplicationInfo();
|
||||
mAInfo.packageName = mAInfo.applicationInfo.packageName = TEST_PACKAGE_NAME;
|
||||
@@ -195,6 +206,18 @@ public class ActivityStartInterceptorTest {
|
||||
return dialogInfo;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterceptLockTaskModeViolationPackage() {
|
||||
when(mLockTaskController.isActivityAllowed(
|
||||
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT))
|
||||
.thenReturn(false);
|
||||
|
||||
assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
|
||||
|
||||
assertTrue(BlockedAppActivity.createIntent(TEST_USER_ID, TEST_PACKAGE_NAME)
|
||||
.filterEquals(mInterceptor.mIntent));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterceptQuietProfile() {
|
||||
// GIVEN that the user the activity is starting as is currently in quiet mode
|
||||
|
||||
@@ -25,10 +25,14 @@ import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE;
|
||||
import static android.app.StatusBarManager.DISABLE_HOME;
|
||||
import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
|
||||
import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS;
|
||||
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK;
|
||||
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_HOME;
|
||||
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD;
|
||||
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
|
||||
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS;
|
||||
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
|
||||
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
|
||||
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
|
||||
import static android.os.Process.SYSTEM_UID;
|
||||
import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT;
|
||||
|
||||
@@ -693,6 +697,45 @@ public class LockTaskControllerTest {
|
||||
assertTrue((StatusBarManager.DISABLE2_QUICK_SETTINGS & flags.second) != 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsActivityAllowed() {
|
||||
// WHEN lock task mode is not enabled
|
||||
assertTrue(mLockTaskController.isActivityAllowed(
|
||||
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
|
||||
|
||||
// Start lock task mode
|
||||
Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
|
||||
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
|
||||
|
||||
// WHEN LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK is not enabled
|
||||
assertTrue(mLockTaskController.isActivityAllowed(
|
||||
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
|
||||
|
||||
// Enable LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK feature
|
||||
mLockTaskController.updateLockTaskFeatures(
|
||||
TEST_USER_ID, LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK);
|
||||
|
||||
// package with LOCK_TASK_LAUNCH_MODE_ALWAYS should always be allowed
|
||||
assertTrue(mLockTaskController.isActivityAllowed(
|
||||
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_ALWAYS));
|
||||
|
||||
// unwhitelisted package should not be allowed
|
||||
assertFalse(mLockTaskController.isActivityAllowed(
|
||||
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
|
||||
|
||||
// update the whitelist
|
||||
String[] whitelist = new String[] { TEST_PACKAGE_NAME };
|
||||
mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
|
||||
|
||||
// whitelisted package should be allowed
|
||||
assertTrue(mLockTaskController.isActivityAllowed(
|
||||
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
|
||||
|
||||
// package with LOCK_TASK_LAUNCH_MODE_NEVER should never be allowed
|
||||
assertFalse(mLockTaskController.isActivityAllowed(
|
||||
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_NEVER));
|
||||
}
|
||||
|
||||
private Task getTask(int lockTaskAuth) {
|
||||
return getTask(TEST_PACKAGE_NAME, lockTaskAuth);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user