Merge "Perform user restriction check before creating install session" into udc-dev

This commit is contained in:
Song Chun Fan
2023-05-10 22:38:00 +00:00
committed by Android (Google) Code Review
3 changed files with 158 additions and 108 deletions

View File

@@ -20,6 +20,8 @@ import static com.android.packageinstaller.PackageUtil.getMaxTargetSdkVersionFor
import android.Manifest;
import android.app.Activity;
import android.app.DialogFragment;
import android.app.admin.DevicePolicyManager;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -31,6 +33,8 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Process;
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
@@ -45,16 +49,24 @@ import java.util.Arrays;
* it.
*/
public class InstallStart extends Activity {
private static final String LOG_TAG = InstallStart.class.getSimpleName();
private static final String TAG = InstallStart.class.getSimpleName();
private static final String DOWNLOADS_AUTHORITY = "downloads";
private static final int DLG_INSTALL_APPS_RESTRICTED_FOR_USER = 1;
private static final int DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER = 2;
private PackageManager mPackageManager;
private UserManager mUserManager;
private boolean mAbortInstall = false;
private final boolean mLocalLOGV = false;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPackageManager = getPackageManager();
mUserManager = getSystemService(UserManager.class);
Intent intent = getIntent();
String callingPackage = getCallingPackage();
String callingAttributionTag = null;
@@ -80,8 +92,7 @@ public class InstallStart extends Activity {
// Uid of the source package, coming from ActivityManager
int callingUid = getLaunchedFromUid();
if (callingUid == Process.INVALID_UID) {
// Cannot reach ActivityManager. Aborting install.
Log.e(LOG_TAG, "Could not determine the launching uid.");
Log.e(TAG, "Could not determine the launching uid.");
}
// Uid of the source package, with a preference to uid from ApplicationInfo
final int originatingUid = sourceInfo != null ? sourceInfo.uid : callingUid;
@@ -104,12 +115,12 @@ public class InstallStart extends Activity {
&& originatingUid != Process.INVALID_UID) {
final int targetSdkVersion = getMaxTargetSdkVersionForUid(this, originatingUid);
if (targetSdkVersion < 0) {
Log.w(LOG_TAG, "Cannot get target sdk version for uid " + originatingUid);
Log.w(TAG, "Cannot get target sdk version for uid " + originatingUid);
// Invalid originating uid supplied. Abort install.
mAbortInstall = true;
} else if (targetSdkVersion >= Build.VERSION_CODES.O && !isUidRequestingPermission(
originatingUid, Manifest.permission.REQUEST_INSTALL_PACKAGES)) {
Log.e(LOG_TAG, "Requesting uid " + originatingUid + " needs to declare permission "
Log.e(TAG, "Requesting uid " + originatingUid + " needs to declare permission "
+ Manifest.permission.REQUEST_INSTALL_PACKAGES);
mAbortInstall = true;
}
@@ -119,6 +130,8 @@ public class InstallStart extends Activity {
mAbortInstall = true;
}
checkDevicePolicyRestriction();
final String installerPackageNameFromIntent = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (installerPackageNameFromIntent != null) {
@@ -126,7 +139,7 @@ public class InstallStart extends Activity {
if (!TextUtils.equals(installerPackageNameFromIntent, callingPkgName)
&& mPackageManager.checkPermission(Manifest.permission.INSTALL_PACKAGES,
callingPkgName) != PackageManager.PERMISSION_GRANTED) {
Log.e(LOG_TAG, "The given installer package name " + installerPackageNameFromIntent
Log.e(TAG, "The given installer package name " + installerPackageNameFromIntent
+ " is invalid. Remove it.");
EventLog.writeEvent(0x534e4554, "236687884", getLaunchedFromUid(),
"Invalid EXTRA_INSTALLER_PACKAGE_NAME");
@@ -270,4 +283,97 @@ public class InstallStart extends Activity {
int installerUid = packageInstaller.getSessionInfo(sessionId).getInstallerUid();
return (originatingUid == Process.ROOT_UID) || (originatingUid == installerUid);
}
private void checkDevicePolicyRestriction() {
// Check for install apps user restriction first.
final int installAppsRestrictionSource = mUserManager.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_APPS, Process.myUserHandle());
if ((installAppsRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
if (mLocalLOGV) Log.i(TAG, "install not allowed: " + UserManager.DISALLOW_INSTALL_APPS);
mAbortInstall = true;
showDialogInner(DLG_INSTALL_APPS_RESTRICTED_FOR_USER);
return;
} else if (installAppsRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
if (mLocalLOGV) {
Log.i(TAG, "install not allowed by admin; showing "
+ Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
}
mAbortInstall = true;
startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
return;
}
final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle());
final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, Process.myUserHandle());
final int systemRestriction = UserManager.RESTRICTION_SOURCE_SYSTEM
& (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource);
if (systemRestriction != 0) {
if (mLocalLOGV) Log.i(TAG, "Showing DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER");
mAbortInstall = true;
showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
} else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
mAbortInstall = true;
startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
} else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
mAbortInstall = true;
startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
}
}
/**
* Replace any dialog shown by the dialog with the one for the given {@link #createDialog(int)}.
*
* @param id The dialog type to add
*/
private void showDialogInner(int id) {
if (mLocalLOGV) Log.i(TAG, "showDialogInner(" + id + ")");
DialogFragment currentDialog =
(DialogFragment) getFragmentManager().findFragmentByTag("dialog");
if (currentDialog != null) {
currentDialog.dismissAllowingStateLoss();
}
DialogFragment newDialog = createDialog(id);
if (newDialog != null) {
getFragmentManager().beginTransaction()
.add(newDialog, "dialog").commitAllowingStateLoss();
}
}
/**
* Create a new dialog.
*
* @param id The id of the dialog (determines dialog type)
*
* @return The dialog
*/
private DialogFragment createDialog(int id) {
if (mLocalLOGV) Log.i(TAG, "createDialog(" + id + ")");
switch (id) {
case DLG_INSTALL_APPS_RESTRICTED_FOR_USER:
return PackageUtil.SimpleErrorDialog.newInstance(
R.string.install_apps_user_restriction_dlg_text);
case DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER:
return PackageUtil.SimpleErrorDialog.newInstance(
R.string.unknown_apps_user_restriction_dlg_text);
}
return null;
}
private void startAdminSupportDetailsActivity(String restriction) {
if (mLocalLOGV) Log.i(TAG, "startAdminSupportDetailsActivity(): " + restriction);
// If the given restriction is set by an admin, display information about the
// admin enforcing the restriction for the affected user.
final DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
final Intent showAdminSupportDetailsIntent = dpm.createAdminSupportIntent(restriction);
if (showAdminSupportDetailsIntent != null) {
if (mLocalLOGV) Log.i(TAG, "starting " + showAdminSupportDetailsIntent);
startActivity(showAdminSupportDetailsIntent);
} else {
if (mLocalLOGV) Log.w(TAG, "not intent for " + restriction);
}
}
}

View File

@@ -26,7 +26,6 @@ import android.app.AlertDialog;
import android.app.AppOpsManager;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.admin.DevicePolicyManager;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context;
@@ -56,7 +55,6 @@ import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import java.io.File;
import java.util.ArrayList;
@@ -123,13 +121,11 @@ public class PackageInstallerActivity extends AlertActivity {
// Dialog identifiers used in showDialog
private static final int DLG_BASE = 0;
private static final int DLG_PACKAGE_ERROR = DLG_BASE + 2;
private static final int DLG_OUT_OF_SPACE = DLG_BASE + 3;
private static final int DLG_INSTALL_ERROR = DLG_BASE + 4;
private static final int DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER = DLG_BASE + 5;
private static final int DLG_ANONYMOUS_SOURCE = DLG_BASE + 6;
private static final int DLG_EXTERNAL_SOURCE_BLOCKED = DLG_BASE + 7;
private static final int DLG_INSTALL_APPS_RESTRICTED_FOR_USER = DLG_BASE + 8;
private static final int DLG_PACKAGE_ERROR = DLG_BASE + 1;
private static final int DLG_OUT_OF_SPACE = DLG_BASE + 2;
private static final int DLG_INSTALL_ERROR = DLG_BASE + 3;
private static final int DLG_ANONYMOUS_SOURCE = DLG_BASE + 4;
private static final int DLG_EXTERNAL_SOURCE_BLOCKED = DLG_BASE + 5;
// If unknown sources are temporary allowed
private boolean mAllowUnknownSources;
@@ -218,19 +214,13 @@ public class PackageInstallerActivity extends AlertActivity {
if (mLocalLOGV) Log.i(TAG, "createDialog(" + id + ")");
switch (id) {
case DLG_PACKAGE_ERROR:
return SimpleErrorDialog.newInstance(R.string.Parse_error_dlg_text);
return PackageUtil.SimpleErrorDialog.newInstance(R.string.Parse_error_dlg_text);
case DLG_OUT_OF_SPACE:
return OutOfSpaceDialog.newInstance(
mPm.getApplicationLabel(mPkgInfo.applicationInfo));
case DLG_INSTALL_ERROR:
return InstallErrorDialog.newInstance(
mPm.getApplicationLabel(mPkgInfo.applicationInfo));
case DLG_INSTALL_APPS_RESTRICTED_FOR_USER:
return SimpleErrorDialog.newInstance(
R.string.install_apps_user_restriction_dlg_text);
case DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER:
return SimpleErrorDialog.newInstance(
R.string.unknown_apps_user_restriction_dlg_text);
case DLG_EXTERNAL_SOURCE_BLOCKED:
return ExternalSourcesBlockedDialog.newInstance(mOriginatingPackage);
case DLG_ANONYMOUS_SOURCE:
@@ -524,69 +514,17 @@ public class PackageInstallerActivity extends AlertActivity {
}
/**
* Check if it is allowed to install the package and initiate install if allowed. If not allowed
* show the appropriate dialog.
* Check if it is allowed to install the package and initiate install if allowed.
*/
private void checkIfAllowedAndInitiateInstall() {
// Check for install apps user restriction first.
final int installAppsRestrictionSource = mUserManager.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_APPS, Process.myUserHandle());
if ((installAppsRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
if (mLocalLOGV) Log.i(TAG, "install not allowed: " + UserManager.DISALLOW_INSTALL_APPS);
showDialogInner(DLG_INSTALL_APPS_RESTRICTED_FOR_USER);
return;
} else if (installAppsRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
if (mLocalLOGV) {
Log.i(TAG, "install not allowed by admin; showing "
+ Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
}
startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
finish();
return;
}
if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
if (mLocalLOGV) Log.i(TAG, "install allowed");
initiateInstall();
} else {
// Check for unknown sources restrictions.
final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle());
final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, Process.myUserHandle());
final int systemRestriction = UserManager.RESTRICTION_SOURCE_SYSTEM
& (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource);
if (systemRestriction != 0) {
if (mLocalLOGV) Log.i(TAG, "Showing DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER");
showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
} else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
} else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
startAdminSupportDetailsActivity(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
} else {
handleUnknownSources();
}
handleUnknownSources();
}
}
private void startAdminSupportDetailsActivity(String restriction) {
if (mLocalLOGV) Log.i(TAG, "startAdminSupportDetailsActivity(): " + restriction);
// If the given restriction is set by an admin, display information about the
// admin enforcing the restriction for the affected user.
final DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
final Intent showAdminSupportDetailsIntent = dpm.createAdminSupportIntent(restriction);
if (showAdminSupportDetailsIntent != null) {
if (mLocalLOGV) Log.i(TAG, "starting " + showAdminSupportDetailsIntent);
startActivity(showAdminSupportDetailsIntent);
} else {
if (mLocalLOGV) Log.w(TAG, "not intent for " + restriction);
}
finish();
}
private void handleUnknownSources() {
if (mOriginatingPackage == null) {
Log.i(TAG, "No source found for package " + mPkgInfo.packageName);
@@ -761,38 +699,6 @@ public class PackageInstallerActivity extends AlertActivity {
finish();
}
/**
* A simple error dialog showing a message
*/
public static class SimpleErrorDialog extends DialogFragment {
private static final String MESSAGE_KEY =
SimpleErrorDialog.class.getName() + "MESSAGE_KEY";
static SimpleErrorDialog newInstance(@StringRes int message) {
SimpleErrorDialog dialog = new SimpleErrorDialog();
Bundle args = new Bundle();
args.putInt(MESSAGE_KEY, message);
dialog.setArguments(args);
return dialog;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setMessage(getArguments().getInt(MESSAGE_KEY))
.setPositiveButton(R.string.ok, (dialog, which) -> getActivity().finish())
.create();
}
@Override
public void onCancel(DialogInterface dialog) {
getActivity().setResult(Activity.RESULT_CANCELED);
getActivity().finish();
}
}
/**
* Dialog to show when the source of apk can not be identified
*/

View File

@@ -18,12 +18,17 @@
package com.android.packageinstaller;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
import android.view.View;
@@ -32,6 +37,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import java.io.Closeable;
import java.io.File;
@@ -207,4 +213,36 @@ public class PackageUtil {
}
}
}
/**
* A simple error dialog showing a message
*/
public static class SimpleErrorDialog extends DialogFragment {
private static final String MESSAGE_KEY =
SimpleErrorDialog.class.getName() + "MESSAGE_KEY";
static SimpleErrorDialog newInstance(@StringRes int message) {
SimpleErrorDialog dialog = new SimpleErrorDialog();
Bundle args = new Bundle();
args.putInt(MESSAGE_KEY, message);
dialog.setArguments(args);
return dialog;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setMessage(getArguments().getInt(MESSAGE_KEY))
.setPositiveButton(R.string.ok, (dialog, which) -> getActivity().finish())
.create();
}
@Override
public void onCancel(DialogInterface dialog) {
getActivity().setResult(Activity.RESULT_CANCELED);
getActivity().finish();
}
}
}