Shortcut permissions for default text classifier

- Add two shortcut related permissions as SystemAPI for the default
text classifier.

- The default text classifier package name still comes from the
system resource.

Bug: 73083596
Bug: 71555985
Test: atest CtsPermission2TestCases
Test: Manual test with a test package, with the following in config.xml
<string name="config_defaultTextClassifierPackage" translatable="false">com.example.android.pm.shortcutlauncherdemo</string>

Change-Id: I19081d9d6ba0b33eb25d19aa55b4fe2f26a75897
This commit is contained in:
Makoto Onuki
2018-02-15 10:59:41 -08:00
parent f9a02975ea
commit 700feef8a6
18 changed files with 184 additions and 38 deletions

View File

@@ -11388,6 +11388,8 @@ package android.content.pm {
ctor public PermissionInfo();
ctor public PermissionInfo(android.content.pm.PermissionInfo);
method public int describeContents();
method public int getProtection();
method public int getProtectionFlags();
method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
field public static final android.os.Parcelable.Creator<android.content.pm.PermissionInfo> CREATOR;
field public static final int FLAG_COSTS_MONEY = 1; // 0x1
@@ -11404,8 +11406,8 @@ package android.content.pm {
field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
field public static final int PROTECTION_MASK_BASE = 15; // 0xf
field public static final int PROTECTION_MASK_FLAGS = 65520; // 0xfff0
field public static final deprecated int PROTECTION_MASK_BASE = 15; // 0xf
field public static final deprecated int PROTECTION_MASK_FLAGS = 65520; // 0xfff0
field public static final int PROTECTION_NORMAL = 0; // 0x0
field public static final int PROTECTION_SIGNATURE = 2; // 0x2
field public static final deprecated int PROTECTION_SIGNATURE_OR_SYSTEM = 3; // 0x3
@@ -11413,7 +11415,7 @@ package android.content.pm {
field public int flags;
field public java.lang.String group;
field public java.lang.CharSequence nonLocalizedDescription;
field public int protectionLevel;
field public deprecated int protectionLevel;
}
public final class ProviderInfo extends android.content.pm.ComponentInfo implements android.os.Parcelable {

View File

@@ -10,6 +10,7 @@ package android {
field public static final java.lang.String ACCESS_MTP = "android.permission.ACCESS_MTP";
field public static final java.lang.String ACCESS_NETWORK_CONDITIONS = "android.permission.ACCESS_NETWORK_CONDITIONS";
field public static final java.lang.String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
field public static final java.lang.String ACCESS_SHORTCUTS = "android.permission.ACCESS_SHORTCUTS";
field public static final java.lang.String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
@@ -179,6 +180,7 @@ package android {
field public static final java.lang.String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
field public static final java.lang.String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
field public static final java.lang.String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER";
field public static final java.lang.String UNLIMITED_SHORTCUTS_API_CALLS = "android.permission.UNLIMITED_SHORTCUTS_API_CALLS";
field public static final java.lang.String UPDATE_APP_OPS_STATS = "android.permission.UPDATE_APP_OPS_STATS";
field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
@@ -1085,6 +1087,7 @@ package android.content.pm {
public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
field public static final int FLAG_REMOVED = 2; // 0x2
field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
field public int requestRes;
}

View File

@@ -215,6 +215,7 @@ package android.content.pm {
}
public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
}

View File

@@ -2802,4 +2802,13 @@ public class ApplicationPackageManager extends PackageManager {
return mArtManager;
}
}
@Override
public String getSystemTextClassifierPackageName() {
try {
return mPM.getSystemTextClassifierPackageName();
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
}

View File

@@ -660,4 +660,6 @@ interface IPackageManager {
boolean hasSigningCertificate(String packageName, in byte[] signingCertificate, int flags);
boolean hasUidSigningCertificate(int uid, in byte[] signingCertificate, int flags);
String getSystemTextClassifierPackageName();
}

View File

@@ -6022,4 +6022,14 @@ public abstract class PackageManager {
throw new UnsupportedOperationException(
"hasSigningCertificate not implemented in subclass");
}
/**
* @return the system defined text classifier package name, or null if there's none.
*
* @hide
*/
public String getSystemTextClassifierPackageName() {
throw new UnsupportedOperationException(
"getSystemTextClassifierPackageName not implemented in subclass");
}
}

View File

@@ -43,12 +43,14 @@ public abstract class PackageManagerInternal {
public static final int PACKAGE_INSTALLER = 2;
public static final int PACKAGE_VERIFIER = 3;
public static final int PACKAGE_BROWSER = 4;
public static final int PACKAGE_SYSTEM_TEXT_CLASSIFIER = 5;
@IntDef(value = {
PACKAGE_SYSTEM,
PACKAGE_SETUP_WIZARD,
PACKAGE_INSTALLER,
PACKAGE_VERIFIER,
PACKAGE_BROWSER,
PACKAGE_SYSTEM_TEXT_CLASSIFIER,
})
@Retention(RetentionPolicy.SOURCE)
public @interface KnownPackage {}

View File

@@ -3182,7 +3182,7 @@ public class PackageParser {
perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);
if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) {
if (perm.info.getProtectionFlags() != 0) {
if ( (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_INSTANT) == 0
&& (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) == 0
&& (perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) !=

View File

@@ -16,12 +16,16 @@
package android.content.pm;
import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Information you can retrieve about a particular security permission
* known to the system. This corresponds to information collected from the
@@ -56,6 +60,16 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
@Deprecated
public static final int PROTECTION_SIGNATURE_OR_SYSTEM = 3;
/** @hide */
@IntDef(flag = false, prefix = { "PROTECTION_" }, value = {
PROTECTION_NORMAL,
PROTECTION_DANGEROUS,
PROTECTION_SIGNATURE,
PROTECTION_SIGNATURE_OR_SYSTEM,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Protection {}
/**
* Additional flag for {@link #protectionLevel}, corresponding
* to the <code>privileged</code> value of
@@ -155,30 +169,71 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 0x8000;
/**
* Mask for {@link #protectionLevel}: the basic protection type.
* Additional flag for {@link #protectionLevel}, corresponding
* to the <code>text_classifier</code> value of
* {@link android.R.attr#protectionLevel}.
*
* @hide
*/
@SystemApi
@TestApi
public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 0x10000;
/** @hide */
@IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = {
PROTECTION_FLAG_PRIVILEGED,
PROTECTION_FLAG_SYSTEM,
PROTECTION_FLAG_DEVELOPMENT,
PROTECTION_FLAG_APPOP,
PROTECTION_FLAG_PRE23,
PROTECTION_FLAG_INSTALLER,
PROTECTION_FLAG_VERIFIER,
PROTECTION_FLAG_PREINSTALLED,
PROTECTION_FLAG_SETUP,
PROTECTION_FLAG_INSTANT,
PROTECTION_FLAG_RUNTIME_ONLY,
PROTECTION_FLAG_OEM,
PROTECTION_FLAG_VENDOR_PRIVILEGED,
PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProtectionFlags {}
/**
* Mask for {@link #protectionLevel}: the basic protection type.
*
* @deprecated Use #getProtection() instead.
*/
@Deprecated
public static final int PROTECTION_MASK_BASE = 0xf;
/**
* Mask for {@link #protectionLevel}: additional flag bits.
*
* @deprecated Use #getProtectionFlags() instead.
*/
@Deprecated
public static final int PROTECTION_MASK_FLAGS = 0xfff0;
/**
* The level of access this permission is protecting, as per
* {@link android.R.attr#protectionLevel}. Consists of
* a base permission type and zero or more flags:
* a base permission type and zero or more flags. Use the following functions
* to extract them.
*
* <pre>
* int basePermissionType = protectionLevel & {@link #PROTECTION_MASK_BASE};
* int permissionFlags = protectionLevel & {@link #PROTECTION_MASK_FLAGS};
* int basePermissionType = permissionInfo.getProtection();
* int permissionFlags = permissionInfo.getProtectionFlags();
* </pre>
*
* <p></p>Base permission types are {@link #PROTECTION_NORMAL},
* {@link #PROTECTION_DANGEROUS}, {@link #PROTECTION_SIGNATURE}
* and the deprecated {@link #PROTECTION_SIGNATURE_OR_SYSTEM}.
* Flags are listed under {@link android.R.attr#protectionLevel}.
*
* @deprecated Use #getProtection() and #getProtectionFlags() instead.
*/
@Deprecated
public int protectionLevel;
/**
@@ -304,6 +359,9 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
if ((level & PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0) {
protLevel += "|vendorPrivileged";
}
if ((level & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER) != 0) {
protLevel += "|textClassifier";
}
return protLevel;
}
@@ -344,6 +402,22 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
return null;
}
/**
* Return the base permission type.
*/
@Protection
public int getProtection() {
return protectionLevel & PROTECTION_MASK_BASE;
}
/**
* Return the additional flags in {@link #protectionLevel}.
*/
@ProtectionFlags
public int getProtectionFlags() {
return protectionLevel & ~PROTECTION_MASK_BASE;
}
@Override
public String toString() {
return "PermissionInfo{"

View File

@@ -26,6 +26,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.CancellationSignal;
import android.os.IBinder;
@@ -37,8 +38,6 @@ import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
import android.view.textclassifier.TextSelection;
import com.android.internal.R;
/**
* Abstract base class for the TextClassifier service.
*
@@ -263,28 +262,33 @@ public abstract class TextClassifierService extends Service {
*/
@Nullable
public static ComponentName getServiceComponentName(Context context) {
final String str = context.getString(R.string.config_defaultTextClassifierService);
if (!TextUtils.isEmpty(str)) {
try {
final ComponentName componentName = ComponentName.unflattenFromString(str);
final Intent intent = new Intent(SERVICE_INTERFACE).setComponent(componentName);
final ServiceInfo si = context.getPackageManager()
.getServiceInfo(intent.getComponent(), 0);
final String permission = si == null ? null : si.permission;
if (Manifest.permission.BIND_TEXTCLASSIFIER_SERVICE.equals(permission)) {
return componentName;
}
Slog.w(LOG_TAG, String.format(
"Service %s should require %s permission. Found %s permission",
intent.getComponent().flattenToString(),
Manifest.permission.BIND_TEXTCLASSIFIER_SERVICE,
si.permission));
} catch (PackageManager.NameNotFoundException e) {
Slog.w(LOG_TAG, String.format("Service %s not found", str));
}
} else {
final String packageName = context.getPackageManager().getSystemTextClassifierPackageName();
if (TextUtils.isEmpty(packageName)) {
Slog.d(LOG_TAG, "No configured system TextClassifierService");
return null;
}
final Intent intent = new Intent(SERVICE_INTERFACE).setPackage(packageName);
final ResolveInfo ri = context.getPackageManager().resolveService(intent,
PackageManager.MATCH_SYSTEM_ONLY);
if ((ri == null) || (ri.serviceInfo == null)) {
Slog.w(LOG_TAG, String.format("Package or service not found in package %s",
packageName));
return null;
}
final ServiceInfo si = ri.serviceInfo;
final String permission = si.permission;
if (Manifest.permission.BIND_TEXTCLASSIFIER_SERVICE.equals(permission)) {
return si.getComponentName();
}
Slog.w(LOG_TAG, String.format(
"Service %s should require %s permission. Found %s permission",
si.getComponentName(),
Manifest.permission.BIND_TEXTCLASSIFIER_SERVICE,
si.permission));
return null;
}
}

View File

@@ -3810,9 +3810,15 @@
<permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"
android:protectionLevel="signature|development|instant|appop" />
<!-- @hide Allows system components to access all app shortcuts. -->
<!-- @SystemApi Allows to access all app shortcuts.
@hide -->
<permission android:name="android.permission.ACCESS_SHORTCUTS"
android:protectionLevel="signature" />
android:protectionLevel="signature|textClassifier" />
<!-- @SystemApi Allows unlimited calls to shortcut mutation APIs.
@hide -->
<permission android:name="android.permission.UNLIMITED_SHORTCUTS_API_CALLS"
android:protectionLevel="signature|textClassifier" />
<!-- @SystemApi Allows an application to read the runtime profiles of other apps.
@hide <p>Not for use by third-party applications. -->

View File

@@ -173,10 +173,10 @@
values listed below. If no protectionLevel is defined for a custom
permission, the system assigns the default ("normal").
<p>Each protection level consists of a base permission type and zero or
more flags:
more flags. Use the following functions to extract those.
<pre>
int basePermissionType = protectionLevel & {@link android.content.pm.PermissionInfo#PROTECTION_MASK_BASE};
int permissionFlags = protectionLevel & {@link android.content.pm.PermissionInfo#PROTECTION_MASK_FLAGS};
int basePermissionType = permissionInfo.getProtection();
int permissionFlags = permissionInfo.getProtectionFlags();
</pre>
-->
<attr name="protectionLevel">
@@ -265,6 +265,9 @@
<!-- Additional flag from base permission type: this permission can be granted to
privileged apps in vendor partition. -->
<flag name="vendorPrivileged" value="0x8000" />
<!-- Additional flag from base permission type: this permission can be automatically
granted to the system default text classifier -->
<flag name="textClassifier" value="0x10000" />
</attr>
<!-- Flags indicating more context for a permission group. -->

View File

@@ -3150,14 +3150,14 @@
-->
<string name="config_defaultAutofillService" translatable="false"></string>
<!-- The component name, flattened to a string, for the default system textclassifier service.
<!-- The package name for the default system textclassifier service.
This service must be trusted, as it can be activated without explicit consent of the user.
(e.g. com.android.textclassifier/.TextClassifierServiceImpl).
If no textclassifier service with the specified name exists on the device (or if this is
set to empty string), a default textclassifier will be loaded in the calling app's process.
See android.view.textclassifier.TextClassificationManager.
-->
<string name="config_defaultTextClassifierService" translatable="false"></string>
<string name="config_defaultTextClassifierPackage" translatable="false"></string>
<!-- Whether the device uses the default focus highlight when focus state isn't specified. -->
<bool name="config_useDefaultFocusHighlight">true</bool>

View File

@@ -3105,7 +3105,7 @@
<java-symbol type="string" name="notification_channel_heavy_weight_app" />
<java-symbol type="string" name="notification_channel_system_changes" />
<java-symbol type="string" name="config_defaultAutofillService" />
<java-symbol type="string" name="config_defaultTextClassifierService" />
<java-symbol type="string" name="config_defaultTextClassifierPackage" />
<java-symbol type="string" name="notification_channel_foreground_service" />
<java-symbol type="string" name="foreground_service_app_in_background" />

View File

@@ -237,6 +237,7 @@ import android.provider.Settings.Secure;
import android.security.KeyStore;
import android.security.SystemKeyStore;
import android.service.pm.PackageServiceDumpProto;
import android.service.textclassifier.TextClassifierService;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
@@ -1391,6 +1392,7 @@ public class PackageManagerService extends IPackageManager.Stub
final @NonNull String mRequiredUninstallerPackage;
final @Nullable String mSetupWizardPackage;
final @Nullable String mStorageManagerPackage;
final @Nullable String mSystemTextClassifierPackage;
final @NonNull String mServicesSystemSharedLibraryPackageName;
final @NonNull String mSharedSystemSharedLibraryPackageName;
@@ -2951,6 +2953,9 @@ public class PackageManagerService extends IPackageManager.Stub
filter.setPriority(0);
}
}
mSystemTextClassifierPackage = getSystemTextClassifierPackageName();
mDeferProtectedFilters = false;
mProtectedFilters.clear();
@@ -20246,6 +20251,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
}
@Override
public String getSystemTextClassifierPackageName() {
return mContext.getString(R.string.config_defaultTextClassifierPackage);
}
@Override
public void setApplicationEnabledSetting(String appPackageName,
int newState, int flags, int userId, String callingPackage) {
@@ -23374,6 +23384,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
return "android";
case PackageManagerInternal.PACKAGE_VERIFIER:
return mRequiredVerifierPackage;
case PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER:
return mSystemTextClassifierPackage;
}
return null;
}

View File

@@ -228,6 +228,10 @@ public final class BasePermission {
public boolean isVendorPrivileged() {
return (protectionLevel & PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0;
}
public boolean isSystemTextClassifier() {
return (protectionLevel & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER)
!= 0;
}
public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
if (!origPackageName.equals(sourcePackageName)) {

View File

@@ -1148,6 +1148,13 @@ public class PermissionManagerService {
// this app is a setup wizard, then it gets the permission.
allowed = true;
}
if (!allowed && bp.isSystemTextClassifier()
&& pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER,
UserHandle.USER_SYSTEM))) {
// Special permissions for the system default text classifier.
allowed = true;
}
}
return allowed;
}

View File

@@ -1209,4 +1209,11 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
/**
* @hide
*/
@Override
public String getSystemTextClassifierPackageName() {
throw new UnsupportedOperationException();
}
}