diff options
152 files changed, 4228 insertions, 1880 deletions
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index 4c8790f47bb6..1e92826ee8a0 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -15,161 +15,51 @@ */ package com.android.server.stats; -import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED; -import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; -import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; -import static android.os.Process.getUidForPid; -import static android.os.storage.VolumeInfo.TYPE_PRIVATE; -import static android.os.storage.VolumeInfo.TYPE_PUBLIC; - -import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; -import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs; -import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs; -import static com.android.server.stats.pull.ProcfsMemoryUtil.forEachPid; -import static com.android.server.stats.pull.ProcfsMemoryUtil.readCmdlineFromProcfs; -import static com.android.server.stats.pull.ProcfsMemoryUtil.readMemorySnapshotFromProcfs; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.ActivityManagerInternal; + import android.app.AlarmManager; import android.app.AlarmManager.OnAlarmListener; -import android.app.AppOpsManager; -import android.app.AppOpsManager.HistoricalOps; -import android.app.AppOpsManager.HistoricalOpsRequest; -import android.app.AppOpsManager.HistoricalPackageOps; -import android.app.AppOpsManager.HistoricalUidOps; -import android.app.INotificationManager; -import android.app.ProcessMemoryState; import android.app.StatsManager; -import android.bluetooth.BluetoothActivityEnergyInfo; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.UidTraffic; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PermissionInfo; -import android.content.pm.UserInfo; -import android.hardware.biometrics.BiometricsProtoEnums; -import android.hardware.face.FaceManager; -import android.hardware.fingerprint.FingerprintManager; -import android.net.ConnectivityManager; -import android.net.INetworkStatsService; -import android.net.Network; -import android.net.NetworkRequest; -import android.net.NetworkStats; -import android.net.wifi.WifiManager; -import android.os.BatteryStats; -import android.os.BatteryStatsInternal; import android.os.Binder; -import android.os.Build; import android.os.Bundle; -import android.os.CoolingDevice; -import android.os.Environment; -import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.IStatsCompanionService; import android.os.IStatsd; -import android.os.IStoraged; -import android.os.IThermalEventListener; -import android.os.IThermalService; import android.os.Looper; import android.os.ParcelFileDescriptor; -import android.os.Parcelable; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.StatsFrameworkInitializer; -import android.os.StatFs; -import android.os.StatsLogEventWrapper; -import android.os.SynchronousResultReceiver; import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.Temperature; import android.os.UserHandle; import android.os.UserManager; -import android.os.connectivity.WifiActivityEnergyInfo; -import android.os.storage.DiskInfo; -import android.os.storage.StorageManager; -import android.os.storage.VolumeInfo; -import android.provider.Settings; -import android.stats.storage.StorageEnums; -import android.telephony.ModemActivityInfo; -import android.telephony.TelephonyManager; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.Log; import android.util.Slog; -import android.util.StatsLog; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; -import com.android.internal.app.procstats.IProcessStats; -import com.android.internal.app.procstats.ProcessStats; -import com.android.internal.os.BatterySipper; -import com.android.internal.os.BatteryStatsHelper; -import com.android.internal.os.BinderCallsStats.ExportedCallStat; -import com.android.internal.os.KernelCpuSpeedReader; -import com.android.internal.os.KernelCpuThreadReader; -import com.android.internal.os.KernelCpuThreadReaderDiff; -import com.android.internal.os.KernelCpuThreadReaderSettingsObserver; -import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader; -import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader; -import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader; -import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader; -import com.android.internal.os.KernelWakelockReader; -import com.android.internal.os.KernelWakelockStats; import com.android.internal.os.LooperStats; -import com.android.internal.os.PowerProfile; -import com.android.internal.os.ProcessCpuTracker; -import com.android.internal.os.StoragedUidIoStatsReader; import com.android.internal.util.DumpUtils; import com.android.server.BinderCallsStatsService; import com.android.server.LocalServices; -import com.android.server.SystemServiceManager; -import com.android.server.am.MemoryStatUtil.MemoryStat; -import com.android.server.notification.NotificationManagerService; -import com.android.server.role.RoleManagerInternal; -import com.android.server.stats.pull.IonMemoryUtil.IonAllocations; -import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot; -import com.android.server.storage.DiskStatsFileLogger; -import com.android.server.storage.DiskStatsLoggingService; - -import com.google.android.collect.Sets; import libcore.io.IoUtils; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - import java.io.File; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; /** * Helper service for statsd (the native stats management service in cmds/statsd/). @@ -178,10 +68,7 @@ import java.util.concurrent.TimeoutException; * @hide */ public class StatsCompanionService extends IStatsCompanionService.Stub { - /** - * How long to wait on an individual subsystem to return its stats. - */ - private static final long EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS = 2000; + private static final long MILLIS_IN_A_DAY = TimeUnit.DAYS.toMillis(1); public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity"; @@ -201,45 +88,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private static final int INSTALLER_FIELD_ID = 5; public static final int DEATH_THRESHOLD = 10; - /** - * Which native processes to snapshot memory for. - * - * <p>Processes are matched by their cmdline in procfs. Example: cat /proc/pid/cmdline returns - * /system/bin/statsd for the stats daemon. - */ - private static final Set<String> MEMORY_INTERESTING_NATIVE_PROCESSES = Sets.newHashSet( - "/system/bin/statsd", // Stats daemon. - "/system/bin/surfaceflinger", - "/system/bin/apexd", // APEX daemon. - "/system/bin/audioserver", - "/system/bin/cameraserver", - "/system/bin/drmserver", - "/system/bin/healthd", - "/system/bin/incidentd", - "/system/bin/installd", - "/system/bin/lmkd", // Low memory killer daemon. - "/system/bin/logd", - "media.codec", - "media.extractor", - "media.metrics", - "/system/bin/mediadrmserver", - "/system/bin/mediaserver", - "/system/bin/performanced", - "/system/bin/tombstoned", - "/system/bin/traced", // Perfetto. - "/system/bin/traced_probes", // Perfetto. - "webview_zygote", - "zygote", - "zygote64"); - /** - * Lowest available uid for apps. - * - * <p>Used to quickly discard memory snapshots of the zygote forks from native process - * measurements. - */ - private static final int MIN_APP_UID = 10_000; - - private static final int CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES = 8; static final class CompanionHandler extends Handler { CompanionHandler(Looper looper) { @@ -249,7 +97,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private final Context mContext; private final AlarmManager mAlarmManager; - private final INetworkStatsService mNetworkStatsService; @GuardedBy("sStatsdLock") private static IStatsd sStatsd; private static final Object sStatsdLock = new Object(); @@ -263,52 +110,16 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private StatsManagerService mStatsManagerService; - private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader(); - private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats(); - private WifiManager mWifiManager = null; - private TelephonyManager mTelephony = null; @GuardedBy("sStatsdLock") private final HashSet<Long> mDeathTimeMillis = new HashSet<>(); @GuardedBy("sStatsdLock") private final HashMap<Long, String> mDeletedFiles = new HashMap<>(); private final CompanionHandler mHandler; - // Disables throttler on CPU time readers. - private KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader = - new KernelCpuUidUserSysTimeReader(false); - private KernelCpuSpeedReader[] mKernelCpuSpeedReaders; - private KernelCpuUidFreqTimeReader mCpuUidFreqTimeReader = - new KernelCpuUidFreqTimeReader(false); - private KernelCpuUidActiveTimeReader mCpuUidActiveTimeReader = - new KernelCpuUidActiveTimeReader(false); - private KernelCpuUidClusterTimeReader mCpuUidClusterTimeReader = - new KernelCpuUidClusterTimeReader(false); - private StoragedUidIoStatsReader mStoragedUidIoStatsReader = - new StoragedUidIoStatsReader(); - @Nullable - private final KernelCpuThreadReaderDiff mKernelCpuThreadReader; - - private long mDebugElapsedClockPreviousValue = 0; - private long mDebugElapsedClockPullCount = 0; - private long mDebugFailingElapsedClockPreviousValue = 0; - private long mDebugFailingElapsedClockPullCount = 0; - private BatteryStatsHelper mBatteryStatsHelper = null; - private static final int MAX_BATTERY_STATS_HELPER_FREQUENCY_MS = 1000; - private long mBatteryStatsHelperTimestampMs = -MAX_BATTERY_STATS_HELPER_FREQUENCY_MS; - - private static IThermalService sThermalService; - private File mBaseDir = - new File(SystemServiceManager.ensureSystemDir(), "stats_companion"); - @GuardedBy("this") - ProcessCpuTracker mProcessCpuTracker = null; - public StatsCompanionService(Context context) { super(); mContext = context; mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); - mNetworkStatsService = INetworkStatsService.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); - mBaseDir.mkdirs(); mAppUpdateReceiver = new AppUpdateReceiver(); mUserUpdateReceiver = new BroadcastReceiver() { @Override @@ -331,47 +142,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { }; mShutdownEventReceiver = new ShutdownEventReceiver(); if (DEBUG) Slog.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED."); - PowerProfile powerProfile = new PowerProfile(context); - final int numClusters = powerProfile.getNumCpuClusters(); - mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters]; - int firstCpuOfCluster = 0; - for (int i = 0; i < numClusters; i++) { - final int numSpeedSteps = powerProfile.getNumSpeedStepsInCpuCluster(i); - mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster, - numSpeedSteps); - firstCpuOfCluster += powerProfile.getNumCoresInCpuCluster(i); - } - - // Enable push notifications of throttling from vendor thermal - // management subsystem via thermalservice. - IBinder b = ServiceManager.getService("thermalservice"); - - if (b != null) { - sThermalService = IThermalService.Stub.asInterface(b); - try { - sThermalService.registerThermalEventListener( - new ThermalEventListener()); - Slog.i(TAG, "register thermal listener successfully"); - } catch (RemoteException e) { - // Should never happen. - Slog.e(TAG, "register thermal listener error"); - } - } else { - Slog.e(TAG, "cannot find thermalservice, no throttling push notifications"); - } - - // Default NetworkRequest should cover all transport types. - final NetworkRequest request = new NetworkRequest.Builder().build(); - final ConnectivityManager connectivityManager = - (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - connectivityManager.registerNetworkCallback(request, new ConnectivityStatsCallback()); - HandlerThread handlerThread = new HandlerThread(TAG); handlerThread.start(); mHandler = new CompanionHandler(handlerThread.getLooper()); - mKernelCpuThreadReader = - KernelCpuThreadReaderSettingsObserver.getSettingsModifiedReader(mContext); } private final static int[] toIntArray(List<Integer> list) { @@ -855,8 +629,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { mDeathTimeMillis.add(now); if (mDeathTimeMillis.size() >= DEATH_THRESHOLD) { mDeathTimeMillis.clear(); - File[] configs = FileUtils.listFilesOrEmpty(new File(CONFIG_DIR)); - if (configs.length > 0) { + File[] configs = new File(CONFIG_DIR).listFiles(); + if (configs != null && configs.length > 0) { String fileName = configs[0].getName(); if (configs[0].delete()) { mDeletedFiles.put(now, fileName); @@ -909,28 +683,4 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } } - - // Thermal event received from vendor thermal management subsystem - private static final class ThermalEventListener extends IThermalEventListener.Stub { - @Override - public void notifyThrottling(Temperature temp) { - StatsLog.write(StatsLog.THERMAL_THROTTLING_SEVERITY_STATE_CHANGED, temp.getType(), - temp.getName(), (int) (temp.getValue() * 10), temp.getStatus()); - } - } - - private static final class ConnectivityStatsCallback extends - ConnectivityManager.NetworkCallback { - @Override - public void onAvailable(Network network) { - StatsLog.write(StatsLog.CONNECTIVITY_STATE_CHANGED, network.netId, - StatsLog.CONNECTIVITY_STATE_CHANGED__STATE__CONNECTED); - } - - @Override - public void onLost(Network network) { - StatsLog.write(StatsLog.CONNECTIVITY_STATE_CHANGED, network.netId, - StatsLog.CONNECTIVITY_STATE_CHANGED__STATE__DISCONNECTED); - } - } } diff --git a/api/current.txt b/api/current.txt index 326ae6b54b0b..4ab54b3654b8 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3901,6 +3901,7 @@ package android.app { method public void setImmersive(boolean); method public void setInheritShowWhenLocked(boolean); method public void setIntent(android.content.Intent); + method public void setLocusContext(@Nullable android.content.LocusId, @Nullable android.os.Bundle); method public final void setMediaController(android.media.session.MediaController); method public void setPictureInPictureParams(@NonNull android.app.PictureInPictureParams); method @Deprecated public final void setProgress(int); @@ -6918,6 +6919,7 @@ package android.app.admin { method public boolean removeOverrideApn(@NonNull android.content.ComponentName, int); method public boolean removeUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle); method public boolean requestBugreport(@NonNull android.content.ComponentName); + method public void requestSetLocationProviderAllowed(@NonNull android.content.ComponentName, @NonNull String, boolean); method @Deprecated public boolean resetPassword(String, int); method public boolean resetPasswordWithToken(@NonNull android.content.ComponentName, String, byte[], int); method @Nullable public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(@Nullable android.content.ComponentName, long); @@ -16737,6 +16739,7 @@ package android.hardware { field public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated"; field public static final String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat"; field public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate"; + field public static final String STRING_TYPE_HINGE_ANGLE = "android.sensor.hinge_angle"; field public static final String STRING_TYPE_LIGHT = "android.sensor.light"; field public static final String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration"; field public static final String STRING_TYPE_LOW_LATENCY_OFFBODY_DETECT = "android.sensor.low_latency_offbody_detect"; @@ -16766,6 +16769,7 @@ package android.hardware { field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10 field public static final int TYPE_HEART_BEAT = 31; // 0x1f field public static final int TYPE_HEART_RATE = 21; // 0x15 + field public static final int TYPE_HINGE_ANGLE = 36; // 0x24 field public static final int TYPE_LIGHT = 5; // 0x5 field public static final int TYPE_LINEAR_ACCELERATION = 10; // 0xa field public static final int TYPE_LOW_LATENCY_OFFBODY_DETECT = 34; // 0x22 @@ -25986,6 +25990,7 @@ package android.media { field public static final String KEY_CAPTURE_RATE = "capture-rate"; field public static final String KEY_CHANNEL_COUNT = "channel-count"; field public static final String KEY_CHANNEL_MASK = "channel-mask"; + field public static final String KEY_CODECS_STRING = "codecs-string"; field public static final String KEY_COLOR_FORMAT = "color-format"; field public static final String KEY_COLOR_RANGE = "color-range"; field public static final String KEY_COLOR_STANDARD = "color-standard"; @@ -30046,6 +30051,7 @@ package android.net { method public int getLinkDownstreamBandwidthKbps(); method public int getLinkUpstreamBandwidthKbps(); method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier(); + method public int getOwnerUid(); method public int getSignalStrength(); method @Nullable public android.net.TransportInfo getTransportInfo(); method public boolean hasCapability(int); @@ -30055,6 +30061,7 @@ package android.net { method @NonNull public android.net.NetworkCapabilities setLinkDownstreamBandwidthKbps(int); method @NonNull public android.net.NetworkCapabilities setLinkUpstreamBandwidthKbps(int); method @NonNull public android.net.NetworkCapabilities setNetworkSpecifier(@NonNull android.net.NetworkSpecifier); + method public void setOwnerUid(int); method @NonNull public android.net.NetworkCapabilities setSignalStrength(int); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR; diff --git a/api/system-current.txt b/api/system-current.txt index b4825bfe3695..5691bf3fddbc 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1830,6 +1830,7 @@ package android.content { field @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public static final String ACTION_MANAGE_SPECIAL_APP_ACCESSES = "android.intent.action.MANAGE_SPECIAL_APP_ACCESSES"; field public static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION"; field public static final String ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION"; + field public static final String ACTION_PACKAGE_UNSUSPENDED_MANUALLY = "android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY"; field public static final String ACTION_PENDING_INCIDENT_REPORTS_CHANGED = "android.intent.action.PENDING_INCIDENT_REPORTS_CHANGED"; field public static final String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED"; field public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART"; @@ -1898,26 +1899,6 @@ package android.content { package android.content.integrity { - public final class AppInstallMetadata { - method @NonNull public String getAppCertificate(); - method @Nullable public String getInstallerCertificate(); - method @Nullable public String getInstallerName(); - method @NonNull public String getPackageName(); - method public int getVersionCode(); - method public boolean isPreInstalled(); - } - - public static final class AppInstallMetadata.Builder { - ctor public AppInstallMetadata.Builder(); - method @NonNull public android.content.integrity.AppInstallMetadata build(); - method @NonNull public android.content.integrity.AppInstallMetadata.Builder setAppCertificate(@NonNull String); - method @NonNull public android.content.integrity.AppInstallMetadata.Builder setInstallerCertificate(@NonNull String); - method @NonNull public android.content.integrity.AppInstallMetadata.Builder setInstallerName(@NonNull String); - method @NonNull public android.content.integrity.AppInstallMetadata.Builder setIsPreInstalled(boolean); - method @NonNull public android.content.integrity.AppInstallMetadata.Builder setPackageName(@NonNull String); - method @NonNull public android.content.integrity.AppInstallMetadata.Builder setVersionCode(int); - } - public class AppIntegrityManager { method @NonNull public String getCurrentRuleSetProvider(); method @NonNull public String getCurrentRuleSetVersion(); @@ -1927,84 +1908,28 @@ package android.content.integrity { field public static final int STATUS_SUCCESS = 0; // 0x0 } - public abstract class AtomicFormula implements android.content.integrity.Formula { - ctor public AtomicFormula(int); - method public int getKey(); - field public static final int APP_CERTIFICATE = 1; // 0x1 - field public static final int EQ = 0; // 0x0 - field public static final int GE = 4; // 0x4 - field public static final int GT = 3; // 0x3 - field public static final int INSTALLER_CERTIFICATE = 3; // 0x3 - field public static final int INSTALLER_NAME = 2; // 0x2 - field public static final int LE = 2; // 0x2 - field public static final int LT = 1; // 0x1 - field public static final int PACKAGE_NAME = 0; // 0x0 - field public static final int PRE_INSTALLED = 5; // 0x5 - field public static final int VERSION_CODE = 4; // 0x4 - } - - public static final class AtomicFormula.BooleanAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable { - ctor public AtomicFormula.BooleanAtomicFormula(int, boolean); - method public int describeContents(); - method public int getTag(); - method public boolean getValue(); - method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.AtomicFormula.BooleanAtomicFormula> CREATOR; - } - - public static final class AtomicFormula.IntAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable { - ctor public AtomicFormula.IntAtomicFormula(int, int, int); - method public int describeContents(); - method public int getOperator(); - method public int getTag(); - method public int getValue(); - method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.AtomicFormula.IntAtomicFormula> CREATOR; - } - - public static final class AtomicFormula.StringAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable { - ctor public AtomicFormula.StringAtomicFormula(int, @NonNull String, boolean); - method public int describeContents(); - method public boolean getIsHashedValue(); - method public int getTag(); - method @NonNull public String getValue(); - method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.AtomicFormula.StringAtomicFormula> CREATOR; - } - - public final class CompoundFormula implements android.content.integrity.Formula android.os.Parcelable { - ctor public CompoundFormula(int, @NonNull java.util.List<android.content.integrity.Formula>); - method public int describeContents(); - method public int getConnector(); - method @NonNull public java.util.List<android.content.integrity.Formula> getFormulas(); - method public int getTag(); - method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field public static final int AND = 0; // 0x0 - field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.CompoundFormula> CREATOR; - field public static final int NOT = 2; // 0x2 - field public static final int OR = 1; // 0x1 - } - - public interface Formula { - method public int getTag(); - method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata); - method @NonNull public static android.content.integrity.Formula readFromParcel(@NonNull android.os.Parcel); - method public static void writeToParcel(@NonNull android.content.integrity.Formula, @NonNull android.os.Parcel, int); - field public static final int BOOLEAN_ATOMIC_FORMULA_TAG = 3; // 0x3 - field public static final int COMPOUND_FORMULA_TAG = 0; // 0x0 - field public static final int INT_ATOMIC_FORMULA_TAG = 2; // 0x2 - field public static final int STRING_ATOMIC_FORMULA_TAG = 1; // 0x1 + public abstract class IntegrityFormula { + method @NonNull public static android.content.integrity.IntegrityFormula all(@NonNull android.content.integrity.IntegrityFormula...); + method @NonNull public static android.content.integrity.IntegrityFormula any(@NonNull android.content.integrity.IntegrityFormula...); + method @NonNull public android.content.integrity.IntegrityFormula equalTo(@NonNull String); + method @NonNull public android.content.integrity.IntegrityFormula equalTo(boolean); + method @NonNull public android.content.integrity.IntegrityFormula equalTo(long); + method @NonNull public android.content.integrity.IntegrityFormula greaterThan(long); + method @NonNull public android.content.integrity.IntegrityFormula greaterThanOrEquals(long); + method @NonNull public static android.content.integrity.IntegrityFormula not(@NonNull android.content.integrity.IntegrityFormula); + field @NonNull public static final android.content.integrity.IntegrityFormula APP_CERTIFICATE; + field @NonNull public static final android.content.integrity.IntegrityFormula INSTALLER_CERTIFICATE; + field @NonNull public static final android.content.integrity.IntegrityFormula INSTALLER_NAME; + field @NonNull public static final android.content.integrity.IntegrityFormula PACKAGE_NAME; + field @NonNull public static final android.content.integrity.IntegrityFormula PRE_INSTALLED; + field @NonNull public static final android.content.integrity.IntegrityFormula VERSION_CODE; } public final class Rule implements android.os.Parcelable { - ctor public Rule(@NonNull android.content.integrity.Formula, int); + ctor public Rule(@NonNull android.content.integrity.IntegrityFormula, int); method public int describeContents(); method public int getEffect(); - method @NonNull public android.content.integrity.Formula getFormula(); + method @NonNull public android.content.integrity.IntegrityFormula getFormula(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.Rule> CREATOR; field public static final int DENY = 0; // 0x0 @@ -2042,8 +1967,8 @@ package android.content.om { public class OverlayManager { method @Nullable public android.content.om.OverlayInfo getOverlayInfo(@NonNull String, @NonNull android.os.UserHandle); method @NonNull @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public java.util.List<android.content.om.OverlayInfo> getOverlayInfosForTarget(@NonNull String, @NonNull android.os.UserHandle); - method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public void setEnabled(@NonNull String, boolean, @NonNull android.os.UserHandle); - method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public void setEnabledExclusiveInCategory(@NonNull String, @NonNull android.os.UserHandle); + method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public void setEnabled(@NonNull String, boolean, @NonNull android.os.UserHandle) throws java.lang.IllegalStateException, java.lang.SecurityException; + method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public void setEnabledExclusiveInCategory(@NonNull String, @NonNull android.os.UserHandle) throws java.lang.IllegalStateException, java.lang.SecurityException; } } @@ -2259,6 +2184,7 @@ package android.content.pm { method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable String); method @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable android.content.pm.SuspendDialogInfo); method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public void setSyntheticAppDetailsActivityEnabled(@NonNull String, boolean); + method public void setSystemAppState(@NonNull String, int); method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public abstract void setUpdateAvailable(@NonNull String, boolean); method @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS) public abstract boolean updateIntentVerificationStatusAsUser(@NonNull String, int, int); method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, @android.content.pm.PackageManager.PermissionFlags int, @android.content.pm.PackageManager.PermissionFlags int, @NonNull android.os.UserHandle); @@ -2339,6 +2265,10 @@ package android.content.pm { field public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 1; // 0x1 field public static final int RESTRICTION_HIDE_NOTIFICATIONS = 2; // 0x2 field public static final int RESTRICTION_NONE = 0; // 0x0 + field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN = 0; // 0x0 + field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE = 1; // 0x1 + field public static final int SYSTEM_APP_STATE_INSTALLED = 2; // 0x2 + field public static final int SYSTEM_APP_STATE_UNINSTALLED = 3; // 0x3 } public abstract static class PackageManager.DexModuleRegisterCallback { @@ -2399,6 +2329,8 @@ package android.content.pm { public final class SuspendDialogInfo implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); + field public static final int BUTTON_ACTION_MORE_DETAILS = 0; // 0x0 + field public static final int BUTTON_ACTION_UNSUSPEND = 1; // 0x1 field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.SuspendDialogInfo> CREATOR; } @@ -2408,6 +2340,7 @@ package android.content.pm { method @NonNull public android.content.pm.SuspendDialogInfo.Builder setIcon(@DrawableRes int); method @NonNull public android.content.pm.SuspendDialogInfo.Builder setMessage(@NonNull String); method @NonNull public android.content.pm.SuspendDialogInfo.Builder setMessage(@StringRes int); + method @NonNull public android.content.pm.SuspendDialogInfo.Builder setNeutralButtonAction(int); method @NonNull public android.content.pm.SuspendDialogInfo.Builder setNeutralButtonText(@StringRes int); method @NonNull public android.content.pm.SuspendDialogInfo.Builder setTitle(@StringRes int); } @@ -8411,7 +8344,7 @@ package android.os { method @NonNull public android.os.BatterySaverPolicyConfig.Builder setLocationMode(int); } - public final class BatteryStatsManager { + public class BatteryStatsManager { method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.CellularBatteryStats getCellularBatteryStats(); method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.WifiBatteryStats getWifiBatteryStats(); method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockAcquiredFromSource(@NonNull android.os.WorkSource); @@ -8891,7 +8824,6 @@ package android.os { method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getEuiccControllerService(); method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getIccPhoneBookServiceRegisterer(); method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getOpportunisticNetworkServiceRegisterer(); - method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getPackageManagerServiceRegisterer(); method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getPhoneSubServiceRegisterer(); method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getSmsServiceRegisterer(); method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getSubscriptionServiceRegisterer(); @@ -9232,6 +9164,7 @@ package android.permission { public final class PermissionManager { method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public int getRuntimePermissionsVersion(); method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions(); + method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledCarrierApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledImsServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledTelephonyDataServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToLuiApp(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); @@ -12270,6 +12203,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption(); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void resetIms(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig(); method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings(); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index d952be5218a4..d8b5e7f3b5b0 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -45,6 +45,7 @@ import android.content.CursorLoader; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; +import android.content.LocusId; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; @@ -1025,6 +1026,39 @@ public class Activity extends ContextThemeWrapper mIntent = newIntent; } + /** + * Sets the {@link android.content.LocusId} for this activity. The locus id + * helps identify different instances of the same {@code Activity} class. + * <p> For example, a locus id based on a specific conversation could be set on a + * conversation app's chat {@code Activity}. The system can then use this locus id + * along with app's contents to provide ranking signals in various UI surfaces + * including sharing, notifications, shortcuts and so on. + * <p> It is recommended to set the same locus id in the shortcut's locus id using + * {@link android.content.pm.ShortcutInfo.Builder#setLocusId(android.content.LocusId) + * setLocusId} + * so that the system can learn appropriate ranking signals linking the activity's + * locus id with the matching shortcut. + * + * @param locusId a unique, stable id that identifies this {@code Activity} instance from + * others. This can be linked to a shortcut using + * {@link android.content.pm.ShortcutInfo.Builder#setLocusId(android.content.LocusId) + * setLocusId} with the same locus id string. + * @param bundle extras set or updated as part of this locus context. This may help provide + * additional metadata such as URLs, conversation participants specific to this + * {@code Activity}'s context. + * + * @see android.view.contentcapture.ContentCaptureManager + * @see android.view.contentcapture.ContentCaptureContext + */ + public void setLocusContext(@Nullable LocusId locusId, @Nullable Bundle bundle) { + try { + ActivityManager.getService().setActivityLocusContext(mComponent, locusId, mToken); + } catch (RemoteException re) { + re.rethrowFromSystemServer(); + } + // TODO(b/147750355): Pass locusId and bundle to the Content Capture. + } + /** Return the application that owns this activity. */ public final Application getApplication() { return mApplication; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index f7c4d96d0d40..e0a4ae287408 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -73,6 +73,7 @@ import android.util.DisplayMetrics; import android.util.Singleton; import android.util.Size; import android.view.IWindowContainer; +import android.view.Surface; import com.android.internal.app.LocalePicker; import com.android.internal.app.procstats.ProcessStats; @@ -1928,7 +1929,12 @@ public class ActivityManager { // Top activity in task when snapshot was taken private final ComponentName mTopActivityComponent; private final GraphicBuffer mSnapshot; + /** Indicates whether task was in landscape or portrait */ + @Configuration.Orientation private final int mOrientation; + /** See {@link android.view.Surface.Rotation} */ + @Surface.Rotation + private int mRotation; private final Rect mContentInsets; // Whether this snapshot is a down-sampled version of the full resolution, used mainly for // low-ram devices @@ -1945,7 +1951,7 @@ public class ActivityManager { public TaskSnapshot(long id, @NonNull ComponentName topActivityComponent, GraphicBuffer snapshot, - @NonNull ColorSpace colorSpace, int orientation, Rect contentInsets, + @NonNull ColorSpace colorSpace, int orientation, int rotation, Rect contentInsets, boolean reducedResolution, float scale, boolean isRealSnapshot, int windowingMode, int systemUiVisibility, boolean isTranslucent) { mId = id; @@ -1954,6 +1960,7 @@ public class ActivityManager { mColorSpace = colorSpace.getId() < 0 ? ColorSpace.get(ColorSpace.Named.SRGB) : colorSpace; mOrientation = orientation; + mRotation = rotation; mContentInsets = new Rect(contentInsets); mReducedResolution = reducedResolution; mScale = scale; @@ -1972,6 +1979,7 @@ public class ActivityManager { ? ColorSpace.get(ColorSpace.Named.values()[colorSpaceId]) : ColorSpace.get(ColorSpace.Named.SRGB); mOrientation = source.readInt(); + mRotation = source.readInt(); mContentInsets = source.readParcelable(null /* classLoader */); mReducedResolution = source.readBoolean(); mScale = source.readFloat(); @@ -2019,6 +2027,13 @@ public class ActivityManager { } /** + * @return The screen rotation the screenshot was taken in. + */ + public int getRotation() { + return mRotation; + } + + /** * @return The system/content insets on the snapshot. These can be clipped off in order to * remove any areas behind system bars in the snapshot. */ @@ -2087,6 +2102,7 @@ public class ActivityManager { dest.writeParcelable(mSnapshot, 0); dest.writeInt(mColorSpace.getId()); dest.writeInt(mOrientation); + dest.writeInt(mRotation); dest.writeParcelable(mContentInsets, 0); dest.writeBoolean(mReducedResolution); dest.writeFloat(mScale); @@ -2106,6 +2122,7 @@ public class ActivityManager { + " mSnapshot=" + mSnapshot + " (" + width + "x" + height + ")" + " mColorSpace=" + mColorSpace.toString() + " mOrientation=" + mOrientation + + " mRotation=" + mRotation + " mContentInsets=" + mContentInsets.toShortString() + " mReducedResolution=" + mReducedResolution + " mScale=" + mScale + " mIsRealSnapshot=" + mIsRealSnapshot + " mWindowingMode=" + mWindowingMode @@ -2129,6 +2146,7 @@ public class ActivityManager { private GraphicBuffer mSnapshot; private ColorSpace mColorSpace; private int mOrientation; + private int mRotation; private Rect mContentInsets; private boolean mReducedResolution; private float mScaleFraction; @@ -2163,6 +2181,11 @@ public class ActivityManager { return this; } + public Builder setRotation(int rotation) { + mRotation = rotation; + return this; + } + public Builder setContentInsets(Rect contentInsets) { mContentInsets = contentInsets; return this; @@ -2218,6 +2241,7 @@ public class ActivityManager { mSnapshot, mColorSpace, mOrientation, + mRotation, mContentInsets, mReducedResolution, mScaleFraction, diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 4e6319db97f4..c09aa1ff05a8 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -131,7 +131,7 @@ public class ApplicationPackageManager extends PackageManager { private static final int DEFAULT_EPHEMERAL_COOKIE_MAX_SIZE_BYTES = 16384; // 16KB // Default flags to use with PackageManager when no flags are given. - private final static int sDefaultFlags = PackageManager.GET_SHARED_LIBRARY_FILES; + private static final int sDefaultFlags = GET_SHARED_LIBRARY_FILES; // Name of the resource which provides background permission button string public static final String APP_PERMISSION_BUTTON_ALLOW_ALWAYS = @@ -907,7 +907,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public boolean hasSigningCertificate( - String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) { + String packageName, byte[] certificate, @CertificateInputType int type) { try { return mPM.hasSigningCertificate(packageName, certificate, type); } catch (RemoteException e) { @@ -917,7 +917,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public boolean hasSigningCertificate( - int uid, byte[] certificate, @PackageManager.CertificateInputType int type) { + int uid, byte[] certificate, @CertificateInputType int type) { try { return mPM.hasUidSigningCertificate(uid, certificate, type); } catch (RemoteException e) { @@ -1464,8 +1464,7 @@ public class ApplicationPackageManager extends PackageManager { return getActivityIcon(intent.getComponent()); } - ResolveInfo info = resolveActivity( - intent, PackageManager.MATCH_DEFAULT_ONLY); + ResolveInfo info = resolveActivity(intent, MATCH_DEFAULT_ONLY); if (info != null) { return info.activityInfo.loadIcon(this); } @@ -1500,7 +1499,7 @@ public class ApplicationPackageManager extends PackageManager { } ResolveInfo info = resolveActivity( - intent, PackageManager.MATCH_DEFAULT_ONLY); + intent, MATCH_DEFAULT_ONLY); if (info != null) { return info.activityInfo.loadBanner(this); } @@ -1532,8 +1531,7 @@ public class ApplicationPackageManager extends PackageManager { return getActivityLogo(intent.getComponent()); } - ResolveInfo info = resolveActivity( - intent, PackageManager.MATCH_DEFAULT_ONLY); + ResolveInfo info = resolveActivity(intent, MATCH_DEFAULT_ONLY); if (info != null) { return info.activityInfo.loadLogo(this); } @@ -2017,7 +2015,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public int installExistingPackage(String packageName) throws NameNotFoundException { - return installExistingPackage(packageName, PackageManager.INSTALL_REASON_UNKNOWN); + return installExistingPackage(packageName, INSTALL_REASON_UNKNOWN); } @Override @@ -2029,7 +2027,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public int installExistingPackageAsUser(String packageName, int userId) throws NameNotFoundException { - return installExistingPackageAsUser(packageName, PackageManager.INSTALL_REASON_UNKNOWN, + return installExistingPackageAsUser(packageName, INSTALL_REASON_UNKNOWN, userId); } @@ -2404,7 +2402,7 @@ public class ApplicationPackageManager extends PackageManager { public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags, int userId) { try { - mPM.deletePackageAsUser(packageName, PackageManager.VERSION_CODE_HIGHEST, + mPM.deletePackageAsUser(packageName, VERSION_CODE_HIGHEST, observer, userId, flags); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -2651,11 +2649,11 @@ public class ApplicationPackageManager extends PackageManager { public void setSyntheticAppDetailsActivityEnabled(String packageName, boolean enabled) { try { ComponentName componentName = new ComponentName(packageName, - PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME); + APP_DETAILS_ACTIVITY_CLASS_NAME); mPM.setComponentEnabledSetting(componentName, enabled - ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT - : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP, getUserId()); + ? COMPONENT_ENABLED_STATE_DEFAULT + : COMPONENT_ENABLED_STATE_DISABLED, + DONT_KILL_APP, getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2665,10 +2663,10 @@ public class ApplicationPackageManager extends PackageManager { public boolean getSyntheticAppDetailsActivityEnabled(String packageName) { try { ComponentName componentName = new ComponentName(packageName, - PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME); + APP_DETAILS_ACTIVITY_CLASS_NAME); int state = mPM.getComponentEnabledSetting(componentName, getUserId()); - return state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED - || state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; + return state == COMPONENT_ENABLED_STATE_ENABLED + || state == COMPONENT_ENABLED_STATE_DEFAULT; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2744,6 +2742,30 @@ public class ApplicationPackageManager extends PackageManager { /** @hide */ @Override + public void setSystemAppState(String packageName, @SystemAppState int state) { + try { + switch (state) { + case SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN: + mPM.setSystemAppHiddenUntilInstalled(packageName, true); + break; + case SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE: + mPM.setSystemAppHiddenUntilInstalled(packageName, false); + break; + case SYSTEM_APP_STATE_INSTALLED: + mPM.setSystemAppInstallState(packageName, true, getUserId()); + break; + case SYSTEM_APP_STATE_UNINSTALLED: + mPM.setSystemAppInstallState(packageName, false, getUserId()); + break; + default: + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ + @Override public KeySet getKeySetByAlias(String packageName, String alias) { Objects.requireNonNull(packageName); Objects.requireNonNull(alias); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 7d04ca0afe7e..3ffd7c70b40d 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -53,6 +53,7 @@ import android.content.pm.ParceledListSlice; import android.content.pm.ProviderInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; +import android.content.LocusId; import android.graphics.Bitmap; import android.graphics.GraphicBuffer; import android.graphics.Point; @@ -637,4 +638,13 @@ interface IActivityManager { * and the given process is imperceptible. */ void killProcessesWhenImperceptible(in int[] pids, String reason); + + /** + * Set locus context for a given activity. + * @param activity + * @param locusId a unique, stable id that identifies this activity instance from others. + * @param appToken ActivityRecord's appToken. + */ + void setActivityLocusContext(in ComponentName activity, in LocusId locusId, + in IBinder appToken); } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index f4dc0bffd5ed..d1b5a83e7142 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -8855,6 +8855,49 @@ public class DevicePolicyManager { } /** + * Called by device owners to request a location provider to change its allowed state. For a + * provider to be enabled requires both that the master location setting is enabled, and that + * the provider itself is allowed. Most location providers are always allowed. Some location + * providers may have user consents or terms and conditions that must be accepted, or some other + * type of blocker before they are allowed however. Every location provider is responsible for + * its own allowed state. + * + * <p>This method requests that a location provider change its allowed state. For providers that + * are always allowed and have no state to change, this will have no effect. If the provider + * does require some consent, terms and conditions, or other blocking state, using this API + * implies that the device owner is agreeing/disagreeing to any consents, terms and conditions, + * etc, and the provider should make a best effort to adjust it's allowed state accordingly. + * + * <p>Location providers are generally only responsible for the current user, and callers must + * assume that this method will only affect provider state for the current user. Callers are + * responsible for tracking current user changes and re-updating provider state as necessary. + * + * <p>While providers are expected to make a best effort to honor this request, it is not a + * given that all providers will support such a request. If a provider does change its state as + * a result of this request, that may happen asynchronously after some delay. Test location + * providers set through {@link android.location.LocationManager#addTestProvider} will respond + * to this request to aide in testing. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with + * @param provider A location provider as listed by + * {@link android.location.LocationManager#getAllProviders()} + * @param providerAllowed Whether the location provider is being requested to enable or disable + * itself + * @throws SecurityException if {@code admin} is not a device owner. + */ + public void requestSetLocationProviderAllowed(@NonNull ComponentName admin, + @NonNull String provider, boolean providerAllowed) { + throwIfParentInstance("requestSetLocationProviderAllowed"); + if (mService != null) { + try { + mService.requestSetLocationProviderAllowed(admin, provider, providerAllowed); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** * Called by profile or device owners to update {@link android.provider.Settings.Secure} * settings. Validation that the value of the setting is in the correct form for the setting * type should be performed by the caller. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index ab0598b76b82..e3dba310ab44 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -270,6 +270,7 @@ interface IDevicePolicyManager { boolean isLockdownAdminConfiguredNetworks(in ComponentName who); void setLocationEnabled(in ComponentName who, boolean locationEnabled); + void requestSetLocationProviderAllowed(in ComponentName who, in String provider, boolean providerAllowed); boolean setTime(in ComponentName who, long millis); boolean setTimeZone(in ComponentName who, String timeZone); diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index 6ab880dfb36d..ab71e73fd58c 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -290,10 +290,16 @@ public final class UsageEvents implements Parcelable { public static final int USER_STOPPED = 29; /** + * An event type denoting that new locusId has been set for a given activity. + * @hide + */ + public static final int LOCUS_ID_SET = 30; + + /** * Keep in sync with the greatest event type value. * @hide */ - public static final int MAX_EVENT_TYPE = 29; + public static final int MAX_EVENT_TYPE = 30; /** @hide */ public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0; @@ -436,6 +442,18 @@ public final class UsageEvents implements Parcelable { */ public int mNotificationChannelIdToken = UNASSIGNED_TOKEN; + /** + * LocusId. + * Currently LocusId only present for {@link #LOCUS_ID_SET} event types. + * {@hide} + */ + public String mLocusId; + + /** + * {@hide} + */ + public int mLocusIdToken = UNASSIGNED_TOKEN; + /** @hide */ @EventFlags public int mFlags; @@ -609,6 +627,16 @@ public final class UsageEvents implements Parcelable { return ret; } + /** + * Returns the locusId for this event if the event is of type {@link #LOCUS_ID_SET}, + * otherwise it returns null. + * @hide + */ + @Nullable + public String getLocusId() { + return mLocusId; + } + private void copyFrom(Event orig) { mPackage = orig.mPackage; mClass = orig.mClass; @@ -625,6 +653,7 @@ public final class UsageEvents implements Parcelable { mFlags = orig.mFlags; mBucketAndReason = orig.mBucketAndReason; mNotificationChannelId = orig.mNotificationChannelId; + mLocusId = orig.mLocusId; } } @@ -823,6 +852,9 @@ public final class UsageEvents implements Parcelable { case Event.NOTIFICATION_INTERRUPTION: p.writeString(event.mNotificationChannelId); break; + case Event.LOCUS_ID_SET: + p.writeString(event.mLocusId); + break; } p.writeInt(event.mFlags); } @@ -871,6 +903,7 @@ public final class UsageEvents implements Parcelable { eventOut.mContentType = null; eventOut.mContentAnnotations = null; eventOut.mNotificationChannelId = null; + eventOut.mLocusId = null; switch (eventOut.mEventType) { case Event.CONFIGURATION_CHANGE: @@ -891,6 +924,9 @@ public final class UsageEvents implements Parcelable { case Event.NOTIFICATION_INTERRUPTION: eventOut.mNotificationChannelId = p.readString(); break; + case Event.LOCUS_ID_SET: + eventOut.mLocusId = p.readString(); + break; } eventOut.mFlags = p.readInt(); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 5852a93ea221..a07625315a2d 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -36,6 +36,7 @@ import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; +import android.content.pm.SuspendDialogInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Rect; @@ -2667,6 +2668,34 @@ public class Intent implements Parcelable, Cloneable { "android.intent.action.SHOW_SUSPENDED_APP_DETAILS"; /** + * Broadcast Action: Sent to indicate that the user unsuspended a package. + * + * <p>This can happen when the user taps on the neutral button of the + * {@linkplain SuspendDialogInfo suspend-dialog} which was created by using + * {@link SuspendDialogInfo#BUTTON_ACTION_UNSUSPEND}. This broadcast is only sent to the + * suspending app that originally specified this dialog while calling + * {@link PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle, + * PersistableBundle, SuspendDialogInfo)}. + * + * <p>Includes an extra {@link #EXTRA_PACKAGE_NAME} which is the name of the package that just + * got unsuspended. + * + * <p class="note">This is a protected intent that can only be sent + * by the system. <em>This will be delivered to {@link BroadcastReceiver} components declared in + * the manifest.</em> + * + * @see PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle, + * PersistableBundle, SuspendDialogInfo) + * @see PackageManager#isPackageSuspended() + * @see SuspendDialogInfo#BUTTON_ACTION_MORE_DETAILS + * @hide + */ + @SystemApi + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_PACKAGE_UNSUSPENDED_MANUALLY = + "android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY"; + + /** * Broadcast Action: Sent to a package that has been unsuspended. * * <p class="note">This is a protected intent that can only be sent diff --git a/core/java/android/content/LocusId.aidl b/core/java/android/content/LocusId.aidl new file mode 100644 index 000000000000..eb98db06ccbf --- /dev/null +++ b/core/java/android/content/LocusId.aidl @@ -0,0 +1,19 @@ +/** + * 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 android.content; + +parcelable LocusId; diff --git a/core/java/android/content/integrity/AppInstallMetadata.java b/core/java/android/content/integrity/AppInstallMetadata.java index 85af8813fa94..351edc92888d 100644 --- a/core/java/android/content/integrity/AppInstallMetadata.java +++ b/core/java/android/content/integrity/AppInstallMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -17,10 +17,6 @@ package android.content.integrity; import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; - -import com.android.internal.annotations.VisibleForTesting; import java.util.Objects; @@ -34,8 +30,6 @@ import java.util.Objects; * * @hide */ -@SystemApi -@VisibleForTesting public final class AppInstallMetadata { private final String mPackageName; // Raw string encoding for the SHA-256 hash of the certificate of the app. @@ -43,7 +37,7 @@ public final class AppInstallMetadata { private final String mInstallerName; // Raw string encoding for the SHA-256 hash of the certificate of the installer. private final String mInstallerCertificate; - private final int mVersionCode; + private final long mVersionCode; private final boolean mIsPreInstalled; private AppInstallMetadata(Builder builder) { @@ -65,18 +59,18 @@ public final class AppInstallMetadata { return mAppCertificate; } - @Nullable + @NonNull public String getInstallerName() { return mInstallerName; } - @Nullable + @NonNull public String getInstallerCertificate() { return mInstallerCertificate; } - /** @see AppInstallMetadata.Builder#setVersionCode(int) */ - public int getVersionCode() { + /** @see AppInstallMetadata.Builder#setVersionCode(long) */ + public long getVersionCode() { return mVersionCode; } @@ -104,7 +98,7 @@ public final class AppInstallMetadata { private String mAppCertificate; private String mInstallerName; private String mInstallerCertificate; - private int mVersionCode; + private long mVersionCode; private boolean mIsPreInstalled; /** @@ -163,7 +157,7 @@ public final class AppInstallMetadata { * @see AppInstallMetadata#getVersionCode() */ @NonNull - public Builder setVersionCode(int versionCode) { + public Builder setVersionCode(long versionCode) { this.mVersionCode = versionCode; return this; } diff --git a/core/java/android/content/integrity/AtomicFormula.java b/core/java/android/content/integrity/AtomicFormula.java index 574a93ff9355..4c10a8f7ad38 100644 --- a/core/java/android/content/integrity/AtomicFormula.java +++ b/core/java/android/content/integrity/AtomicFormula.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -20,15 +20,16 @@ import static com.android.internal.util.Preconditions.checkArgument; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; -import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.Objects; /** @@ -38,29 +39,28 @@ import java.util.Objects; * * @hide */ -@SystemApi @VisibleForTesting -public abstract class AtomicFormula implements Formula { - - private static final String TAG = "AtomicFormula"; +public abstract class AtomicFormula extends IntegrityFormula { /** @hide */ @IntDef( value = { - PACKAGE_NAME, - APP_CERTIFICATE, - INSTALLER_NAME, - INSTALLER_CERTIFICATE, - VERSION_CODE, - PRE_INSTALLED, + PACKAGE_NAME, + APP_CERTIFICATE, + INSTALLER_NAME, + INSTALLER_CERTIFICATE, + VERSION_CODE, + PRE_INSTALLED, }) @Retention(RetentionPolicy.SOURCE) - public @interface Key {} + public @interface Key { + } /** @hide */ - @IntDef(value = {EQ, LT, LE, GT, GE}) + @IntDef(value = {EQ, GT, GTE}) @Retention(RetentionPolicy.SOURCE) - public @interface Operator {} + public @interface Operator { + } /** * Package name of the app. @@ -94,7 +94,7 @@ public abstract class AtomicFormula implements Formula { /** * Version code of the app. * - * <p>Can only be used in {@link IntAtomicFormula}. + * <p>Can only be used in {@link LongAtomicFormula}. */ public static final int VERSION_CODE = 4; @@ -106,10 +106,8 @@ public abstract class AtomicFormula implements Formula { public static final int PRE_INSTALLED = 5; public static final int EQ = 0; - public static final int LT = 1; - public static final int LE = 2; - public static final int GT = 3; - public static final int GE = 4; + public static final int GT = 1; + public static final int GTE = 2; private final @Key int mKey; @@ -118,78 +116,99 @@ public abstract class AtomicFormula implements Formula { mKey = key; } - /** An {@link AtomicFormula} with an key and int value. */ - public static final class IntAtomicFormula extends AtomicFormula implements Parcelable { - private final int mValue; - private final @Operator int mOperator; + /** An {@link AtomicFormula} with an key and long value. */ + public static final class LongAtomicFormula extends AtomicFormula implements Parcelable { + private final Long mValue; + private final @Operator Integer mOperator; + + /** + * Constructs an empty {@link LongAtomicFormula}. This should only be used as a base. + * + * <p>This formula will always return false. + * + * @throws IllegalArgumentException if {@code key} cannot be used with long value + */ + public LongAtomicFormula(@Key int key) { + super(key); + checkArgument( + key == VERSION_CODE, + String.format( + "Key %s cannot be used with LongAtomicFormula", keyToString(key))); + mValue = null; + mOperator = null; + } /** - * Constructs a new {@link IntAtomicFormula}. + * Constructs a new {@link LongAtomicFormula}. * * <p>This formula will hold if and only if the corresponding information of an install * specified by {@code key} is of the correct relationship to {@code value} as specified by * {@code operator}. * - * @throws IllegalArgumentException if {@code key} cannot be used with integer value + * @throws IllegalArgumentException if {@code key} cannot be used with long value */ - public IntAtomicFormula(@Key int key, @Operator int operator, int value) { + public LongAtomicFormula(@Key int key, @Operator int operator, long value) { super(key); checkArgument( key == VERSION_CODE, - String.format("Key %s cannot be used with IntAtomicFormula", keyToString(key))); - checkArgument(isValidOperator(operator), - String.format("Unknown operator: %d", operator)); + String.format( + "Key %s cannot be used with LongAtomicFormula", keyToString(key))); + checkArgument( + isValidOperator(operator), String.format("Unknown operator: %d", operator)); mOperator = operator; mValue = value; } - IntAtomicFormula(Parcel in) { + LongAtomicFormula(Parcel in) { super(in.readInt()); - mValue = in.readInt(); + mValue = in.readLong(); mOperator = in.readInt(); } @NonNull - public static final Creator<IntAtomicFormula> CREATOR = - new Creator<IntAtomicFormula>() { + public static final Creator<LongAtomicFormula> CREATOR = + new Creator<LongAtomicFormula>() { @Override - public IntAtomicFormula createFromParcel(Parcel in) { - return new IntAtomicFormula(in); + public LongAtomicFormula createFromParcel(Parcel in) { + return new LongAtomicFormula(in); } @Override - public IntAtomicFormula[] newArray(int size) { - return new IntAtomicFormula[size]; + public LongAtomicFormula[] newArray(int size) { + return new LongAtomicFormula[size]; } }; @Override - public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) { - int metadataValue = getMetadataValueByKey(appInstallMetadata); + public int getTag() { + return IntegrityFormula.LONG_ATOMIC_FORMULA_TAG; + } + + @Override + public boolean matches(AppInstallMetadata appInstallMetadata) { + if (mValue == null || mOperator == null) { + return false; + } + + long metadataValue = getLongMetadataValue(appInstallMetadata, getKey()); switch (mOperator) { case EQ: return metadataValue == mValue; - case LE: - return metadataValue <= mValue; - case LT: - return metadataValue < mValue; - case GE: - return metadataValue >= mValue; case GT: return metadataValue > mValue; + case GTE: + return metadataValue >= mValue; default: - Slog.i(TAG, String.format("Unexpected operator %d", mOperator)); - return false; + throw new IllegalArgumentException( + String.format("Unexpected operator %d", mOperator)); } } @Override - public int getTag() { - return Formula.INT_ATOMIC_FORMULA_TAG; - } - - @Override public String toString() { + if (mValue == null || mOperator == null) { + return String.format("(%s)", keyToString(getKey())); + } return String.format( "(%s %s %s)", keyToString(getKey()), operatorToString(mOperator), mValue); } @@ -202,7 +221,7 @@ public abstract class AtomicFormula implements Formula { if (o == null || getClass() != o.getClass()) { return false; } - IntAtomicFormula that = (IntAtomicFormula) o; + LongAtomicFormula that = (LongAtomicFormula) o; return getKey() == that.getKey() && mValue == that.mValue && mOperator == that.mOperator; @@ -220,35 +239,35 @@ public abstract class AtomicFormula implements Formula { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { + if (mValue == null || mOperator == null) { + throw new IllegalStateException("Cannot write an empty LongAtomicFormula."); + } dest.writeInt(getKey()); - dest.writeInt(mValue); + dest.writeLong(mValue); dest.writeInt(mOperator); } - public int getValue() { + public Long getValue() { return mValue; } - public int getOperator() { + public Integer getOperator() { return mOperator; } - private int getMetadataValueByKey(AppInstallMetadata appInstallMetadata) { - switch (getKey()) { - case VERSION_CODE: - return appInstallMetadata.getVersionCode(); - default: - throw new IllegalStateException( - "Unexpected key in IntAtomicFormula" + getKey()); - } - } - private static boolean isValidOperator(int operator) { return operator == EQ - || operator == LT - || operator == LE || operator == GT - || operator == GE; + || operator == GTE; + } + + private static long getLongMetadataValue(AppInstallMetadata appInstallMetadata, int key) { + switch (key) { + case AtomicFormula.VERSION_CODE: + return appInstallMetadata.getVersionCode(); + default: + throw new IllegalStateException("Unexpected key in IntAtomicFormula" + key); + } } } @@ -256,7 +275,27 @@ public abstract class AtomicFormula implements Formula { public static final class StringAtomicFormula extends AtomicFormula implements Parcelable { private final String mValue; // Indicates whether the value is the actual value or the hashed value. - private final boolean mIsHashedValue; + private final Boolean mIsHashedValue; + + /** + * Constructs an empty {@link StringAtomicFormula}. This should only be used as a base. + * + * <p>An empty formula will always match to false. + * + * @throws IllegalArgumentException if {@code key} cannot be used with string value + */ + public StringAtomicFormula(@Key int key) { + super(key); + checkArgument( + key == PACKAGE_NAME + || key == APP_CERTIFICATE + || key == INSTALLER_CERTIFICATE + || key == INSTALLER_NAME, + String.format( + "Key %s cannot be used with StringAtomicFormula", keyToString(key))); + mValue = null; + mIsHashedValue = null; + } /** * Constructs a new {@link StringAtomicFormula}. @@ -266,9 +305,8 @@ public abstract class AtomicFormula implements Formula { * * @throws IllegalArgumentException if {@code key} cannot be used with string value */ - public StringAtomicFormula(@Key int key, @NonNull String value, boolean isHashedValue) { + public StringAtomicFormula(@Key int key, @NonNull String value, boolean isHashed) { super(key); - mIsHashedValue = isHashedValue; checkArgument( key == PACKAGE_NAME || key == APP_CERTIFICATE @@ -277,6 +315,30 @@ public abstract class AtomicFormula implements Formula { String.format( "Key %s cannot be used with StringAtomicFormula", keyToString(key))); mValue = value; + mIsHashedValue = isHashed; + } + + /** + * Constructs a new {@link StringAtomicFormula} together with handling the necessary + * hashing for the given key. + * + * <p> The value will be hashed with SHA256 and the hex digest will be computed; for + * all cases except when the key is PACKAGE_NAME or INSTALLER_NAME and the value + * is less than 33 characters. + * + * @throws IllegalArgumentException if {@code key} cannot be used with string value. + */ + public StringAtomicFormula(@Key int key, @NonNull String value) { + super(key); + checkArgument( + key == PACKAGE_NAME + || key == APP_CERTIFICATE + || key == INSTALLER_CERTIFICATE + || key == INSTALLER_NAME, + String.format( + "Key %s cannot be used with StringAtomicFormula", keyToString(key))); + mValue = hashValue(key, value); + mIsHashedValue = !mValue.equals(value); } StringAtomicFormula(Parcel in) { @@ -300,18 +362,23 @@ public abstract class AtomicFormula implements Formula { }; @Override - public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) { - String metadataValue = getMetadataValueByKey(appInstallMetadata); - return metadataValue.equals(mValue); + public int getTag() { + return IntegrityFormula.STRING_ATOMIC_FORMULA_TAG; } @Override - public int getTag() { - return Formula.STRING_ATOMIC_FORMULA_TAG; + public boolean matches(AppInstallMetadata appInstallMetadata) { + if (mValue == null || mIsHashedValue == null) { + return false; + } + return getStringMetadataValue(appInstallMetadata, getKey()).equals(mValue); } @Override public String toString() { + if (mValue == null || mIsHashedValue == null) { + return String.format("(%s)", keyToString(getKey())); + } return String.format("(%s %s %s)", keyToString(getKey()), operatorToString(EQ), mValue); } @@ -339,40 +406,80 @@ public abstract class AtomicFormula implements Formula { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { + if (mValue == null || mIsHashedValue == null) { + throw new IllegalStateException("Cannot write an empty StringAtomicFormula."); + } dest.writeInt(getKey()); dest.writeStringNoHelper(mValue); dest.writeByte((byte) (mIsHashedValue ? 1 : 0)); } - @NonNull public String getValue() { return mValue; } - public boolean getIsHashedValue() { + public Boolean getIsHashedValue() { return mIsHashedValue; } - private String getMetadataValueByKey(AppInstallMetadata appInstallMetadata) { - switch (getKey()) { - case PACKAGE_NAME: + private static String getStringMetadataValue( + AppInstallMetadata appInstallMetadata, int key) { + switch (key) { + case AtomicFormula.PACKAGE_NAME: return appInstallMetadata.getPackageName(); - case APP_CERTIFICATE: + case AtomicFormula.APP_CERTIFICATE: return appInstallMetadata.getAppCertificate(); - case INSTALLER_CERTIFICATE: + case AtomicFormula.INSTALLER_CERTIFICATE: return appInstallMetadata.getInstallerCertificate(); - case INSTALLER_NAME: + case AtomicFormula.INSTALLER_NAME: return appInstallMetadata.getInstallerName(); default: throw new IllegalStateException( - "Unexpected key in StringAtomicFormula: " + getKey()); + "Unexpected key in StringAtomicFormula: " + key); + } + } + + private static String hashValue(@Key int key, String value) { + // Hash the string value unless it is a PACKAGE_NAME or INSTALLER_NAME and the value is + // less than 33 characters. + if (value.length() <= 32) { + if (key == PACKAGE_NAME || key == INSTALLER_NAME) { + return value; + } + } + return hash(value); + } + + private static String hash(String value) { + try { + MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); + byte[] hashBytes = messageDigest.digest(value.getBytes(StandardCharsets.UTF_8)); + return IntegrityUtils.getHexDigest(hashBytes); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("SHA-256 algorithm not found", e); } } } /** An {@link AtomicFormula} with a key and boolean value. */ public static final class BooleanAtomicFormula extends AtomicFormula implements Parcelable { - private final boolean mValue; + private final Boolean mValue; + + /** + * Constructs an empty {@link BooleanAtomicFormula}. This should only be used as a base. + * + * <p>An empty formula will always match to false. + * + * @throws IllegalArgumentException if {@code key} cannot be used with boolean value + */ + public BooleanAtomicFormula(@Key int key) { + super(key); + checkArgument( + key == PRE_INSTALLED, + String.format( + "Key %s cannot be used with BooleanAtomicFormula", keyToString(key))); + mValue = null; + } /** * Constructs a new {@link BooleanAtomicFormula}. @@ -411,18 +518,23 @@ public abstract class AtomicFormula implements Formula { }; @Override - public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) { - boolean metadataValue = getMetadataValueByKey(appInstallMetadata); - return metadataValue == mValue; + public int getTag() { + return IntegrityFormula.BOOLEAN_ATOMIC_FORMULA_TAG; } @Override - public int getTag() { - return Formula.BOOLEAN_ATOMIC_FORMULA_TAG; + public boolean matches(AppInstallMetadata appInstallMetadata) { + if (mValue == null) { + return false; + } + return getBooleanMetadataValue(appInstallMetadata, getKey()) == mValue; } @Override public String toString() { + if (mValue == null) { + return String.format("(%s)", keyToString(getKey())); + } return String.format("(%s %s %s)", keyToString(getKey()), operatorToString(EQ), mValue); } @@ -450,21 +562,25 @@ public abstract class AtomicFormula implements Formula { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { + if (mValue == null) { + throw new IllegalStateException("Cannot write an empty BooleanAtomicFormula."); + } dest.writeInt(getKey()); dest.writeByte((byte) (mValue ? 1 : 0)); } - public boolean getValue() { + public Boolean getValue() { return mValue; } - private boolean getMetadataValueByKey(AppInstallMetadata appInstallMetadata) { - switch (getKey()) { - case PRE_INSTALLED: + private static boolean getBooleanMetadataValue( + AppInstallMetadata appInstallMetadata, int key) { + switch (key) { + case AtomicFormula.PRE_INSTALLED: return appInstallMetadata.isPreInstalled(); default: throw new IllegalStateException( - "Unexpected key in BooleanAtomicFormula: " + getKey()); + "Unexpected key in BooleanAtomicFormula: " + key); } } } @@ -496,14 +612,10 @@ public abstract class AtomicFormula implements Formula { switch (op) { case EQ: return "EQ"; - case LT: - return "LT"; - case LE: - return "LE"; case GT: return "GT"; - case GE: - return "GE"; + case GTE: + return "GTE"; default: throw new IllegalArgumentException("Unknown operator " + op); } diff --git a/core/java/android/content/integrity/CompoundFormula.java b/core/java/android/content/integrity/CompoundFormula.java index 2a651d9e90d8..56061df21388 100644 --- a/core/java/android/content/integrity/CompoundFormula.java +++ b/core/java/android/content/integrity/CompoundFormula.java @@ -20,10 +20,8 @@ import static com.android.internal.util.Preconditions.checkArgument; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; -import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -42,16 +40,11 @@ import java.util.Objects; * * @hide */ -@SystemApi @VisibleForTesting -public final class CompoundFormula implements Formula, Parcelable { - private static final String TAG = "OpenFormula"; +public final class CompoundFormula extends IntegrityFormula implements Parcelable { /** @hide */ - @IntDef( - value = { - AND, OR, NOT, - }) + @IntDef(value = {AND, OR, NOT}) @Retention(RetentionPolicy.SOURCE) public @interface Connector {} @@ -65,7 +58,7 @@ public final class CompoundFormula implements Formula, Parcelable { public static final int NOT = 2; private final @Connector int mConnector; - private final @NonNull List<Formula> mFormulas; + private final @NonNull List<IntegrityFormula> mFormulas; @NonNull public static final Creator<CompoundFormula> CREATOR = @@ -85,9 +78,10 @@ public final class CompoundFormula implements Formula, Parcelable { * Create a new formula from operator and operands. * * @throws IllegalArgumentException if the number of operands is not matching the requirements - * for that operator (at least 2 for {@link #AND} and {@link #OR}, 1 for {@link #NOT}). + * for that operator (at least 2 for {@link #AND} and {@link + * #OR}, 1 for {@link #NOT}). */ - public CompoundFormula(@Connector int connector, @NonNull List<Formula> formulas) { + public CompoundFormula(@Connector int connector, List<IntegrityFormula> formulas) { checkArgument( isValidConnector(connector), String.format("Unknown connector: %d", connector)); validateFormulas(connector, formulas); @@ -101,7 +95,7 @@ public final class CompoundFormula implements Formula, Parcelable { checkArgument(length >= 0, "Must have non-negative length. Got " + length); mFormulas = new ArrayList<>(length); for (int i = 0; i < length; i++) { - mFormulas.add(Formula.readFromParcel(in)); + mFormulas.add(IntegrityFormula.readFromParcel(in)); } validateFormulas(mConnector, mFormulas); } @@ -111,33 +105,32 @@ public final class CompoundFormula implements Formula, Parcelable { } @NonNull - public List<Formula> getFormulas() { + public List<IntegrityFormula> getFormulas() { return mFormulas; } @Override - public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) { - switch (mConnector) { + public int getTag() { + return IntegrityFormula.COMPOUND_FORMULA_TAG; + } + + @Override + public boolean matches(AppInstallMetadata appInstallMetadata) { + switch (getConnector()) { case NOT: - return !mFormulas.get(0).isSatisfied(appInstallMetadata); + return !getFormulas().get(0).matches(appInstallMetadata); case AND: - return mFormulas.stream() - .allMatch(formula -> formula.isSatisfied(appInstallMetadata)); + return getFormulas().stream() + .allMatch(formula -> formula.matches(appInstallMetadata)); case OR: - return mFormulas.stream() - .anyMatch(formula -> formula.isSatisfied(appInstallMetadata)); + return getFormulas().stream() + .anyMatch(formula -> formula.matches(appInstallMetadata)); default: - Slog.i(TAG, "Unknown connector " + mConnector); - return false; + throw new IllegalArgumentException("Unknown connector " + getConnector()); } } @Override - public int getTag() { - return Formula.COMPOUND_FORMULA_TAG; - } - - @Override public String toString() { StringBuilder sb = new StringBuilder(); if (mFormulas.size() == 1) { @@ -180,12 +173,13 @@ public final class CompoundFormula implements Formula, Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mConnector); dest.writeInt(mFormulas.size()); - for (Formula formula : mFormulas) { - Formula.writeToParcel(formula, dest, flags); + for (IntegrityFormula formula : mFormulas) { + IntegrityFormula.writeToParcel(formula, dest, flags); } } - private static void validateFormulas(@Connector int connector, List<Formula> formulas) { + private static void validateFormulas( + @Connector int connector, List<IntegrityFormula> formulas) { switch (connector) { case AND: case OR: diff --git a/core/java/android/content/integrity/Formula.java b/core/java/android/content/integrity/Formula.java deleted file mode 100644 index b092a22c0191..000000000000 --- a/core/java/android/content/integrity/Formula.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2019 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 android.content.integrity; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.content.integrity.AtomicFormula.BooleanAtomicFormula; -import android.content.integrity.AtomicFormula.IntAtomicFormula; -import android.content.integrity.AtomicFormula.StringAtomicFormula; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.annotations.VisibleForTesting; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Represents a rule logic/content. - * - * @hide - */ -@SystemApi -@VisibleForTesting -public interface Formula { - /** @hide */ - @IntDef( - value = { - COMPOUND_FORMULA_TAG, - STRING_ATOMIC_FORMULA_TAG, - INT_ATOMIC_FORMULA_TAG, - BOOLEAN_ATOMIC_FORMULA_TAG - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Tag {} - - int COMPOUND_FORMULA_TAG = 0; - int STRING_ATOMIC_FORMULA_TAG = 1; - int INT_ATOMIC_FORMULA_TAG = 2; - int BOOLEAN_ATOMIC_FORMULA_TAG = 3; - - /** - * Returns if this formula can be satisfied by substituting the corresponding information of - * {@code appInstallMetadata} into the formula. - */ - boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata); - - /** Returns the tag that identifies the current class. */ - @Tag int getTag(); - - /** - * Write a {@link Formula} to {@link android.os.Parcel}. - * - * <p>This helper method is needed because non-final class/interface are not allowed to be - * {@link Parcelable}. - * - * @throws IllegalArgumentException if {@link Formula} is not a recognized subclass - */ - static void writeToParcel(@NonNull Formula formula, @NonNull Parcel dest, int flags) { - dest.writeInt(formula.getTag()); - ((Parcelable) formula).writeToParcel(dest, flags); - } - - /** - * Read a {@link Formula} from a {@link android.os.Parcel}. - * - * <p>We need this (hacky) helper method because non-final class/interface cannot be {@link - * Parcelable} (api lint error). - * - * @throws IllegalArgumentException if the parcel cannot be parsed - */ - @NonNull - static Formula readFromParcel(@NonNull Parcel in) { - int tag = in.readInt(); - switch (tag) { - case COMPOUND_FORMULA_TAG: - return CompoundFormula.CREATOR.createFromParcel(in); - case STRING_ATOMIC_FORMULA_TAG: - return StringAtomicFormula.CREATOR.createFromParcel(in); - case INT_ATOMIC_FORMULA_TAG: - return IntAtomicFormula.CREATOR.createFromParcel(in); - case BOOLEAN_ATOMIC_FORMULA_TAG: - return BooleanAtomicFormula.CREATOR.createFromParcel(in); - default: - throw new IllegalArgumentException("Unknown formula tag " + tag); - } - } -} diff --git a/core/java/android/content/integrity/IntegrityFormula.java b/core/java/android/content/integrity/IntegrityFormula.java new file mode 100644 index 000000000000..0660f93e9f01 --- /dev/null +++ b/core/java/android/content/integrity/IntegrityFormula.java @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2019 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 android.content.integrity; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.content.integrity.AtomicFormula.BooleanAtomicFormula; +import android.content.integrity.AtomicFormula.LongAtomicFormula; +import android.content.integrity.AtomicFormula.StringAtomicFormula; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.annotations.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; + +/** + * Represents a rule logic/content. + * + * @hide + */ +@SystemApi +@VisibleForTesting +public abstract class IntegrityFormula { + + /** + * A static formula base for package name formulas. + * + * This formulation is incomplete and should always be used with {@code equals} formulation. + * Evaluates to false when used directly and cannot be written as a parcel. + */ + @NonNull + public static final IntegrityFormula PACKAGE_NAME = + new StringAtomicFormula(AtomicFormula.PACKAGE_NAME); + + /** + * A static formula base for app certificate formulas. + * + * This formulation is incomplete and should always be used with {@code equals} formulation. + * Evaluates to false when used directly and cannot be written as a parcel. + */ + @NonNull + public static final IntegrityFormula APP_CERTIFICATE = + new StringAtomicFormula(AtomicFormula.APP_CERTIFICATE); + + /** + * A static formula base for installer name formulas. + * + * This formulation is incomplete and should always be used with {@code equals} formulation. + * Evaluates to false when used directly and cannot be written as a parcel. + */ + @NonNull + public static final IntegrityFormula INSTALLER_NAME = + new StringAtomicFormula(AtomicFormula.INSTALLER_NAME); + + /** + * A static formula base for installer certificate formulas. + * + * This formulation is incomplete and should always be used with {@code equals} formulation. + * Evaluates to false when used directly and cannot be written as a parcel. + */ + @NonNull + public static final IntegrityFormula INSTALLER_CERTIFICATE = + new StringAtomicFormula(AtomicFormula.INSTALLER_CERTIFICATE); + + /** + * A static formula base for version code name formulas. + * + * This formulation is incomplete and should always be used with {@code equals}, + * {@code greaterThan} and {@code greaterThanEquals} formulation. Evaluates to false when used + * directly and cannot be written as a parcel. + */ + @NonNull + public static final IntegrityFormula VERSION_CODE = + new LongAtomicFormula(AtomicFormula.VERSION_CODE); + + /** + * A static formula base for pre-installed status formulas. + * + * This formulation is incomplete and should always be used with {@code equals} formulation. + * Evaluates to false when used directly and cannot be written as a parcel. + */ + @NonNull + public static final IntegrityFormula PRE_INSTALLED = + new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED); + + /** @hide */ + @IntDef( + value = { + COMPOUND_FORMULA_TAG, + STRING_ATOMIC_FORMULA_TAG, + LONG_ATOMIC_FORMULA_TAG, + BOOLEAN_ATOMIC_FORMULA_TAG + }) + @Retention(RetentionPolicy.SOURCE) + @interface Tag {} + + /** @hide */ + public static final int COMPOUND_FORMULA_TAG = 0; + /** @hide */ + public static final int STRING_ATOMIC_FORMULA_TAG = 1; + /** @hide */ + public static final int LONG_ATOMIC_FORMULA_TAG = 2; + /** @hide */ + public static final int BOOLEAN_ATOMIC_FORMULA_TAG = 3; + + /** + * Returns the tag that identifies the current class. + * + * @hide + */ + public abstract @Tag int getTag(); + + /** + * Returns true when the integrity formula is satisfied by the {@code appInstallMetadata}. + * + * @hide + */ + public abstract @Tag boolean matches(AppInstallMetadata appInstallMetadata); + + /** + * Write an {@link IntegrityFormula} to {@link android.os.Parcel}. + * + * <p>This helper method is needed because non-final class/interface are not allowed to be + * {@link Parcelable}. + * + * @throws IllegalArgumentException if {@link IntegrityFormula} is not a recognized subclass + * + * @hide + */ + public static void writeToParcel( + @NonNull IntegrityFormula formula, @NonNull Parcel dest, int flags) { + dest.writeInt(formula.getTag()); + ((Parcelable) formula).writeToParcel(dest, flags); + } + + /** + * Read a {@link IntegrityFormula} from a {@link android.os.Parcel}. + * + * <p>We need this (hacky) helper method because non-final class/interface cannot be {@link + * Parcelable} (api lint error). + * + * @throws IllegalArgumentException if the parcel cannot be parsed + * @hide + */ + @NonNull + public static IntegrityFormula readFromParcel(@NonNull Parcel in) { + int tag = in.readInt(); + switch (tag) { + case COMPOUND_FORMULA_TAG: + return CompoundFormula.CREATOR.createFromParcel(in); + case STRING_ATOMIC_FORMULA_TAG: + return StringAtomicFormula.CREATOR.createFromParcel(in); + case LONG_ATOMIC_FORMULA_TAG: + return LongAtomicFormula.CREATOR.createFromParcel(in); + case BOOLEAN_ATOMIC_FORMULA_TAG: + return BooleanAtomicFormula.CREATOR.createFromParcel(in); + default: + throw new IllegalArgumentException("Unknown formula tag " + tag); + } + } + + /** + * Returns an integrity formula that evaluates to true when value of the key matches to the + * provided string value. + * + * <p>The value will be hashed with SHA256 and the hex digest will be computed; for + * all cases except when the key is PACKAGE_NAME or INSTALLER_NAME and the value is less than + * 32 characters. + * + * <p>Throws an {@link IllegalArgumentException} if the key is not string typed. + */ + @NonNull + public IntegrityFormula equalTo(@NonNull String value) { + AtomicFormula baseFormula = (AtomicFormula) this; + return new AtomicFormula.StringAtomicFormula(baseFormula.getKey(), value); + } + + /** + * Returns an integrity formula that evaluates to true when the boolean value of the key matches + * the provided boolean value. It can only be used with the boolean comparison keys. + * + * <p>Throws an {@link IllegalArgumentException} if the key is not boolean typed. + */ + @NonNull + public IntegrityFormula equalTo(boolean value) { + AtomicFormula baseFormula = (AtomicFormula) this; + return new AtomicFormula.BooleanAtomicFormula(baseFormula.getKey(), value); + } + + /** + * Returns a formula that evaluates to true when the value of the key in the package being + * installed is equal to {@code value}. + * + * <p>Throws an {@link IllegalArgumentException} if the key is not long typed. + */ + @NonNull + public IntegrityFormula equalTo(long value) { + AtomicFormula baseFormula = (AtomicFormula) this; + return new AtomicFormula.LongAtomicFormula(baseFormula.getKey(), AtomicFormula.EQ, value); + } + + /** + * Returns a formula that evaluates to true when the value of the key in the package being + * installed is greater than {@code value}. + * + * <p>Throws an {@link IllegalArgumentException} if the key is not long typed. + */ + @NonNull + public IntegrityFormula greaterThan(long value) { + AtomicFormula baseFormula = (AtomicFormula) this; + return new AtomicFormula.LongAtomicFormula(baseFormula.getKey(), AtomicFormula.GT, value); + } + + /** + * Returns a formula that evaluates to true when the value of the key in the package being + * installed is greater than or equals to the {@code value}. + * + * <p>Throws an {@link IllegalArgumentException} if the key is not long typed. + */ + @NonNull + public IntegrityFormula greaterThanOrEquals(long value) { + AtomicFormula baseFormula = (AtomicFormula) this; + return new AtomicFormula.LongAtomicFormula(baseFormula.getKey(), AtomicFormula.GTE, value); + } + + /** + * Returns a formula that evaluates to true when any formula in {@code formulae} evaluates to + * true. + * + * <p>Throws an {@link IllegalArgumentException} if formulae has less than two elements. + */ + @NonNull + public static IntegrityFormula any(@NonNull IntegrityFormula... formulae) { + return new CompoundFormula(CompoundFormula.OR, Arrays.asList(formulae)); + } + + /** + * Returns a formula that evaluates to true when all formula in {@code formulae} evaluates to + * true. + * + * <p>Throws an {@link IllegalArgumentException} if formulae has less than two elements. + */ + @NonNull + public static IntegrityFormula all(@NonNull IntegrityFormula... formulae) { + return new CompoundFormula(CompoundFormula.AND, Arrays.asList(formulae)); + } + + /** + * Returns a formula that evaluates to true when {@code formula} evaluates to false. + */ + @NonNull + public static IntegrityFormula not(@NonNull IntegrityFormula formula) { + return new CompoundFormula(CompoundFormula.NOT, Arrays.asList(formula)); + } + + // Constructor is package private so it cannot be inherited outside of this package. + IntegrityFormula() { + } +} diff --git a/services/core/java/com/android/server/integrity/IntegrityUtils.java b/core/java/android/content/integrity/IntegrityUtils.java index f49c675dbd8d..c3f762469348 100644 --- a/services/core/java/com/android/server/integrity/IntegrityUtils.java +++ b/core/java/android/content/integrity/IntegrityUtils.java @@ -14,11 +14,15 @@ * limitations under the License. */ -package com.android.server.integrity; +package android.content.integrity; import static com.android.internal.util.Preconditions.checkArgument; -/** Utils class for simple operations used in integrity module. */ +/** + * Utils class for simple operations used in integrity module. + * + * @hide + */ public class IntegrityUtils { private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray(); diff --git a/core/java/android/content/integrity/Rule.java b/core/java/android/content/integrity/Rule.java index 77587851b18c..c421c4076d16 100644 --- a/core/java/android/content/integrity/Rule.java +++ b/core/java/android/content/integrity/Rule.java @@ -59,17 +59,17 @@ public final class Rule implements Parcelable { */ public static final int FORCE_ALLOW = 1; - private final @NonNull Formula mFormula; + private final @NonNull IntegrityFormula mFormula; private final @Effect int mEffect; - public Rule(@NonNull Formula formula, @Effect int effect) { + public Rule(@NonNull IntegrityFormula formula, @Effect int effect) { checkArgument(isValidEffect(effect), String.format("Unknown effect: %d", effect)); this.mFormula = Objects.requireNonNull(formula); this.mEffect = effect; } Rule(Parcel in) { - mFormula = Formula.readFromParcel(in); + mFormula = IntegrityFormula.readFromParcel(in); mEffect = in.readInt(); } @@ -94,12 +94,12 @@ public final class Rule implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - Formula.writeToParcel(mFormula, dest, flags); + IntegrityFormula.writeToParcel(mFormula, dest, flags); dest.writeInt(mEffect); } @NonNull - public Formula getFormula() { + public IntegrityFormula getFormula() { return mFormula; } @@ -141,7 +141,6 @@ public final class Rule implements Parcelable { } private static boolean isValidEffect(int effect) { - return effect == DENY - || effect == FORCE_ALLOW; + return effect == DENY || effect == FORCE_ALLOW; } } diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java index a2f8886eb7d2..33d17763fb24 100644 --- a/core/java/android/content/om/OverlayManager.java +++ b/core/java/android/content/om/OverlayManager.java @@ -22,7 +22,11 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.content.Context; +import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -40,6 +44,10 @@ public class OverlayManager { private final IOverlayManager mService; private final Context mContext; + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) + private static final long THROW_SECURITY_EXCEPTIONS = 147340954; + /** * Creates a new instance. * @@ -69,6 +77,9 @@ public class OverlayManager { * @param packageName the name of the overlay package to enable. * @param user The user for which to change the overlay. * + * @throws SecurityException when caller is not allowed to enable {@param packageName} + * @throws IllegalStateException when enabling fails otherwise + * * @hide */ @SystemApi @@ -77,11 +88,13 @@ public class OverlayManager { "android.permission.INTERACT_ACROSS_USERS_FULL" }) public void setEnabledExclusiveInCategory(@NonNull final String packageName, - @NonNull UserHandle user) { + @NonNull UserHandle user) throws SecurityException, IllegalStateException { try { if (!mService.setEnabledExclusiveInCategory(packageName, user.getIdentifier())) { throw new IllegalStateException("setEnabledExclusiveInCategory failed"); } + } catch (SecurityException e) { + rethrowSecurityException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -97,6 +110,9 @@ public class OverlayManager { * @param enable {@code false} if the overlay should be turned off. * @param user The user for which to change the overlay. * + * @throws SecurityException when caller is not allowed to enable/disable {@param packageName} + * @throws IllegalStateException when enabling/disabling fails otherwise + * * @hide */ @SystemApi @@ -105,15 +121,16 @@ public class OverlayManager { "android.permission.INTERACT_ACROSS_USERS_FULL" }) public void setEnabled(@NonNull final String packageName, final boolean enable, - @NonNull UserHandle user) { + @NonNull UserHandle user) throws SecurityException, IllegalStateException { try { if (!mService.setEnabled(packageName, enable, user.getIdentifier())) { throw new IllegalStateException("setEnabled failed"); } + } catch (SecurityException e) { + rethrowSecurityException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - return; } /** @@ -187,4 +204,29 @@ public class OverlayManager { throw e.rethrowFromSystemServer(); } } + + /** + * Starting on R, actor enforcement and app visibility changes introduce additional failure + * cases, but the SecurityException thrown with these checks is unexpected for existing + * consumers of the API. + * + * The only prior case it would be thrown is with a permission failure, but the calling + * application would be able to verify that themselves, and so they may choose to ignore + * catching SecurityException when calling these APIs. + * + * For R, this no longer holds true, and SecurityExceptions can be thrown for any number of + * reasons, none of which are exposed to the caller. So for consumers targeting below R, + * transform these SecurityExceptions into IllegalStateExceptions, which are a little more + * expected to be thrown by the setEnabled APIs. + * + * This will mask the prior permission exception if it applies, but it's assumed that apps + * wouldn't call the APIs without the permission on prior versions, and so it's safe to ignore. + */ + private void rethrowSecurityException(SecurityException e) { + if (!Compatibility.isChangeEnabled(THROW_SECURITY_EXCEPTIONS)) { + throw new IllegalStateException(e); + } else { + throw e; + } + } } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 0e7ad5de4675..66a2b7a3ac66 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3527,6 +3527,44 @@ public abstract class PackageManager { public static final long FILTER_APPLICATION_QUERY = 135549675L; /** {@hide} */ + @IntDef(prefix = {"SYSTEM_APP_STATE_"}, value = { + SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN, + SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE, + SYSTEM_APP_STATE_INSTALLED, + SYSTEM_APP_STATE_UNINSTALLED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SystemAppState {} + + /** + * Constant for noting system app state as hidden before installation + * @hide + */ + @SystemApi + public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN = 0; + + /** + * Constant for noting system app state as visible before installation + * @hide + */ + @SystemApi + public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE = 1; + + /** + * Constant for noting system app state as installed + * @hide + */ + @SystemApi + public static final int SYSTEM_APP_STATE_INSTALLED = 2; + + /** + * Constant for noting system app state as not installed + * @hide + */ + @SystemApi + public static final int SYSTEM_APP_STATE_UNINSTALLED = 3; + + /** {@hide} */ public int getUserId() { return UserHandle.myUserId(); } @@ -6630,6 +6668,17 @@ public abstract class PackageManager { @NonNull UserHandle userHandle); /** + * Sets system app state + * @param packageName Package name of the app. + * @param state State of the app. + * @hide + */ + @SystemApi + public void setSystemAppState(@NonNull String packageName, @SystemAppState int state) { + throw new RuntimeException("Not implemented. Must override in a subclass"); + } + + /** * Return whether the device has been booted into safe mode. */ public abstract boolean isSafeMode(); diff --git a/core/java/android/content/pm/SuspendDialogInfo.java b/core/java/android/content/pm/SuspendDialogInfo.java index 73b75df80e5b..851a08116f56 100644 --- a/core/java/android/content/pm/SuspendDialogInfo.java +++ b/core/java/android/content/pm/SuspendDialogInfo.java @@ -19,6 +19,7 @@ package android.content.pm; import static android.content.res.Resources.ID_NULL; import android.annotation.DrawableRes; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; @@ -36,20 +37,21 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlSerializer; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Locale; import java.util.Objects; /** * A container to describe the dialog to be shown when the user tries to launch a suspended - * application. - * The suspending app can customize the dialog's following attributes: + * application. The suspending app can customize the dialog's following attributes: * <ul> * <li>The dialog icon, by providing a resource id. * <li>The title text, by providing a resource id. * <li>The text of the dialog's body, by providing a resource id or a string. - * <li>The text on the neutral button which starts the - * {@link android.content.Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS SHOW_SUSPENDED_APP_DETAILS} - * activity, by providing a resource id. + * <li>The text on the neutral button by providing a resource id. + * <li>The action performed on tapping the neutral button. Only {@link #BUTTON_ACTION_UNSUSPEND} + * and {@link #BUTTON_ACTION_MORE_DETAILS} are currently supported. * </ul> * System defaults are used whenever any of these are not provided, or any of the provided resource * ids cannot be resolved at the time of displaying the dialog. @@ -67,12 +69,47 @@ public final class SuspendDialogInfo implements Parcelable { private static final String XML_ATTR_DIALOG_MESSAGE_RES_ID = "dialogMessageResId"; private static final String XML_ATTR_DIALOG_MESSAGE = "dialogMessage"; private static final String XML_ATTR_BUTTON_TEXT_RES_ID = "buttonTextResId"; + private static final String XML_ATTR_BUTTON_ACTION = "buttonAction"; private final int mIconResId; private final int mTitleResId; private final int mDialogMessageResId; private final String mDialogMessage; private final int mNeutralButtonTextResId; + private final int mNeutralButtonAction; + + /** + * Used with {@link Builder#setNeutralButtonAction(int)} to create a neutral button that + * starts the {@link android.content.Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS} activity. + * @see Builder#setNeutralButtonAction(int) + */ + public static final int BUTTON_ACTION_MORE_DETAILS = 0; + + /** + * Used with {@link Builder#setNeutralButtonAction(int)} to create a neutral button that + * unsuspends the app that the user was trying to launch and continues with the launch. The + * system also sends the broadcast + * {@link android.content.Intent#ACTION_PACKAGE_UNSUSPENDED_MANUALLY} to the suspending app + * when this happens. + * @see Builder#setNeutralButtonAction(int) + * @see android.content.Intent#ACTION_PACKAGE_UNSUSPENDED_MANUALLY + */ + public static final int BUTTON_ACTION_UNSUSPEND = 1; + + /** + * Button actions to specify what happens when the user taps on the neutral button. + * To be used with {@link Builder#setNeutralButtonAction(int)}. + * + * @hide + * @see Builder#setNeutralButtonAction(int) + */ + @IntDef(flag = true, prefix = {"BUTTON_ACTION_"}, value = { + BUTTON_ACTION_MORE_DETAILS, + BUTTON_ACTION_UNSUSPEND + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ButtonAction { + } /** * @return the resource id of the icon to be used with the dialog @@ -102,8 +139,8 @@ public final class SuspendDialogInfo implements Parcelable { } /** - * @return the text to be shown in the dialog's body. Returns {@code null} if - * {@link #getDialogMessageResId()} returns a valid resource id. + * @return the text to be shown in the dialog's body. Returns {@code null} if {@link + * #getDialogMessageResId()} returns a valid resource id * @hide */ @Nullable @@ -121,6 +158,15 @@ public final class SuspendDialogInfo implements Parcelable { } /** + * @return The {@link ButtonAction} that happens on tapping this button + * @hide + */ + @ButtonAction + public int getNeutralButtonAction() { + return mNeutralButtonAction; + } + + /** * @hide */ public void saveToXml(XmlSerializer out) throws IOException { @@ -138,6 +184,7 @@ public final class SuspendDialogInfo implements Parcelable { if (mNeutralButtonTextResId != ID_NULL) { XmlUtils.writeIntAttribute(out, XML_ATTR_BUTTON_TEXT_RES_ID, mNeutralButtonTextResId); } + XmlUtils.writeIntAttribute(out, XML_ATTR_BUTTON_ACTION, mNeutralButtonAction); } /** @@ -150,6 +197,8 @@ public final class SuspendDialogInfo implements Parcelable { final int titleId = XmlUtils.readIntAttribute(in, XML_ATTR_TITLE_RES_ID, ID_NULL); final int buttonTextId = XmlUtils.readIntAttribute(in, XML_ATTR_BUTTON_TEXT_RES_ID, ID_NULL); + final int buttonAction = XmlUtils.readIntAttribute(in, XML_ATTR_BUTTON_ACTION, + BUTTON_ACTION_MORE_DETAILS); final int dialogMessageResId = XmlUtils.readIntAttribute( in, XML_ATTR_DIALOG_MESSAGE_RES_ID, ID_NULL); final String dialogMessage = XmlUtils.readStringAttribute(in, XML_ATTR_DIALOG_MESSAGE); @@ -168,6 +217,7 @@ public final class SuspendDialogInfo implements Parcelable { } else if (dialogMessage != null) { dialogInfoBuilder.setMessage(dialogMessage); } + dialogInfoBuilder.setNeutralButtonAction(buttonAction); } catch (Exception e) { Slog.e(TAG, "Exception while parsing from xml. Some fields may default", e); } @@ -181,6 +231,7 @@ public final class SuspendDialogInfo implements Parcelable { hashCode = 31 * hashCode + mNeutralButtonTextResId; hashCode = 31 * hashCode + mDialogMessageResId; hashCode = 31 * hashCode + Objects.hashCode(mDialogMessage); + hashCode = 31 * hashCode + mNeutralButtonAction; return hashCode; } @@ -197,6 +248,7 @@ public final class SuspendDialogInfo implements Parcelable { && mTitleResId == otherDialogInfo.mTitleResId && mDialogMessageResId == otherDialogInfo.mDialogMessageResId && mNeutralButtonTextResId == otherDialogInfo.mNeutralButtonTextResId + && mNeutralButtonAction == otherDialogInfo.mNeutralButtonAction && Objects.equals(mDialogMessage, otherDialogInfo.mDialogMessage); } @@ -228,6 +280,8 @@ public final class SuspendDialogInfo implements Parcelable { builder.append(mDialogMessage); builder.append("\" "); } + builder.append("mNeutralButtonAction = "); + builder.append(mNeutralButtonAction); builder.append("}"); return builder.toString(); } @@ -244,6 +298,7 @@ public final class SuspendDialogInfo implements Parcelable { dest.writeInt(mDialogMessageResId); dest.writeString(mDialogMessage); dest.writeInt(mNeutralButtonTextResId); + dest.writeInt(mNeutralButtonAction); } private SuspendDialogInfo(Parcel source) { @@ -252,6 +307,7 @@ public final class SuspendDialogInfo implements Parcelable { mDialogMessageResId = source.readInt(); mDialogMessage = source.readString(); mNeutralButtonTextResId = source.readInt(); + mNeutralButtonAction = source.readInt(); } SuspendDialogInfo(Builder b) { @@ -260,9 +316,11 @@ public final class SuspendDialogInfo implements Parcelable { mDialogMessageResId = b.mDialogMessageResId; mDialogMessage = (mDialogMessageResId == ID_NULL) ? b.mDialogMessage : null; mNeutralButtonTextResId = b.mNeutralButtonTextResId; + mNeutralButtonAction = b.mNeutralButtonAction; } - public static final @android.annotation.NonNull Creator<SuspendDialogInfo> CREATOR = new Creator<SuspendDialogInfo>() { + public static final @NonNull Creator<SuspendDialogInfo> CREATOR = + new Creator<SuspendDialogInfo>() { @Override public SuspendDialogInfo createFromParcel(Parcel source) { return new SuspendDialogInfo(source); @@ -283,6 +341,7 @@ public final class SuspendDialogInfo implements Parcelable { private int mTitleResId = ID_NULL; private int mIconResId = ID_NULL; private int mNeutralButtonTextResId = ID_NULL; + private int mNeutralButtonAction = BUTTON_ACTION_MORE_DETAILS; /** * Set the resource id of the icon to be used. If not provided, no icon will be shown. @@ -333,8 +392,8 @@ public final class SuspendDialogInfo implements Parcelable { /** * Set the resource id of the dialog message to be shown. If no dialog message is provided - * via either this method or {@link #setMessage(String)}, the system will use a - * default message. + * via either this method or {@link #setMessage(String)}, the system will use a default + * message. * <p> * The system will use {@link android.content.res.Resources#getString(int, Object...) * getString} to insert the suspended app name into the message, so an example format string @@ -353,9 +412,10 @@ public final class SuspendDialogInfo implements Parcelable { } /** - * Set the resource id of text to be shown on the neutral button. Tapping this button starts - * the {@link android.content.Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS} activity. If this is - * not provided, the system will use a default text. + * Set the resource id of text to be shown on the neutral button. Tapping this button would + * perform the {@link ButtonAction action} specified through + * {@link #setNeutralButtonAction(int)}. If this is not provided, the system will use a + * default text. * * @param resId The resource id of the button text * @return this builder object. @@ -368,6 +428,22 @@ public final class SuspendDialogInfo implements Parcelable { } /** + * Set the action expected to happen on neutral button tap. Defaults to + * {@link #BUTTON_ACTION_MORE_DETAILS} if this is not provided. + * + * @param buttonAction Either {@link #BUTTON_ACTION_MORE_DETAILS} or + * {@link #BUTTON_ACTION_UNSUSPEND}. + * @return this builder object + */ + @NonNull + public Builder setNeutralButtonAction(@ButtonAction int buttonAction) { + Preconditions.checkArgument(buttonAction == BUTTON_ACTION_MORE_DETAILS + || buttonAction == BUTTON_ACTION_UNSUSPEND, "Invalid button action"); + mNeutralButtonAction = buttonAction; + return this; + } + + /** * Build the final object based on given inputs. * * @return The {@link SuspendDialogInfo} object built using this builder. diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java index a71a7b63f30e..cc4c45699bd4 100644 --- a/core/java/android/hardware/Sensor.java +++ b/core/java/android/hardware/Sensor.java @@ -693,6 +693,22 @@ public final class Sensor { "android.sensor.accelerometer_uncalibrated"; /** + * A constant describing a hinge angle sensor. + * + * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details. + * + */ + public static final int TYPE_HINGE_ANGLE = 36; + + /** + * A constant string describing a hinge angle sensor. + * + * @see #TYPE_HINGE_ANGLE + * + */ + public static final String STRING_TYPE_HINGE_ANGLE = "android.sensor.hinge_angle"; + + /** * A constant describing all sensor types. */ @@ -811,6 +827,7 @@ public final class Sensor { 16, // skip over additional sensor info type 1, // SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT 6, // SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED + 1, // SENSOR_TYPE_HINGE_ANGLE }; /** @@ -1226,6 +1243,8 @@ public final class Sensor { case TYPE_ACCELEROMETER_UNCALIBRATED: mStringType = STRING_TYPE_ACCELEROMETER_UNCALIBRATED; return true; + case TYPE_HINGE_ANGLE: + mStringType = STRING_TYPE_HINGE_ANGLE; default: return false; } diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java index 64c45bf290ec..5fbf0da8b5a5 100644 --- a/core/java/android/hardware/SensorEvent.java +++ b/core/java/android/hardware/SensorEvent.java @@ -630,6 +630,16 @@ public class SensorEvent { * x_bias, y_bias, z_bias are the estimated biases. * </p> * + * <h4>{@link android.hardware.Sensor#TYPE_HINGE_ANGLE Sensor.TYPE_HINGE_ANGLE}:</h4> + * + * A sensor of this type measures the angle, in degrees, between two integral parts of the + * device. Movement of a hinge measured by this sensor type is expected to alter the ways in + * which the user may interact with the device, for example by unfolding or revealing a display. + * + * <ul> + * <li> values[0]: Measured hinge angle between 0 and 360 degrees inclusive</li> + * </ul> + * * @see GeomagneticField */ public final float[] values; diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java index 456481386cc9..b13e4b72aa22 100644 --- a/core/java/android/net/ConnectivityDiagnosticsManager.java +++ b/core/java/android/net/ConnectivityDiagnosticsManager.java @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringDef; import android.content.Context; +import android.os.Binder; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; @@ -544,6 +545,53 @@ public class ConnectivityDiagnosticsManager { }; } + /** @hide */ + @VisibleForTesting + public static class ConnectivityDiagnosticsBinder + extends IConnectivityDiagnosticsCallback.Stub { + @NonNull private final ConnectivityDiagnosticsCallback mCb; + @NonNull private final Executor mExecutor; + + /** @hide */ + @VisibleForTesting + public ConnectivityDiagnosticsBinder( + @NonNull ConnectivityDiagnosticsCallback cb, @NonNull Executor executor) { + this.mCb = cb; + this.mExecutor = executor; + } + + /** @hide */ + @VisibleForTesting + public void onConnectivityReport(@NonNull ConnectivityReport report) { + Binder.withCleanCallingIdentity(() -> { + mExecutor.execute(() -> { + mCb.onConnectivityReport(report); + }); + }); + } + + /** @hide */ + @VisibleForTesting + public void onDataStallSuspected(@NonNull DataStallReport report) { + Binder.withCleanCallingIdentity(() -> { + mExecutor.execute(() -> { + mCb.onDataStallSuspected(report); + }); + }); + } + + /** @hide */ + @VisibleForTesting + public void onNetworkConnectivityReported( + @NonNull Network network, boolean hasConnectivity) { + Binder.withCleanCallingIdentity(() -> { + mExecutor.execute(() -> { + mCb.onNetworkConnectivityReported(network, hasConnectivity); + }); + }); + } + } + /** * Abstract base class for Connectivity Diagnostics callbacks. Used for notifications about * network connectivity events. Must be extended by applications wanting notifications. diff --git a/core/java/android/net/IConnectivityDiagnosticsCallback.aidl b/core/java/android/net/IConnectivityDiagnosticsCallback.aidl new file mode 100644 index 000000000000..3a161bfabfd2 --- /dev/null +++ b/core/java/android/net/IConnectivityDiagnosticsCallback.aidl @@ -0,0 +1,28 @@ +/** + * + * Copyright (C) 2019 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 android.net; + +import android.net.ConnectivityDiagnosticsManager; +import android.net.Network; + +/** @hide */ +oneway interface IConnectivityDiagnosticsCallback { + void onConnectivityReport(in ConnectivityDiagnosticsManager.ConnectivityReport report); + void onDataStallSuspected(in ConnectivityDiagnosticsManager.DataStallReport report); + void onNetworkConnectivityReported(in Network n, boolean hasConnectivity); +}
\ No newline at end of file diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 186196bd31c7..3e9e7faccb02 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -18,6 +18,7 @@ package android.net; import android.app.PendingIntent; import android.net.ConnectionInfo; +import android.net.IConnectivityDiagnosticsCallback; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkAgentConfig; @@ -211,5 +212,9 @@ interface IConnectivityManager boolean isCallerCurrentAlwaysOnVpnApp(); boolean isCallerCurrentAlwaysOnVpnLockdownApp(); + void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback, + in NetworkRequest request); + void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback); + IBinder startOrGetTestNetworkService(); } diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index a94109dae7d5..4f4e27b446ef 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -26,6 +26,7 @@ import android.net.ConnectivityManager.NetworkCallback; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.os.Process; import android.util.ArraySet; import android.util.proto.ProtoOutputStream; @@ -58,7 +59,6 @@ import java.util.StringJoiner; */ public final class NetworkCapabilities implements Parcelable { private static final String TAG = "NetworkCapabilities"; - private static final int INVALID_UID = -1; // Set to true when private DNS is broken. private boolean mPrivateDnsBroken; @@ -85,8 +85,8 @@ public final class NetworkCapabilities implements Parcelable { mTransportInfo = null; mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED; mUids = null; - mEstablishingVpnAppUid = INVALID_UID; mAdministratorUids.clear(); + mOwnerUid = Process.INVALID_UID; mSSID = null; mPrivateDnsBroken = false; } @@ -104,8 +104,8 @@ public final class NetworkCapabilities implements Parcelable { mTransportInfo = nc.mTransportInfo; mSignalStrength = nc.mSignalStrength; setUids(nc.mUids); // Will make the defensive copy - mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid; setAdministratorUids(nc.mAdministratorUids); + mOwnerUid = nc.mOwnerUid; mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities; mSSID = nc.mSSID; mPrivateDnsBroken = nc.mPrivateDnsBroken; @@ -810,31 +810,26 @@ public final class NetworkCapabilities implements Parcelable { } /** - * UID of the app that manages this network, or INVALID_UID if none/unknown. + * UID of the app that owns this network, or INVALID_UID if none/unknown. * - * This field keeps track of the UID of the app that created this network and is in charge - * of managing it. In the practice, it is used to store the UID of VPN apps so it is named - * accordingly, but it may be renamed if other mechanisms are offered for third party apps - * to create networks. - * - * Because this field is only used in the services side (and to avoid apps being able to - * set this to whatever they want), this field is not parcelled and will not be conserved - * across the IPC boundary. - * @hide + * <p>This field keeps track of the UID of the app that created this network and is in charge of + * its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running + * VPN, or Carrier Service app managing a cellular data connection. */ - private int mEstablishingVpnAppUid = INVALID_UID; + private int mOwnerUid = Process.INVALID_UID; /** - * Set the UID of the managing app. - * @hide + * Set the UID of the owner app. */ - public void setEstablishingVpnAppUid(final int uid) { - mEstablishingVpnAppUid = uid; + public void setOwnerUid(final int uid) { + mOwnerUid = uid; } - /** @hide */ - public int getEstablishingVpnAppUid() { - return mEstablishingVpnAppUid; + /** + * Retrieves the UID of the owner app. + */ + public int getOwnerUid() { + return mOwnerUid; } /** @@ -1157,7 +1152,7 @@ public final class NetworkCapabilities implements Parcelable { * member is null, then the network is not restricted by app UID. If it's an empty list, then * it means nobody can use it. * As a special exception, the app managing this network (as identified by its UID stored in - * mEstablishingVpnAppUid) can always see this network. This is embodied by a special check in + * mOwnerUid) can always see this network. This is embodied by a special check in * satisfiedByUids. That still does not mean the network necessarily <strong>applies</strong> * to the app that manages it as determined by #appliesToUid. * <p> @@ -1264,7 +1259,7 @@ public final class NetworkCapabilities implements Parcelable { * in the passed nc (representing the UIDs that this network is available to). * <p> * As a special exception, the UID that created the passed network (as represented by its - * mEstablishingVpnAppUid field) always satisfies a NetworkRequest requiring it (of LISTEN + * mOwnerUid field) always satisfies a NetworkRequest requiring it (of LISTEN * or REQUEST types alike), even if the network does not apply to it. That is so a VPN app * can see its own network when it listens for it. * <p> @@ -1275,7 +1270,7 @@ public final class NetworkCapabilities implements Parcelable { public boolean satisfiedByUids(@NonNull NetworkCapabilities nc) { if (null == nc.mUids || null == mUids) return true; // The network satisfies everything. for (UidRange requiredRange : mUids) { - if (requiredRange.contains(nc.mEstablishingVpnAppUid)) return true; + if (requiredRange.contains(nc.mOwnerUid)) return true; if (!nc.appliesToUidRange(requiredRange)) { return false; } @@ -1541,6 +1536,7 @@ public final class NetworkCapabilities implements Parcelable { dest.writeString(mSSID); dest.writeBoolean(mPrivateDnsBroken); dest.writeList(mAdministratorUids); + dest.writeInt(mOwnerUid); } public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR = @@ -1562,6 +1558,7 @@ public final class NetworkCapabilities implements Parcelable { netCap.mSSID = in.readString(); netCap.mPrivateDnsBroken = in.readBoolean(); netCap.setAdministratorUids(in.readArrayList(null)); + netCap.mOwnerUid = in.readInt(); return netCap; } @Override @@ -1611,8 +1608,8 @@ public final class NetworkCapabilities implements Parcelable { sb.append(" Uids: <").append(mUids).append(">"); } } - if (mEstablishingVpnAppUid != INVALID_UID) { - sb.append(" EstablishingAppUid: ").append(mEstablishingVpnAppUid); + if (mOwnerUid != Process.INVALID_UID) { + sb.append(" OwnerUid: ").append(mOwnerUid); } if (!mAdministratorUids.isEmpty()) { diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java index f2e16b46422f..152141edb52d 100644 --- a/core/java/android/os/BatteryStatsManager.java +++ b/core/java/android/os/BatteryStatsManager.java @@ -42,7 +42,7 @@ import java.lang.annotation.RetentionPolicy; */ @SystemApi @SystemService(Context.BATTERY_STATS_SERVICE) -public final class BatteryStatsManager { +public class BatteryStatsManager { /** * Wifi states. * diff --git a/core/java/android/os/TelephonyServiceManager.java b/core/java/android/os/TelephonyServiceManager.java index c93eba6523f0..c67dedb4ac17 100644 --- a/core/java/android/os/TelephonyServiceManager.java +++ b/core/java/android/os/TelephonyServiceManager.java @@ -191,14 +191,6 @@ public class TelephonyServiceManager { } /** - * Returns {@link ServiceRegisterer} for the package manager service. - */ - @NonNull - public ServiceRegisterer getPackageManagerServiceRegisterer() { - return new ServiceRegisterer("package"); - } - - /** * Returns {@link ServiceRegisterer} for the ICC phone book service. */ @NonNull diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 5a1ba7fe534c..4812ea98b569 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -266,6 +266,28 @@ public final class PermissionManager { } } + /** + * Grant default permissions to currently enabled carrier apps + * @param packageNames Package names of the apps to be granted permissions + * @param user The user handle + * @param executor The executor for the callback + * @param callback The callback provided by caller to be notified when grant completes + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) + public void grantDefaultPermissionsToEnabledCarrierApps(@NonNull String[] packageNames, + @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<Boolean> callback) { + try { + mPermissionManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, + user.getIdentifier()); + executor.execute(() -> callback.accept(true)); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + private List<SplitPermissionInfo> splitPermissionInfoListToNonParcelableList( List<SplitPermissionInfoParcelable> parcelableList) { final int size = parcelableList.size(); @@ -416,4 +438,4 @@ public final class PermissionManager { e.rethrowFromSystemServer(); } } -} +}
\ No newline at end of file diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 38768c393e18..21d99fcf8231 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9737,6 +9737,15 @@ public final class Settings { */ public static final String PACKAGE_VERIFIER_INCLUDE_ADB = "verifier_verify_adb_installs"; + /** + * Run integrity checks for integrity rule providers. + * 0 = bypass integrity verification on installs from rule providers (default) + * 1 = perform integrity verification on installs from rule providers + * @hide + */ + public static final String INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER = + "verify_integrity_for_rule_provider"; + /** * Time since last fstrim (milliseconds) after which we force one to happen * during device startup. If unset, the default is 3 days. diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java index 4f400a8e9cb2..c5d97b718ff0 100644 --- a/core/java/android/service/notification/StatusBarNotification.java +++ b/core/java/android/service/notification/StatusBarNotification.java @@ -17,7 +17,8 @@ package android.service.notification; import static android.app.NotificationChannel.PLACEHOLDER_CONVERSATION_ID; -import static android.util.FeatureFlagUtils.*; +import static android.util.FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ; +import static android.util.FeatureFlagUtils.isEnabled; import android.annotation.NonNull; import android.app.Notification; @@ -33,7 +34,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; import android.text.TextUtils; -import android.util.FeatureFlagUtils; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -454,11 +454,23 @@ public class StatusBarNotification implements Parcelable { return conversationId; } - private String getGroupLogTag() { + /** + * Returns a probably-unique string based on the notification's group name, + * with no more than MAX_LOG_TAG_LENGTH characters. + * @return String based on group name of notification. + * @hide + */ + public String getGroupLogTag() { return shortenTag(getGroup()); } - private String getChannelIdLogTag() { + /** + * Returns a probably-unique string based on the notification's channel ID, + * with no more than MAX_LOG_TAG_LENGTH characters. + * @return String based on channel ID of notification. + * @hide + */ + public String getChannelIdLogTag() { if (notification.getChannelId() == null) { return null; } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index d9c502e14e68..14390f1c209b 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -748,4 +748,9 @@ interface IWindowManager void getWindowInsets(in WindowManager.LayoutParams attrs, int displayId, out Rect outContentInsets, out Rect outStableInsets, out DisplayCutout.ParcelableWrapper displayCutout); + + /** + * Called to show global actions. + */ + void showGlobalActions(); } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index f7b87cce7338..811b0637db98 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -2551,6 +2551,7 @@ public final class SurfaceControl implements Parcelable { /** * @hide */ + @Deprecated @UnsupportedAppUsage public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface, long frameNumber) { diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 1981bdd93eeb..75d5538faedd 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -414,7 +414,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } t.setAlpha(mSurfaceControl, alpha); if (!useBLAST) { - t.deferTransactionUntilSurface(mSurfaceControl, parent, frame); + t.deferTransactionUntil(mSurfaceControl, + viewRoot.getRenderSurfaceControl(), frame); } } // It's possible that mSurfaceControl is released in the UI thread before @@ -1122,7 +1123,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (frameNumber > 0 && !WindowManagerGlobal.USE_BLAST_ADAPTER) { final ViewRootImpl viewRoot = getViewRootImpl(); - t.deferTransactionUntilSurface(surface, viewRoot.mSurface, + t.deferTransactionUntil(surface, viewRoot.getRenderSurfaceControl(), frameNumber); } @@ -1217,8 +1218,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (frameNumber > 0 && viewRoot != null && !useBLAST) { if (viewRoot.mSurface.isValid()) { - mRtTransaction.deferTransactionUntilSurface(mSurfaceControl, viewRoot.mSurface, - frameNumber); + mRtTransaction.deferTransactionUntil(mSurfaceControl, + viewRoot.getRenderSurfaceControl(), frameNumber); } } t.hide(mSurfaceControl); diff --git a/core/java/android/view/SyncRtSurfaceTransactionApplier.java b/core/java/android/view/SyncRtSurfaceTransactionApplier.java index a6536f5d83b7..abe44f45aba5 100644 --- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java +++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java @@ -38,7 +38,7 @@ public class SyncRtSurfaceTransactionApplier { public static final int FLAG_CORNER_RADIUS = 1 << 4; public static final int FLAG_VISIBILITY = 1 << 5; - private final Surface mTargetSurface; + private SurfaceControl mTargetSc; private final ViewRootImpl mTargetViewRootImpl; private final float[] mTmpFloat9 = new float[9]; @@ -47,7 +47,6 @@ public class SyncRtSurfaceTransactionApplier { */ public SyncRtSurfaceTransactionApplier(View targetView) { mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null; - mTargetSurface = mTargetViewRootImpl != null ? mTargetViewRootImpl.mSurface : null; } /** @@ -60,15 +59,16 @@ public class SyncRtSurfaceTransactionApplier { if (mTargetViewRootImpl == null) { return; } + mTargetSc = mTargetViewRootImpl.getRenderSurfaceControl(); mTargetViewRootImpl.registerRtFrameCallback(frame -> { - if (mTargetSurface == null || !mTargetSurface.isValid()) { + if (mTargetSc == null || !mTargetSc.isValid()) { return; } Transaction t = new Transaction(); for (int i = params.length - 1; i >= 0; i--) { SurfaceParams surfaceParams = params[i]; SurfaceControl surface = surfaceParams.surface; - t.deferTransactionUntilSurface(surface, mTargetSurface, frame); + t.deferTransactionUntil(surface, mTargetSc, frame); applyParams(t, surfaceParams, mTmpFloat9); } t.setEarlyWakeup(); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index f5cfbec924ac..7a93dcc9e4ec 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1733,8 +1733,8 @@ public final class ViewRootImpl implements ViewParent, private void updateBoundsLayer() { if (mBoundsLayer != null) { setBoundsLayerCrop(); - mTransaction.deferTransactionUntilSurface(mBoundsLayer, - mSurface, mSurface.getNextFrameNumber()) + mTransaction.deferTransactionUntil(mBoundsLayer, + getRenderSurfaceControl(), mSurface.getNextFrameNumber()) .apply(); } } @@ -9539,4 +9539,12 @@ public final class ViewRootImpl implements ViewParent, SurfaceControl.Transaction getBLASTSyncTransaction() { return mRtBLASTSyncTransaction; } + + SurfaceControl getRenderSurfaceControl() { + if (WindowManagerGlobal.USE_BLAST_ADAPTER) { + return mBlastSurfaceControl; + } else { + return mSurfaceControl; + } + } } diff --git a/core/java/com/android/internal/app/BlockedAppActivity.java b/core/java/com/android/internal/app/BlockedAppActivity.java deleted file mode 100644 index fbdbbfb06b78..000000000000 --- a/core/java/com/android/internal/app/BlockedAppActivity.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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); - } -} diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 68d6e03f654c..96ab0bb4afc4 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -1101,6 +1101,9 @@ public class ResolverActivity extends Activity implements } if (target != null) { + if (intent != null) { + intent.fixUris(UserHandle.myUserId()); + } safelyStartActivity(target); // Rely on the ActivityManager to pop up a dialog regarding app suspension diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java index c610ac4503c9..0589baa76b8a 100644 --- a/core/java/com/android/internal/app/SuspendedAppActivity.java +++ b/core/java/com/android/internal/app/SuspendedAppActivity.java @@ -18,23 +18,31 @@ package com.android.internal.app; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; +import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS; +import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND; import static android.content.res.Resources.ID_NULL; import android.Manifest; +import android.annotation.Nullable; import android.app.AlertDialog; +import android.app.AppGlobals; import android.content.DialogInterface; import android.content.Intent; +import android.content.IntentSender; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.SuspendDialogInfo; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import android.view.WindowManager; import com.android.internal.R; +import com.android.internal.util.ArrayUtils; public class SuspendedAppActivity extends AlertActivity implements DialogInterface.OnClickListener { @@ -46,8 +54,13 @@ public class SuspendedAppActivity extends AlertActivity PACKAGE_NAME + ".extra.SUSPENDING_PACKAGE"; public static final String EXTRA_DIALOG_INFO = PACKAGE_NAME + ".extra.DIALOG_INFO"; public static final String EXTRA_ACTIVITY_OPTIONS = PACKAGE_NAME + ".extra.ACTIVITY_OPTIONS"; + public static final String EXTRA_UNSUSPEND_INTENT = PACKAGE_NAME + ".extra.UNSUSPEND_INTENT"; private Intent mMoreDetailsIntent; + private IntentSender mOnUnsuspend; + private String mSuspendedPackage; + private String mSuspendingPackage; + private int mNeutralButtonAction; private int mUserId; private PackageManager mPm; private Resources mSuspendingAppResources; @@ -63,16 +76,15 @@ public class SuspendedAppActivity extends AlertActivity return packageName; } - private Intent getMoreDetailsActivity(String suspendingPackage, String suspendedPackage, - int userId) { + private Intent getMoreDetailsActivity() { final Intent moreDetailsIntent = new Intent(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS) - .setPackage(suspendingPackage); + .setPackage(mSuspendingPackage); final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS; final ResolveInfo resolvedInfo = mPm.resolveActivityAsUser(moreDetailsIntent, - MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE, userId); + MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE, mUserId); if (resolvedInfo != null && resolvedInfo.activityInfo != null && requiredPermission.equals(resolvedInfo.activityInfo.permission)) { - moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage) + moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, mSuspendedPackage) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); return moreDetailsIntent; } @@ -105,8 +117,8 @@ public class SuspendedAppActivity extends AlertActivity return getString(R.string.app_suspended_title); } - private String resolveDialogMessage(String suspendingPkg, String suspendedPkg) { - final CharSequence suspendedAppLabel = getAppLabel(suspendedPkg); + private String resolveDialogMessage() { + final CharSequence suspendedAppLabel = getAppLabel(mSuspendedPackage); if (mSuppliedDialogInfo != null) { final int messageId = mSuppliedDialogInfo.getDialogMessageResId(); final String message = mSuppliedDialogInfo.getDialogMessage(); @@ -122,10 +134,30 @@ public class SuspendedAppActivity extends AlertActivity } } return getString(R.string.app_suspended_default_message, suspendedAppLabel, - getAppLabel(suspendingPkg)); + getAppLabel(mSuspendingPackage)); } + /** + * Returns a text to be displayed on the neutral button or {@code null} if the button should + * not be shown. + */ + @Nullable private String resolveNeutralButtonText() { + final int defaultButtonTextId; + switch (mNeutralButtonAction) { + case BUTTON_ACTION_MORE_DETAILS: + if (mMoreDetailsIntent == null) { + return null; + } + defaultButtonTextId = R.string.app_suspended_more_details; + break; + case BUTTON_ACTION_UNSUSPEND: + defaultButtonTextId = R.string.app_suspended_unsuspend_message; + break; + default: + Slog.w(TAG, "Unknown neutral button action: " + mNeutralButtonAction); + return null; + } final int buttonTextId = (mSuppliedDialogInfo != null) ? mSuppliedDialogInfo.getNeutralButtonTextResId() : ID_NULL; if (buttonTextId != ID_NULL && mSuspendingAppResources != null) { @@ -135,7 +167,7 @@ public class SuspendedAppActivity extends AlertActivity Slog.e(TAG, "Could not resolve string resource id " + buttonTextId); } } - return getString(R.string.app_suspended_more_details); + return getString(defaultButtonTextId); } @Override @@ -152,27 +184,29 @@ public class SuspendedAppActivity extends AlertActivity finish(); return; } - final String suspendedPackage = intent.getStringExtra(EXTRA_SUSPENDED_PACKAGE); - final String suspendingPackage = intent.getStringExtra(EXTRA_SUSPENDING_PACKAGE); + mSuspendedPackage = intent.getStringExtra(EXTRA_SUSPENDED_PACKAGE); + mSuspendingPackage = intent.getStringExtra(EXTRA_SUSPENDING_PACKAGE); mSuppliedDialogInfo = intent.getParcelableExtra(EXTRA_DIALOG_INFO); + mOnUnsuspend = intent.getParcelableExtra(EXTRA_UNSUSPEND_INTENT); if (mSuppliedDialogInfo != null) { try { - mSuspendingAppResources = mPm.getResourcesForApplicationAsUser(suspendingPackage, + mSuspendingAppResources = mPm.getResourcesForApplicationAsUser(mSuspendingPackage, mUserId); } catch (PackageManager.NameNotFoundException ne) { - Slog.e(TAG, "Could not find resources for " + suspendingPackage, ne); + Slog.e(TAG, "Could not find resources for " + mSuspendingPackage, ne); } } + mNeutralButtonAction = (mSuppliedDialogInfo != null) + ? mSuppliedDialogInfo.getNeutralButtonAction() : BUTTON_ACTION_MORE_DETAILS; + mMoreDetailsIntent = (mNeutralButtonAction == BUTTON_ACTION_MORE_DETAILS) + ? getMoreDetailsActivity() : null; final AlertController.AlertParams ap = mAlertParams; ap.mIcon = resolveIcon(); ap.mTitle = resolveTitle(); - ap.mMessage = resolveDialogMessage(suspendingPackage, suspendedPackage); + ap.mMessage = resolveDialogMessage(); ap.mPositiveButtonText = getString(android.R.string.ok); - mMoreDetailsIntent = getMoreDetailsActivity(suspendingPackage, suspendedPackage, mUserId); - if (mMoreDetailsIntent != null) { - ap.mNeutralButtonText = resolveNeutralButtonText(); - } + ap.mNeutralButtonText = resolveNeutralButtonText(); ap.mPositiveButtonListener = ap.mNeutralButtonListener = this; setupAlert(); } @@ -181,21 +215,62 @@ public class SuspendedAppActivity extends AlertActivity public void onClick(DialogInterface dialog, int which) { switch (which) { case AlertDialog.BUTTON_NEUTRAL: - startActivityAsUser(mMoreDetailsIntent, mOptions, UserHandle.of(mUserId)); - Slog.i(TAG, "Started activity: " + mMoreDetailsIntent.getAction() - + " in user " + mUserId); + switch (mNeutralButtonAction) { + case BUTTON_ACTION_MORE_DETAILS: + if (mMoreDetailsIntent != null) { + startActivityAsUser(mMoreDetailsIntent, mOptions, + UserHandle.of(mUserId)); + } else { + Slog.wtf(TAG, "Neutral button should not have existed!"); + } + break; + case BUTTON_ACTION_UNSUSPEND: + final IPackageManager ipm = AppGlobals.getPackageManager(); + try { + final String[] errored = ipm.setPackagesSuspendedAsUser( + new String[]{mSuspendedPackage}, false, null, null, null, + mSuspendingPackage, mUserId); + if (ArrayUtils.contains(errored, mSuspendedPackage)) { + Slog.e(TAG, "Could not unsuspend " + mSuspendedPackage); + break; + } + } catch (RemoteException re) { + Slog.e(TAG, "Can't talk to system process", re); + break; + } + final Intent reportUnsuspend = new Intent() + .setAction(Intent.ACTION_PACKAGE_UNSUSPENDED_MANUALLY) + .putExtra(Intent.EXTRA_PACKAGE_NAME, mSuspendedPackage) + .setPackage(mSuspendingPackage) + .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + sendBroadcastAsUser(reportUnsuspend, UserHandle.of(mUserId)); + + if (mOnUnsuspend != null) { + try { + mOnUnsuspend.sendIntent(this, 0, null, null, null); + } catch (IntentSender.SendIntentException e) { + Slog.e(TAG, "Error while starting intent " + mOnUnsuspend, e); + } + } + break; + default: + Slog.e(TAG, "Unexpected action on neutral button: " + mNeutralButtonAction); + break; + } break; } finish(); } public static Intent createSuspendedAppInterceptIntent(String suspendedPackage, - String suspendingPackage, SuspendDialogInfo dialogInfo, Bundle options, int userId) { + String suspendingPackage, SuspendDialogInfo dialogInfo, Bundle options, + IntentSender onUnsuspend, int userId) { return new Intent() .setClassName("android", SuspendedAppActivity.class.getName()) .putExtra(EXTRA_SUSPENDED_PACKAGE, suspendedPackage) .putExtra(EXTRA_DIALOG_INFO, dialogInfo) .putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage) + .putExtra(EXTRA_UNSUSPEND_INTENT, onUnsuspend) .putExtra(EXTRA_ACTIVITY_OPTIONS, options) .putExtra(Intent.EXTRA_USER_ID, userId) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK diff --git a/core/proto/android/server/usagestatsservice_v2.proto b/core/proto/android/server/usagestatsservice_v2.proto index a28fcf3589f1..24b0728c29ec 100644 --- a/core/proto/android/server/usagestatsservice_v2.proto +++ b/core/proto/android/server/usagestatsservice_v2.proto @@ -99,6 +99,7 @@ message EventObfuscatedProto { optional int32 instance_id = 10; optional int32 task_root_package_token = 11; optional int32 task_root_class_token = 12; + optional int32 locus_id_token = 13; } /** @@ -117,6 +118,7 @@ message PendingEventProto { optional int32 instance_id = 10; optional string task_root_package = 11; optional string task_root_class = 12; + optional string locus_id = 13; } /** diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 4595bab82465..c069c82d3a1d 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -53,6 +53,7 @@ <protected-broadcast android:name="android.intent.action.PACKAGE_VERIFIED" /> <protected-broadcast android:name="android.intent.action.PACKAGES_SUSPENDED" /> <protected-broadcast android:name="android.intent.action.PACKAGES_UNSUSPENDED" /> + <protected-broadcast android:name="android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY" /> <protected-broadcast android:name="android.intent.action.DISTRACTING_PACKAGES_CHANGED" /> <protected-broadcast android:name="android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED" /> <protected-broadcast android:name="android.intent.action.UID_REMOVED" /> @@ -5046,12 +5047,6 @@ 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"> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index be2b678565d3..83ef456cbbcf 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4923,6 +4923,8 @@ </string> <!-- Title of the button to show users more details about why the app has been suspended [CHAR LIMIT=50]--> <string name="app_suspended_more_details">Learn more</string> + <!-- Title of the button to unsuspend a suspended app immediately [CHAR LIMIT=50]--> + <string name="app_suspended_unsuspend_message">Unpause app</string> <!-- Title of a dialog. The string is asking if the user wants to turn on their work profile, which contains work apps that are managed by their employer. "Work" is an adjective. [CHAR LIMIT=30] --> <string name="work_mode_off_title">Turn on work profile?</string> @@ -4931,13 +4933,6 @@ <!-- 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 suspended 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 suspended 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] --> @@ -5318,7 +5313,8 @@ <string name="accessibility_system_action_lock_screen_label">Lock Screen</string> <!-- Label for taking screenshot action [CHAR LIMIT=NONE] --> <string name="accessibility_system_action_screenshot_label">Screenshot</string> - + <!-- Label for showing accessibility menu action [CHAR LIMIT=NONE] --> + <string name="accessibility_system_action_accessibility_menu_label">Accessibility Menu</string> <!-- Accessibility description of caption view --> <string name="accessibility_freeform_caption">Caption bar of <xliff:g id="app_name">%1$s</xliff:g>.</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 18ca003dd8c6..9414cdba92f5 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3039,11 +3039,9 @@ <java-symbol type="string" name="app_suspended_title" /> <java-symbol type="string" name="app_suspended_more_details" /> + <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" /> @@ -3804,6 +3802,7 @@ <java-symbol type="string" name="accessibility_system_action_recents_label" /> <java-symbol type="string" name="accessibility_system_action_screenshot_label" /> <java-symbol type="string" name="accessibility_system_action_toggle_split_screen_label" /> + <java-symbol type="string" name="accessibility_system_action_accessibility_menu_label" /> <java-symbol type="string" name="accessibility_freeform_caption" /> diff --git a/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java b/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java index e48f1c3a89c7..c0d9be5dde59 100644 --- a/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java +++ b/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java @@ -18,12 +18,9 @@ package android.content.integrity; import static android.content.integrity.TestUtils.assertExpectException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; import android.content.integrity.AtomicFormula.BooleanAtomicFormula; -import android.content.integrity.AtomicFormula.IntAtomicFormula; import android.content.integrity.AtomicFormula.StringAtomicFormula; import android.os.Parcel; @@ -36,19 +33,93 @@ public class AtomicFormulaTest { @Test public void testValidAtomicFormula_stringValue() { + String packageName = "com.test.app"; StringAtomicFormula stringAtomicFormula = new StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */ false); + AtomicFormula.PACKAGE_NAME, packageName, /* isHashedValue= */false); - assertEquals(AtomicFormula.PACKAGE_NAME, stringAtomicFormula.getKey()); + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.PACKAGE_NAME); + assertThat(stringAtomicFormula.getValue()).isEqualTo(packageName); + assertThat(stringAtomicFormula.getIsHashedValue()).isFalse(); } @Test - public void testValidAtomicFormula_intValue() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, 1); + public void testValidAtomicFormula_stringValue_autoHash_packageNameLessThanLimit() { + String packageName = "com.test.app"; + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, packageName); + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.PACKAGE_NAME); + assertThat(stringAtomicFormula.getValue()).isEqualTo(packageName); + assertThat(stringAtomicFormula.getIsHashedValue()).isFalse(); + } + + @Test + public void testValidAtomicFormula_stringValue_autoHash_longPackageName() { + String packageName = "com.test.app.test.app.test.app.test.app.test.app"; + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, packageName); + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.PACKAGE_NAME); + assertThat(stringAtomicFormula.getValue()).doesNotMatch(packageName); + assertThat(stringAtomicFormula.getIsHashedValue()).isTrue(); + } + + @Test + public void testValidAtomicFormula_stringValue_autoHash_installerNameLessThanLimit() { + String installerName = "com.test.app"; + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula(AtomicFormula.INSTALLER_NAME, installerName); + + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.INSTALLER_NAME); + assertThat(stringAtomicFormula.getValue()).isEqualTo(installerName); + assertThat(stringAtomicFormula.getIsHashedValue()).isFalse(); + } + + @Test + public void testValidAtomicFormula_stringValue_autoHash_longInstallerName() { + String installerName = "com.test.app.test.app.test.app.test.app.test.app"; + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula(AtomicFormula.INSTALLER_NAME, installerName); - assertEquals(AtomicFormula.VERSION_CODE, intAtomicFormula.getKey()); + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.INSTALLER_NAME); + assertThat(stringAtomicFormula.getValue()).doesNotMatch(installerName); + assertThat(stringAtomicFormula.getIsHashedValue()).isTrue(); + } + + @Test + public void testValidAtomicFormula_stringValue_appCertificateAutoHashed() { + String appCert = "cert"; + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, appCert); + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.APP_CERTIFICATE); + assertThat(stringAtomicFormula.getValue()).doesNotMatch(appCert); + assertThat(stringAtomicFormula.getIsHashedValue()).isTrue(); + } + + @Test + public void testValidAtomicFormula_stringValue_installerCertificateAutoHashed() { + String installerCert = "cert"; + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula(AtomicFormula.INSTALLER_CERTIFICATE, + installerCert); + + assertThat(stringAtomicFormula.getKey()).isEqualTo( + AtomicFormula.INSTALLER_CERTIFICATE); + assertThat(stringAtomicFormula.getValue()).doesNotMatch(installerCert); + assertThat(stringAtomicFormula.getIsHashedValue()).isTrue(); + } + + @Test + public void testValidAtomicFormula_longValue() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.GTE, 1); + + assertThat(longAtomicFormula.getKey()).isEqualTo(AtomicFormula.VERSION_CODE); + assertThat(longAtomicFormula.getValue()).isEqualTo(1); } @Test @@ -56,7 +127,8 @@ public class AtomicFormulaTest { BooleanAtomicFormula atomicFormula = new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true); - assertEquals(AtomicFormula.PRE_INSTALLED, atomicFormula.getKey()); + assertThat(atomicFormula.getKey()).isEqualTo(AtomicFormula.PRE_INSTALLED); + assertThat(atomicFormula.getValue()).isTrue(); } @Test @@ -73,12 +145,14 @@ public class AtomicFormulaTest { } @Test - public void testInvalidAtomicFormula_intValue() { + public void testInvalidAtomicFormula_longValue() { assertExpectException( IllegalArgumentException.class, /* expectedExceptionMessageRegex */ - String.format("Key PACKAGE_NAME cannot be used with IntAtomicFormula"), - () -> new IntAtomicFormula(AtomicFormula.PACKAGE_NAME, AtomicFormula.EQ, 1)); + String.format("Key PACKAGE_NAME cannot be used with LongAtomicFormula"), + () -> + new AtomicFormula.LongAtomicFormula( + AtomicFormula.PACKAGE_NAME, AtomicFormula.EQ, 1)); } @Test @@ -91,197 +165,174 @@ public class AtomicFormulaTest { } @Test - public void testIsSatisfiable_string_true() { - StringAtomicFormula stringAtomicFormula = + public void testParcelUnparcel_string() { + StringAtomicFormula formula = new StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */ false); - AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setPackageName("com.test.app").build(); + AtomicFormula.PACKAGE_NAME, "abc", /* isHashedValue= */ false); + Parcel p = Parcel.obtain(); + formula.writeToParcel(p, 0); + p.setDataPosition(0); + StringAtomicFormula newFormula = StringAtomicFormula.CREATOR.createFromParcel(p); - assertTrue(stringAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(newFormula).isEqualTo(formula); } @Test - public void testIsSatisfiable_string_false() { - StringAtomicFormula stringAtomicFormula = - new StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */ false); - AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setPackageName("com.foo.bar").build(); + public void testParcelUnparcel_int() { + AtomicFormula.LongAtomicFormula formula = + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.GT, 1); + Parcel p = Parcel.obtain(); + formula.writeToParcel(p, 0); + p.setDataPosition(0); + AtomicFormula.LongAtomicFormula newFormula = + AtomicFormula.LongAtomicFormula.CREATOR.createFromParcel(p); - assertFalse(stringAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(newFormula).isEqualTo(formula); } @Test - public void testIsSatisfiable_int_eq_true() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 0); - AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(0).build(); + public void testParcelUnparcel_bool() { + BooleanAtomicFormula formula = new BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true); + Parcel p = Parcel.obtain(); + formula.writeToParcel(p, 0); + p.setDataPosition(0); + BooleanAtomicFormula newFormula = BooleanAtomicFormula.CREATOR.createFromParcel(p); - assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(newFormula).isEqualTo(formula); } @Test - public void testIsSatisfiable_int_eq_false() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 0); - AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(1).build(); - - assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata)); + public void testInvalidAtomicFormula_invalidKey() { + assertExpectException( + IllegalArgumentException.class, + /* expectedExceptionMessageRegex */ "Unknown key: -1", + () -> new AtomicFormula.LongAtomicFormula(/* key= */ -1, AtomicFormula.EQ, 0)); } @Test - public void testIsSatisfiable_int_gt_true() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GT, 0); - AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(1).build(); - - assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata)); + public void testInvalidAtomicFormula_invalidOperator() { + assertExpectException( + IllegalArgumentException.class, + /* expectedExceptionMessageRegex */ "Unknown operator: -1", + () -> + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, /* operator= */ -1, 0)); } @Test - public void testIsSatisfiable_int_gt_false() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GT, 1); + public void testFormulaMatches_string_true() { + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula( + AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */ + false); AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(0).build(); + getAppInstallMetadataBuilder().setPackageName("com.test.app").build(); - assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(stringAtomicFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_int_ge_true() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GE, 0); + public void testFormulaMatches_string_false() { + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula( + AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */ + false); AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(1).build(); + getAppInstallMetadataBuilder().setPackageName("com.foo.bar").build(); - assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(stringAtomicFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_int_ge_false() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GE, 1); + public void testFormulaMatches_long_eq_true() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 0); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setVersionCode(0).build(); - assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(longAtomicFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_int_lt_true() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LT, 1); + public void testFormulaMatches_long_eq_false() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 0); AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(0).build(); + getAppInstallMetadataBuilder().setVersionCode(1).build(); - assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(longAtomicFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_int_lt_false() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LT, 1); + public void testFormulaMatches_long_gt_true() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GT, + 0); AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(2).build(); + getAppInstallMetadataBuilder().setVersionCode(1).build(); - assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(longAtomicFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_int_le_true() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, 1); + public void testFormulaMatches_long_gt_false() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GT, + 1); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setVersionCode(0).build(); - assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(longAtomicFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_int_le_false() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, 1); - AppInstallMetadata appInstallMetadata = + public void testFormulaMatches_long_gte_true() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.GTE, 1); + + AppInstallMetadata appInstallMetadata1 = + getAppInstallMetadataBuilder().setVersionCode(1).build(); + assertThat(longAtomicFormula.matches(appInstallMetadata1)).isTrue(); + + AppInstallMetadata appInstallMetadata2 = getAppInstallMetadataBuilder().setVersionCode(2).build(); + assertThat(longAtomicFormula.matches(appInstallMetadata2)).isTrue(); + } - assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata)); + @Test + public void testFormulaMatches_long_gte_false() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.GTE, 1); + AppInstallMetadata appInstallMetadata = + getAppInstallMetadataBuilder().setVersionCode(0).build(); + + assertThat(longAtomicFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_bool_true() { + public void testFormulaMatches_bool_true() { BooleanAtomicFormula boolFormula = new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setIsPreInstalled(true).build(); - assertTrue(boolFormula.isSatisfied(appInstallMetadata)); + assertThat(boolFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_bool_false() { + public void testFormulaMatches_bool_false() { BooleanAtomicFormula boolFormula = new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setIsPreInstalled(false).build(); - assertFalse(boolFormula.isSatisfied(appInstallMetadata)); - } - - @Test - public void testParcelUnparcel_string() { - StringAtomicFormula formula = - new StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, "abc", /* isHashedValue= */ false); - Parcel p = Parcel.obtain(); - formula.writeToParcel(p, 0); - p.setDataPosition(0); - StringAtomicFormula newFormula = StringAtomicFormula.CREATOR.createFromParcel(p); - - assertEquals(formula, newFormula); - } - - @Test - public void testParcelUnparcel_int() { - IntAtomicFormula formula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LT, 1); - Parcel p = Parcel.obtain(); - formula.writeToParcel(p, 0); - p.setDataPosition(0); - IntAtomicFormula newFormula = IntAtomicFormula.CREATOR.createFromParcel(p); - - assertEquals(formula, newFormula); - } - - @Test - public void testParcelUnparcel_bool() { - BooleanAtomicFormula formula = new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true); - Parcel p = Parcel.obtain(); - formula.writeToParcel(p, 0); - p.setDataPosition(0); - BooleanAtomicFormula newFormula = BooleanAtomicFormula.CREATOR.createFromParcel(p); - - assertEquals(formula, newFormula); - } - - @Test - public void testInvalidAtomicFormula_invalidKey() { - assertExpectException( - IllegalArgumentException.class, - /* expectedExceptionMessageRegex */ "Unknown key: -1", - () -> new IntAtomicFormula(/* key= */ -1, AtomicFormula.EQ, 0)); - } - - @Test - public void testInvalidAtomicFormula_invalidOperator() { - assertExpectException( - IllegalArgumentException.class, - /* expectedExceptionMessageRegex */ "Unknown operator: -1", - () -> new IntAtomicFormula(AtomicFormula.VERSION_CODE, /* operator= */ -1, 0)); + assertThat(boolFormula.matches(appInstallMetadata)).isFalse(); } /** Returns a builder with all fields filled with some dummy data. */ diff --git a/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java index 927e4dbb5200..fa3d671c09e5 100644 --- a/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java +++ b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java @@ -18,9 +18,9 @@ package android.content.integrity; import static android.content.integrity.TestUtils.assertExpectException; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import android.os.Parcel; @@ -38,7 +38,7 @@ public class CompoundFormulaTest { new AtomicFormula.StringAtomicFormula( AtomicFormula.PACKAGE_NAME, "test1", /* isHashedValue= */ false); private static final AtomicFormula ATOMIC_FORMULA_2 = - new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1); + new AtomicFormula.LongAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1); @Test public void testValidCompoundFormula() { @@ -75,163 +75,156 @@ public class CompoundFormulaTest { } @Test - public void testIsSatisfiable_notFalse_true() { - CompoundFormula compoundFormula = - new CompoundFormula(CompoundFormula.NOT, Arrays.asList(ATOMIC_FORMULA_1)); - AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setPackageName("test2").build(); - // validate assumptions about the metadata - assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); + public void testParcelUnparcel() { + CompoundFormula formula = + new CompoundFormula( + CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_2, ATOMIC_FORMULA_1)); + Parcel p = Parcel.obtain(); + formula.writeToParcel(p, 0); + p.setDataPosition(0); + CompoundFormula newFormula = CompoundFormula.CREATOR.createFromParcel(p); + + assertEquals(formula, newFormula); + } - assertTrue(compoundFormula.isSatisfied(appInstallMetadata)); + @Test + public void testInvalidCompoundFormula_invalidConnector() { + assertExpectException( + IllegalArgumentException.class, + /* expectedExceptionMessageRegex */ "Unknown connector: -1", + () -> + new CompoundFormula( + /* connector= */ -1, + Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2))); } @Test - public void testIsSatisfiable_notTrue_false() { + public void testFormulaMatches_notFalse_true() { + AppInstallMetadata appInstallMetadata = + getAppInstallMetadataBuilder().setPackageName("test2").build(); + + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isFalse(); + CompoundFormula compoundFormula = new CompoundFormula(CompoundFormula.NOT, Arrays.asList(ATOMIC_FORMULA_1)); + assertThat(compoundFormula.matches(appInstallMetadata)).isTrue(); + } + + @Test + public void testFormulaMatches_notTrue_false() { AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test1").build(); - // validate assumptions about the metadata - assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertFalse(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isTrue(); + + CompoundFormula compoundFormula = + new CompoundFormula(CompoundFormula.NOT, Arrays.asList(ATOMIC_FORMULA_1)); + assertThat(compoundFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_trueAndTrue_true() { + public void testFormulaMatches_trueAndTrue_true() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(1).build(); // validate assumptions about the metadata - assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isTrue(); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isTrue(); - assertTrue(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(compoundFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_trueAndFalse_false() { + public void testFormulaMatches_trueAndFalse_false() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(2).build(); - // validate assumptions about the metadata - assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - assertFalse(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isTrue(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isFalse(); + assertThat(compoundFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_falseAndTrue_false() { + public void testFormulaMatches_falseAndTrue_false() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(1).build(); - // validate assumptions about the metadata - assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - assertFalse(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isFalse(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isTrue(); + assertThat(compoundFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_falseAndFalse_false() { + public void testFormulaMatches_falseAndFalse_false() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(2).build(); - // validate assumptions about the metadata - assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - assertFalse(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isFalse(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isFalse(); + assertThat(compoundFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_trueOrTrue_true() { + public void testFormulaMatches_trueOrTrue_true() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(1).build(); - // validate assumptions about the metadata - assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - assertTrue(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isTrue(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isTrue(); + assertThat(compoundFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_trueOrFalse_true() { + public void testFormulaMatches_trueOrFalse_true() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(2).build(); - // validate assumptions about the metadata - assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - assertTrue(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isTrue(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isFalse(); + assertThat(compoundFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_falseOrTrue_true() { + public void testFormulaMatches_falseOrTrue_true() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(1).build(); - // validate assumptions about the metadata - assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - assertTrue(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isFalse(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isTrue(); + assertThat(compoundFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_falseOrFalse_false() { + public void testFormulaMatches_falseOrFalse_false() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(2).build(); - // validate assumptions about the metadata - assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - - assertFalse(compoundFormula.isSatisfied(appInstallMetadata)); - } - - @Test - public void testParcelUnparcel() { - CompoundFormula formula = - new CompoundFormula( - CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_2, ATOMIC_FORMULA_1)); - Parcel p = Parcel.obtain(); - formula.writeToParcel(p, 0); - p.setDataPosition(0); - CompoundFormula newFormula = CompoundFormula.CREATOR.createFromParcel(p); - assertEquals(formula, newFormula); - } - - @Test - public void testInvalidCompoundFormula_invalidConnector() { - assertExpectException( - IllegalArgumentException.class, - /* expectedExceptionMessageRegex */ "Unknown connector: -1", - () -> - new CompoundFormula( - /* connector= */ -1, - Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2))); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isFalse(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isFalse(); + assertThat(compoundFormula.matches(appInstallMetadata)).isFalse(); } /** Returns a builder with all fields filled with some dummy data. */ diff --git a/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java b/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java new file mode 100644 index 000000000000..c1806028f75b --- /dev/null +++ b/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java @@ -0,0 +1,214 @@ +/* + * 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 android.content.integrity; + +import static android.content.integrity.IntegrityFormula.COMPOUND_FORMULA_TAG; + +import static com.google.common.truth.Truth.assertThat; + +import static org.testng.Assert.assertThrows; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class IntegrityFormulaTest { + + @Test + public void createEqualsFormula_packageName() { + String packageName = "com.test.app"; + IntegrityFormula formula = + IntegrityFormula.PACKAGE_NAME.equalTo(packageName); + + AtomicFormula.StringAtomicFormula stringAtomicFormula = + (AtomicFormula.StringAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.PACKAGE_NAME); + assertThat(stringAtomicFormula.getValue()).isEqualTo(packageName); + assertThat(stringAtomicFormula.getIsHashedValue()).isEqualTo(false); + } + + @Test + public void createEqualsFormula_appCertificate() { + String appCertificate = "com.test.app"; + IntegrityFormula formula = + IntegrityFormula.APP_CERTIFICATE.equalTo(appCertificate); + + AtomicFormula.StringAtomicFormula stringAtomicFormula = + (AtomicFormula.StringAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.APP_CERTIFICATE); + assertThat(stringAtomicFormula.getValue()).doesNotMatch(appCertificate); + assertThat(stringAtomicFormula.getIsHashedValue()).isEqualTo(true); + } + + @Test + public void createEqualsFormula_installerName() { + String installerName = "com.test.app"; + IntegrityFormula formula = + IntegrityFormula.INSTALLER_NAME.equalTo(installerName); + + AtomicFormula.StringAtomicFormula stringAtomicFormula = + (AtomicFormula.StringAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.INSTALLER_NAME); + assertThat(stringAtomicFormula.getValue()).isEqualTo(installerName); + assertThat(stringAtomicFormula.getIsHashedValue()).isEqualTo(false); + } + + @Test + public void createEqualsFormula_installerCertificate() { + String installerCertificate = "com.test.app"; + IntegrityFormula formula = + IntegrityFormula.INSTALLER_CERTIFICATE.equalTo(installerCertificate); + + AtomicFormula.StringAtomicFormula stringAtomicFormula = + (AtomicFormula.StringAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.INSTALLER_CERTIFICATE); + assertThat(stringAtomicFormula.getValue()).doesNotMatch(installerCertificate); + assertThat(stringAtomicFormula.getIsHashedValue()).isEqualTo(true); + } + + @Test + public void createEqualsFormula_versionCode() { + int versionCode = 12; + IntegrityFormula formula = + IntegrityFormula.VERSION_CODE.equalTo(versionCode); + + AtomicFormula.LongAtomicFormula stringAtomicFormula = + (AtomicFormula.LongAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.VERSION_CODE); + assertThat(stringAtomicFormula.getValue()).isEqualTo(versionCode); + assertThat(stringAtomicFormula.getOperator()).isEqualTo(AtomicFormula.EQ); + } + + @Test + public void createEqualsFormula_invalidKeyTypeForStringParameter() { + assertThrows( + IllegalArgumentException.class, + () -> IntegrityFormula.PRE_INSTALLED.equalTo("wrongString")); + } + + @Test + public void createEqualsFormula_invalidKeyTypeForLongParameter() { + assertThrows( + IllegalArgumentException.class, + () -> IntegrityFormula.PACKAGE_NAME.equalTo(12)); + } + + @Test + public void createGreaterThanFormula_versionCode() { + int versionCode = 12; + IntegrityFormula formula = + IntegrityFormula.VERSION_CODE.greaterThan(versionCode); + + AtomicFormula.LongAtomicFormula stringAtomicFormula = + (AtomicFormula.LongAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.VERSION_CODE); + assertThat(stringAtomicFormula.getValue()).isEqualTo(versionCode); + assertThat(stringAtomicFormula.getOperator()).isEqualTo(AtomicFormula.GT); + } + + @Test + public void createGreaterThanFormula_invalidKeyTypeForLongParameter() { + assertThrows( + IllegalArgumentException.class, + () -> IntegrityFormula.PACKAGE_NAME.greaterThan(12)); + } + + @Test + public void createGreaterThanOrEqualsToFormula_versionCode() { + int versionCode = 12; + IntegrityFormula formula = + IntegrityFormula.VERSION_CODE.greaterThanOrEquals(versionCode); + + AtomicFormula.LongAtomicFormula stringAtomicFormula = + (AtomicFormula.LongAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.VERSION_CODE); + assertThat(stringAtomicFormula.getValue()).isEqualTo(versionCode); + assertThat(stringAtomicFormula.getOperator()).isEqualTo(AtomicFormula.GTE); + } + + @Test + public void createGreaterThanOrEqualsToFormula_invalidKeyTypeForLongParameter() { + assertThrows( + IllegalArgumentException.class, + () -> IntegrityFormula.PACKAGE_NAME.greaterThanOrEquals(12)); + } + + @Test + public void createIsTrueFormula_preInstalled() { + IntegrityFormula formula = IntegrityFormula.PRE_INSTALLED.equalTo(true); + + AtomicFormula.BooleanAtomicFormula stringAtomicFormula = + (AtomicFormula.BooleanAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.PRE_INSTALLED); + assertThat(stringAtomicFormula.getValue()).isTrue(); + } + + @Test + public void createIsTrueFormula_invalidKeyTypeForBoolParameter() { + assertThrows( + IllegalArgumentException.class, + () -> IntegrityFormula.PACKAGE_NAME.equalTo(true)); + } + + @Test + public void createAllFormula() { + String packageName = "com.test.package"; + String certificateName = "certificate"; + IntegrityFormula formula1 = + IntegrityFormula.PACKAGE_NAME.equalTo(packageName); + IntegrityFormula formula2 = + IntegrityFormula.APP_CERTIFICATE.equalTo(certificateName); + + IntegrityFormula compoundFormula = IntegrityFormula.all(formula1, formula2); + + assertThat(compoundFormula.getTag()).isEqualTo(COMPOUND_FORMULA_TAG); + } + + @Test + public void createAnyFormula() { + String packageName = "com.test.package"; + String certificateName = "certificate"; + IntegrityFormula formula1 = + IntegrityFormula.PACKAGE_NAME.equalTo(packageName); + IntegrityFormula formula2 = + IntegrityFormula.APP_CERTIFICATE.equalTo(certificateName); + + IntegrityFormula compoundFormula = IntegrityFormula.any(formula1, formula2); + + assertThat(compoundFormula.getTag()).isEqualTo(COMPOUND_FORMULA_TAG); + } + + @Test + public void createNotFormula() { + String packageName = "com.test.package"; + + IntegrityFormula compoundFormula = + IntegrityFormula.not( + IntegrityFormula.PACKAGE_NAME.equalTo(packageName)); + + assertThat(compoundFormula.getTag()).isEqualTo(COMPOUND_FORMULA_TAG); + } +} diff --git a/services/tests/servicestests/src/com/android/server/integrity/IntegrityUtilsTest.java b/core/tests/coretests/src/android/content/integrity/IntegrityUtilsTest.java index ac7f8f98ab9b..639adf6a05d7 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/IntegrityUtilsTest.java +++ b/core/tests/coretests/src/android/content/integrity/IntegrityUtilsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,48 +14,44 @@ * limitations under the License. */ -package com.android.server.integrity; +package android.content.integrity; -import static com.android.server.integrity.IntegrityUtils.getBytesFromHexDigest; -import static com.android.server.integrity.IntegrityUtils.getHexDigest; -import static com.android.server.testutils.TestUtils.assertExpectException; +import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import androidx.test.runner.AndroidJUnit4; +import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; -/** Unit test for {@link com.android.server.integrity.IntegrityUtils} */ -@RunWith(AndroidJUnit4.class) +/** Unit test for {@link IntegrityUtils} */ +@RunWith(JUnit4.class) public class IntegrityUtilsTest { private static final String HEX_DIGEST = "1234567890ABCDEF"; private static final byte[] BYTES = - new byte[] {0x12, 0x34, 0x56, 0x78, (byte) 0x90, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF}; + new byte[]{0x12, 0x34, 0x56, 0x78, (byte) 0x90, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF}; @Test public void testGetBytesFromHexDigest() { - assertArrayEquals(BYTES, getBytesFromHexDigest(HEX_DIGEST)); + assertArrayEquals(BYTES, IntegrityUtils.getBytesFromHexDigest(HEX_DIGEST)); } @Test public void testGetHexDigest() { - assertEquals(HEX_DIGEST, getHexDigest(BYTES)); + assertThat(IntegrityUtils.getHexDigest(BYTES)).isEqualTo(HEX_DIGEST); } @Test public void testInvalidHexDigest() { - assertExpectException( + TestUtils.assertExpectException( IllegalArgumentException.class, "must have even length", - () -> getBytesFromHexDigest("ABC")); + () -> IntegrityUtils.getBytesFromHexDigest("ABC")); - assertExpectException( + TestUtils.assertExpectException( IllegalArgumentException.class, "Invalid hex char", - () -> getBytesFromHexDigest("GH")); + () -> IntegrityUtils.getBytesFromHexDigest("GH")); } } diff --git a/core/tests/coretests/src/android/content/integrity/RuleTest.java b/core/tests/coretests/src/android/content/integrity/RuleTest.java index 19e74e6b93cc..8c4cfca39e90 100644 --- a/core/tests/coretests/src/android/content/integrity/RuleTest.java +++ b/core/tests/coretests/src/android/content/integrity/RuleTest.java @@ -35,11 +35,15 @@ public class RuleTest { private static final @Rule.Effect int DENY_EFFECT = Rule.DENY; private static final String PACKAGE_NAME = "com.test.app"; private static final String APP_CERTIFICATE = "test_cert"; - private static final Formula PACKAGE_NAME_ATOMIC_FORMULA = - new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME, + private static final IntegrityFormula PACKAGE_NAME_ATOMIC_FORMULA = + new AtomicFormula.StringAtomicFormula( + AtomicFormula.PACKAGE_NAME, + PACKAGE_NAME, /* isHashedValue= */ false); - private static final Formula APP_CERTIFICATE_ATOMIC_FORMULA = - new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE, + private static final IntegrityFormula APP_CERTIFICATE_ATOMIC_FORMULA = + new AtomicFormula.StringAtomicFormula( + AtomicFormula.APP_CERTIFICATE, + APP_CERTIFICATE, /* isHashedValue= */ false); @Test diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 687535c3304b..0c5fe787bbbc 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -74,7 +74,7 @@ import java.util.function.Consumer; * still return location results, but the exact location will be obfuscated to a coarse level of * accuracy. */ -@SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"}) +@SuppressWarnings({"deprecation"}) @SystemService(Context.LOCATION_SERVICE) @RequiresFeature(PackageManager.FEATURE_LOCATION) public class LocationManager { diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java new file mode 100644 index 000000000000..44d9d2372665 --- /dev/null +++ b/location/java/android/location/LocationManagerInternal.java @@ -0,0 +1,44 @@ +/* + * 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 android.location; + + +import android.annotation.NonNull; + +/** + * Location manager local system service interface. + * + * @hide Only for use within the system server. + */ +public abstract class LocationManagerInternal { + + /** + * Requests that a provider change its allowed state. A provider may or may not honor this + * request, and if the provider does change its state as a result, that may happen + * asynchronously after some delay. + * + * <p>Setting a provider's state to allowed implies that any consents or terms and conditions + * that may be necessary to allow the provider are agreed to. Setting a providers state to + * disallowed implies that any consents or terms and conditions have their agreement revoked. + * + * @param provider A location provider as listed by {@link LocationManager#getAllProviders()} + * @param allowed Whether the location provider is being requested to allow or disallow + * itself + * @throws IllegalArgumentException if provider is null + */ + public abstract void requestSetProviderAllowed(@NonNull String provider, boolean allowed); +} diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl index 4246c6cd1004..b7817ff1e1fc 100644 --- a/location/java/com/android/internal/location/ILocationProvider.aidl +++ b/location/java/com/android/internal/location/ILocationProvider.aidl @@ -37,4 +37,6 @@ interface ILocationProvider { @UnsupportedAppUsage oneway void sendExtraCommand(String command, in Bundle extras); + + oneway void requestSetAllowed(boolean allowed); } diff --git a/location/java/com/android/internal/location/ILocationProviderManager.aidl b/location/java/com/android/internal/location/ILocationProviderManager.aidl index 85e18ba5ec4b..439039148773 100644 --- a/location/java/com/android/internal/location/ILocationProviderManager.aidl +++ b/location/java/com/android/internal/location/ILocationProviderManager.aidl @@ -29,7 +29,7 @@ interface ILocationProviderManager { void onSetAdditionalProviderPackages(in List<String> packageNames); @UnsupportedAppUsage - void onSetEnabled(boolean enabled); + void onSetAllowed(boolean allowed); @UnsupportedAppUsage void onSetProperties(in ProviderProperties properties); diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt index 5471bea549f4..49fcaabe981a 100644 --- a/location/lib/api/current.txt +++ b/location/lib/api/current.txt @@ -9,18 +9,21 @@ package com.android.location.provider { public abstract class LocationProviderBase { ctor public LocationProviderBase(String, com.android.location.provider.ProviderPropertiesUnbundled); method public android.os.IBinder getBinder(); - method @RequiresApi(android.os.Build.VERSION_CODES.Q) public boolean isEnabled(); + method @RequiresApi(android.os.Build.VERSION_CODES.R) public boolean isAllowed(); + method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public boolean isEnabled(); method @Deprecated protected void onDisable(); method @Deprecated protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, String[]); method @Deprecated protected void onEnable(); method @Deprecated protected int onGetStatus(android.os.Bundle); method @Deprecated protected long onGetStatusUpdateTime(); method protected void onInit(); + method protected void onRequestSetAllowed(boolean); method protected boolean onSendExtraCommand(@Nullable String, @Nullable android.os.Bundle); method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource); method public void reportLocation(android.location.Location); method @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setAdditionalProviderPackages(java.util.List<java.lang.String>); - method @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setEnabled(boolean); + method @RequiresApi(android.os.Build.VERSION_CODES.R) public void setAllowed(boolean); + method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setEnabled(boolean); method @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setProperties(com.android.location.provider.ProviderPropertiesUnbundled); field public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation"; field public static final String FUSED_PROVIDER = "fused"; diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java index fc7bff3c6dab..f67d08e045e2 100644 --- a/location/lib/java/com/android/location/provider/LocationProviderBase.java +++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java @@ -92,7 +92,7 @@ public abstract class LocationProviderBase { // write locked on mBinder, read lock is optional depending on atomicity requirements @Nullable private volatile ILocationProviderManager mManager; private volatile ProviderProperties mProperties; - private volatile boolean mEnabled; + private volatile boolean mAllowed; private final ArrayList<String> mAdditionalProviderPackages; public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) { @@ -104,7 +104,7 @@ public abstract class LocationProviderBase { mManager = null; mProperties = properties.getProviderProperties(); - mEnabled = true; + mAllowed = true; mAdditionalProviderPackages = new ArrayList<>(0); } @@ -113,35 +113,44 @@ public abstract class LocationProviderBase { } /** - * Sets whether this provider is currently enabled or not. Note that this is specific to the + * @deprecated Use {@link #setAllowed(boolean)} instead. + */ + @Deprecated + @RequiresApi(VERSION_CODES.Q) + public void setEnabled(boolean enabled) { + setAllowed(enabled); + } + + /** + * Sets whether this provider is currently allowed or not. Note that this is specific to the * provider only, and is not related to global location settings. This is a hint to the Location * Manager that this provider will generally be unable to fulfill incoming requests. This - * provider may still receive callbacks to onSetRequest while not enabled, and must decide + * provider may still receive callbacks to onSetRequest while not allowed, and must decide * whether to attempt to satisfy those requests or not. * - * Some guidelines: providers should set their own enabled/disabled status based only on state - * "owned" by that provider. For instance, providers should not take into account the state of - * the location master setting when setting themselves enabled or disabled, as this state is not - * owned by a particular provider. If a provider requires some additional user consent that is - * particular to the provider, this should be use to set the enabled/disabled state. If the - * provider proxies to another provider, the child provider's enabled/disabled state should be - * taken into account in the parent's enabled/disabled state. For most providers, it is expected - * that they will be always enabled. + * <p>Some guidelines: providers should set their own allowed/disallowed status based only on + * state "owned" by that provider. For instance, providers should not take into account the + * state of the location master setting when setting themselves allowed or disallowed, as this + * state is not owned by a particular provider. If a provider requires some additional user + * consent that is particular to the provider, this should be use to set the allowed/disallowed + * state. If the provider proxies to another provider, the child provider's allowed/disallowed + * state should be taken into account in the parent's allowed state. For most providers, it is + * expected that they will be always allowed. */ - @RequiresApi(VERSION_CODES.Q) - public void setEnabled(boolean enabled) { + @RequiresApi(VERSION_CODES.R) + public void setAllowed(boolean allowed) { synchronized (mBinder) { - if (mEnabled == enabled) { + if (mAllowed == allowed) { return; } - mEnabled = enabled; + mAllowed = allowed; } ILocationProviderManager manager = mManager; if (manager != null) { try { - manager.onSetEnabled(mEnabled); + manager.onSetAllowed(mAllowed); } catch (RemoteException | RuntimeException e) { Log.w(mTag, e); } @@ -193,12 +202,20 @@ public abstract class LocationProviderBase { } /** - * Returns true if this provider has been set as enabled. This will be true unless explicitly - * set otherwise. + * @deprecated Use {@link #isAllowed()} instead. */ + @Deprecated @RequiresApi(VERSION_CODES.Q) public boolean isEnabled() { - return mEnabled; + return isAllowed(); + } + + /** + * Returns true if this provider is allowed. Providers start as allowed on construction. + */ + @RequiresApi(VERSION_CODES.R) + public boolean isAllowed() { + return mAllowed; } /** @@ -285,6 +302,17 @@ public abstract class LocationProviderBase { return false; } + /** + * Invoked when the system wishes to request that the provider sets its allowed state as + * desired. This implies that the caller is providing/retracting consent for any terms and + * conditions or consents associated with the provider. + * + * <p>It is generally only necessary to override this function if the provider has some barriers + * or gates for enabling/disabling itself, in which case this function should handle those + * appropriately. A provider that is always allowed has no need to override this function. + */ + protected void onRequestSetAllowed(boolean allowed) {} + private final class Service extends ILocationProvider.Stub { @Override @@ -295,7 +323,7 @@ public abstract class LocationProviderBase { manager.onSetAdditionalProviderPackages(mAdditionalProviderPackages); } manager.onSetProperties(mProperties); - manager.onSetEnabled(mEnabled); + manager.onSetAllowed(mAllowed); } catch (RemoteException e) { Log.w(mTag, e); } @@ -315,5 +343,10 @@ public abstract class LocationProviderBase { public void sendExtraCommand(String command, Bundle extras) { onSendExtraCommand(command, extras); } + + @Override + public void requestSetAllowed(boolean allowed) { + onRequestSetAllowed(allowed); + } } } diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index cbc9683b9cc1..197786f42490 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -763,7 +763,13 @@ public final class MediaCodecInfo { int maxLevel = 0; for (CodecProfileLevel pl : profileLevels) { if (pl.profile == profile && pl.level > maxLevel) { - maxLevel = pl.level; + // H.263 levels are not completely ordered: + // Level45 support only implies Level10 support + if (!mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263) + || pl.level != CodecProfileLevel.H263Level45 + || maxLevel == CodecProfileLevel.H263Level10) { + maxLevel = pl.level; + } } } levelCaps = createFromProfileLevel(mMime, profile, maxLevel); diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index f408ac344d7c..f61d55ef2a30 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -20,6 +20,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; +import android.media.MediaCodec; +import android.media.MediaParser; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -45,6 +47,7 @@ import java.util.stream.Collectors; * <table> * <tr><th>Name</th><th>Value Type</th><th>Description</th></tr> * <tr><td>{@link #KEY_MIME}</td><td>String</td><td>The type of the format.</td></tr> + * <tr><td>{@link #KEY_CODECS_STRING}</td><td>String</td><td>optional, the RFC 6381 codecs string of the MediaFormat</td></tr> * <tr><td>{@link #KEY_MAX_INPUT_SIZE}</td><td>Integer</td><td>optional, maximum size of a buffer of input data</td></tr> * <tr><td>{@link #KEY_PIXEL_ASPECT_RATIO_WIDTH}</td><td>Integer</td><td>optional, the pixel aspect ratio width</td></tr> * <tr><td>{@link #KEY_PIXEL_ASPECT_RATIO_HEIGHT}</td><td>Integer</td><td>optional, the pixel aspect ratio height</td></tr> @@ -217,6 +220,15 @@ public final class MediaFormat { public static final String KEY_MIME = "mime"; /** + * A key describing the codecs string of the MediaFormat. See RFC 6381 section 3.2 for the + * syntax of the value. The value does not hold {@link MediaCodec}-exposed codec names. + * The associated value is a string. + * + * @see MediaParser.TrackData#mediaFormat + */ + public static final String KEY_CODECS_STRING = "codecs-string"; + + /** * An optional key describing the low latency decoding mode. This is an optional parameter * that applies only to decoders. If enabled, the decoder doesn't hold input and output * data more than required by the codec standards. diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java index 4cd581b6628c..1617b875c6f7 100644 --- a/media/java/android/media/MediaMetadataRetriever.java +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -28,6 +28,7 @@ import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.IBinder; +import android.text.TextUtils; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -44,6 +45,162 @@ import java.util.Map; * frame and meta data from an input media file. */ public class MediaMetadataRetriever implements AutoCloseable { + + // borrowed from ExoPlayer + private static final String[] STANDARD_GENRES = new String[] { + // These are the official ID3v1 genres. + "Blues", + "Classic Rock", + "Country", + "Dance", + "Disco", + "Funk", + "Grunge", + "Hip-Hop", + "Jazz", + "Metal", + "New Age", + "Oldies", + "Other", + "Pop", + "R&B", + "Rap", + "Reggae", + "Rock", + "Techno", + "Industrial", + "Alternative", + "Ska", + "Death Metal", + "Pranks", + "Soundtrack", + "Euro-Techno", + "Ambient", + "Trip-Hop", + "Vocal", + "Jazz+Funk", + "Fusion", + "Trance", + "Classical", + "Instrumental", + "Acid", + "House", + "Game", + "Sound Clip", + "Gospel", + "Noise", + "AlternRock", + "Bass", + "Soul", + "Punk", + "Space", + "Meditative", + "Instrumental Pop", + "Instrumental Rock", + "Ethnic", + "Gothic", + "Darkwave", + "Techno-Industrial", + "Electronic", + "Pop-Folk", + "Eurodance", + "Dream", + "Southern Rock", + "Comedy", + "Cult", + "Gangsta", + "Top 40", + "Christian Rap", + "Pop/Funk", + "Jungle", + "Native American", + "Cabaret", + "New Wave", + "Psychadelic", + "Rave", + "Showtunes", + "Trailer", + "Lo-Fi", + "Tribal", + "Acid Punk", + "Acid Jazz", + "Polka", + "Retro", + "Musical", + "Rock & Roll", + "Hard Rock", + // These were made up by the authors of Winamp and later added to the ID3 spec. + "Folk", + "Folk-Rock", + "National Folk", + "Swing", + "Fast Fusion", + "Bebob", + "Latin", + "Revival", + "Celtic", + "Bluegrass", + "Avantgarde", + "Gothic Rock", + "Progressive Rock", + "Psychedelic Rock", + "Symphonic Rock", + "Slow Rock", + "Big Band", + "Chorus", + "Easy Listening", + "Acoustic", + "Humour", + "Speech", + "Chanson", + "Opera", + "Chamber Music", + "Sonata", + "Symphony", + "Booty Bass", + "Primus", + "Porn Groove", + "Satire", + "Slow Jam", + "Club", + "Tango", + "Samba", + "Folklore", + "Ballad", + "Power Ballad", + "Rhythmic Soul", + "Freestyle", + "Duet", + "Punk Rock", + "Drum Solo", + "A capella", + "Euro-House", + "Dance Hall", + // These were made up by the authors of Winamp but have not been added to the ID3 spec. + "Goa", + "Drum & Bass", + "Club-House", + "Hardcore", + "Terror", + "Indie", + "BritPop", + "Afro-Punk", + "Polsk Punk", + "Beat", + "Christian Gangsta Rap", + "Heavy Metal", + "Black Metal", + "Crossover", + "Contemporary Christian", + "Christian Rock", + "Merengue", + "Salsa", + "Thrash Metal", + "Anime", + "Jpop", + "Synthpop" + }; + static { System.loadLibrary("media_jni"); native_init(); @@ -225,6 +382,8 @@ public class MediaMetadataRetriever implements AutoCloseable { private native void _setDataSource(MediaDataSource dataSource) throws IllegalArgumentException; + private native @Nullable String nativeExtractMetadata(int keyCode); + /** * Call this method after setDataSource(). This method retrieves the * meta data value associated with the keyCode. @@ -236,7 +395,118 @@ public class MediaMetadataRetriever implements AutoCloseable { * @return The meta data value associate with the given keyCode on success; * null on failure. */ - public native @Nullable String extractMetadata(int keyCode); + public @Nullable String extractMetadata(int keyCode) { + String meta = nativeExtractMetadata(keyCode); + if (keyCode == METADATA_KEY_GENRE) { + // translate numeric genre code(s) to human readable + meta = convertGenreTag(meta); + } + return meta; + } + + /* + * The id3v2 spec doesn't specify the syntax of the genre tag very precisely, so + * some assumptions are made. Using one possible interpretation of the id3v2 + * spec, this method converts an id3 genre tag string to a human readable string, + * as follows: + * - if the first character of the tag is a digit, the entire tag is assumed to + * be an id3v1 numeric genre code. If the tag does not parse to a number, or + * the number is outside the range of defined standard genres, it is ignored. + * - if the tag does not start with a digit, it is assumed to be an id3v2 style + * tag consisting of one or more genres, with each genre being either a parenthesized + * integer referring to an id3v1 numeric genre code, the special indicators "(CR)" or + * "(RX)" (for "Cover" or "Remix", respectively), or a custom genre string. When + * a custom genre string is encountered, it is assumed to continue until the end + * of the tag, unless it starts with "((" in which case it is assumed to continue + * until the next close-parenthesis or the end of the tag. Any parse error in the tag + * causes it to be ignored. + * The human-readable genre string is not localized, and uses the English genre names + * from the spec. + */ + private String convertGenreTag(String meta) { + if (TextUtils.isEmpty(meta)) { + return null; + } + + if (Character.isDigit(meta.charAt(0))) { + // assume a single id3v1-style bare number without any extra characters + try { + int genreIndex = Integer.parseInt(meta); + if (genreIndex >= 0 && genreIndex < STANDARD_GENRES.length) { + return STANDARD_GENRES[genreIndex]; + } + } catch (NumberFormatException e) { + // ignore and fall through + } + return null; + } else { + // assume id3v2-style genre tag, with parenthesized numeric genres + // and/or literal genre strings, possibly more than one per tag. + StringBuilder genres = null; + String nextGenre = null; + while (true) { + if (!TextUtils.isEmpty(nextGenre)) { + if (genres == null) { + genres = new StringBuilder(); + } + if (genres.length() != 0) { + genres.append(", "); + } + genres.append(nextGenre); + nextGenre = null; + } + if (TextUtils.isEmpty(meta)) { + // entire tag has been processed. + break; + } + if (meta.startsWith("(RX)")) { + nextGenre = "Remix"; + meta = meta.substring(4); + } else if (meta.startsWith("(CR)")) { + nextGenre = "Cover"; + meta = meta.substring(4); + } else if (meta.startsWith("((")) { + // the id3v2 spec says that custom genres that start with a parenthesis + // should be "escaped" with another parenthesis, however the spec doesn't + // specify escaping parentheses inside the custom string. We'll parse any + // such strings until a closing parenthesis is found, or the end of + // the tag is reached. + int closeParenOffset = meta.indexOf(')'); + if (closeParenOffset == -1) { + // string continues to end of tag + nextGenre = meta.substring(1); + meta = ""; + } else { + nextGenre = meta.substring(1, closeParenOffset + 1); + meta = meta.substring(closeParenOffset + 1); + } + } else if (meta.startsWith("(")) { + // should be a parenthesized numeric genre + int closeParenOffset = meta.indexOf(')'); + if (closeParenOffset == -1) { + return null; + } + String genreNumString = meta.substring(1, closeParenOffset); + try { + int genreIndex = Integer.parseInt(genreNumString.toString()); + if (genreIndex >= 0 && genreIndex < STANDARD_GENRES.length) { + nextGenre = STANDARD_GENRES[genreIndex]; + } else { + return null; + } + } catch (NumberFormatException e) { + return null; + } + meta = meta.substring(closeParenOffset + 1); + } else { + // custom genre + nextGenre = meta; + meta = ""; + } + } + return genres == null || genres.length() == 0 ? null : genres.toString(); + } + } /** * This method is similar to {@link #getFrameAtTime(long, int, BitmapParams)} diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index ab6966d5d1c3..9b37f955fa17 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -1750,22 +1750,150 @@ static void android_media_MediaCodec_queueSecureInputBuffer( return; } - NativeCryptoInfo cryptoInfo{env, cryptoInfoObj}; + jint numSubSamples = + env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID); + + jintArray numBytesOfClearDataObj = + (jintArray)env->GetObjectField( + cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID); + + jintArray numBytesOfEncryptedDataObj = + (jintArray)env->GetObjectField( + cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID); + + jbyteArray keyObj = + (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID); + + jbyteArray ivObj = + (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID); + + jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID); + enum CryptoPlugin::Mode mode; + if (jmode == gCryptoModes.Unencrypted) { + mode = CryptoPlugin::kMode_Unencrypted; + } else if (jmode == gCryptoModes.AesCtr) { + mode = CryptoPlugin::kMode_AES_CTR; + } else if (jmode == gCryptoModes.AesCbc) { + mode = CryptoPlugin::kMode_AES_CBC; + } else { + throwExceptionAsNecessary(env, INVALID_OPERATION); + return; + } + + jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID); + + CryptoPlugin::Pattern pattern; + if (patternObj == NULL) { + pattern.mEncryptBlocks = 0; + pattern.mSkipBlocks = 0; + } else { + pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID); + pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID); + } + + status_t err = OK; + + CryptoPlugin::SubSample *subSamples = NULL; + jbyte *key = NULL; + jbyte *iv = NULL; + + if (numSubSamples <= 0) { + err = -EINVAL; + } else if (numBytesOfClearDataObj == NULL + && numBytesOfEncryptedDataObj == NULL) { + err = -EINVAL; + } else if (numBytesOfEncryptedDataObj != NULL + && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { + err = -ERANGE; + } else if (numBytesOfClearDataObj != NULL + && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { + err = -ERANGE; + // subSamples array may silently overflow if number of samples are too large. Use + // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms + } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) { + err = -EINVAL; + } else { + jboolean isCopy; + + jint *numBytesOfClearData = + (numBytesOfClearDataObj == NULL) + ? NULL + : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); + + jint *numBytesOfEncryptedData = + (numBytesOfEncryptedDataObj == NULL) + ? NULL + : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); + + subSamples = new CryptoPlugin::SubSample[numSubSamples]; + + for (jint i = 0; i < numSubSamples; ++i) { + subSamples[i].mNumBytesOfClearData = + (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; + + subSamples[i].mNumBytesOfEncryptedData = + (numBytesOfEncryptedData == NULL) + ? 0 : numBytesOfEncryptedData[i]; + } + + if (numBytesOfEncryptedData != NULL) { + env->ReleaseIntArrayElements( + numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); + numBytesOfEncryptedData = NULL; + } + + if (numBytesOfClearData != NULL) { + env->ReleaseIntArrayElements( + numBytesOfClearDataObj, numBytesOfClearData, 0); + numBytesOfClearData = NULL; + } + } + + if (err == OK && keyObj != NULL) { + if (env->GetArrayLength(keyObj) != 16) { + err = -EINVAL; + } else { + jboolean isCopy; + key = env->GetByteArrayElements(keyObj, &isCopy); + } + } + + if (err == OK && ivObj != NULL) { + if (env->GetArrayLength(ivObj) != 16) { + err = -EINVAL; + } else { + jboolean isCopy; + iv = env->GetByteArrayElements(ivObj, &isCopy); + } + } + AString errorDetailMsg; - status_t err = cryptoInfo.mErr; if (err == OK) { err = codec->queueSecureInputBuffer( index, offset, - cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples, - (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv, - cryptoInfo.mMode, - cryptoInfo.mPattern, + subSamples, numSubSamples, + (const uint8_t *)key, (const uint8_t *)iv, + mode, + pattern, timestampUs, flags, &errorDetailMsg); } + if (iv != NULL) { + env->ReleaseByteArrayElements(ivObj, iv, 0); + iv = NULL; + } + + if (key != NULL) { + env->ReleaseByteArrayElements(keyObj, key, 0); + key = NULL; + } + + delete[] subSamples; + subSamples = NULL; + throwExceptionAsNecessary( env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); } diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index a5c62cb720cf..1c9b349a7eed 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -728,7 +728,7 @@ static const JNINativeMethod nativeMethods[] = { (void *)android_media_MediaMetadataRetriever_getFrameAtIndex }, - {"extractMetadata", "(I)Ljava/lang/String;", + {"nativeExtractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata}, {"getEmbeddedPicture", "(I)[B", (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture}, diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java index 33126510bc53..d1a379afa25e 100644 --- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java +++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java @@ -205,7 +205,7 @@ public class FusedLocationServiceTest { } @Override - public void onSetEnabled(boolean enabled) { + public void onSetAllowed(boolean allowed) { } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 486386f3d284..107207638205 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -4488,7 +4488,7 @@ public class SettingsProvider extends ContentProvider { try { overlayManager.setEnabledExclusiveInCategory( NAV_BAR_MODE_2BUTTON_OVERLAY, UserHandle.USER_CURRENT); - } catch (RemoteException e) { + } catch (SecurityException | IllegalStateException | RemoteException e) { throw new IllegalStateException( "Failed to set nav bar interaction mode overlay"); } diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index b896a2a8d9a4..fa2e36538dc3 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -574,7 +574,8 @@ public class SettingsBackupTest { Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT, Settings.Global.MODEM_STACK_ENABLED_FOR_SLOT, Settings.Global.POWER_BUTTON_LONG_PRESS, - Settings.Global.POWER_BUTTON_VERY_LONG_PRESS); + Settings.Global.POWER_BUTTON_VERY_LONG_PRESS, + Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER); private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS = newHashSet( diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index e52010600ab3..edcd8012c82c 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -296,6 +296,7 @@ <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item> <item>com.android.systemui.theme.ThemeOverlayController</item> <item>com.android.systemui.accessibility.WindowMagnification</item> + <item>com.android.systemui.accessibility.SystemActions</item> </string-array> <!-- SystemUI vender service, used in config_systemUIServiceComponents. --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 65ca9f2132cd..b40c5c0b0264 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -96,6 +96,9 @@ <!-- Spacing before the airplane mode icon if there are any icons preceding it. --> <dimen name="status_bar_airplane_spacer_width">4dp</dimen> + <!-- Spacing between system icons. --> + <dimen name="status_bar_system_icon_spacing">0dp</dimen> + <!-- The amount to scale each of the status bar icons by. A value of 1 means no scaling. --> <item name="status_bar_icon_scale_factor" format="float" type="dimen">1.0</item> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java index 98b7e2484478..44a8d3c53db7 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java @@ -16,6 +16,7 @@ package com.android.systemui.shared.recents.model; +import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_UNDEFINED; @@ -31,6 +32,7 @@ public class ThumbnailData { public final Bitmap thumbnail; public int orientation; + public int rotation; public Rect insets; public boolean reducedResolution; public boolean isRealSnapshot; @@ -43,6 +45,7 @@ public class ThumbnailData { public ThumbnailData() { thumbnail = null; orientation = ORIENTATION_UNDEFINED; + rotation = ROTATION_UNDEFINED; insets = new Rect(); reducedResolution = false; scale = 1f; @@ -57,6 +60,7 @@ public class ThumbnailData { thumbnail = Bitmap.wrapHardwareBuffer(snapshot.getSnapshot(), snapshot.getColorSpace()); insets = new Rect(snapshot.getContentInsets()); orientation = snapshot.getOrientation(); + rotation = snapshot.getRotation(); reducedResolution = snapshot.isReducedResolution(); scale = snapshot.getScale(); isRealSnapshot = snapshot.isRealSnapshot(); diff --git a/packages/SystemUI/src/com/android/systemui/DumpController.kt b/packages/SystemUI/src/com/android/systemui/DumpController.kt index f14c4cd8e6c6..7a83a8948bb0 100644 --- a/packages/SystemUI/src/com/android/systemui/DumpController.kt +++ b/packages/SystemUI/src/com/android/systemui/DumpController.kt @@ -19,10 +19,10 @@ package com.android.systemui import android.util.ArraySet import android.util.Log import androidx.annotation.GuardedBy -import com.android.internal.util.Preconditions import java.io.FileDescriptor import java.io.PrintWriter import java.lang.ref.WeakReference +import java.util.Objects.requireNonNull import javax.inject.Inject import javax.inject.Singleton @@ -58,7 +58,7 @@ class DumpController @Inject constructor() : Dumpable { * @param dumpable the [Dumpable] to be added */ fun registerDumpable(dumpable: Dumpable) { - Preconditions.checkNotNull(dumpable, "The dumpable to be added cannot be null") + requireNonNull(dumpable, "The dumpable to be added cannot be null") registerDumpable(dumpable.javaClass.simpleName, dumpable) } @@ -71,7 +71,7 @@ class DumpController @Inject constructor() : Dumpable { * @param dumpable the [Dumpable] to be added */ fun registerDumpable(tag: String, dumpable: Dumpable) { - Preconditions.checkNotNull(dumpable, "The dumpable to be added cannot be null") + requireNonNull(dumpable, "The dumpable to be added cannot be null") if (DEBUG) Log.v(TAG, "*** register callback for $dumpable") synchronized<Unit>(listeners) { if (listeners.any { it.tag == tag }) { diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java new file mode 100644 index 000000000000..7262f8caac89 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java @@ -0,0 +1,393 @@ +/* + * 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.systemui.accessibility; + +import android.accessibilityservice.AccessibilityService; +import android.app.PendingIntent; +import android.app.RemoteAction; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.drawable.Icon; +import android.hardware.input.InputManager; +import android.os.Handler; +import android.os.Looper; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.SystemClock; +import android.util.Log; +import android.view.Display; +import android.view.IWindowManager; +import android.view.InputDevice; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.WindowManager; +import android.view.WindowManagerGlobal; +import android.view.accessibility.AccessibilityManager; + +import com.android.internal.R; +import com.android.internal.util.ScreenshotHelper; +import com.android.systemui.Dependency; +import com.android.systemui.SystemUI; +import com.android.systemui.recents.Recents; +import com.android.systemui.statusbar.phone.StatusBar; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Class to register system actions with accessibility framework. + */ +@Singleton +public class SystemActions extends SystemUI { + private static final String TAG = "SystemActions"; + // TODO(b/147916452): add implementation on launcher side to register this action. + + /** + * Action ID to go back. + */ + private static final int SYSTEM_ACTION_ID_BACK = AccessibilityService.GLOBAL_ACTION_BACK; // = 1 + + /** + * Action ID to go home. + */ + private static final int SYSTEM_ACTION_ID_HOME = AccessibilityService.GLOBAL_ACTION_HOME; // = 2 + + /** + * Action ID to toggle showing the overview of recent apps. Will fail on platforms that don't + * show recent apps. + */ + private static final int SYSTEM_ACTION_ID_RECENTS = + AccessibilityService.GLOBAL_ACTION_RECENTS; // = 3 + + /** + * Action ID to open the notifications. + */ + private static final int SYSTEM_ACTION_ID_NOTIFICATIONS = + AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS; // = 4 + + /** + * Action ID to open the quick settings. + */ + private static final int SYSTEM_ACTION_ID_QUICK_SETTINGS = + AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS; // = 5 + + /** + * Action ID to open the power long-press dialog. + */ + private static final int SYSTEM_ACTION_ID_POWER_DIALOG = + AccessibilityService.GLOBAL_ACTION_POWER_DIALOG; // = 6 + + /** + * Action ID to toggle docking the current app's window + */ + private static final int SYSTEM_ACTION_ID_TOGGLE_SPLIT_SCREEN = + AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN; // = 7 + + /** + * Action ID to lock the screen + */ + private static final int SYSTEM_ACTION_ID_LOCK_SCREEN = + AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN; // = 8 + + /** + * Action ID to take a screenshot + */ + private static final int SYSTEM_ACTION_ID_TAKE_SCREENSHOT = + AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT; // = 9 + + /** + * Action ID to show accessibility menu + */ + private static final int SYSTEM_ACTION_ID_ACCESSIBILITY_MENU = 10; + + private Recents mRecents; + private StatusBar mStatusBar; + private SystemActionsBroadcastReceiver mReceiver; + + @Inject + public SystemActions(Context context) { + super(context); + mRecents = Dependency.get(Recents.class); + mStatusBar = Dependency.get(StatusBar.class); + mReceiver = new SystemActionsBroadcastReceiver(); + } + + @Override + public void start() { + mContext.registerReceiverForAllUsers(mReceiver, mReceiver.createIntentFilter(), null, null); + + // TODO(b/148087487): update the icon used below to a valid one + RemoteAction actionBack = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_back_label), + mContext.getString(R.string.accessibility_system_action_back_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_BACK)); + RemoteAction actionHome = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_home_label), + mContext.getString(R.string.accessibility_system_action_home_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_HOME)); + + RemoteAction actionRecents = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_recents_label), + mContext.getString(R.string.accessibility_system_action_recents_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_RECENTS)); + + RemoteAction actionNotifications = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_notifications_label), + mContext.getString(R.string.accessibility_system_action_notifications_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_NOTIFICATIONS)); + + RemoteAction actionQuickSettings = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_quick_settings_label), + mContext.getString(R.string.accessibility_system_action_quick_settings_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_QUICK_SETTINGS)); + + RemoteAction actionPowerDialog = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_power_dialog_label), + mContext.getString(R.string.accessibility_system_action_power_dialog_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_POWER_DIALOG)); + + RemoteAction actionToggleSplitScreen = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_toggle_split_screen_label), + mContext.getString(R.string.accessibility_system_action_toggle_split_screen_label), + mReceiver.createPendingIntent( + mContext, + SystemActionsBroadcastReceiver.INTENT_ACTION_TOGGLE_SPLIT_SCREEN)); + + RemoteAction actionLockScreen = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_lock_screen_label), + mContext.getString(R.string.accessibility_system_action_lock_screen_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_LOCK_SCREEN)); + + RemoteAction actionTakeScreenshot = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_screenshot_label), + mContext.getString(R.string.accessibility_system_action_screenshot_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_TAKE_SCREENSHOT)); + + RemoteAction actionAccessibilityMenu = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_accessibility_menu_label), + mContext.getString(R.string.accessibility_system_action_accessibility_menu_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_MENU)); + + AccessibilityManager am = (AccessibilityManager) mContext.getSystemService( + Context.ACCESSIBILITY_SERVICE); + + am.registerSystemAction(actionBack, SYSTEM_ACTION_ID_BACK); + am.registerSystemAction(actionHome, SYSTEM_ACTION_ID_HOME); + am.registerSystemAction(actionRecents, SYSTEM_ACTION_ID_RECENTS); + am.registerSystemAction(actionNotifications, SYSTEM_ACTION_ID_NOTIFICATIONS); + am.registerSystemAction(actionQuickSettings, SYSTEM_ACTION_ID_QUICK_SETTINGS); + am.registerSystemAction(actionPowerDialog, SYSTEM_ACTION_ID_POWER_DIALOG); + am.registerSystemAction(actionToggleSplitScreen, SYSTEM_ACTION_ID_TOGGLE_SPLIT_SCREEN); + am.registerSystemAction(actionLockScreen, SYSTEM_ACTION_ID_LOCK_SCREEN); + am.registerSystemAction(actionTakeScreenshot, SYSTEM_ACTION_ID_TAKE_SCREENSHOT); + am.registerSystemAction(actionAccessibilityMenu, SYSTEM_ACTION_ID_ACCESSIBILITY_MENU); + } + + private void handleBack() { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK); + } + + private void handleHome() { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME); + } + + private void sendDownAndUpKeyEvents(int keyCode) { + final long downTime = SystemClock.uptimeMillis(); + sendKeyEventIdentityCleared(keyCode, KeyEvent.ACTION_DOWN, downTime, downTime); + sendKeyEventIdentityCleared( + keyCode, KeyEvent.ACTION_UP, downTime, SystemClock.uptimeMillis()); + } + + private void sendKeyEventIdentityCleared(int keyCode, int action, long downTime, long time) { + KeyEvent event = KeyEvent.obtain(downTime, time, action, keyCode, 0, 0, + KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, + InputDevice.SOURCE_KEYBOARD, null); + InputManager.getInstance() + .injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); + event.recycle(); + } + + private void handleRecents() { + mRecents.toggleRecentApps(); + } + + private void handleNotifications() { + mStatusBar.animateExpandNotificationsPanel(); + } + + private void handleQuickSettings() { + mStatusBar.animateExpandSettingsPanel(null); + } + + private void handlePowerDialog() { + IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService(); + + try { + windowManager.showGlobalActions(); + } catch (RemoteException e) { + Log.e(TAG, "failed to display power dialog."); + } + } + + private void handleToggleSplitScreen() { + mStatusBar.toggleSplitScreen(); + } + + private void handleLockScreen() { + IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService(); + + mContext.getSystemService(PowerManager.class).goToSleep(SystemClock.uptimeMillis(), + PowerManager.GO_TO_SLEEP_REASON_ACCESSIBILITY, 0); + try { + windowManager.lockNow(null); + } catch (RemoteException e) { + Log.e(TAG, "failed to lock screen."); + } + } + + private void handleTakeScreenshot() { + ScreenshotHelper screenshotHelper = new ScreenshotHelper(mContext); + screenshotHelper.takeScreenshot(WindowManager.TAKE_SCREENSHOT_FULLSCREEN, + true, true, new Handler(Looper.getMainLooper()), null); + } + + private void handleAccessibilityMenu() { + AccessibilityManager.getInstance(mContext).notifyAccessibilityButtonClicked( + Display.DEFAULT_DISPLAY); + } + + private class SystemActionsBroadcastReceiver extends BroadcastReceiver { + private static final String INTENT_ACTION_BACK = "SYSTEM_ACTION_BACK"; + private static final String INTENT_ACTION_HOME = "SYSTEM_ACTION_HOME"; + private static final String INTENT_ACTION_RECENTS = "SYSTEM_ACTION_RECENTS"; + private static final String INTENT_ACTION_NOTIFICATIONS = "SYSTEM_ACTION_NOTIFICATIONS"; + private static final String INTENT_ACTION_QUICK_SETTINGS = "SYSTEM_ACTION_QUICK_SETTINGS"; + private static final String INTENT_ACTION_POWER_DIALOG = "SYSTEM_ACTION_POWER_DIALOG"; + private static final String INTENT_ACTION_TOGGLE_SPLIT_SCREEN = + "SYSTEM_ACTION_TOGGLE_SPLIT_SCREEN"; + private static final String INTENT_ACTION_LOCK_SCREEN = "SYSTEM_ACTION_LOCK_SCREEN"; + private static final String INTENT_ACTION_TAKE_SCREENSHOT = "SYSTEM_ACTION_TAKE_SCREENSHOT"; + private static final String INTENT_ACTION_ACCESSIBILITY_MENU = + "SYSTEM_ACTION_ACCESSIBILITY_MENU"; + + private PendingIntent createPendingIntent(Context context, String intentAction) { + switch (intentAction) { + case INTENT_ACTION_BACK: + case INTENT_ACTION_HOME: + case INTENT_ACTION_RECENTS: + case INTENT_ACTION_NOTIFICATIONS: + case INTENT_ACTION_QUICK_SETTINGS: + case INTENT_ACTION_POWER_DIALOG: + case INTENT_ACTION_TOGGLE_SPLIT_SCREEN: + case INTENT_ACTION_LOCK_SCREEN: + case INTENT_ACTION_TAKE_SCREENSHOT: + case INTENT_ACTION_ACCESSIBILITY_MENU: { + Intent intent = new Intent(intentAction); + return PendingIntent.getBroadcast(context, 0, intent, 0); + } + default: + break; + } + return null; + } + + private IntentFilter createIntentFilter() { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(INTENT_ACTION_BACK); + intentFilter.addAction(INTENT_ACTION_HOME); + intentFilter.addAction(INTENT_ACTION_RECENTS); + intentFilter.addAction(INTENT_ACTION_NOTIFICATIONS); + intentFilter.addAction(INTENT_ACTION_QUICK_SETTINGS); + intentFilter.addAction(INTENT_ACTION_POWER_DIALOG); + intentFilter.addAction(INTENT_ACTION_TOGGLE_SPLIT_SCREEN); + intentFilter.addAction(INTENT_ACTION_LOCK_SCREEN); + intentFilter.addAction(INTENT_ACTION_TAKE_SCREENSHOT); + intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_MENU); + return intentFilter; + } + + @Override + public void onReceive(Context context, Intent intent) { + String intentAction = intent.getAction(); + switch (intentAction) { + case INTENT_ACTION_BACK: { + handleBack(); + break; + } + case INTENT_ACTION_HOME: { + handleHome(); + break; + } + case INTENT_ACTION_RECENTS: { + handleRecents(); + break; + } + case INTENT_ACTION_NOTIFICATIONS: { + handleNotifications(); + break; + } + case INTENT_ACTION_QUICK_SETTINGS: { + handleQuickSettings(); + break; + } + case INTENT_ACTION_POWER_DIALOG: { + handlePowerDialog(); + break; + } + case INTENT_ACTION_TOGGLE_SPLIT_SCREEN: { + handleToggleSplitScreen(); + break; + } + case INTENT_ACTION_LOCK_SCREEN: { + handleLockScreen(); + break; + } + case INTENT_ACTION_TAKE_SCREENSHOT: { + handleTakeScreenshot(); + break; + } + case INTENT_ACTION_ACCESSIBILITY_MENU: { + handleAccessibilityMenu(); + break; + } + default: + break; + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java index 99dd5e2356d6..d4e47f699345 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java @@ -21,6 +21,7 @@ import com.android.systemui.ScreenDecorations; import com.android.systemui.SizeCompatModeActivityController; import com.android.systemui.SliceBroadcastRelayHandler; import com.android.systemui.SystemUI; +import com.android.systemui.accessibility.SystemActions; import com.android.systemui.accessibility.WindowMagnification; import com.android.systemui.biometrics.AuthController; import com.android.systemui.globalactions.GlobalActionsComponent; @@ -140,6 +141,12 @@ public abstract class SystemUIBinder { @ClassKey(StatusBar.class) public abstract SystemUI bindsStatusBar(StatusBar sysui); + /** Inject into SystemActions. */ + @Binds + @IntoMap + @ClassKey(SystemActions.class) + public abstract SystemUI bindSystemActions(SystemActions sysui); + /** Inject into ThemeOverlayController. */ @Binds @IntoMap diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java index d6336ed3e18a..826af669cb39 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java @@ -387,7 +387,7 @@ public class NavigationModeController implements Dumpable { Log.d(TAG, "setModeOverlay: overlayPackage=" + overlayPkg + " userId=" + userId); } - } catch (RemoteException e) { + } catch (SecurityException | IllegalStateException | RemoteException e) { Log.e(TAG, "Failed to enable overlay " + overlayPkg + " for user " + userId); } }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java index d06164963f7b..5a7c5c9b5ebc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java @@ -56,6 +56,7 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { private static final int MAX_DOTS = 1; private int mDotPadding; + private int mIconSpacing; private int mStaticDotDiameter; private int mUnderflowWidth; private int mUnderflowStart = 0; @@ -99,6 +100,7 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { mIconDotFrameWidth = getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_icon_size); mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding); + mIconSpacing = getResources().getDimensionPixelSize(R.dimen.status_bar_system_icon_spacing); int radius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius); mStaticDotDiameter = 2 * radius; mUnderflowWidth = mIconDotFrameWidth + (MAX_DOTS - 1) * (mStaticDotDiameter + mDotPadding); @@ -163,20 +165,21 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { // Measure all children so that they report the correct width int childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.UNSPECIFIED); mNeedsUnderflow = mShouldRestrictIcons && visibleCount > MAX_ICONS; - for (int i = 0; i < mMeasureViews.size(); i++) { + for (int i = 0; i < visibleCount; i++) { // Walking backwards View child = mMeasureViews.get(visibleCount - i - 1); measureChild(child, childWidthSpec, heightMeasureSpec); + int spacing = i == visibleCount - 1 ? 0 : mIconSpacing; if (mShouldRestrictIcons) { if (i < maxVisible && trackWidth) { - totalWidth += getViewTotalMeasuredWidth(child); + totalWidth += getViewTotalMeasuredWidth(child) + spacing; } else if (trackWidth) { // We've hit the icon limit; add space for dots totalWidth += mUnderflowWidth; trackWidth = false; } } else { - totalWidth += getViewTotalMeasuredWidth(child); + totalWidth += getViewTotalMeasuredWidth(child) + spacing; } } @@ -284,11 +287,15 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { continue; } + // Move translationX to the spot within StatusIconContainer's layout to add the view + // without cutting off the child view. + translationX -= getViewTotalWidth(child); childState.visibleState = STATE_ICON; - childState.xTranslation = translationX - getViewTotalWidth(child); + childState.xTranslation = translationX; mLayoutStates.add(0, childState); - translationX -= getViewTotalWidth(child); + // Shift translationX over by mIconSpacing for the next view. + translationX -= mIconSpacing; } // Show either 1-MAX_ICONS icons, or (MAX_ICONS - 1) icons + overflow @@ -306,7 +313,8 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { firstUnderflowIndex = i; break; } - mUnderflowStart = (int) Math.max(contentStart, state.xTranslation - mUnderflowWidth); + mUnderflowStart = (int) Math.max( + contentStart, state.xTranslation - mUnderflowWidth - mIconSpacing); visible++; } diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java index 41e026af7c72..665cb6307b6a 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java @@ -178,7 +178,7 @@ class ThemeOverlayManager { } else { mOverlayManager.setEnabled(pkg, false, userHandle); } - } catch (IllegalStateException e) { + } catch (SecurityException | IllegalStateException e) { Log.e(TAG, String.format("setEnabled failed: %s %s %b", pkg, userHandle, enabled), e); } diff --git a/proto/src/task_snapshot.proto b/proto/src/task_snapshot.proto index 821db860dd96..789019ce8b75 100644 --- a/proto/src/task_snapshot.proto +++ b/proto/src/task_snapshot.proto @@ -34,4 +34,5 @@ string top_activity_component = 10; float scale = 11; int64 id = 12; + int32 rotation = 13; } diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 26245b15f92b..28298cb51f6e 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -634,8 +634,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku final SuspendDialogInfo dialogInfo = mPackageManagerInternal.getSuspendedDialogInfo(providerPackage, suspendingPackage, providerUserId); + // TODO(b/148035643): Send the original widget intent or ACTION_MAIN as an + // IntentSender to SuspendedAppActivity. onClickIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent( - providerPackage, suspendingPackage, dialogInfo, null, providerUserId); + providerPackage, suspendingPackage, dialogInfo, null, null, + providerUserId); } } else if (provider.maskedByQuietProfile) { showBadge = true; diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java index f3647602e69b..a8be66990fff 100644 --- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -16,10 +16,14 @@ package android.app.usage; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.usage.UsageStatsManager.StandbyBuckets; import android.content.ComponentName; +import android.content.LocusId; import android.content.res.Configuration; +import android.os.IBinder; import android.os.UserHandle; import android.os.UserManager; @@ -111,6 +115,20 @@ public abstract class UsageStatsManagerInternal { public abstract void reportContentProviderUsage(String name, String pkgName, @UserIdInt int userId); + + /** + * Reports locusId update for a given activity. + * + * @param activity The component name of the app. + * @param userId The user id of who uses the app. + * @param locusId The locusId a unique, stable id that identifies this activity. + * @param appToken ActivityRecord's appToken. + * {@link UsageEvents} + * @hide + */ + public abstract void reportLocusUpdate(@NonNull ComponentName activity, @UserIdInt int userId, + @Nullable LocusId locusId, @NonNull IBinder appToken); + /** * Prepares the UsageStatsService for shutdown. */ diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 994c3147d70c..27b6bfb8f5fd 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -252,11 +252,23 @@ public abstract class PackageManagerInternal { String packageName, int userId); /** + * Do a straight uid lookup for the given package/application in the given user. This enforces + * app visibility rules and permissions. Call {@link #getPackageUidInternal} for the internal + * implementation. + * @deprecated Use {@link PackageManager#getPackageUid(String, int)} + * @return The app's uid, or < 0 if the package was not found in that user + */ + @Deprecated + public abstract int getPackageUid(String packageName, + @PackageInfoFlags int flags, int userId); + + /** * Do a straight uid lookup for the given package/application in the given user. * @see PackageManager#getPackageUidAsUser(String, int, int) * @return The app's uid, or < 0 if the package was not found in that user + * TODO(b/148235092): rename this to getPackageUid */ - public abstract int getPackageUid(String packageName, + public abstract int getPackageUidInternal(String packageName, @PackageInfoFlags int flags, int userId); /** diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 882b417dd679..dd33566322e2 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -64,6 +64,7 @@ import android.net.CaptivePortal; import android.net.ConnectionInfo; import android.net.ConnectivityManager; import android.net.ICaptivePortal; +import android.net.IConnectivityDiagnosticsCallback; import android.net.IConnectivityManager; import android.net.IDnsResolver; import android.net.IIpConnectivityMetrics; @@ -1623,7 +1624,8 @@ public class ConnectivityService extends IConnectivityManager.Stub return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network)); } - private NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions( + @VisibleForTesting + NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions( NetworkCapabilities nc, int callerPid, int callerUid) { final NetworkCapabilities newNc = new NetworkCapabilities(nc); if (!checkSettingsPermission(callerPid, callerUid)) { @@ -1634,9 +1636,23 @@ public class ConnectivityService extends IConnectivityManager.Stub newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact()); } newNc.setAdministratorUids(Collections.EMPTY_LIST); + + maybeSanitizeLocationInfoForCaller(newNc, callerUid); + return newNc; } + private void maybeSanitizeLocationInfoForCaller( + NetworkCapabilities nc, int callerUid) { + // TODO(b/142072839): Conditionally reset the owner UID if the following + // conditions are not met: + // 1. The destination app is the network owner + // 2. The destination app has the ACCESS_COARSE_LOCATION permission granted + // if target SDK<29 or otherwise has the ACCESS_FINE_LOCATION permission granted + // 3. The user's location toggle is on + nc.setOwnerUid(INVALID_UID); + } + private LinkProperties linkPropertiesRestrictedForCallerPermissions( LinkProperties lp, int callerPid, int callerUid) { if (lp == null) return new LinkProperties(); @@ -1665,6 +1681,9 @@ public class ConnectivityService extends IConnectivityManager.Stub nc.setSingleUid(Binder.getCallingUid()); } nc.setAdministratorUids(Collections.EMPTY_LIST); + + // Clear owner UID; this can never come from an app. + nc.setOwnerUid(INVALID_UID); } private void restrictBackgroundRequestForCaller(NetworkCapabilities nc) { @@ -5801,7 +5820,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } final Set<UidRange> ranges = nai.networkCapabilities.getUids(); - final int vpnAppUid = nai.networkCapabilities.getEstablishingVpnAppUid(); + final int vpnAppUid = nai.networkCapabilities.getOwnerUid(); // TODO: this create a window of opportunity for apps to receive traffic between the time // when the old rules are removed and the time when new rules are added. To fix this, // make eBPF support two whitelisted interfaces so here new rules can be added before the @@ -6000,7 +6019,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (nc == null || lp == null) return false; return nai.isVPN() && !nai.networkAgentConfig.allowBypass - && nc.getEstablishingVpnAppUid() != Process.SYSTEM_UID + && nc.getOwnerUid() != Process.SYSTEM_UID && lp.getInterfaceName() != null && (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute()); } @@ -6048,12 +6067,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO Fix this window by computing an accurate diff on Set<UidRange>, so the old range // to be removed will never overlap with the new range to be added. if (wasFiltering && !prevRanges.isEmpty()) { - mPermissionMonitor.onVpnUidRangesRemoved(iface, prevRanges, - prevNc.getEstablishingVpnAppUid()); + mPermissionMonitor.onVpnUidRangesRemoved(iface, prevRanges, prevNc.getOwnerUid()); } if (shouldFilter && !newRanges.isEmpty()) { - mPermissionMonitor.onVpnUidRangesAdded(iface, newRanges, - newNc.getEstablishingVpnAppUid()); + mPermissionMonitor.onVpnUidRangesAdded(iface, newRanges, newNc.getOwnerUid()); } } catch (Exception e) { // Never crash! @@ -7314,4 +7331,20 @@ public class ConnectivityService extends IConnectivityManager.Stub return mTNS; } } + + @Override + public void registerConnectivityDiagnosticsCallback( + @NonNull IConnectivityDiagnosticsCallback callback, @NonNull NetworkRequest request) { + // TODO(b/146444622): implement register IConnectivityDiagnosticsCallback functionality + throw new UnsupportedOperationException( + "registerConnectivityDiagnosticsCallback not yet implemented"); + } + + @Override + public void unregisterConnectivityDiagnosticsCallback( + @NonNull IConnectivityDiagnosticsCallback callback) { + // TODO(b/146444622): implement register IConnectivityDiagnosticsCallback functionality + throw new UnsupportedOperationException( + "unregisterConnectivityDiagnosticsCallback not yet implemented"); + } } diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index de0b6fcbd4ae..3b6ff26d5f03 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -52,6 +52,7 @@ import android.location.ILocationListener; import android.location.ILocationManager; import android.location.Location; import android.location.LocationManager; +import android.location.LocationManagerInternal; import android.location.LocationRequest; import android.location.LocationTime; import android.os.Binder; @@ -133,11 +134,12 @@ public class LocationManagerService extends ILocationManager.Stub { */ public static class Lifecycle extends SystemService { - private LocationManagerService mService; + private final LocationManagerService mService; public Lifecycle(Context context) { super(context); mService = new LocationManagerService(context); + LocalServices.addService(LocationManagerInternal.class, mService.new LocalService()); } @Override @@ -465,7 +467,7 @@ public class LocationManagerService extends ILocationManager.Stub { mContext.sendBroadcastAsUser(intent, UserHandle.of(userId)); for (LocationProviderManager manager : mProviderManagers) { - manager.onUseableChangedLocked(userId); + manager.onEnabledChangedLocked(userId); } } @@ -633,10 +635,10 @@ public class LocationManagerService extends ILocationManager.Stub { for (LocationProviderManager manager : mProviderManagers) { // update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility mSettingsStore.setLocationProviderAllowed(manager.getName(), - manager.isUseable(newUserId), newUserId); + manager.isEnabled(newUserId), newUserId); - manager.onUseableChangedLocked(oldUserId); - manager.onUseableChangedLocked(newUserId); + manager.onEnabledChangedLocked(oldUserId); + manager.onEnabledChangedLocked(newUserId); } } @@ -650,22 +652,22 @@ public class LocationManagerService extends ILocationManager.Stub { // acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary protected final MockableLocationProvider mProvider; - // useable state for parent user ids, no entry implies false. location state is only kept + // enabled state for parent user ids, no entry implies false. location state is only kept // for parent user ids, the location state for a profile user id is assumed to be the same // as for the parent. if querying this structure, ensure that the user id being used is a // parent id or the results may be incorrect. @GuardedBy("mLock") - private final SparseArray<Boolean> mUseable; + private final SparseArray<Boolean> mEnabled; private LocationProviderManager(String name) { mName = name; - mUseable = new SparseArray<>(1); + mEnabled = new SparseArray<>(1); // initialize last since this lets our reference escape mProvider = new MockableLocationProvider(mContext, mLock, this); - // we can assume all users start with unuseable location state since the initial state - // of all providers is disabled. no need to initialize mUseable further. + // we can assume all users start with disabled location state since the initial state + // of all providers is disabled. no need to initialize mEnabled further. } public String getName() { @@ -693,13 +695,13 @@ public class LocationManagerService extends ILocationManager.Stub { return mProvider.getState().properties; } - public void setMockProviderEnabled(boolean enabled) { + public void setMockProviderAllowed(boolean enabled) { synchronized (mLock) { if (!mProvider.isMock()) { throw new IllegalArgumentException(mName + " provider is not a test provider"); } - mProvider.setMockProviderEnabled(enabled); + mProvider.setMockProviderAllowed(enabled); } } @@ -760,7 +762,7 @@ public class LocationManagerService extends ILocationManager.Stub { return; } - if (!GPS_PROVIDER.equals(mName) || !isUseable()) { + if (!GPS_PROVIDER.equals(mName) || !isEnabled()) { Slog.w(TAG, "reportLocationBatch() called without user permission"); return; } @@ -771,30 +773,33 @@ public class LocationManagerService extends ILocationManager.Stub { @GuardedBy("mLock") @Override public void onStateChanged(State oldState, State newState) { - if (oldState.enabled != newState.enabled) { + if (oldState.allowed != newState.allowed) { // it would be more correct to call this for all users, but we know this can // only affect the current user since providers are disabled for non-current // users - onUseableChangedLocked(mUserInfoStore.getCurrentUserId()); + onEnabledChangedLocked(mUserInfoStore.getCurrentUserId()); } } - public boolean isUseable() { - return isUseable(mUserInfoStore.getCurrentUserId()); + public void requestSetAllowed(boolean allowed) { + mProvider.requestSetAllowed(allowed); } - public boolean isUseable(int userId) { + public boolean isEnabled() { + return isEnabled(mUserInfoStore.getCurrentUserId()); + } + + public boolean isEnabled(int userId) { synchronized (mLock) { // normalize user id to always refer to parent since profile state is always the // same as parent state userId = mUserInfoStore.getParentUserId(userId); - - return mUseable.get(userId, Boolean.FALSE); + return mEnabled.get(userId, Boolean.FALSE); } } @GuardedBy("mLock") - public void onUseableChangedLocked(int userId) { + public void onEnabledChangedLocked(int userId) { if (userId == UserHandle.USER_NULL) { // only used during initialization - we don't care about the null user return; @@ -804,36 +809,36 @@ public class LocationManagerService extends ILocationManager.Stub { // as parent state userId = mUserInfoStore.getParentUserId(userId); - // if any property that contributes to "useability" here changes state, it MUST result - // in a direct or indrect call to onUseableChangedLocked. this allows the provider to + // if any property that contributes to "enabled" here changes state, it MUST result + // in a direct or indrect call to onEnabledChangedLocked. this allows the provider to // guarantee that it will always eventually reach the correct state. - boolean useable = (userId == mUserInfoStore.getCurrentUserId()) - && mSettingsStore.isLocationEnabled(userId) && mProvider.getState().enabled; + boolean enabled = (userId == mUserInfoStore.getCurrentUserId()) + && mSettingsStore.isLocationEnabled(userId) && mProvider.getState().allowed; - if (useable == isUseable(userId)) { + if (enabled == isEnabled(userId)) { return; } - mUseable.put(userId, useable); + mEnabled.put(userId, enabled); if (D) { - Log.d(TAG, "[u" + userId + "] " + mName + " provider useable = " + useable); + Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled); } // fused and passive provider never get public updates for legacy reasons if (!FUSED_PROVIDER.equals(mName) && !PASSIVE_PROVIDER.equals(mName)) { // update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility - mSettingsStore.setLocationProviderAllowed(mName, useable, userId); + mSettingsStore.setLocationProviderAllowed(mName, enabled, userId); Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION) .putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName) - .putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, useable) + .putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, enabled) .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY) .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendBroadcastAsUser(intent, UserHandle.of(userId)); } - if (!useable) { + if (!enabled) { // If any provider has been disabled, clear all last locations for all // providers. This is to be on the safe side in case a provider has location // derived from this disabled provider. @@ -841,7 +846,7 @@ public class LocationManagerService extends ILocationManager.Stub { mLastLocationCoarseInterval.clear(); } - updateProviderUseableLocked(this); + updateProviderEnabledLocked(this); } public void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { @@ -854,10 +859,10 @@ public class LocationManagerService extends ILocationManager.Stub { pw.increaseIndent(); - boolean useable = isUseable(); - pw.println("useable=" + useable); - if (!useable) { - pw.println("enabled=" + mProvider.getState().enabled); + boolean enabled = isEnabled(); + pw.println("enabled=" + enabled); + if (!enabled) { + pw.println("allowed=" + mProvider.getState().allowed); } pw.println("properties=" + mProvider.getState().properties); @@ -1009,7 +1014,7 @@ public class LocationManagerService extends ILocationManager.Stub { if (manager == null) { continue; } - if (!manager.isUseable() && !isSettingsExemptLocked(updateRecord)) { + if (!manager.isEnabled() && !isSettingsExemptLocked(updateRecord)) { continue; } @@ -1425,7 +1430,7 @@ public class LocationManagerService extends ILocationManager.Stub { if (FUSED_PROVIDER.equals(name)) { continue; } - if (enabledOnly && !manager.isUseable()) { + if (enabledOnly && !manager.isEnabled()) { continue; } if (criteria != null @@ -1467,8 +1472,8 @@ public class LocationManagerService extends ILocationManager.Stub { } @GuardedBy("mLock") - private void updateProviderUseableLocked(LocationProviderManager manager) { - boolean useable = manager.isUseable(); + private void updateProviderEnabledLocked(LocationProviderManager manager) { + boolean enabled = manager.isEnabled(); ArrayList<Receiver> deadReceivers = null; @@ -1486,7 +1491,7 @@ public class LocationManagerService extends ILocationManager.Stub { } // Sends a notification message to the receiver - if (!record.mReceiver.callProviderEnabledLocked(manager.getName(), useable)) { + if (!record.mReceiver.callProviderEnabledLocked(manager.getName(), enabled)) { if (deadReceivers == null) { deadReceivers = new ArrayList<>(); } @@ -1553,7 +1558,7 @@ public class LocationManagerService extends ILocationManager.Stub { } final boolean isBatterySaverDisablingLocation = shouldThrottleRequests || (isForegroundOnlyMode && !record.mIsForegroundUid); - if (!manager.isUseable() || isBatterySaverDisablingLocation) { + if (!manager.isEnabled() || isBatterySaverDisablingLocation) { if (isSettingsExemptLocked(record)) { providerRequest.setLocationSettingsIgnored(true); providerRequest.setLowPowerMode(false); @@ -1970,7 +1975,7 @@ public class LocationManagerService extends ILocationManager.Stub { oldRecord.disposeLocked(false); } - if (!manager.isUseable() && !isSettingsExemptLocked(record)) { + if (!manager.isEnabled() && !isSettingsExemptLocked(record)) { // Notify the listener that updates are currently disabled - but only if the request // does not ignore location settings receiver.callProviderEnabledLocked(name, false); @@ -2082,7 +2087,7 @@ public class LocationManagerService extends ILocationManager.Stub { return null; } - if (!manager.isUseable()) { + if (!manager.isEnabled()) { return null; } @@ -2204,7 +2209,7 @@ public class LocationManagerService extends ILocationManager.Stub { synchronized (mLock) { LocationProviderManager manager = getLocationProviderManager(location.getProvider()); - if (manager == null || !manager.isUseable()) { + if (manager == null || !manager.isEnabled()) { return false; } @@ -2491,7 +2496,7 @@ public class LocationManagerService extends ILocationManager.Stub { synchronized (mLock) { LocationProviderManager manager = getLocationProviderManager(providerName); - return manager != null && manager.isUseable(userId); + return manager != null && manager.isEnabled(userId); } } @@ -2549,8 +2554,8 @@ public class LocationManagerService extends ILocationManager.Stub { long now = SystemClock.elapsedRealtime(); - // only update last location for locations that come from useable providers - if (manager.isUseable()) { + // only update last location for locations that come from enabled providers + if (manager.isEnabled()) { updateLastLocationLocked(location, manager.getName()); } @@ -2560,7 +2565,7 @@ public class LocationManagerService extends ILocationManager.Stub { if (lastLocationCoarseInterval == null) { lastLocationCoarseInterval = new Location(location); - if (manager.isUseable()) { + if (manager.isEnabled()) { mLastLocationCoarseInterval.put(manager.getName(), lastLocationCoarseInterval); } } @@ -2593,7 +2598,7 @@ public class LocationManagerService extends ILocationManager.Stub { Receiver receiver = r.mReceiver; boolean receiverDead = false; - if (!manager.isUseable() && !isSettingsExemptLocked(r)) { + if (!manager.isEnabled() && !isSettingsExemptLocked(r)) { continue; } @@ -2812,7 +2817,7 @@ public class LocationManagerService extends ILocationManager.Stub { throw new IllegalArgumentException("provider doesn't exist: " + provider); } - manager.setMockProviderEnabled(enabled); + manager.setMockProviderAllowed(enabled); } @Override @@ -2946,4 +2951,19 @@ public class LocationManagerService extends ILocationManager.Stub { } } } + + private class LocalService extends LocationManagerInternal { + + @Override + public void requestSetProviderAllowed(String provider, boolean allowed) { + Preconditions.checkArgument(provider != null, "invalid null provider"); + + synchronized (mLock) { + LocationProviderManager manager = getLocationProviderManager(provider); + if (manager != null) { + manager.requestSetAllowed(allowed); + } + } + } + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5596b2fcb762..41a4bd433be5 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -199,6 +199,7 @@ import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentFilter; +import android.content.LocusId; import android.content.pm.ActivityInfo; import android.content.pm.ActivityPresentationInfo; import android.content.pm.ApplicationInfo; @@ -19642,4 +19643,19 @@ public class ActivityManagerService extends IActivityManager.Stub } } } + + @Override + public void setActivityLocusContext(ComponentName activity, LocusId locusId, IBinder appToken) { + final int callingUid = Binder.getCallingUid(); + final int userId = UserHandle.getCallingUserId(); + if (getPackageManagerInternalLocked().getPackageUid(activity.getPackageName(), + /*flags=*/ 0, userId) != callingUid) { + throw new SecurityException("Calling uid " + callingUid + " cannot set locusId" + + "for package " + activity.getPackageName()); + } + + if (mUsageStatsService != null) { + mUsageStatsService.reportLocusUpdate(activity, userId, locusId, appToken); + } + } } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 0c9abae2e0fc..423e0212dfd6 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -954,7 +954,7 @@ public class Vpn { NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig(); networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown; - mNetworkCapabilities.setEstablishingVpnAppUid(Binder.getCallingUid()); + mNetworkCapabilities.setOwnerUid(Binder.getCallingUid()); mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserHandle, mConfig.allowedApplications, mConfig.disallowedApplications)); long token = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java index 442211f451ee..214dcc0220ff 100644 --- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java @@ -17,16 +17,15 @@ package com.android.server.integrity; import static android.content.Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION; +import static android.content.Intent.EXTRA_LONG_VERSION_CODE; import static android.content.Intent.EXTRA_ORIGINATING_UID; import static android.content.Intent.EXTRA_PACKAGE_NAME; -import static android.content.Intent.EXTRA_VERSION_CODE; import static android.content.integrity.AppIntegrityManager.EXTRA_STATUS; import static android.content.integrity.AppIntegrityManager.STATUS_FAILURE; import static android.content.integrity.AppIntegrityManager.STATUS_SUCCESS; +import static android.content.integrity.IntegrityUtils.getHexDigest; import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID; -import static com.android.server.integrity.IntegrityUtils.getHexDigest; - import android.annotation.NonNull; import android.annotation.Nullable; import android.content.BroadcastReceiver; @@ -75,18 +74,29 @@ import java.util.Map; /** Implementation of {@link AppIntegrityManagerService}. */ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { + /** + * This string will be used as the "installer" for formula evaluation when the app's installer + * cannot be determined. + * + * <p>This may happen for various reasons. e.g., the installing app's package name may not match + * its UID. + */ + private static final String UNKNOWN_INSTALLER = ""; + /** + * This string will be used as the "installer" for formula evaluation when the app is being + * installed via ADB. + */ + private static final String ADB_INSTALLER = "adb"; + private static final String TAG = "AppIntegrityManagerServiceImpl"; private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; - private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray(); private static final String PACKAGE_INSTALLER = "com.google.android.packageinstaller"; private static final String BASE_APK_FILE = "base.apk"; private static final String ALLOWED_INSTALLERS_METADATA_NAME = "allowed-installers"; private static final String ALLOWED_INSTALLER_DELIMITER = ","; private static final String INSTALLER_PACKAGE_CERT_DELIMITER = "\\|"; - private static final String ADB_INSTALLER = "adb"; - private static final String UNKNOWN_INSTALLER = ""; private static final String INSTALLER_CERT_NOT_APPLICABLE = ""; // Access to files inside mRulesDir is protected by mRulesLock; @@ -241,7 +251,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { builder.setPackageName(getPackageNameNormalized(packageName)); builder.setAppCertificate(appCert == null ? "" : appCert); - builder.setVersionCode(intent.getIntExtra(EXTRA_VERSION_CODE, -1)); + builder.setVersionCode(intent.getLongExtra(EXTRA_LONG_VERSION_CODE, -1)); builder.setInstallerName(getPackageNameNormalized(installerPackageName)); builder.setInstallerCertificate( getInstallerCertificateFingerprint(installerPackageName)); @@ -262,14 +272,11 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { + " due to " + result.getRule()); - // TODO(b/147095027): Remove when the proto type is fixed. - int dummyBreakageFixerInt = 0; - StatsLog.write( StatsLog.INTEGRITY_CHECK_RESULT_REPORTED, packageName, appCert, - dummyBreakageFixerInt, + appInstallMetadata.getVersionCode(), installerPackageName, getLoggingResponse(result), isCausedByAppCertRule(result), diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java index 07eacbfd87dd..1a6b3d8b8411 100644 --- a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java +++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java @@ -19,7 +19,7 @@ package com.android.server.integrity.engine; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import android.util.Slog; @@ -65,7 +65,7 @@ public class RuleEvaluationEngine { * Load, and match the list of rules against an app install metadata. * * @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules - * against. + * against. * @return result of the integrity check */ public IntegrityCheckResult evaluate( @@ -89,14 +89,14 @@ public class RuleEvaluationEngine { return Optional.empty(); } - List<Formula> formulas = new ArrayList<>(allowedInstallers.size()); + List<IntegrityFormula> formulas = new ArrayList<>(allowedInstallers.size()); allowedInstallers.forEach( (installer, cert) -> { formulas.add(allowedInstallerFormula(installer, cert)); }); // We need this special case since OR-formulas require at least two operands. - Formula allInstallersFormula = + IntegrityFormula allInstallersFormula = formulas.size() == 1 ? formulas.get(0) : new CompoundFormula(CompoundFormula.OR, formulas); @@ -108,7 +108,7 @@ public class RuleEvaluationEngine { Rule.DENY)); } - private static Formula allowedInstallerFormula(String installer, String cert) { + private static IntegrityFormula allowedInstallerFormula(String installer, String cert) { return new CompoundFormula( CompoundFormula.AND, Arrays.asList( @@ -117,8 +117,7 @@ public class RuleEvaluationEngine { installer, /* isHashedValue= */ false), new AtomicFormula.StringAtomicFormula( - AtomicFormula.INSTALLER_CERTIFICATE, - cert, - /* isHashedValue= */ false))); + AtomicFormula.INSTALLER_CERTIFICATE, cert, /* isHashedValue= */ + false))); } } diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java index b1c20d27c792..66537ff6105e 100644 --- a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java +++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java @@ -22,7 +22,6 @@ import static android.content.integrity.Rule.FORCE_ALLOW; import android.annotation.NonNull; import android.content.integrity.AppInstallMetadata; import android.content.integrity.Rule; -import android.util.Slog; import com.android.server.integrity.model.IntegrityCheckResult; @@ -35,8 +34,6 @@ import java.util.List; */ final class RuleEvaluator { - private static final String TAG = "RuleEvaluator"; - /** * Match the list of rules against an app install metadata. * @@ -53,7 +50,7 @@ final class RuleEvaluator { List<Rule> rules, AppInstallMetadata appInstallMetadata) { List<Rule> matchedRules = new ArrayList<>(); for (Rule rule : rules) { - if (rule.getFormula().isSatisfied(appInstallMetadata)) { + if (rule.getFormula().matches(appInstallMetadata)) { matchedRules.add(rule); } } @@ -71,8 +68,7 @@ final class RuleEvaluator { case FORCE_ALLOW: return IntegrityCheckResult.allow(rule); default: - Slog.e(TAG, "Matched an unknown effect rule: " + rule); - return IntegrityCheckResult.allow(); + throw new IllegalArgumentException("Matched an unknown effect rule: " + rule); } } return denied ? IntegrityCheckResult.deny(denyRule) : IntegrityCheckResult.allow(); diff --git a/services/core/java/com/android/server/integrity/model/BitOutputStream.java b/services/core/java/com/android/server/integrity/model/BitOutputStream.java index 7d1bb3fb8203..14b35fd016eb 100644 --- a/services/core/java/com/android/server/integrity/model/BitOutputStream.java +++ b/services/core/java/com/android/server/integrity/model/BitOutputStream.java @@ -61,7 +61,7 @@ public class BitOutputStream { /** * Set the next bit in the stream to value. * - * @param value The value to set the bit to. + * @param value The value to set the bit to */ public void setNext(boolean value) throws IOException { int byteToWrite = mNextBitIndex / BYTE_BITS; diff --git a/services/core/java/com/android/server/integrity/parser/BinaryFileOperations.java b/services/core/java/com/android/server/integrity/parser/BinaryFileOperations.java index 2c5b7d3c122c..f09e035ecc78 100644 --- a/services/core/java/com/android/server/integrity/parser/BinaryFileOperations.java +++ b/services/core/java/com/android/server/integrity/parser/BinaryFileOperations.java @@ -19,7 +19,8 @@ package com.android.server.integrity.parser; import static com.android.server.integrity.model.ComponentBitSize.IS_HASHED_BITS; import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS; -import com.android.server.integrity.IntegrityUtils; +import android.content.integrity.IntegrityUtils; + import com.android.server.integrity.model.BitInputStream; import java.io.IOException; diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java index 90954ff21d57..4b8efafcb6b0 100644 --- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java +++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java @@ -35,7 +35,7 @@ import static com.android.server.integrity.parser.BinaryFileOperations.getString import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import com.android.server.integrity.model.BitInputStream; @@ -121,7 +121,7 @@ public class RuleBinaryParser implements RuleParser { } private Rule parseRule(BitInputStream bitInputStream) throws IOException { - Formula formula = parseFormula(bitInputStream); + IntegrityFormula formula = parseFormula(bitInputStream); int effect = bitInputStream.getNext(EFFECT_BITS); if (bitInputStream.getNext(SIGNAL_BIT) != 1) { @@ -131,7 +131,7 @@ public class RuleBinaryParser implements RuleParser { return new Rule(formula, effect); } - private Formula parseFormula(BitInputStream bitInputStream) throws IOException { + private IntegrityFormula parseFormula(BitInputStream bitInputStream) throws IOException { int separator = bitInputStream.getNext(SEPARATOR_BITS); switch (separator) { case ATOMIC_FORMULA_START: @@ -148,9 +148,9 @@ public class RuleBinaryParser implements RuleParser { private CompoundFormula parseCompoundFormula(BitInputStream bitInputStream) throws IOException { int connector = bitInputStream.getNext(CONNECTOR_BITS); - List<Formula> formulas = new ArrayList<>(); + List<IntegrityFormula> formulas = new ArrayList<>(); - Formula parsedFormula = parseFormula(bitInputStream); + IntegrityFormula parsedFormula = parseFormula(bitInputStream); while (parsedFormula != null) { formulas.add(parsedFormula); parsedFormula = parseFormula(bitInputStream); @@ -173,8 +173,11 @@ public class RuleBinaryParser implements RuleParser { String stringValue = getStringValue(bitInputStream, valueSize, isHashedValue); return new AtomicFormula.StringAtomicFormula(key, stringValue, isHashedValue); case AtomicFormula.VERSION_CODE: - int intValue = getIntValue(bitInputStream); - return new AtomicFormula.IntAtomicFormula(key, operator, intValue); + // TODO(b/147880712): temporary hack until our input handles long + long upper = getIntValue(bitInputStream); + long lower = getIntValue(bitInputStream); + long longValue = (upper << 32) | lower; + return new AtomicFormula.LongAtomicFormula(key, operator, longValue); case AtomicFormula.PRE_INSTALLED: boolean booleanValue = getBooleanValue(bitInputStream); return new AtomicFormula.BooleanAtomicFormula(key, booleanValue); diff --git a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java index 53b0c2e59453..f37ca1efce13 100644 --- a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java +++ b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java @@ -18,7 +18,7 @@ package com.android.server.integrity.parser; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import android.util.Xml; @@ -107,7 +107,7 @@ public final class RuleXmlParser implements RuleParser { } private static Rule parseRule(XmlPullParser parser) throws IOException, XmlPullParserException { - Formula formula = null; + IntegrityFormula formula = null; int effect = Integer.parseInt(extractAttributeValue(parser, EFFECT_ATTRIBUTE).orElse("-1")); int eventType; @@ -139,11 +139,11 @@ public final class RuleXmlParser implements RuleParser { return new Rule(formula, effect); } - private static Formula parseCompoundFormula(XmlPullParser parser) + private static IntegrityFormula parseCompoundFormula(XmlPullParser parser) throws IOException, XmlPullParserException { int connector = Integer.parseInt(extractAttributeValue(parser, CONNECTOR_ATTRIBUTE).orElse("-1")); - List<Formula> formulas = new ArrayList<>(); + List<IntegrityFormula> formulas = new ArrayList<>(); int eventType; while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) { @@ -175,7 +175,7 @@ public final class RuleXmlParser implements RuleParser { return new CompoundFormula(connector, formulas); } - private static Formula parseAtomicFormula(XmlPullParser parser) + private static IntegrityFormula parseAtomicFormula(XmlPullParser parser) throws IOException, XmlPullParserException { int key = Integer.parseInt(extractAttributeValue(parser, KEY_ATTRIBUTE).orElse("-1")); int operator = @@ -193,7 +193,7 @@ public final class RuleXmlParser implements RuleParser { return constructAtomicFormulaBasedOnKey(key, operator, value, isHashedValue); } - private static Formula constructAtomicFormulaBasedOnKey( + private static IntegrityFormula constructAtomicFormulaBasedOnKey( @AtomicFormula.Key int key, @AtomicFormula.Operator int operator, String value, @@ -208,7 +208,7 @@ public final class RuleXmlParser implements RuleParser { case AtomicFormula.PRE_INSTALLED: return new AtomicFormula.BooleanAtomicFormula(key, Boolean.parseBoolean(value)); case AtomicFormula.VERSION_CODE: - return new AtomicFormula.IntAtomicFormula(key, operator, Integer.parseInt(value)); + return new AtomicFormula.LongAtomicFormula(key, operator, Integer.parseInt(value)); default: throw new RuntimeException(String.format("Found unexpected key: %d", key)); } diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java index f5ed975bf772..d01499668e8c 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java @@ -36,11 +36,11 @@ import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAG import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; +import android.content.integrity.IntegrityUtils; import android.content.integrity.Rule; import com.android.internal.util.Preconditions; -import com.android.server.integrity.IntegrityUtils; import com.android.server.integrity.model.BitOutputStream; import com.android.server.integrity.model.ByteTrackedOutputStream; @@ -192,7 +192,7 @@ public class RuleBinarySerializer implements RuleSerializer { bitOutputStream.setNext(); } - private void serializeFormula(Formula formula, BitOutputStream bitOutputStream) + private void serializeFormula(IntegrityFormula formula, BitOutputStream bitOutputStream) throws IOException { if (formula instanceof AtomicFormula) { serializeAtomicFormula((AtomicFormula) formula, bitOutputStream); @@ -212,7 +212,7 @@ public class RuleBinarySerializer implements RuleSerializer { bitOutputStream.setNext(SEPARATOR_BITS, COMPOUND_FORMULA_START); bitOutputStream.setNext(CONNECTOR_BITS, compoundFormula.getConnector()); - for (Formula formula : compoundFormula.getFormulas()) { + for (IntegrityFormula formula : compoundFormula.getFormulas()) { serializeFormula(formula, bitOutputStream); } bitOutputStream.setNext(SEPARATOR_BITS, COMPOUND_FORMULA_END); @@ -234,11 +234,14 @@ public class RuleBinarySerializer implements RuleSerializer { stringAtomicFormula.getValue(), stringAtomicFormula.getIsHashedValue(), bitOutputStream); - } else if (atomicFormula.getTag() == AtomicFormula.INT_ATOMIC_FORMULA_TAG) { - AtomicFormula.IntAtomicFormula intAtomicFormula = - (AtomicFormula.IntAtomicFormula) atomicFormula; - bitOutputStream.setNext(OPERATOR_BITS, intAtomicFormula.getOperator()); - serializeIntValue(intAtomicFormula.getValue(), bitOutputStream); + } else if (atomicFormula.getTag() == AtomicFormula.LONG_ATOMIC_FORMULA_TAG) { + AtomicFormula.LongAtomicFormula longAtomicFormula = + (AtomicFormula.LongAtomicFormula) atomicFormula; + bitOutputStream.setNext(OPERATOR_BITS, longAtomicFormula.getOperator()); + // TODO(b/147880712): Temporary hack until we support long values in bitOutputStream + long value = longAtomicFormula.getValue(); + serializeIntValue((int) (value >>> 32), bitOutputStream); + serializeIntValue((int) value, bitOutputStream); } else if (atomicFormula.getTag() == AtomicFormula.BOOLEAN_ATOMIC_FORMULA_TAG) { AtomicFormula.BooleanAtomicFormula booleanAtomicFormula = (AtomicFormula.BooleanAtomicFormula) atomicFormula; diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java index 7d9a90188983..6f7d172aabcc 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java @@ -22,7 +22,7 @@ import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAG import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import java.util.ArrayList; @@ -76,15 +76,15 @@ class RuleIndexingDetailsIdentifier { return typeOrganizedRuleMap; } - private static RuleIndexingDetails getIndexingDetails(Formula formula) { + private static RuleIndexingDetails getIndexingDetails(IntegrityFormula formula) { switch (formula.getTag()) { - case Formula.COMPOUND_FORMULA_TAG: + case IntegrityFormula.COMPOUND_FORMULA_TAG: return getIndexingDetailsForCompoundFormula((CompoundFormula) formula); - case Formula.STRING_ATOMIC_FORMULA_TAG: + case IntegrityFormula.STRING_ATOMIC_FORMULA_TAG: return getIndexingDetailsForStringAtomicFormula( (AtomicFormula.StringAtomicFormula) formula); - case Formula.INT_ATOMIC_FORMULA_TAG: - case Formula.BOOLEAN_ATOMIC_FORMULA_TAG: + case IntegrityFormula.LONG_ATOMIC_FORMULA_TAG: + case IntegrityFormula.BOOLEAN_ATOMIC_FORMULA_TAG: // Package name and app certificate related formulas are string atomic formulas. return new RuleIndexingDetails(NOT_INDEXED); default: @@ -96,7 +96,7 @@ class RuleIndexingDetailsIdentifier { private static RuleIndexingDetails getIndexingDetailsForCompoundFormula( CompoundFormula compoundFormula) { int connector = compoundFormula.getConnector(); - List<Formula> formulas = compoundFormula.getFormulas(); + List<IntegrityFormula> formulas = compoundFormula.getFormulas(); switch (connector) { case CompoundFormula.AND: diff --git a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java index 8f164e645434..6e1218064096 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java @@ -22,7 +22,7 @@ import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAG import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import android.util.Xml; @@ -128,7 +128,8 @@ public class RuleXmlSerializer implements RuleSerializer { xmlSerializer.endTag(NAMESPACE, RULE_TAG); } - private void serializeFormula(Formula formula, XmlSerializer xmlSerializer) throws IOException { + private void serializeFormula(IntegrityFormula formula, XmlSerializer xmlSerializer) + throws IOException { if (formula instanceof AtomicFormula) { serializeAtomicFormula((AtomicFormula) formula, xmlSerializer); } else if (formula instanceof CompoundFormula) { @@ -147,7 +148,7 @@ public class RuleXmlSerializer implements RuleSerializer { xmlSerializer.startTag(NAMESPACE, COMPOUND_FORMULA_TAG); serializeAttributeValue( CONNECTOR_ATTRIBUTE, String.valueOf(compoundFormula.getConnector()), xmlSerializer); - for (Formula formula : compoundFormula.getFormulas()) { + for (IntegrityFormula formula : compoundFormula.getFormulas()) { serializeFormula(formula, xmlSerializer); } xmlSerializer.endTag(NAMESPACE, COMPOUND_FORMULA_TAG); @@ -171,14 +172,14 @@ public class RuleXmlSerializer implements RuleSerializer { String.valueOf( ((AtomicFormula.StringAtomicFormula) atomicFormula).getIsHashedValue()), xmlSerializer); - } else if (atomicFormula.getTag() == AtomicFormula.INT_ATOMIC_FORMULA_TAG) { + } else if (atomicFormula.getTag() == AtomicFormula.LONG_ATOMIC_FORMULA_TAG) { serializeAttributeValue( OPERATOR_ATTRIBUTE, - String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getOperator()), + String.valueOf(((AtomicFormula.LongAtomicFormula) atomicFormula).getOperator()), xmlSerializer); serializeAttributeValue( VALUE_ATTRIBUTE, - String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getValue()), + String.valueOf(((AtomicFormula.LongAtomicFormula) atomicFormula).getValue()), xmlSerializer); } else if (atomicFormula.getTag() == AtomicFormula.BOOLEAN_ATOMIC_FORMULA_TAG) { serializeAttributeValue( diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java index ed6a759409d4..5afa48a2b34d 100644 --- a/services/core/java/com/android/server/location/AbstractLocationProvider.java +++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java @@ -79,9 +79,9 @@ public abstract class AbstractLocationProvider { Collections.emptySet()); /** - * The provider's enabled state. + * The provider's allowed state. */ - public final boolean enabled; + public final boolean allowed; /** * The provider's properties. @@ -93,18 +93,18 @@ public abstract class AbstractLocationProvider { */ public final Set<String> providerPackageNames; - private State(boolean enabled, ProviderProperties properties, + private State(boolean allowed, ProviderProperties properties, Set<String> providerPackageNames) { - this.enabled = enabled; + this.allowed = allowed; this.properties = properties; this.providerPackageNames = Objects.requireNonNull(providerPackageNames); } - private State withEnabled(boolean enabled) { - if (enabled == this.enabled) { + private State withAllowed(boolean allowed) { + if (allowed == this.allowed) { return this; } else { - return new State(enabled, properties, providerPackageNames); + return new State(allowed, properties, providerPackageNames); } } @@ -112,7 +112,7 @@ public abstract class AbstractLocationProvider { if (properties.equals(this.properties)) { return this; } else { - return new State(enabled, properties, providerPackageNames); + return new State(allowed, properties, providerPackageNames); } } @@ -120,7 +120,7 @@ public abstract class AbstractLocationProvider { if (providerPackageNames.equals(this.providerPackageNames)) { return this; } else { - return new State(enabled, properties, providerPackageNames); + return new State(allowed, properties, providerPackageNames); } } @@ -133,13 +133,13 @@ public abstract class AbstractLocationProvider { return false; } State state = (State) o; - return enabled == state.enabled && properties == state.properties + return allowed == state.allowed && properties == state.properties && providerPackageNames.equals(state.providerPackageNames); } @Override public int hashCode() { - return Objects.hash(enabled, properties, providerPackageNames); + return Objects.hash(allowed, properties, providerPackageNames); } } @@ -259,10 +259,10 @@ public abstract class AbstractLocationProvider { } /** - * The current enabled state of this provider. + * The current allowed state of this provider. */ - protected boolean isEnabled() { - return mInternalState.get().state.enabled; + protected boolean isAllowed() { + return mInternalState.get().state.allowed; } /** @@ -281,10 +281,10 @@ public abstract class AbstractLocationProvider { } /** - * Call this method to report a change in provider enabled/disabled status. + * Call this method to report a change in provider allowed status. */ - protected void setEnabled(boolean enabled) { - setState(state -> state.withEnabled(enabled)); + protected void setAllowed(boolean allowed) { + setState(state -> state.withAllowed(allowed)); } /** @@ -358,6 +358,19 @@ public abstract class AbstractLocationProvider { protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {} /** + * Requests a provider to enable itself for the given user id. + */ + public final void requestSetAllowed(boolean allowed) { + // all calls into the provider must be moved onto the provider thread to prevent deadlock + mExecutor.execute(() -> onRequestSetAllowed(allowed)); + } + + /** + * Always invoked on the provider executor. + */ + protected void onRequestSetAllowed(boolean allowed) {} + + /** * Dumps debug or log information. May be invoked from any thread. */ public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args); diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 15cf190952d1..306e1e3afcd7 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -729,7 +729,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements }, UserHandle.USER_ALL); setProperties(PROPERTIES); - setEnabled(true); + setAllowed(true); } /** diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java index 805b018a8f45..cf299fe9bb2a 100644 --- a/services/core/java/com/android/server/location/LocationProviderProxy.java +++ b/services/core/java/com/android/server/location/LocationProviderProxy.java @@ -97,8 +97,8 @@ public class LocationProviderProxy extends AbstractLocationProvider { // executed on binder thread @Override - public void onSetEnabled(boolean enabled) { - setEnabled(enabled); + public void onSetAllowed(boolean allowed) { + setAllowed(allowed); } // executed on binder thread @@ -169,6 +169,14 @@ public class LocationProviderProxy extends AbstractLocationProvider { } @Override + public void onRequestSetAllowed(boolean allowed) { + mServiceWatcher.runOnBinder(binder -> { + ILocationProvider service = ILocationProvider.Stub.asInterface(binder); + service.requestSetAllowed(allowed); + }); + } + + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("service=" + mServiceWatcher); } diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java index 60c9fc12c201..bcec8b12b371 100644 --- a/services/core/java/com/android/server/location/MockProvider.java +++ b/services/core/java/com/android/server/location/MockProvider.java @@ -42,9 +42,9 @@ public class MockProvider extends AbstractLocationProvider { setProperties(properties); } - /** Sets the enabled state of this mock provider. */ - public void setProviderEnabled(boolean enabled) { - setEnabled(enabled); + /** Sets the allowed state of this mock provider. */ + public void setProviderAllowed(boolean allowed) { + setAllowed(allowed); } /** Sets the location to report for this mock provider. */ @@ -56,10 +56,15 @@ public class MockProvider extends AbstractLocationProvider { } @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("last mock location=" + mLocation); + public void onSetRequest(ProviderRequest request) {} + + @Override + protected void onRequestSetAllowed(boolean allowed) { + setAllowed(allowed); } @Override - public void onSetRequest(ProviderRequest request) {} + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("last mock location=" + mLocation); + } } diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java index f50dfe7edbb7..18615f87609f 100644 --- a/services/core/java/com/android/server/location/MockableLocationProvider.java +++ b/services/core/java/com/android/server/location/MockableLocationProvider.java @@ -170,13 +170,13 @@ public class MockableLocationProvider extends AbstractLocationProvider { } /** - * Sets the mock provider implementation's enabled state. Will throw an exception if the mock + * Sets the mock provider implementation's allowed state. Will throw an exception if the mock * provider is not currently the active implementation. */ - public void setMockProviderEnabled(boolean enabled) { + public void setMockProviderAllowed(boolean allowed) { synchronized (mOwnerLock) { Preconditions.checkState(isMock()); - mMockProvider.setProviderEnabled(enabled); + mMockProvider.setProviderAllowed(allowed); } } /** diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java index b33877069d70..ef157a39fa28 100644 --- a/services/core/java/com/android/server/location/PassiveProvider.java +++ b/services/core/java/com/android/server/location/PassiveProvider.java @@ -56,7 +56,7 @@ public class PassiveProvider extends AbstractLocationProvider { mReportLocation = false; setProperties(PROPERTIES); - setEnabled(true); + setAllowed(true); } @Override diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 7cc67324032a..e92f3ec5a836 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -513,6 +513,7 @@ public class NotificationManagerService extends SystemService { private TriPredicate<String, Integer, String> mAllowedManagedServicePackages; private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable(); + private NotificationRecordLogger mNotificationRecordLogger; private static class Archive { final int mBufferSize; @@ -1727,7 +1728,14 @@ public class NotificationManagerService extends SystemService { } public NotificationManagerService(Context context) { + this(context, new NotificationRecordLoggerImpl()); + } + + @VisibleForTesting + public NotificationManagerService(Context context, + NotificationRecordLogger notificationRecordLogger) { super(context); + mNotificationRecordLogger = notificationRecordLogger; Notification.processWhitelistToken = WHITELIST_TOKEN; } @@ -6304,9 +6312,11 @@ public class NotificationManagerService extends SystemService { mRankingHelper.extractSignals(r); mRankingHelper.sort(mNotificationList); + final int position = mRankingHelper.indexOf(mNotificationList, r); + int buzzBeepBlinkLoggingCode = 0; if (!r.isHidden()) { - buzzBeepBlinkLocked(r); + buzzBeepBlinkLoggingCode = buzzBeepBlinkLocked(r); } if (notification.getSmallIcon() != null) { @@ -6346,6 +6356,10 @@ public class NotificationManagerService extends SystemService { } maybeRecordInterruptionLocked(r); + + // Log event to statsd + mNotificationRecordLogger.logNotificationReported(r, old, position, + buzzBeepBlinkLoggingCode); } finally { int N = mEnqueuedNotifications.size(); for (int i = 0; i < N; i++) { @@ -6574,9 +6588,13 @@ public class NotificationManagerService extends SystemService { @VisibleForTesting @GuardedBy("mNotificationLock") - void buzzBeepBlinkLocked(NotificationRecord record) { + /** + * Determine whether this notification should attempt to make noise, vibrate, or flash the LED + * @return buzzBeepBlink - bitfield (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0) + */ + int buzzBeepBlinkLocked(NotificationRecord record) { if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) { - return; + return 0; } boolean buzz = false; boolean beep = false; @@ -6674,7 +6692,8 @@ public class NotificationManagerService extends SystemService { } else if (wasShowLights) { updateLightsLocked(); } - if (buzz || beep || blink) { + final int buzzBeepBlink = (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0); + if (buzzBeepBlink > 0) { // Ignore summary updates because we don't display most of the information. if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) { if (DEBUG_INTERRUPTIVENESS) { @@ -6696,10 +6715,11 @@ public class NotificationManagerService extends SystemService { MetricsLogger.action(record.getLogMaker() .setCategory(MetricsEvent.NOTIFICATION_ALERT) .setType(MetricsEvent.TYPE_OPEN) - .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0))); + .setSubtype(buzzBeepBlink)); EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0); } record.setAudiblyAlerted(buzz || beep); + return buzzBeepBlink; } @GuardedBy("mNotificationLock") diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 2bea21891f8f..660d574fe64e 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -675,6 +675,10 @@ public final class NotificationRecord { } } + String getAdjustmentIssuer() { + return mAdjustmentIssuer; + } + public void setIsAppImportanceLocked(boolean isAppImportanceLocked) { mIsAppImportanceLocked = isAppImportanceLocked; calculateUserSentiment(); @@ -783,10 +787,22 @@ public final class NotificationRecord { return mImportance; } + int getInitialImportance() { + return stats.naturalImportance; + } + public float getRankingScore() { return mRankingScore; } + int getImportanceExplanationCode() { + return mImportanceExplanationCode; + } + + int getInitialImportanceExplanationCode() { + return mInitialImportanceExplanationCode; + } + public CharSequence getImportanceExplanation() { switch (mImportanceExplanationCode) { case MetricsEvent.IMPORTANCE_EXPLANATION_UNKNOWN: diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java new file mode 100644 index 000000000000..03929e883852 --- /dev/null +++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java @@ -0,0 +1,142 @@ +/* + * 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.server.notification; + +import android.annotation.Nullable; +import android.app.Notification; +import android.app.Person; +import android.os.Bundle; + +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * Interface for writing NotificationReported atoms to statsd log. + * @hide + */ +public interface NotificationRecordLogger { + + /** + * Logs a NotificationReported atom reflecting the posting or update of a notification. + * @param r The new NotificationRecord. If null, no action is taken. + * @param old The previous NotificationRecord. Null if there was no previous record. + * @param position The position at which this notification is ranked. + * @param buzzBeepBlink Logging code reflecting whether this notification alerted the user. + */ + void logNotificationReported(@Nullable NotificationRecord r, @Nullable NotificationRecord old, + int position, int buzzBeepBlink); + + /** + * The UiEvent enums that this class can log. + */ + enum NotificationReportedEvents implements UiEventLogger.UiEventEnum { + INVALID(0), + @UiEvent(doc = "New notification enqueued to post") + NOTIFICATION_POSTED(162), + @UiEvent(doc = "Notification substantially updated") + NOTIFICATION_UPDATED(163); + + private final int mId; + NotificationReportedEvents(int id) { + mId = id; + } + @Override public int getId() { + return mId; + } + } + + /** + * A helper for extracting logging information from one or two NotificationRecords. + */ + class NotificationRecordPair { + public final NotificationRecord r, old; + /** + * Construct from one or two NotificationRecords. + * @param r The new NotificationRecord. If null, only shouldLog() method is usable. + * @param old The previous NotificationRecord. Null if there was no previous record. + */ + NotificationRecordPair(@Nullable NotificationRecord r, @Nullable NotificationRecord old) { + this.r = r; + this.old = old; + } + + /** + * @return True if old is null, alerted, or important logged fields have changed. + */ + boolean shouldLog(int buzzBeepBlink) { + if (r == null) { + return false; + } + if ((old == null) || (buzzBeepBlink > 0)) { + return true; + } + + return !(Objects.equals(r.sbn.getChannelIdLogTag(), old.sbn.getChannelIdLogTag()) + && Objects.equals(r.sbn.getGroupLogTag(), old.sbn.getGroupLogTag()) + && (r.sbn.getNotification().isGroupSummary() + == old.sbn.getNotification().isGroupSummary()) + && Objects.equals(r.sbn.getNotification().category, + old.sbn.getNotification().category) + && (r.getImportance() == old.getImportance())); + } + + NotificationReportedEvents getUiEvent() { + return (old != null) ? NotificationReportedEvents.NOTIFICATION_UPDATED : + NotificationReportedEvents.NOTIFICATION_POSTED; + } + + /** + * @return hash code for the notification style class, or 0 if none exists. + */ + public int getStyle() { + return getStyle(r.sbn.getNotification().extras); + } + + private int getStyle(@Nullable Bundle extras) { + if (extras != null) { + String template = extras.getString(Notification.EXTRA_TEMPLATE); + if (template != null && !template.isEmpty()) { + return template.hashCode(); + } + } + return 0; + } + + int getNumPeople() { + return getNumPeople(r.sbn.getNotification().extras); + } + + private int getNumPeople(@Nullable Bundle extras) { + if (extras != null) { + ArrayList<Person> people = extras.getParcelableArrayList( + Notification.EXTRA_PEOPLE_LIST); + if (people != null && !people.isEmpty()) { + return people.size(); + } + } + return 0; + } + + int getAssistantHash() { + String assistant = r.getAdjustmentIssuer(); + return (assistant == null) ? 0 : assistant.hashCode(); + } + } +} diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java new file mode 100644 index 000000000000..d637ad5e368b --- /dev/null +++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java @@ -0,0 +1,69 @@ +/* + * 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.server.notification; + +import android.util.StatsLog; + +/** + * Standard implementation of NotificationRecordLogger interface. + * @hide + */ +public class NotificationRecordLoggerImpl implements NotificationRecordLogger { + + @Override + public void logNotificationReported(NotificationRecord r, NotificationRecord old, + int position, int buzzBeepBlink) { + NotificationRecordPair p = new NotificationRecordPair(r, old); + if (!p.shouldLog(buzzBeepBlink)) { + return; + } + StatsLog.write(StatsLog.NOTIFICATION_REPORTED, + /* int32 event_id = 1 */ p.getUiEvent().getId(), + /* int32 uid = 2 */ r.getUid(), + /* string package_name = 3 */ r.sbn.getPackageName(), + /* int32 instance_id = 4 */ 0, // TODO generate and fill instance ids + /* int32 notification_id = 5 */ r.sbn.getId(), + /* string notification_tag = 6 */ r.sbn.getTag(), + /* string channel_id = 7 */ r.sbn.getChannelIdLogTag(), + /* string group_id = 8 */ r.sbn.getGroupLogTag(), + /* int32 group_instance_id = 9 */ 0, // TODO generate and fill instance ids + /* bool is_group_summary = 10 */ r.sbn.getNotification().isGroupSummary(), + /* string category = 11 */ r.sbn.getNotification().category, + /* int32 style = 12 */ p.getStyle(), + /* int32 num_people = 13 */ p.getNumPeople(), + /* int32 position = 14 */ position, + /* android.stats.sysui.NotificationImportance importance = 15 */ r.getImportance(), + /* int32 alerting = 16 */ buzzBeepBlink, + /* NotificationImportanceExplanation importance_source = 17 */ + r.getImportanceExplanationCode(), + /* android.stats.sysui.NotificationImportance importance_initial = 18 */ + r.getInitialImportance(), + /* NotificationImportanceExplanation importance_initial_source = 19 */ + r.getInitialImportanceExplanationCode(), + /* android.stats.sysui.NotificationImportance importance_asst = 20 */ + r.getAssistantImportance(), + /* int32 assistant_hash = 21 */ p.getAssistantHash(), + /* float assistant_ranking_score = 22 */ 0 // TODO connect up ranking score + ); + } + + + + + + +} diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java index ac3bf9ad5d8a..0a9f923ac817 100644 --- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java +++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java @@ -43,6 +43,9 @@ import java.util.Map; */ public class OverlayActorEnforcer { + // By default, the reason is not logged to prevent leaks of why it failed + private static final boolean DEBUG_REASON = false; + private final VerifyCallback mVerifyCallback; /** @@ -92,7 +95,7 @@ public class OverlayActorEnforcer { throw new SecurityException("UID" + callingUid + " is not allowed to call " + methodName + " for " + (TextUtils.isEmpty(targetOverlayableName) ? "" : (targetOverlayableName + " in ")) - + overlayInfo.targetPackageName + " because " + actorState + + overlayInfo.targetPackageName + (DEBUG_REASON ? (" because " + actorState) : "") ); } diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 9dff7754c4f3..6e7e5d884a4a 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -662,7 +662,7 @@ public class AppsFilter { String description, Throwable throwable) { Slog.wtf(TAG, "interaction: " + callingPkgSetting - + " -> " + targetPkgSetting.name + " " + + " -> " + targetPkgSetting + " " + description, throwable); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ca4ae0277aaf..d54b104731dc 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -27,6 +27,7 @@ import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import static android.content.Intent.ACTION_MAIN; import static android.content.Intent.CATEGORY_DEFAULT; import static android.content.Intent.CATEGORY_HOME; +import static android.content.Intent.EXTRA_LONG_VERSION_CODE; import static android.content.Intent.EXTRA_PACKAGE_NAME; import static android.content.Intent.EXTRA_VERSION_CODE; import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509; @@ -124,8 +125,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; -import android.app.ApplicationPackageManager; import android.app.AppOpsManager; +import android.app.ApplicationPackageManager; import android.app.BroadcastOptions; import android.app.IActivityManager; import android.app.ResourcesManager; @@ -4554,7 +4555,10 @@ public class PackageManagerService extends IPackageManager.Stub flags = updateFlagsForPackage(flags, userId); mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "getPackageUid"); + return getPackageUidInternal(packageName, flags, userId, callingUid); + } + private int getPackageUidInternal(String packageName, int flags, int userId, int callingUid) { // reader synchronized (mLock) { final AndroidPackage p = mPackages.get(packageName); @@ -14375,6 +14379,7 @@ public class PackageManagerService extends IPackageManager.Stub integrityVerification.putExtra(EXTRA_VERIFICATION_ID, verificationId); integrityVerification.putExtra(EXTRA_PACKAGE_NAME, pkgLite.packageName); integrityVerification.putExtra(EXTRA_VERSION_CODE, pkgLite.versionCode); + integrityVerification.putExtra(EXTRA_LONG_VERSION_CODE, pkgLite.getLongVersionCode()); populateInstallerExtras(integrityVerification); // send to integrity component only. @@ -20211,8 +20216,8 @@ public class PackageManagerService extends IPackageManager.Stub // Disable any carrier apps. We do this very early in boot to prevent the apps from being // disabled after already being started. - CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this, - mPermissionManagerService, UserHandle.USER_SYSTEM, mContext); + CarrierAppUtils.disableCarrierAppsUntilPrivileged( + mContext.getOpPackageName(), UserHandle.USER_SYSTEM, mContext); disableSkuSpecificApps(); @@ -23098,6 +23103,12 @@ public class PackageManagerService extends IPackageManager.Stub } @Override + public int getPackageUidInternal(String packageName, int flags, int userId) { + return PackageManagerService.this + .getPackageUidInternal(packageName, flags, userId, Process.SYSTEM_UID); + } + + @Override public ApplicationInfo getApplicationInfo( String packageName, int flags, int filterCallingUid, int userId) { return PackageManagerService.this diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index a0e6be4d9a6b..39d1a51c01de 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -20,7 +20,6 @@ import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED; import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; import static android.os.Debug.getIonHeapsSizeKb; -import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import static android.os.Process.getUidForPid; import static android.os.storage.VolumeInfo.TYPE_PRIVATE; import static android.os.storage.VolumeInfo.TYPE_PUBLIC; @@ -32,11 +31,8 @@ import static com.android.server.stats.pull.ProcfsMemoryUtil.forEachPid; import static com.android.server.stats.pull.ProcfsMemoryUtil.readCmdlineFromProcfs; import static com.android.server.stats.pull.ProcfsMemoryUtil.readMemorySnapshotFromProcfs; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManagerInternal; -import android.app.AlarmManager; -import android.app.AlarmManager.OnAlarmListener; import android.app.AppOpsManager; import android.app.AppOpsManager.HistoricalOps; import android.app.AppOpsManager.HistoricalOpsRequest; @@ -49,10 +45,7 @@ import android.app.StatsManager.PullAtomMetadata; import android.bluetooth.BluetoothActivityEnergyInfo; import android.bluetooth.BluetoothAdapter; import android.bluetooth.UidTraffic; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -74,23 +67,14 @@ import android.os.Build; import android.os.Bundle; import android.os.CoolingDevice; import android.os.Environment; -import android.os.FileUtils; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.IPullAtomCallback; -import android.os.IStatsCompanionService; -import android.os.IStatsd; import android.os.IStoraged; import android.os.IThermalEventListener; import android.os.IThermalService; -import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; import android.os.StatFs; -import android.os.StatsLogEventWrapper; import android.os.SynchronousResultReceiver; import android.os.SystemClock; import android.os.SystemProperties; @@ -134,7 +118,6 @@ import com.android.internal.os.LooperStats; import com.android.internal.os.PowerProfile; import com.android.internal.os.ProcessCpuTracker; import com.android.internal.os.StoragedUidIoStatsReader; -import com.android.internal.util.DumpUtils; import com.android.server.BinderCallsStatsService; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -156,20 +139,15 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.File; -import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.MissingResourceException; -import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -229,6 +207,25 @@ public class StatsPullAtomService extends SystemService { mTelephony = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); mStorageManager = (StorageManager) mContext.getSystemService(StorageManager.class); + final ConnectivityManager connectivityManager = + (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + // Default NetworkRequest should cover all transport types. + final NetworkRequest request = new NetworkRequest.Builder().build(); + connectivityManager.registerNetworkCallback(request, new ConnectivityStatsCallback()); + + // Enable push notifications of throttling from vendor thermal + // management subsystem via thermalservice. + IThermalService thermalService = getIThermalService(); + if (thermalService != null) { + try { + thermalService.registerThermalEventListener( + new ThermalEventListener()); + Slog.i(TAG, "register thermal listener successfully"); + } catch (RemoteException e) { + Slog.i(TAG, "failed to register thermal listener"); + } + } + // Initialize state for CPU_TIME_PER_FREQ atom PowerProfile powerProfile = new PowerProfile(mContext); final int numClusters = powerProfile.getNumCpuClusters(); @@ -2896,4 +2893,29 @@ public class StatsPullAtomService extends SystemService { BackgroundThread.getExecutor() ); } + + + // Thermal event received from vendor thermal management subsystem + private static final class ThermalEventListener extends IThermalEventListener.Stub { + @Override + public void notifyThrottling(Temperature temp) { + StatsLog.write(StatsLog.THERMAL_THROTTLING_SEVERITY_STATE_CHANGED, temp.getType(), + temp.getName(), (int) (temp.getValue() * 10), temp.getStatus()); + } + } + + private static final class ConnectivityStatsCallback extends + ConnectivityManager.NetworkCallback { + @Override + public void onAvailable(Network network) { + StatsLog.write(StatsLog.CONNECTIVITY_STATE_CHANGED, network.netId, + StatsLog.CONNECTIVITY_STATE_CHANGED__STATE__CONNECTED); + } + + @Override + public void onLost(Network network) { + StatsLog.write(StatsLog.CONNECTIVITY_STATE_CHANGED, network.netId, + StatsLog.CONNECTIVITY_STATE_CHANGED__STATE__DISCONNECTED); + } + } } diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java index 0abe68f270f3..8130546e2699 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.os.Binder; import android.os.PatternMatcher; import android.os.Process; @@ -34,6 +35,7 @@ import android.webkit.WebViewProviderInfo; import android.webkit.WebViewProviderResponse; import com.android.internal.util.DumpUtils; +import com.android.server.LocalServices; import com.android.server.SystemService; import java.io.FileDescriptor; @@ -191,7 +193,26 @@ public class WebViewUpdateService extends SystemService { throw new IllegalStateException("Cannot create a WebView from the SystemServer"); } - return WebViewUpdateService.this.mImpl.waitForAndGetProvider(); + final WebViewProviderResponse webViewProviderResponse = + WebViewUpdateService.this.mImpl.waitForAndGetProvider(); + if (webViewProviderResponse.packageInfo != null) { + grantVisibilityToCaller( + webViewProviderResponse.packageInfo.packageName, Binder.getCallingUid()); + } + return webViewProviderResponse; + } + + /** + * Grants app visibility of the webViewPackageName to the currently bound caller. + * @param webViewPackageName + */ + private void grantVisibilityToCaller(String webViewPackageName, int callingUid) { + final PackageManagerInternal pmInternal = LocalServices.getService( + PackageManagerInternal.class); + final int webviewUid = pmInternal.getPackageUidInternal( + webViewPackageName, 0, UserHandle.getUserId(callingUid)); + pmInternal.grantImplicitAccess(UserHandle.getUserId(callingUid), null, webviewUid, + UserHandle.getAppId(callingUid)); } /** @@ -231,13 +252,18 @@ public class WebViewUpdateService extends SystemService { @Override // Binder call public String getCurrentWebViewPackageName() { - PackageInfo pi = WebViewUpdateService.this.mImpl.getCurrentWebViewPackage(); + PackageInfo pi = getCurrentWebViewPackage(); return pi == null ? null : pi.packageName; } @Override // Binder call public PackageInfo getCurrentWebViewPackage() { - return WebViewUpdateService.this.mImpl.getCurrentWebViewPackage(); + final PackageInfo currentWebViewPackage = + WebViewUpdateService.this.mImpl.getCurrentWebViewPackage(); + if (currentWebViewPackage != null) { + grantVisibilityToCaller(currentWebViewPackage.packageName, Binder.getCallingUid()); + } + return currentWebViewPackage; } @Override // Binder call diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d1c8448f2a4a..57865957b8d4 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1627,7 +1627,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A requestedVrComponent = (aInfo.requestedVrComponent == null) ? null : ComponentName.unflattenFromString(aInfo.requestedVrComponent); - lockTaskLaunchMode = getLockTaskLaunchMode(aInfo, options); + 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; + } if (options != null) { pendingOptions = options; @@ -1635,25 +1640,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (usageReport != null) { appTimeTracker = new AppTimeTracker(usageReport); } - // 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(); + 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(); } - return lockTaskLaunchMode; } @Override diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java index d61d29d1084e..2fb0ac5fbeaa 100644 --- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java @@ -52,7 +52,6 @@ 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; @@ -167,9 +166,6 @@ 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. @@ -178,6 +174,11 @@ class ActivityStartInterceptor { return interceptWorkProfileChallengeIfNeeded(); } + private boolean hasCrossProfileAnimation() { + return mActivityOptions != null + && mActivityOptions.getAnimationType() == ANIM_OPEN_CROSS_PROFILE_APPS; + } + /** * If the activity option is the {@link ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} one, * defer the animation until the original intent is started. @@ -185,8 +186,7 @@ class ActivityStartInterceptor { * @return the activity option used to start the original intent. */ private Bundle deferCrossProfileAppsAnimationIfNecessary() { - if (mActivityOptions != null - && mActivityOptions.getAnimationType() == ANIM_OPEN_CROSS_PROFILE_APPS) { + if (hasCrossProfileAnimation()) { mActivityOptions = null; return ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle(); } @@ -255,28 +255,13 @@ class ActivityStartInterceptor { } final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage, suspendingPackage, mUserId); + final Bundle crossProfileOptions = hasCrossProfileAnimation() + ? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle() + : null; + final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid, + FLAG_IMMUTABLE); mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage, - suspendingPackage, dialogInfo, deferCrossProfileAppsAnimationIfNecessary(), - mUserId); - 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 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); + suspendingPackage, dialogInfo, crossProfileOptions, target, mUserId); mCallingPid = mRealCallingPid; mCallingUid = mRealCallingUid; mResolvedType = null; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 31b7c688d685..40a45641ab04 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -3303,7 +3303,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } - private int sanitizeAndApplyChange(ConfigurationContainer container, + private int sanitizeAndApplyChange(WindowContainer container, WindowContainerTransaction.Change change) { if (!(container instanceof Task || container instanceof ActivityStack)) { throw new RuntimeException("Invalid token in task transaction"); @@ -3347,13 +3347,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } - private int applyWindowContainerChange(ConfigurationContainer cc, + private int applyWindowContainerChange(WindowContainer wc, WindowContainerTransaction.Change c) { - int effects = sanitizeAndApplyChange(cc, c); + int effects = sanitizeAndApplyChange(wc, c); Rect enterPipBounds = c.getEnterPipBounds(); if (enterPipBounds != null) { - Task tr = (Task) cc; + Task tr = (Task) wc; mStackSupervisor.updatePictureInPictureMode(tr, enterPipBounds, true); } @@ -3378,17 +3378,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { while (entries.hasNext()) { final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next(); - final ConfigurationContainer cc = - ConfigurationContainer.RemoteToken.fromBinder( - entry.getKey()).getContainer(); - int containerEffect = applyWindowContainerChange(cc, entry.getValue()); + final WindowContainer wc = WindowContainer.RemoteToken.fromBinder( + entry.getKey()).getContainer(); + int containerEffect = applyWindowContainerChange(wc, entry.getValue()); effects |= containerEffect; // Lifecycle changes will trigger ensureConfig for everything. if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0 && (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { - if (cc instanceof WindowContainer) { - haveConfigChanges.add((WindowContainer) cc); - } + haveConfigChanges.add(wc); } } if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) { diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index 7b23e2d383b6..9bd380a95ad0 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -39,15 +39,11 @@ import android.app.WindowConfiguration; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; -import android.os.IBinder; import android.util.proto.ProtoOutputStream; -import android.view.IWindowContainer; -import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; -import java.lang.ref.WeakReference; import java.util.ArrayList; /** @@ -104,12 +100,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { static final int BOUNDS_CHANGE_SIZE = 1 << 1; /** - * Used as a unique, cross-process identifier for this Container. It also serves a minimal - * interface to other processes. - */ - RemoteToken mRemoteToken = null; - - /** * Returns full configuration applied to this configuration container. * This method should be used for getting settings applied in each particular level of the * hierarchy. @@ -629,21 +619,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { return mFullConfiguration.windowConfiguration.isAlwaysOnTop(); } - /** - * Returns {@code true} if this container is focusable. Generally, if a parent is not focusable, - * this will not be focusable either. - */ - boolean isFocusable() { - // TODO(split): Move this to WindowContainer once Split-screen is based on a WindowContainer - // like DisplayArea vs. TaskTiles. - ConfigurationContainer parent = getParent(); - return parent == null || parent.isFocusable(); - } - - boolean setFocusable(boolean focusable) { - return false; - } - boolean hasChild() { return getChildCount() > 0; } @@ -654,40 +629,4 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { abstract protected ConfigurationContainer getParent(); - // TODO: Consider moving to WindowContainer once hierarchies and Task/Stack are merged. - static class RemoteToken extends IWindowContainer.Stub { - final WeakReference<ConfigurationContainer> mWeakRef; - - RemoteToken(ConfigurationContainer container) { - mWeakRef = new WeakReference<>(container); - } - - ConfigurationContainer getContainer() { - return mWeakRef.get(); - } - - static RemoteToken fromBinder(IBinder binder) { - return (RemoteToken) binder; - } - - @Override - public SurfaceControl getLeash() { - throw new RuntimeException("Not implemented"); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(128); - sb.append("RemoteToken{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(' '); - sb.append(mWeakRef.get()); - sb.append('}'); - return sb.toString(); - } - } - - RemoteToken getRemoteToken() { - return mRemoteToken; - } } diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index 33b0453a25ee..02413bb48518 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -23,8 +23,6 @@ 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; @@ -341,20 +339,6 @@ public class LockTaskController { & DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD) != 0; } - boolean isActivityAllowed(int userId, String packageName, int lockTaskLaunchMode) { - if (mLockTaskModeState != LOCK_TASK_MODE_LOCKED) { - 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) { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 917b437c8244..5ecbec4c1180 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import static android.app.ActivityTaskManager.INVALID_STACK_ID; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED; import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM; @@ -496,7 +495,7 @@ class Task extends WindowContainer<WindowContainer> { } class TaskToken extends RemoteToken { - TaskToken(ConfigurationContainer container) { + TaskToken(WindowContainer container) { super(container); } @@ -2724,6 +2723,7 @@ class Task extends WindowContainer<WindowContainer> { boolean[] foundTop = { false }; final PooledConsumer c = PooledLambda.obtainConsumer(Task::getMaxVisibleBounds, PooledLambda.__(ActivityRecord.class), out, foundTop); + forAllActivities(c); c.recycle(); if (foundTop[0]) { return; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 4cb5de44bef0..10d6823c850f 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -343,6 +343,7 @@ class TaskSnapshotController { builder.setPixelFormat(pixelFormat); builder.setIsTranslucent(isTranslucent); builder.setOrientation(activity.getTask().getConfiguration().orientation); + builder.setRotation(activity.getTask().getDisplayContent().getRotation()); builder.setWindowingMode(task.getWindowingMode()); builder.setSystemUiVisibility(getSystemUiVisibility(task)); return true; @@ -492,7 +493,8 @@ class TaskSnapshotController { return new TaskSnapshot( System.currentTimeMillis() /* id */, topChild.mActivityComponent, hwBitmap.createGraphicBufferHandle(), - hwBitmap.getColorSpace(), topChild.getTask().getConfiguration().orientation, + hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation, + mainWindow.getWindowConfiguration().getRotation(), getInsets(mainWindow), ActivityManager.isLowRamDeviceStatic() /* reduced */, mFullSnapshotScale, false /* isRealSnapshot */, task.getWindowingMode(), getSystemUiVisibility(task), false); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java index 22c1ea59d176..6e9986ffd411 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java @@ -102,8 +102,8 @@ class TaskSnapshotLoader { // For legacy snapshots, restore the scale based on the reduced resolution state final float legacyScale = reducedResolution ? mPersister.getReducedScale() : 1f; final float scale = Float.compare(proto.scale, 0f) != 0 ? proto.scale : legacyScale; - return new TaskSnapshot(proto.id, topActivityComponent, buffer, - hwBitmap.getColorSpace(), proto.orientation, + return new TaskSnapshot(proto.id, topActivityComponent, buffer, hwBitmap.getColorSpace(), + proto.orientation, proto.rotation, new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom), reducedResolution, scale, proto.isRealSnapshot, proto.windowingMode, proto.systemUiVisibility, proto.isTranslucent); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java index 828775a4b934..ee5098b6c699 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java @@ -342,6 +342,7 @@ class TaskSnapshotPersister { boolean writeProto() { final TaskSnapshotProto proto = new TaskSnapshotProto(); proto.orientation = mSnapshot.getOrientation(); + proto.rotation = mSnapshot.getRotation(); proto.insetLeft = mSnapshot.getContentInsets().left; proto.insetTop = mSnapshot.getContentInsets().top; proto.insetRight = mSnapshot.getContentInsets().right; diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 1c876d9cc02f..0ab5f91f0ce9 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -61,6 +61,7 @@ import android.util.Pools; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; +import android.view.IWindowContainer; import android.view.MagnificationSpec; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; @@ -75,6 +76,7 @@ import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.Animatable; import java.io.PrintWriter; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Comparator; import java.util.LinkedList; @@ -249,6 +251,12 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< private boolean mIsFocusable = true; + /** + * Used as a unique, cross-process identifier for this Container. It also serves a minimal + * interface to other processes. + */ + RemoteToken mRemoteToken = null; + WindowContainer(WindowManagerService wms) { mWmService = wms; mPendingTransaction = wms.mTransactionFactory.get(); @@ -860,13 +868,16 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return false; } - @Override + /** + * Returns {@code true} if this container is focusable. Generally, if a parent is not focusable, + * this will not be focusable either. + */ boolean isFocusable() { - return super.isFocusable() && mIsFocusable; + final WindowContainer parent = getParent(); + return (parent == null || parent.isFocusable()) && mIsFocusable; } /** Set whether this container or its children can be focusable */ - @Override boolean setFocusable(boolean focusable) { if (mIsFocusable == focusable) { return false; @@ -2259,4 +2270,40 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< ActivityRecord asActivityRecord() { return null; } + + RemoteToken getRemoteToken() { + return mRemoteToken; + } + + static class RemoteToken extends IWindowContainer.Stub { + final WeakReference<WindowContainer> mWeakRef; + + RemoteToken(WindowContainer container) { + mWeakRef = new WeakReference<>(container); + } + + WindowContainer getContainer() { + return mWeakRef.get(); + } + + static RemoteToken fromBinder(IBinder binder) { + return (RemoteToken) binder; + } + + @Override + public SurfaceControl getLeash() { + throw new RuntimeException("Not implemented"); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("RemoteToken{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + sb.append(mWeakRef.get()); + sb.append('}'); + return sb.toString(); + } + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8d4ad28972e9..27de95a84ab6 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -122,6 +122,7 @@ import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.app.ActivityManager; import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManagerInternal; @@ -2996,7 +2997,13 @@ public class WindowManagerService extends IWindowManager.Stub } } - void showGlobalActions() { + @RequiresPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW) + @Override + public void showGlobalActions() { + if (!checkCallingPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW, + "showGlobalActions()")) { + throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission"); + } mPolicy.showGlobalActions(); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 82f5d50b41c7..d7ea2f53c286 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -180,6 +180,7 @@ import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Color; import android.location.LocationManager; +import android.location.LocationManagerInternal; import android.media.AudioManager; import android.media.IAudioService; import android.net.ConnectivityManager; @@ -2096,6 +2097,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return mContext.getSystemService(LocationManager.class); } + LocationManagerInternal getLocationManagerInternal() { + return LocalServices.getService(LocationManagerInternal.class); + } + IWindowManager getIWindowManager() { return IWindowManager.Stub .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)); @@ -11553,6 +11558,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override + public void requestSetLocationProviderAllowed(ComponentName who, String provider, + boolean providerAllowed) { + Objects.requireNonNull(who, "ComponentName is null"); + enforceDeviceOwner(who); + + mInjector.binderWithCleanCallingIdentity( + () -> mInjector.getLocationManagerInternal().requestSetProviderAllowed(provider, + providerAllowed)); + } + + @Override public boolean setTime(ComponentName who, long millis) { Objects.requireNonNull(who, "ComponentName is null in setTime"); enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(who); diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java index a6af9a99788f..9a633931017e 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java @@ -57,7 +57,6 @@ import android.os.Handler; import android.os.Message; import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; import com.android.server.LocalServices; @@ -68,6 +67,7 @@ import com.android.server.testutils.TestUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; @@ -81,7 +81,7 @@ import java.util.List; import java.util.Map; /** Unit test for {@link com.android.server.integrity.AppIntegrityManagerServiceImpl} */ -@RunWith(AndroidJUnit4.class) +@RunWith(JUnit4.class) public class AppIntegrityManagerServiceImplTest { private static final String TEST_APP_PATH = "/data/local/tmp/AppIntegrityManagerServiceTestApp.apk"; @@ -91,8 +91,10 @@ public class AppIntegrityManagerServiceImplTest { private static final String TEST_FRAMEWORK_PACKAGE = "com.android.frameworks.servicestests"; private static final String PACKAGE_NAME = "com.test.app"; - private static final int VERSION_CODE = 100; + + private static final long VERSION_CODE = 100; private static final String INSTALLER = "com.long.random.test.installer.name"; + // These are obtained by running the test and checking logcat. private static final String APP_CERT = "301AA3CB081134501C45F1422ABC66C24224FD5DED5FDC8F17E697176FD866AA"; @@ -108,7 +110,8 @@ public class AppIntegrityManagerServiceImplTest { "play_store_cert"; private static final String ADB_CERT = ""; - @org.junit.Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); + @org.junit.Rule + public MockitoRule mMockitoRule = MockitoJUnit.rule(); @Mock PackageManagerInternal mPackageManagerInternal; @Mock Context mMockContext; @@ -173,7 +176,8 @@ public class AppIntegrityManagerServiceImplTest { makeUsSystemApp(); Rule rule = new Rule( - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true), Rule.DENY); TestUtils.assertExpectException( SecurityException.class, @@ -191,7 +195,8 @@ public class AppIntegrityManagerServiceImplTest { whitelistUsAsRuleProvider(); Rule rule = new Rule( - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true), Rule.DENY); TestUtils.assertExpectException( SecurityException.class, @@ -210,7 +215,8 @@ public class AppIntegrityManagerServiceImplTest { makeUsSystemApp(); Rule rule = new Rule( - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true), Rule.DENY); // no SecurityException @@ -447,7 +453,7 @@ public class AppIntegrityManagerServiceImplTest { intent.putExtra( EXTRA_VERIFICATION_INSTALLER_UID, mMockContext.getPackageManager().getPackageUid(installer, /* flags= */ 0)); - intent.putExtra(Intent.EXTRA_VERSION_CODE, VERSION_CODE); + intent.putExtra(Intent.EXTRA_LONG_VERSION_CODE, VERSION_CODE); return intent; } } diff --git a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java index a1810b971b09..86daf69fb2d9 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java @@ -22,7 +22,7 @@ import static com.google.common.truth.Truth.assertThat; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; -import android.content.integrity.AtomicFormula.IntAtomicFormula; +import android.content.integrity.AtomicFormula.LongAtomicFormula; import android.content.integrity.AtomicFormula.StringAtomicFormula; import android.content.integrity.CompoundFormula; import android.content.integrity.Rule; @@ -116,7 +116,8 @@ public class IntegrityFileManagerTest { Rule packageCertRule = getAppCertificateIndexedRule(packageCert); Rule versionCodeRule = new Rule( - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, version), + new LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.EQ, version), Rule.DENY); Rule randomRule = new Rule( @@ -127,9 +128,9 @@ public class IntegrityFileManagerTest { AtomicFormula.PACKAGE_NAME, "abc", /* isHashedValue= */ false), - new IntAtomicFormula( + new LongAtomicFormula( AtomicFormula.VERSION_CODE, - AtomicFormula.LE, + AtomicFormula.EQ, version))), Rule.DENY); @@ -201,21 +202,22 @@ public class IntegrityFileManagerTest { private Rule getPackageNameIndexedRule(String packageName) { return new Rule( new StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, packageName, /* isHashedValue= */ false), + AtomicFormula.PACKAGE_NAME, packageName, /* isHashedValue= */false), Rule.DENY); } private Rule getAppCertificateIndexedRule(String appCertificate) { return new Rule( new StringAtomicFormula( - AtomicFormula.APP_CERTIFICATE, appCertificate, /* isHashedValue= */ false), + AtomicFormula.APP_CERTIFICATE, + appCertificate, /* isHashedValue= */ false), Rule.DENY); } private Rule getInstallerCertificateRule(String installerCert) { return new Rule( new StringAtomicFormula( - AtomicFormula.INSTALLER_NAME, installerCert, /* isHashedValue= */ false), + AtomicFormula.INSTALLER_NAME, installerCert, /* isHashedValue= */false), Rule.DENY); } diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java index d3864878d4b2..99157024bb66 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java @@ -50,7 +50,8 @@ public class RuleEvaluationEngineTest { private static final String RANDOM_INSTALLER = "random"; private static final String RANDOM_INSTALLER_CERT = "random_cert"; - @Mock private IntegrityFileManager mIntegrityFileManager; + @Mock + private IntegrityFileManager mIntegrityFileManager; private RuleEvaluationEngine mEngine; @@ -70,29 +71,29 @@ public class RuleEvaluationEngineTest { assertEquals( IntegrityCheckResult.Effect.ALLOW, mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(), + allowedInstallers) .getEffect()); assertEquals( IntegrityCheckResult.Effect.ALLOW, mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_2) - .setInstallerCertificate(INSTALLER_2_CERT) - .build(), - allowedInstallers) + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_2) + .setInstallerCertificate(INSTALLER_2_CERT) + .build(), + allowedInstallers) .getEffect()); assertEquals( IntegrityCheckResult.Effect.ALLOW, mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(RANDOM_INSTALLER) - .setInstallerCertificate(RANDOM_INSTALLER_CERT) - .build(), - allowedInstallers) + getAppInstallMetadataBuilder() + .setInstallerName(RANDOM_INSTALLER) + .setInstallerCertificate(RANDOM_INSTALLER_CERT) + .build(), + allowedInstallers) .getEffect()); } @@ -104,38 +105,38 @@ public class RuleEvaluationEngineTest { assertEquals( IntegrityCheckResult.Effect.ALLOW, mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(), + allowedInstallers) .getEffect()); assertEquals( IntegrityCheckResult.Effect.DENY, mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(RANDOM_INSTALLER) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) + getAppInstallMetadataBuilder() + .setInstallerName(RANDOM_INSTALLER) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(), + allowedInstallers) .getEffect()); assertEquals( IntegrityCheckResult.Effect.DENY, mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(RANDOM_INSTALLER_CERT) - .build(), - allowedInstallers) + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(RANDOM_INSTALLER_CERT) + .build(), + allowedInstallers) .getEffect()); assertEquals( IntegrityCheckResult.Effect.DENY, mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(RANDOM_INSTALLER) - .setInstallerCertificate(RANDOM_INSTALLER_CERT) - .build(), - allowedInstallers) + getAppInstallMetadataBuilder() + .setInstallerName(RANDOM_INSTALLER) + .setInstallerCertificate(RANDOM_INSTALLER_CERT) + .build(), + allowedInstallers) .getEffect()); } @@ -149,38 +150,38 @@ public class RuleEvaluationEngineTest { assertEquals( IntegrityCheckResult.Effect.ALLOW, mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(), + allowedInstallers) .getEffect()); assertEquals( IntegrityCheckResult.Effect.ALLOW, mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_2) - .setInstallerCertificate(INSTALLER_2_CERT) - .build(), - allowedInstallers) + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_2) + .setInstallerCertificate(INSTALLER_2_CERT) + .build(), + allowedInstallers) .getEffect()); assertEquals( IntegrityCheckResult.Effect.DENY, mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(INSTALLER_2_CERT) - .build(), - allowedInstallers) + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_2_CERT) + .build(), + allowedInstallers) .getEffect()); assertEquals( IntegrityCheckResult.Effect.DENY, mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_2) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_2) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(), + allowedInstallers) .getEffect()); } diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java index eda2b701fd8d..629fd14befcc 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java @@ -19,10 +19,11 @@ package com.android.server.integrity.engine; import static com.android.server.integrity.model.IntegrityCheckResult.Effect.ALLOW; import static com.android.server.integrity.model.IntegrityCheckResult.Effect.DENY; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; +import android.content.integrity.AtomicFormula.LongAtomicFormula; import android.content.integrity.AtomicFormula.StringAtomicFormula; import android.content.integrity.CompoundFormula; import android.content.integrity.Rule; @@ -57,7 +58,7 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(rules, APP_INSTALL_METADATA); - assertEquals(ALLOW, result.getEffect()); + assertThat(result.getEffect()).isEqualTo(ALLOW); } @Test @@ -73,7 +74,7 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Collections.singletonList(rule1), APP_INSTALL_METADATA); - assertEquals(ALLOW, result.getEffect()); + assertThat(result.getEffect()).isEqualTo(ALLOW); } @Test @@ -96,8 +97,8 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); - assertEquals(rule1, result.getRule()); + assertThat(result.getEffect()).isEqualTo(DENY); + assertThat(result.getRule()).isEqualTo(rule1); } @Test @@ -126,8 +127,8 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); - assertEquals(rule1, result.getRule()); + assertThat(result.getEffect()).isEqualTo(DENY); + assertThat(result.getRule()).isEqualTo(rule1); } @Test @@ -145,23 +146,23 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); - assertEquals(rule, result.getRule()); + assertThat(result.getEffect()).isEqualTo(DENY); + assertThat(result.getRule()).isEqualTo(rule); } @Test public void testEvaluateRules_ruleWithIntegerOperators_deny() { Rule rule = new Rule( - new AtomicFormula.IntAtomicFormula( - AtomicFormula.VERSION_CODE, AtomicFormula.GT, 1), + new LongAtomicFormula(AtomicFormula.VERSION_CODE, + AtomicFormula.GT, 1), Rule.DENY); IntegrityCheckResult result = RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); - assertEquals(rule, result.getRule()); + assertThat(result.getEffect()).isEqualTo(DENY); + assertThat(result.getRule()).isEqualTo(rule); } @Test @@ -183,8 +184,8 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); - assertEquals(rule, result.getRule()); + assertThat(result.getEffect()).isEqualTo(DENY); + assertThat(result.getRule()).isEqualTo(rule); } @Test @@ -206,7 +207,7 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); + assertThat(result.getEffect()).isEqualTo(DENY); } @Test @@ -230,7 +231,7 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); + assertThat(result.getEffect()).isEqualTo(DENY); } @Test @@ -259,7 +260,7 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA); - assertEquals(ALLOW, result.getEffect()); - assertEquals(rule1, result.getRule()); + assertThat(result.getEffect()).isEqualTo(ALLOW); + assertThat(result.getRule()).isEqualTo(rule1); } -} +}
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/BinaryFileOperationsTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/BinaryFileOperationsTest.java index cfa1de371e8c..723b6c5af451 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/parser/BinaryFileOperationsTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/parser/BinaryFileOperationsTest.java @@ -26,7 +26,8 @@ import static com.android.server.integrity.utils.TestUtils.getValueBits; import static com.google.common.truth.Truth.assertThat; -import com.android.server.integrity.IntegrityUtils; +import android.content.integrity.IntegrityUtils; + import com.android.server.integrity.model.BitInputStream; import org.junit.Test; diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java index e0b2e2257ee4..38cf562f8c5b 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java @@ -36,10 +36,9 @@ import static com.google.common.truth.Truth.assertThat; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; +import android.content.integrity.IntegrityUtils; import android.content.integrity.Rule; -import com.android.server.integrity.IntegrityUtils; - import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -345,7 +344,7 @@ public class RuleBinaryParserTest { + ATOMIC_FORMULA_START_BITS + VERSION_CODE + EQ - + getBits(versionCode, /* numOfBits= */ 32) + + getBits(versionCode, /* numOfBits= */ 64) + DENY + END_BIT; byte[] ruleBytes = getBytes(ruleBits); @@ -356,7 +355,7 @@ public class RuleBinaryParserTest { RuleParser binaryParser = new RuleBinaryParser(); Rule expectedRule = new Rule( - new AtomicFormula.IntAtomicFormula( + new AtomicFormula.LongAtomicFormula( AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1), Rule.DENY); @@ -384,7 +383,8 @@ public class RuleBinaryParserTest { RuleParser binaryParser = new RuleBinaryParser(); Rule expectedRule = new Rule( - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true), Rule.DENY); List<Rule> rules = binaryParser.parse(rule.array()); @@ -400,7 +400,7 @@ public class RuleBinaryParserTest { + ATOMIC_FORMULA_START_BITS + VERSION_CODE + EQ - + getBits(versionCode, /* numOfBits= */ 32) + + getBits(versionCode, /* numOfBits= */ 64) + DENY; byte[] ruleBytes = getBytes(ruleBits); ByteBuffer rule = @@ -488,7 +488,7 @@ public class RuleBinaryParserTest { + ATOMIC_FORMULA_START_BITS + VERSION_CODE + INVALID_OPERATOR - + getBits(versionCode, /* numOfBits= */ 32) + + getBits(versionCode, /* numOfBits= */ 64) + COMPOUND_FORMULA_END_BITS + DENY + END_BIT; diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java index 0f0dee924e29..c57136c1acab 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java @@ -46,15 +46,15 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -83,15 +83,15 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -123,17 +123,17 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + generateTagWithAttribute( - /* tag= */ "AF", appCertificateAttrs, /* closed= */ true) + /* tag= */ "AF", appCertificateAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -168,17 +168,17 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.OR)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.OR)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + generateTagWithAttribute( - /* tag= */ "AF", appCertificateAttrs, /* closed= */ true) + /* tag= */ "AF", appCertificateAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -211,15 +211,15 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -252,17 +252,17 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + generateTagWithAttribute( - /* tag= */ "AF", versionCodeAttrs, /* closed= */ true) + /* tag= */ "AF", versionCodeAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -283,15 +283,15 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -311,15 +311,15 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", "INVALID_EFFECT"), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", "INVALID_EFFECT"), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -339,17 +339,17 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "InvalidAtomicFormula", - packageNameAttrs, - /* closed= */ true) + /* tag= */ "InvalidAtomicFormula", + packageNameAttrs, + /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -369,11 +369,11 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -399,17 +399,17 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", versionCodeAttrs, /* closed= */ true) + /* tag= */ "AF", versionCodeAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); Rule expectedRule = new Rule( - new AtomicFormula.IntAtomicFormula( + new AtomicFormula.LongAtomicFormula( AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1), Rule.DENY); @@ -426,17 +426,18 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", preInstalledAttrs, /* closed= */ true) + /* tag= */ "AF", preInstalledAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); Rule expectedRule = new Rule( - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true), Rule.DENY); List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula.getBytes(StandardCharsets.UTF_8)); @@ -452,11 +453,11 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -481,11 +482,11 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -504,11 +505,11 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("BadEffect", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("BadEffect", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -526,16 +527,16 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap( - "BadConnector", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap( + "BadConnector", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -555,11 +556,11 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -577,15 +578,15 @@ public class RuleXmlParserTest { atomicFormulaAttrs.put("V", "com.app.test"); String ruleXmlWithNoRuleList = generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + "</OF>" + "</R>"; RuleParser xmlParser = new RuleXmlParser(); @@ -603,15 +604,15 @@ public class RuleXmlParserTest { atomicFormulaAttrs.put("V", "com.app.test"); String ruleXmlWithNoRuleList = generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + "</OF>" + "</R>"; RuleParser xmlParser = new RuleXmlParser(); diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java index e5cbeee2860d..f3da286585fd 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java @@ -42,13 +42,12 @@ import static com.google.common.truth.Truth.assertThat; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; +import android.content.integrity.IntegrityUtils; import android.content.integrity.Rule; import androidx.annotation.NonNull; -import com.android.server.integrity.IntegrityUtils; - import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -424,11 +423,12 @@ public class RuleBinarySerializerTest { @Test public void testBinaryString_serializeValidAtomicFormula_integerValue() throws Exception { - int versionCode = 1; + long versionCode = 1; Rule rule = new Rule( - new AtomicFormula.IntAtomicFormula( - AtomicFormula.VERSION_CODE, AtomicFormula.EQ, versionCode), + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.EQ, + versionCode), Rule.DENY); RuleSerializer binarySerializer = new RuleBinarySerializer(); String expectedBits = @@ -436,7 +436,7 @@ public class RuleBinarySerializerTest { + ATOMIC_FORMULA_START_BITS + VERSION_CODE + EQ - + getBits(versionCode, /* numOfBits= */ 32) + + getBits(versionCode, /* numOfBits= */ 64) + DENY + END_BIT; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); @@ -456,7 +456,8 @@ public class RuleBinarySerializerTest { String preInstalled = "1"; Rule rule = new Rule( - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true), Rule.DENY); RuleSerializer binarySerializer = new RuleBinarySerializer(); String expectedBits = @@ -481,7 +482,7 @@ public class RuleBinarySerializerTest { @Test public void testBinaryString_serializeInvalidFormulaType() throws Exception { - Formula invalidFormula = getInvalidFormula(); + IntegrityFormula invalidFormula = getInvalidFormula(); Rule rule = new Rule(invalidFormula, Rule.DENY); RuleSerializer binarySerializer = new RuleBinarySerializer(); @@ -858,16 +859,16 @@ public class RuleBinarySerializerTest { + END_BIT; } - private static Formula getInvalidFormula() { - return new Formula() { + private static IntegrityFormula getInvalidFormula() { + return new AtomicFormula(0) { @Override - public boolean isSatisfied(AppInstallMetadata appInstallMetadata) { - return false; + public int getTag() { + return 0; } @Override - public int getTag() { - return 0; + public boolean matches(AppInstallMetadata appInstallMetadata) { + return false; } @Override diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java index 1674422f3af9..038ab7ff0c35 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java @@ -27,7 +27,7 @@ import static com.google.common.truth.Truth.assertThat; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import androidx.annotation.NonNull; @@ -71,9 +71,11 @@ public class RuleIndexingDetailsIdentifierTest { SAMPLE_INSTALLER_CERTIFICATE, /* isHashedValue= */ false); private static final AtomicFormula ATOMIC_FORMULA_WITH_VERSION_CODE = - new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 12); + new AtomicFormula.LongAtomicFormula(AtomicFormula.VERSION_CODE, + AtomicFormula.EQ, 12); private static final AtomicFormula ATOMIC_FORMULA_WITH_ISPREINSTALLED = - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, /* booleanValue= */ + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, /* booleanValue= */ true); @@ -284,16 +286,16 @@ public class RuleIndexingDetailsIdentifierTest { Rule.DENY); } - private Formula getInvalidFormula() { - return new Formula() { + private IntegrityFormula getInvalidFormula() { + return new AtomicFormula(0) { @Override - public boolean isSatisfied(AppInstallMetadata appInstallMetadata) { - return false; + public int getTag() { + return 4; } @Override - public int getTag() { - return 4; + public boolean matches(AppInstallMetadata appInstallMetadata) { + return false; } @Override diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java index ff7722c07d29..6558cd538638 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java @@ -23,7 +23,7 @@ import static org.junit.Assert.assertEquals; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import androidx.annotation.NonNull; @@ -328,7 +328,7 @@ public class RuleXmlSerializerTest { public void testXmlString_serializeValidAtomicFormula_integerValue() throws Exception { Rule rule = new Rule( - new AtomicFormula.IntAtomicFormula( + new AtomicFormula.LongAtomicFormula( AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1), Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); @@ -384,7 +384,7 @@ public class RuleXmlSerializerTest { @Test public void testXmlString_serializeInvalidFormulaType() throws Exception { - Formula invalidFormula = getInvalidFormula(); + IntegrityFormula invalidFormula = getInvalidFormula(); Rule rule = new Rule(invalidFormula, Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); @@ -530,16 +530,16 @@ public class RuleXmlSerializerTest { + "</R>"; } - private Formula getInvalidFormula() { - return new Formula() { + private IntegrityFormula getInvalidFormula() { + return new AtomicFormula(0) { @Override - public boolean isSatisfied(AppInstallMetadata appInstallMetadata) { - return false; + public int getTag() { + return 0; } @Override - public int getTag() { - return 0; + public boolean matches(AppInstallMetadata appInstallMetadata) { + return false; } @Override diff --git a/services/tests/servicestests/src/com/android/server/integrity/utils/TestUtils.java b/services/tests/servicestests/src/com/android/server/integrity/utils/TestUtils.java index e54410b04b79..55abc7c1050d 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/utils/TestUtils.java +++ b/services/tests/servicestests/src/com/android/server/integrity/utils/TestUtils.java @@ -18,8 +18,8 @@ package com.android.server.integrity.utils; public class TestUtils { - public static String getBits(int component, int numOfBits) { - return String.format("%" + numOfBits + "s", Integer.toBinaryString(component)) + public static String getBits(long component, int numOfBits) { + return String.format("%" + numOfBits + "s", Long.toBinaryString(component)) .replace(' ', '0'); } diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index 8329227360e7..cf51fa31fad3 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -20,6 +20,8 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; +import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS; +import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND; import static android.content.res.Resources.ID_NULL; import static org.hamcrest.CoreMatchers.is; @@ -217,6 +219,7 @@ public class PackageManagerSettingsTests { assertThat(params.dialogInfo.getTitleResId(), is(ID_NULL)); assertThat(params.dialogInfo.getIconResId(), is(TEST_RESOURCE_ID)); assertThat(params.dialogInfo.getNeutralButtonTextResId(), is(ID_NULL)); + assertThat(params.dialogInfo.getNeutralButtonAction(), is(BUTTON_ACTION_MORE_DETAILS)); assertThat(params.dialogInfo.getDialogMessageResId(), is(ID_NULL)); } @@ -243,12 +246,14 @@ public class PackageManagerSettingsTests { .setTitle(0x11220002) .setMessage("1st message") .setNeutralButtonText(0x11220003) + .setNeutralButtonAction(BUTTON_ACTION_MORE_DETAILS) .build(); final SuspendDialogInfo dialogInfo2 = new SuspendDialogInfo.Builder() .setIcon(0x22220001) .setTitle(0x22220002) .setMessage("2nd message") .setNeutralButtonText(0x22220003) + .setNeutralButtonAction(BUTTON_ACTION_UNSUSPEND) .build(); ps1.addOrUpdateSuspension("suspendingPackage1", dialogInfo1, appExtras1, launcherExtras1, diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java index 7eccd6728533..322e448d983f 100644 --- a/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java @@ -16,6 +16,9 @@ package com.android.server.pm; +import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS; +import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; @@ -39,7 +42,8 @@ public class SuspendDialogInfoTest { .setIcon(VALID_TEST_RES_ID_1) .setTitle(VALID_TEST_RES_ID_1) .setMessage(VALID_TEST_RES_ID_1) - .setNeutralButtonText(VALID_TEST_RES_ID_1); + .setNeutralButtonText(VALID_TEST_RES_ID_1) + .setNeutralButtonAction(BUTTON_ACTION_MORE_DETAILS); } @Test @@ -73,6 +77,25 @@ public class SuspendDialogInfoTest { } @Test + public void equalsComparesButtonAction() { + final SuspendDialogInfo.Builder dialogBuilder1 = createDefaultDialogBuilder(); + final SuspendDialogInfo.Builder dialogBuilder2 = createDefaultDialogBuilder(); + assertEquals(dialogBuilder1.build(), dialogBuilder2.build()); + // Only button action is different + dialogBuilder2.setNeutralButtonAction(BUTTON_ACTION_UNSUSPEND); + assertNotEquals(dialogBuilder1.build(), dialogBuilder2.build()); + } + + @Test + public void defaultButtonAction() { + final SuspendDialogInfo.Builder dialogBuilder = new SuspendDialogInfo.Builder() + .setIcon(VALID_TEST_RES_ID_1) + .setTitle(VALID_TEST_RES_ID_1) + .setMessage(VALID_TEST_RES_ID_1); + assertEquals(BUTTON_ACTION_MORE_DETAILS, dialogBuilder.build().getNeutralButtonAction()); + } + + @Test public void equalsComparesMessageIds() { final SuspendDialogInfo.Builder dialogBuilder1 = createDefaultDialogBuilder(); final SuspendDialogInfo.Builder dialogBuilder2 = createDefaultDialogBuilder(); diff --git a/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java b/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java index f1b2ef811885..5d849c114e69 100644 --- a/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java @@ -92,6 +92,9 @@ public class IntervalStatsTests { case UsageEvents.Event.NOTIFICATION_INTERRUPTION: event.mNotificationChannelId = "channel" + (i % 5); //"random" channel break; + case UsageEvents.Event.LOCUS_ID_SET: + event.mLocusId = "locus" + (i % 7); //"random" locus + break; } intervalStats.addEvent(event); diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java index e6bb244ef05b..f1c39067994c 100644 --- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java +++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java @@ -52,6 +52,7 @@ import java.util.Set; public class UsageStatsDatabaseTest { private static final int MAX_TESTED_VERSION = 5; + private static final int OLDER_VERSION_MAX_EVENT_TYPE = 29; protected Context mContext; private UsageStatsDatabase mUsageStatsDatabase; private File mTestDir; @@ -79,7 +80,7 @@ public class UsageStatsDatabaseTest { mUsageStatsDatabase = new UsageStatsDatabase(mTestDir); mUsageStatsDatabase.readMappingsLocked(); mUsageStatsDatabase.init(1); - populateIntervalStats(); + populateIntervalStats(MAX_TESTED_VERSION); clearUsageStatsFiles(); } @@ -117,7 +118,7 @@ public class UsageStatsDatabaseTest { return sb.toString(); } - private void populateIntervalStats() { + private void populateIntervalStats(int minVersion) { final int numberOfEvents = 3000; final int timeProgression = 23; long time = System.currentTimeMillis() - (numberOfEvents*timeProgression); @@ -147,9 +148,12 @@ public class UsageStatsDatabaseTest { final int instanceId = i % 11; event.mClass = ".fake.class.name" + instanceId; event.mTimeStamp = time; - event.mEventType = i % (MAX_EVENT_TYPE + 1); //"random" event type event.mInstanceId = instanceId; + int maxEventType = (minVersion < 5) ? OLDER_VERSION_MAX_EVENT_TYPE : MAX_EVENT_TYPE; + event.mEventType = i % (maxEventType + 1); //"random" event type + + final int rootPackageInt = (i % 5); // 5 "apps" start each task event.mTaskRootPackage = "fake.package.name" + rootPackageInt; @@ -174,6 +178,9 @@ public class UsageStatsDatabaseTest { //"random" channel event.mNotificationChannelId = "channel" + (i % 5); break; + case Event.LOCUS_ID_SET: + event.mLocusId = "locus" + (i % 7); //"random" locus + break; } mIntervalStats.addEvent(event); @@ -281,6 +288,10 @@ public class UsageStatsDatabaseTest { assertEquals(e1.mNotificationChannelIdToken, e2.mNotificationChannelIdToken, "Usage event " + debugId); break; + case Event.LOCUS_ID_SET: + assertEquals(e1.mLocusIdToken, e2.mLocusIdToken, + "Usage event " + debugId); + break; } // fallthrough case 4: // test fields added in version 4 @@ -392,6 +403,7 @@ public class UsageStatsDatabaseTest { * version and read the automatically upgraded files on disk in the new file format. */ void runVersionChangeTest(int oldVersion, int newVersion, int interval) throws IOException { + populateIntervalStats(oldVersion); // Write IntervalStats to disk in old version format UsageStatsDatabase prevDB = new UsageStatsDatabase(mTestDir, oldVersion); prevDB.readMappingsLocked(); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index 587cfbf062fb..651ad40a4781 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -98,6 +98,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { NotificationUsageStats mUsageStats; @Mock IAccessibilityManager mAccessibilityService; + NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake(); private NotificationManagerService mService; private String mPkg = "com.android.server.notification"; @@ -148,7 +149,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verify(mAccessibilityService).addClient(any(IAccessibilityManagerClient.class), anyInt()); assertTrue(accessibilityManager.isEnabled()); - mService = spy(new NotificationManagerService(getContext())); + mService = spy(new NotificationManagerService(getContext(), mNotificationRecordLogger)); mService.setAudioManager(mAudioManager); mService.setVibrator(mVibrator); mService.setSystemReady(true); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 93e09dfb3f57..1b92abef7c94 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -256,6 +256,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { UserManager mUm; @Mock NotificationHistoryManager mHistoryManager; + NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake(); + // Use a Testable subclass so we can simulate calls from the system without failing. private static class TestableNotificationManagerService extends NotificationManagerService { @@ -265,8 +267,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Nullable NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback; - TestableNotificationManagerService(Context context) { - super(context); + TestableNotificationManagerService(Context context, NotificationRecordLogger logger) { + super(context, logger); } @Override @@ -353,7 +355,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); - mService = new TestableNotificationManagerService(mContext); + mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger); // Use this testable looper. mTestableLooper = TestableLooper.get(this); @@ -1118,6 +1120,61 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testEnqueueNotificationWithTag_WritesExpectedLog() throws Exception { + final String tag = "testEnqueueNotificationWithTag_WritesExpectedLog"; + mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0, + generateNotificationRecord(null).getNotification(), 0); + waitForIdle(); + assertEquals(1, mNotificationRecordLogger.getCalls().size()); + NotificationRecordLoggerFake.CallRecord call = mNotificationRecordLogger.get(0); + assertTrue(call.shouldLog()); + assertNotNull(call.r); + assertNull(call.old); + assertEquals(0, call.position); + assertEquals(0, call.buzzBeepBlink); + assertEquals(PKG, call.r.sbn.getPackageName()); + assertEquals(0, call.r.sbn.getId()); + assertEquals(tag, call.r.sbn.getTag()); + } + + @Test + public void testEnqueueNotificationWithTag_LogsOnMajorUpdates() throws Exception { + final String tag = "testEnqueueNotificationWithTag_LogsOnMajorUpdates"; + Notification original = new Notification.Builder(mContext, + mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon).build(); + mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0, original, 0); + Notification update = new Notification.Builder(mContext, + mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setCategory(Notification.CATEGORY_ALARM).build(); + mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0, update, 0); + waitForIdle(); + assertEquals(2, mNotificationRecordLogger.getCalls().size()); + assertTrue(mNotificationRecordLogger.get(0).shouldLog()); + assertEquals( + NotificationRecordLogger.NotificationReportedEvents.NOTIFICATION_POSTED, + mNotificationRecordLogger.get(0).getUiEvent()); + assertEquals( + NotificationRecordLogger.NotificationReportedEvents.NOTIFICATION_UPDATED, + mNotificationRecordLogger.get(1).getUiEvent()); + assertTrue(mNotificationRecordLogger.get(1).shouldLog()); + } + + @Test + public void testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdates() throws Exception { + final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdates"; + mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0, + generateNotificationRecord(null).getNotification(), 0); + mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0, + generateNotificationRecord(null).getNotification(), 0); + waitForIdle(); + assertEquals(2, mNotificationRecordLogger.getCalls().size()); + assertTrue(mNotificationRecordLogger.get(0).shouldLog()); + assertFalse(mNotificationRecordLogger.get(1).shouldLog()); + } + + @Test public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception { mBinderService.enqueueNotificationWithTag(PKG, PKG, "testCancelNotificationImmediatelyAfterEnqueue", 0, @@ -2252,7 +2309,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testHasCompanionDevice_noService() { - mService = new TestableNotificationManagerService(mContext); + mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger); assertFalse(mService.hasCompanionDevice(mListener)); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java new file mode 100644 index 000000000000..11972fd6a8dc --- /dev/null +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java @@ -0,0 +1,53 @@ +/* + * 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.server.notification; + +import java.util.ArrayList; +import java.util.List; + +/** + * Fake implementation of NotificationRecordLogger, for testing. + */ +class NotificationRecordLoggerFake implements NotificationRecordLogger { + class CallRecord extends NotificationRecordPair { + public int position, buzzBeepBlink; + CallRecord(NotificationRecord r, NotificationRecord old, int position, + int buzzBeepBlink) { + super(r, old); + this.position = position; + this.buzzBeepBlink = buzzBeepBlink; + } + boolean shouldLog() { + return shouldLog(buzzBeepBlink); + } + } + List<CallRecord> mCalls = new ArrayList<CallRecord>(); + + List<CallRecord> getCalls() { + return mCalls; + } + + CallRecord get(int index) { + return mCalls.get(index); + } + + @Override + public void logNotificationReported(NotificationRecord r, NotificationRecord old, + int position, int buzzBeepBlink) { + mCalls.add(new CallRecord(r, old, position, buzzBeepBlink)); + } +} diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java index c828f02901b3..e18c8919b645 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java @@ -18,7 +18,6 @@ package com.android.server.notification; import static android.app.role.RoleManager.ROLE_DIALER; import static android.app.role.RoleManager.ROLE_EMERGENCY; -import static android.app.role.RoleManager.ROLE_SMS; import static android.content.pm.PackageManager.MATCH_ALL; import static junit.framework.Assert.assertFalse; @@ -92,24 +91,20 @@ public class RoleObserverTest extends UiServiceTestCase { private Executor mExecutor; @Mock private RoleManager mRoleManager; + NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake(); private List<UserInfo> mUsers; private static class TestableNotificationManagerService extends NotificationManagerService { - - TestableNotificationManagerService(Context context) { - super(context); + TestableNotificationManagerService(Context context, NotificationRecordLogger logger) { + super(context, logger); } @Override - protected void handleSavePolicyFile() { - return; - } + protected void handleSavePolicyFile() { } @Override - protected void loadPolicyFile() { - return; - } + protected void loadPolicyFile() { } } @Before @@ -125,7 +120,7 @@ public class RoleObserverTest extends UiServiceTestCase { mUsers.add(new UserInfo(10, "second", 0)); when(mUm.getUsers()).thenReturn(mUsers); - mService = new TestableNotificationManagerService(mContext); + mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger); mRoleObserver = mService.new RoleObserver(mRoleManager, mPm, mExecutor); try { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java index 135d00586329..399cf49ac06f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java @@ -16,7 +16,6 @@ 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; @@ -45,7 +44,6 @@ 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; @@ -107,8 +105,6 @@ public class ActivityStartInterceptorTest { private PackageManagerService mPackageManager; @Mock private ActivityManagerInternal mAmInternal; - @Mock - private LockTaskController mLockTaskController; private ActivityStartInterceptor mInterceptor; private ActivityInfo mAInfo = new ActivityInfo(); @@ -149,13 +145,6 @@ 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; @@ -207,18 +196,6 @@ public class ActivityStartInterceptorTest { } @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 when(mUserManager.isQuietModeEnabled(eq(UserHandle.of(TEST_USER_ID)))).thenReturn(true); diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java index 75ec53d69a71..039ff604f3f1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java @@ -29,9 +29,6 @@ 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; @@ -696,38 +693,6 @@ 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)); - - // WHEN lock task mode is enabled - Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED); - mLockTaskController.startLockTaskMode(tr, false, TEST_UID); - - - // 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); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java index eb8eb98fd484..d73830468359 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java @@ -31,6 +31,7 @@ import android.graphics.Rect; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; +import android.view.Surface; import android.view.View; import androidx.test.filters.MediumTest; @@ -47,7 +48,7 @@ import java.util.function.Predicate; * Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader} * * Build/Install/Run: - * atest WmTests:TaskSnapshotPersisterLoaderTest + * atest TaskSnapshotPersisterLoaderTest */ @MediumTest @Presubmit @@ -316,4 +317,18 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")}; assertTrueForFiles(existsFiles, File::exists, " must exist"); } + + @Test + public void testRotationPersistAndLoadSnapshot() { + TaskSnapshot a = new TaskSnapshotBuilder() + .setRotation(Surface.ROTATION_270) + .build(); + mPersister.persistSnapshot(1 , mTestUserId, createSnapshot()); + mPersister.persistSnapshot(2 , mTestUserId, a); + mPersister.waitForQueueEmpty(); + final TaskSnapshot snapshotA = mLoader.loadTask(1, mTestUserId, false /* reduced */); + final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */); + assertEquals(Surface.ROTATION_0, snapshotA.getRotation()); + assertEquals(Surface.ROTATION_270, snapshotB.getRotation()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java index f7496229f66b..f86c9e63dc48 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java @@ -32,6 +32,7 @@ import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.UserManager; +import android.view.Surface; import org.junit.After; import org.junit.Before; @@ -93,6 +94,7 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { private boolean mIsTranslucent = false; private int mWindowingMode = WINDOWING_MODE_FULLSCREEN; private int mSystemUiVisibility = 0; + private int mRotation = Surface.ROTATION_0; TaskSnapshotBuilder setScale(float scale) { mScale = scale; @@ -124,6 +126,11 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { return this; } + TaskSnapshotBuilder setRotation(int rotation) { + mRotation = rotation; + return this; + } + TaskSnapshot build() { final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888, USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY); @@ -131,7 +138,8 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { c.drawColor(Color.RED); buffer.unlockCanvasAndPost(c); return new TaskSnapshot(MOCK_SNAPSHOT_ID, new ComponentName("", ""), buffer, - ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, TEST_INSETS, + ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, + mRotation, TEST_INSETS, mReducedResolution, mScale, mIsRealSnapshot, mWindowingMode, mSystemUiVisibility, mIsTranslucent); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java index ed87f3a0c604..bb0e5aec8e2e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java @@ -40,6 +40,7 @@ import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; +import android.view.Surface; import android.view.SurfaceControl; import androidx.test.filters.SmallTest; @@ -69,7 +70,8 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { final TaskSnapshot snapshot = new TaskSnapshot( System.currentTimeMillis(), new ComponentName("", ""), buffer, - ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, contentInsets, false, + ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, + Surface.ROTATION_0, contentInsets, false, 1.0f, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */); mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test", diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java index 8fb283adc740..8fadf5eb9333 100644 --- a/services/usage/java/com/android/server/usage/IntervalStats.java +++ b/services/usage/java/com/android/server/usage/IntervalStats.java @@ -28,6 +28,7 @@ import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START; import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_STOP; import static android.app.usage.UsageEvents.Event.KEYGUARD_HIDDEN; import static android.app.usage.UsageEvents.Event.KEYGUARD_SHOWN; +import static android.app.usage.UsageEvents.Event.LOCUS_ID_SET; import static android.app.usage.UsageEvents.Event.NOTIFICATION_INTERRUPTION; import static android.app.usage.UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE; import static android.app.usage.UsageEvents.Event.SCREEN_INTERACTIVE; @@ -568,6 +569,16 @@ public class IntervalStats { continue; } break; + case LOCUS_ID_SET: + event.mLocusId = packagesTokenData.getString(packageToken, event.mLocusIdToken); + if (event.mLocusId == null) { + Slog.e(TAG, "Unable to parse locus " + event.mLocusIdToken + + " for package " + packageToken); + this.events.remove(i); + dataOmitted = true; + continue; + } + break; } } return dataOmitted; @@ -675,6 +686,12 @@ public class IntervalStats { packageToken, event.mPackage, event.mNotificationChannelId); } break; + case LOCUS_ID_SET: + if (!TextUtils.isEmpty(event.mLocusId)) { + event.mLocusIdToken = packagesTokenData.getTokenOrAdd(packageToken, + event.mPackage, event.mLocusId); + } + break; } } } diff --git a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java index fe5da923597e..e4aa9fe0dc1e 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java +++ b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java @@ -277,6 +277,10 @@ final class UsageStatsProtoV2 { event.mTaskRootClassToken = proto.readInt( EventObfuscatedProto.TASK_ROOT_CLASS_TOKEN) - 1; break; + case (int) EventObfuscatedProto.LOCUS_ID_TOKEN: + event.mLocusIdToken = proto.readInt( + EventObfuscatedProto.LOCUS_ID_TOKEN) - 1; + break; case ProtoInputStream.NO_MORE_FIELDS: // timeStamp was not read, assume default value 0 plus beginTime if (event.mTimeStamp == 0) { @@ -398,6 +402,11 @@ final class UsageStatsProtoV2 { proto.write(EventObfuscatedProto.SHORTCUT_ID_TOKEN, event.mShortcutIdToken + 1); } break; + case UsageEvents.Event.LOCUS_ID_SET: + if (event.mLocusIdToken != PackagesTokenData.UNASSIGNED_TOKEN) { + proto.write(EventObfuscatedProto.LOCUS_ID_TOKEN, event.mLocusIdToken + 1); + } + break; case UsageEvents.Event.NOTIFICATION_INTERRUPTION: if (event.mNotificationChannelIdToken != PackagesTokenData.UNASSIGNED_TOKEN) { proto.write(EventObfuscatedProto.NOTIFICATION_CHANNEL_ID_TOKEN, diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 5119e5824f7f..9a18f8cd3a46 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -21,6 +21,7 @@ import static android.app.usage.UsageEvents.Event.CONFIGURATION_CHANGE; import static android.app.usage.UsageEvents.Event.DEVICE_EVENT_PACKAGE_NAME; import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN; import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK; +import static android.app.usage.UsageEvents.Event.LOCUS_ID_SET; import static android.app.usage.UsageEvents.Event.NOTIFICATION_INTERRUPTION; import static android.app.usage.UsageEvents.Event.SHORTCUT_INVOCATION; import static android.app.usage.UsageEvents.Event.USER_STOPPED; @@ -30,6 +31,8 @@ import static android.app.usage.UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVIT import android.Manifest; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.IUidObserver; @@ -52,6 +55,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.LocusId; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; @@ -1987,6 +1991,17 @@ public class UsageStatsService extends SystemService implements } @Override + public void reportLocusUpdate(@NonNull ComponentName activity, @UserIdInt int userId, + @Nullable LocusId locusId, @NonNull IBinder appToken) { + Event event = new Event(LOCUS_ID_SET, SystemClock.elapsedRealtime()); + event.mLocusId = locusId.getId(); + event.mPackage = activity.getPackageName(); + event.mClass = activity.getClassName(); + event.mInstanceId = appToken.hashCode(); + reportEventOrAddToQueue(userId, event); + } + + @Override public void reportContentProviderUsage(String name, String packageName, int userId) { mAppStandby.postReportContentProviderUsage(name, packageName, userId); } diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java index 56c342ee72ca..553bcff931d2 100644 --- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java +++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java @@ -20,12 +20,10 @@ import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.os.RemoteException; import android.os.UserHandle; -import android.permission.IPermissionManager; +import android.permission.PermissionManager; import android.provider.Settings; import android.telephony.TelephonyManager; import android.util.ArrayMap; @@ -76,7 +74,6 @@ public final class CarrierAppUtils { * privileged apps may have changed. */ public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, - IPackageManager packageManager, IPermissionManager permissionManager, TelephonyManager telephonyManager, int userId, Context context) { if (DEBUG) { Log.d(TAG, "disableCarrierAppsUntilPrivileged"); @@ -87,14 +84,14 @@ public final class CarrierAppUtils { ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed = config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps(); ContentResolver contentResolver = getContentResolverForUser(context, userId); - disableCarrierAppsUntilPrivileged(callingPackage, packageManager, permissionManager, - telephonyManager, contentResolver, userId, systemCarrierAppsDisabledUntilUsed, - systemCarrierAssociatedAppsDisabledUntilUsed); + disableCarrierAppsUntilPrivileged(callingPackage, telephonyManager, contentResolver, + userId, systemCarrierAppsDisabledUntilUsed, + systemCarrierAssociatedAppsDisabledUntilUsed, context); } /** - * Like {@link #disableCarrierAppsUntilPrivileged(String, IPackageManager, TelephonyManager, - * ContentResolver, int)}, but assumes that no carrier apps have carrier privileges. + * Like {@link #disableCarrierAppsUntilPrivileged(String, TelephonyManager, int, Context)}, + * but assumes that no carrier apps have carrier privileges. * * This prevents a potential race condition on first boot - since the app's default state is * enabled, we will initially disable it when the telephony stack is first initialized as it has @@ -104,8 +101,7 @@ public final class CarrierAppUtils { * Manager can kill it, and this can lead to crashes as the app is in an unexpected state. */ public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, - IPackageManager packageManager, IPermissionManager permissionManager, int userId, - Context context) { + int userId, Context context) { if (DEBUG) { Log.d(TAG, "disableCarrierAppsUntilPrivileged"); } @@ -113,13 +109,12 @@ public final class CarrierAppUtils { ArraySet<String> systemCarrierAppsDisabledUntilUsed = config.getDisabledUntilUsedPreinstalledCarrierApps(); - ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed = config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps(); ContentResolver contentResolver = getContentResolverForUser(context, userId); - disableCarrierAppsUntilPrivileged(callingPackage, packageManager, permissionManager, - null /* telephonyManager */, contentResolver, userId, - systemCarrierAppsDisabledUntilUsed, systemCarrierAssociatedAppsDisabledUntilUsed); + disableCarrierAppsUntilPrivileged(callingPackage, null /* telephonyManager */, + contentResolver, userId, systemCarrierAppsDisabledUntilUsed, + systemCarrierAssociatedAppsDisabledUntilUsed, context); } private static ContentResolver getContentResolverForUser(Context context, int userId) { @@ -135,21 +130,21 @@ public final class CarrierAppUtils { // Must be public b/c framework unit tests can't access package-private methods. @VisibleForTesting public static void disableCarrierAppsUntilPrivileged(String callingPackage, - IPackageManager packageManager, IPermissionManager permissionManager, - @Nullable TelephonyManager telephonyManager, - ContentResolver contentResolver, int userId, - ArraySet<String> systemCarrierAppsDisabledUntilUsed, - ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) { + @Nullable TelephonyManager telephonyManager, ContentResolver contentResolver, + int userId, ArraySet<String> systemCarrierAppsDisabledUntilUsed, + ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed, + Context context) { + PackageManager packageManager = context.getPackageManager(); + PermissionManager permissionManager = + (PermissionManager) context.getSystemService(Context.PERMISSION_SERVICE); List<ApplicationInfo> candidates = getDefaultNotUpdatedCarrierAppCandidatesHelper( - packageManager, userId, systemCarrierAppsDisabledUntilUsed); + userId, systemCarrierAppsDisabledUntilUsed, context); if (candidates == null || candidates.isEmpty()) { return; } Map<String, List<ApplicationInfo>> associatedApps = getDefaultCarrierAssociatedAppsHelper( - packageManager, - userId, - systemCarrierAssociatedAppsDisabledUntilUsed); + userId, systemCarrierAssociatedAppsDisabledUntilUsed, context); List<String> enabledCarrierPackages = new ArrayList<>(); boolean hasRunOnce = Settings.Secure.getInt(contentResolver, @@ -166,19 +161,18 @@ public final class CarrierAppUtils { && !ArrayUtils.contains(restrictedCarrierApps, packageName); // add hiddenUntilInstalled flag for carrier apps and associated apps - packageManager.setSystemAppHiddenUntilInstalled(packageName, true); + packageManager.setSystemAppState( + packageName, PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN); List<ApplicationInfo> associatedAppList = associatedApps.get(packageName); if (associatedAppList != null) { for (ApplicationInfo associatedApp : associatedAppList) { - packageManager.setSystemAppHiddenUntilInstalled( - associatedApp.packageName, - true - ); + packageManager.setSystemAppState(associatedApp.packageName, + PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN); } } - int enabledSetting = packageManager.getApplicationEnabledSetting(packageName, - userId); + int enabledSetting = context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager().getApplicationEnabledSetting(packageName); if (hasPrivileges) { // Only update enabled state for the app on /system. Once it has been // updated we shouldn't touch it. @@ -189,24 +183,25 @@ public final class CarrierAppUtils { || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { Log.i(TAG, "Update state(" + packageName + "): ENABLED for user " + userId); - packageManager.setSystemAppInstallState( - packageName, - true /*installed*/, - userId); - packageManager.setApplicationEnabledSetting( - packageName, - PackageManager.COMPONENT_ENABLED_STATE_ENABLED, - PackageManager.DONT_KILL_APP, - userId, - callingPackage); + context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .setSystemAppState( + packageName, PackageManager.SYSTEM_APP_STATE_INSTALLED); + context.createPackageContextAsUser(callingPackage, 0, UserHandle.of(userId)) + .getPackageManager() + .setApplicationEnabledSetting( + packageName, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); } // Also enable any associated apps for this carrier app. if (associatedAppList != null) { for (ApplicationInfo associatedApp : associatedAppList) { - int associatedAppEnabledSetting = - packageManager.getApplicationEnabledSetting( - associatedApp.packageName, userId); + int associatedAppEnabledSetting = context + .createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .getApplicationEnabledSetting(associatedApp.packageName); if (associatedAppEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT || associatedAppEnabledSetting @@ -215,16 +210,17 @@ public final class CarrierAppUtils { & ApplicationInfo.FLAG_INSTALLED) == 0) { Log.i(TAG, "Update associated state(" + associatedApp.packageName + "): ENABLED for user " + userId); - packageManager.setSystemAppInstallState( - associatedApp.packageName, - true /*installed*/, - userId); - packageManager.setApplicationEnabledSetting( - associatedApp.packageName, - PackageManager.COMPONENT_ENABLED_STATE_ENABLED, - PackageManager.DONT_KILL_APP, - userId, - callingPackage); + context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .setSystemAppState(associatedApp.packageName, + PackageManager.SYSTEM_APP_STATE_INSTALLED); + context.createPackageContextAsUser( + callingPackage, 0, UserHandle.of(userId)) + .getPackageManager() + .setApplicationEnabledSetting( + associatedApp.packageName, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); } } } @@ -239,10 +235,10 @@ public final class CarrierAppUtils { && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { Log.i(TAG, "Update state(" + packageName + "): DISABLED_UNTIL_USED for user " + userId); - packageManager.setSystemAppInstallState( - packageName, - false /*installed*/, - userId); + context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .setSystemAppState( + packageName, PackageManager.SYSTEM_APP_STATE_UNINSTALLED); } // Also disable any associated apps for this carrier app if this is the first @@ -251,9 +247,10 @@ public final class CarrierAppUtils { if (!hasRunOnce) { if (associatedAppList != null) { for (ApplicationInfo associatedApp : associatedAppList) { - int associatedAppEnabledSetting = - packageManager.getApplicationEnabledSetting( - associatedApp.packageName, userId); + int associatedAppEnabledSetting = context + .createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .getApplicationEnabledSetting(associatedApp.packageName); if (associatedAppEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT && (associatedApp.flags @@ -261,10 +258,10 @@ public final class CarrierAppUtils { Log.i(TAG, "Update associated state(" + associatedApp.packageName + "): DISABLED_UNTIL_USED for user " + userId); - packageManager.setSystemAppInstallState( - associatedApp.packageName, - false /*installed*/, - userId); + context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .setSystemAppState(associatedApp.packageName, + PackageManager.SYSTEM_APP_STATE_UNINSTALLED); } } } @@ -282,9 +279,10 @@ public final class CarrierAppUtils { // apps. String[] packageNames = new String[enabledCarrierPackages.size()]; enabledCarrierPackages.toArray(packageNames); - permissionManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId); + permissionManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, + UserHandle.of(userId), Runnable::run, isSuccess -> { }); } - } catch (RemoteException e) { + } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Could not reach PackageManager", e); } } @@ -293,13 +291,13 @@ public final class CarrierAppUtils { * Returns the list of "default" carrier apps. * * This is the subset of apps returned by - * {@link #getDefaultCarrierAppCandidates(IPackageManager, int)} which currently have carrier + * {@link #getDefaultCarrierAppCandidates(int, Context)} which currently have carrier * privileges per the SIM(s) inserted in the device. */ - public static List<ApplicationInfo> getDefaultCarrierApps(IPackageManager packageManager, - TelephonyManager telephonyManager, int userId) { + public static List<ApplicationInfo> getDefaultCarrierApps( + TelephonyManager telephonyManager, int userId, Context context) { // Get all system apps from the default list. - List<ApplicationInfo> candidates = getDefaultCarrierAppCandidates(packageManager, userId); + List<ApplicationInfo> candidates = getDefaultCarrierAppCandidates(userId, context); if (candidates == null || candidates.isEmpty()) { return null; } @@ -325,25 +323,23 @@ public final class CarrierAppUtils { * Returns the list of "default" carrier app candidates. * * These are the apps subject to the hiding/showing logic in - * {@link CarrierAppUtils#disableCarrierAppsUntilPrivileged(String, IPackageManager, - * TelephonyManager, ContentResolver, int)}, as well as the apps which should have default + * {@link CarrierAppUtils#disableCarrierAppsUntilPrivileged(String, TelephonyManager, int, + * Context)}, as well as the apps which should have default * permissions granted, when a matching SIM is inserted. * * Whether or not the app is actually considered a default app depends on whether the app has * carrier privileges as determined by the SIMs in the device. */ public static List<ApplicationInfo> getDefaultCarrierAppCandidates( - IPackageManager packageManager, int userId) { + int userId, Context context) { ArraySet<String> systemCarrierAppsDisabledUntilUsed = SystemConfig.getInstance().getDisabledUntilUsedPreinstalledCarrierApps(); - return getDefaultCarrierAppCandidatesHelper(packageManager, userId, - systemCarrierAppsDisabledUntilUsed); + return getDefaultCarrierAppCandidatesHelper(userId, systemCarrierAppsDisabledUntilUsed, + context); } private static List<ApplicationInfo> getDefaultCarrierAppCandidatesHelper( - IPackageManager packageManager, - int userId, - ArraySet<String> systemCarrierAppsDisabledUntilUsed) { + int userId, ArraySet<String> systemCarrierAppsDisabledUntilUsed, Context context) { if (systemCarrierAppsDisabledUntilUsed == null) { return null; } @@ -357,7 +353,7 @@ public final class CarrierAppUtils { for (int i = 0; i < size; i++) { String packageName = systemCarrierAppsDisabledUntilUsed.valueAt(i); ApplicationInfo ai = - getApplicationInfoIfSystemApp(packageManager, userId, packageName); + getApplicationInfoIfSystemApp(userId, packageName, context); if (ai != null) { apps.add(ai); } @@ -366,9 +362,7 @@ public final class CarrierAppUtils { } private static List<ApplicationInfo> getDefaultNotUpdatedCarrierAppCandidatesHelper( - IPackageManager packageManager, - int userId, - ArraySet<String> systemCarrierAppsDisabledUntilUsed) { + int userId, ArraySet<String> systemCarrierAppsDisabledUntilUsed, Context context) { if (systemCarrierAppsDisabledUntilUsed == null) { return null; } @@ -382,7 +376,7 @@ public final class CarrierAppUtils { for (int i = 0; i < size; i++) { String packageName = systemCarrierAppsDisabledUntilUsed.valueAt(i); ApplicationInfo ai = - getApplicationInfoIfNotUpdatedSystemApp(packageManager, userId, packageName); + getApplicationInfoIfNotUpdatedSystemApp(userId, packageName, context); if (ai != null) { apps.add(ai); } @@ -391,9 +385,8 @@ public final class CarrierAppUtils { } private static Map<String, List<ApplicationInfo>> getDefaultCarrierAssociatedAppsHelper( - IPackageManager packageManager, - int userId, - ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) { + int userId, ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed, + Context context) { int size = systemCarrierAssociatedAppsDisabledUntilUsed.size(); Map<String, List<ApplicationInfo>> associatedApps = new ArrayMap<>(size); for (int i = 0; i < size; i++) { @@ -403,7 +396,7 @@ public final class CarrierAppUtils { for (int j = 0; j < associatedAppPackages.size(); j++) { ApplicationInfo ai = getApplicationInfoIfNotUpdatedSystemApp( - packageManager, userId, associatedAppPackages.get(j)); + userId, associatedAppPackages.get(j), context); // Only update enabled state for the app on /system. Once it has been updated we // shouldn't touch it. if (ai != null) { @@ -421,19 +414,19 @@ public final class CarrierAppUtils { @Nullable private static ApplicationInfo getApplicationInfoIfNotUpdatedSystemApp( - IPackageManager packageManager, - int userId, - String packageName) { + int userId, String packageName, Context context) { try { - ApplicationInfo ai = packageManager.getApplicationInfo(packageName, - PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS - | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS - | PackageManager.MATCH_SYSTEM_ONLY - | PackageManager.MATCH_FACTORY_ONLY, userId); + ApplicationInfo ai = context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .getApplicationInfo(packageName, + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS + | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS + | PackageManager.MATCH_SYSTEM_ONLY + | PackageManager.MATCH_FACTORY_ONLY); if (ai != null) { return ai; } - } catch (RemoteException e) { + } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Could not reach PackageManager", e); } return null; @@ -441,18 +434,18 @@ public final class CarrierAppUtils { @Nullable private static ApplicationInfo getApplicationInfoIfSystemApp( - IPackageManager packageManager, - int userId, - String packageName) { + int userId, String packageName, Context context) { try { - ApplicationInfo ai = packageManager.getApplicationInfo(packageName, - PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS - | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS - | PackageManager.MATCH_SYSTEM_ONLY, userId); + ApplicationInfo ai = context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .getApplicationInfo(packageName, + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS + | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS + | PackageManager.MATCH_SYSTEM_ONLY); if (ai != null) { return ai; } - } catch (RemoteException e) { + } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Could not reach PackageManager", e); } return null; diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 1d89665c1670..86913a636913 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -7348,6 +7348,30 @@ public class TelephonyManager { } } + + /** + * Resets the {@link android.telephony.ims.ImsService} associated with the specified sim slot. + * Used by diagnostic apps to force the IMS stack to be disabled and re-enabled in an effort to + * recover from scenarios where the {@link android.telephony.ims.ImsService} gets in to a bad + * state. + * + * @param slotIndex the sim slot to reset the IMS stack on. + * @hide */ + @SystemApi + @WorkerThread + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void resetIms(int slotIndex) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + telephony.resetIms(slotIndex); + } + } catch (RemoteException e) { + Rlog.e(TAG, "toggleImsOnOff, RemoteException: " + + e.getMessage()); + } + } + /** * Enables IMS for the framework. This will trigger IMS registration and ImsFeature capability * status updates, if not already enabled. diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 6aa5a52d55d5..3f573c92d022 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -831,6 +831,11 @@ interface ITelephony { void disableIms(int slotId); /** + * Toggle framework IMS disables and enables. + */ + void resetIms(int slotIndex); + + /** * Get IImsMmTelFeature binder from ImsResolver that corresponds to the subId and MMTel feature * as well as registering the MmTelFeature for callbacks using the IImsServiceFeatureCallback * interface. diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java index 797fd83321f7..3e4f3d818840 100644 --- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java @@ -269,6 +269,7 @@ public class NetworkCapabilitiesTest { .setUids(uids) .addCapability(NET_CAPABILITY_EIMS) .addCapability(NET_CAPABILITY_NOT_METERED); + netCap.setOwnerUid(123); assertParcelingIsLossless(netCap); netCap.setSSID(TEST_SSID); assertParcelSane(netCap, 13); diff --git a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java index 065add4fc253..7ab4b56fae80 100644 --- a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java +++ b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java @@ -16,6 +16,8 @@ package android.net; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsBinder; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport; import static android.net.ConnectivityDiagnosticsManager.DataStallReport; @@ -25,12 +27,19 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import android.os.PersistableBundle; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.Mock; + +import java.util.concurrent.Executor; @RunWith(JUnit4.class) public class ConnectivityDiagnosticsManagerTest { @@ -41,6 +50,19 @@ public class ConnectivityDiagnosticsManagerTest { private static final String BUNDLE_KEY = "key"; private static final String BUNDLE_VALUE = "value"; + private static final Executor INLINE_EXECUTOR = x -> x.run(); + + @Mock private ConnectivityDiagnosticsCallback mCb; + + private ConnectivityDiagnosticsBinder mBinder; + + @Before + public void setUp() { + mCb = mock(ConnectivityDiagnosticsCallback.class); + + mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR); + } + private ConnectivityReport createSampleConnectivityReport() { final LinkProperties linkProperties = new LinkProperties(); linkProperties.setInterfaceName(INTERFACE_NAME); @@ -193,4 +215,34 @@ public class ConnectivityDiagnosticsManagerTest { public void testDataStallReportParcelUnparcel() { assertParcelSane(createSampleDataStallReport(), 4); } + + @Test + public void testConnectivityDiagnosticsCallbackOnConnectivityReport() { + mBinder.onConnectivityReport(createSampleConnectivityReport()); + + // The callback will be invoked synchronously by inline executor. Immediately check the + // latch without waiting. + verify(mCb).onConnectivityReport(eq(createSampleConnectivityReport())); + } + + @Test + public void testConnectivityDiagnosticsCallbackOnDataStallSuspected() { + mBinder.onDataStallSuspected(createSampleDataStallReport()); + + // The callback will be invoked synchronously by inline executor. Immediately check the + // latch without waiting. + verify(mCb).onDataStallSuspected(eq(createSampleDataStallReport())); + } + + @Test + public void testConnectivityDiagnosticsCallbackOnNetworkConnectivityReported() { + final Network n = new Network(NET_ID); + final boolean connectivity = true; + + mBinder.onNetworkConnectivityReported(n, connectivity); + + // The callback will be invoked synchronously by inline executor. Immediately check the + // latch without waiting. + verify(mCb).onNetworkConnectivityReported(eq(n), eq(connectivity)); + } } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 09cc69e83f41..a0a1352a6330 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -6313,12 +6313,24 @@ public class ConnectivityServiceTest { assertEquals(wifiLp, mService.getActiveLinkProperties()); } + @Test + public void testNetworkCapabilitiesRestrictedForCallerPermissions() { + int callerUid = Process.myUid(); + final NetworkCapabilities originalNc = new NetworkCapabilities(); + originalNc.setOwnerUid(callerUid); + + final NetworkCapabilities newNc = + mService.networkCapabilitiesRestrictedForCallerPermissions( + originalNc, Process.myPid(), callerUid); + + assertEquals(Process.INVALID_UID, newNc.getOwnerUid()); + } - private TestNetworkAgentWrapper establishVpn(LinkProperties lp, int establishingUid, - Set<UidRange> vpnRange) throws Exception { + private TestNetworkAgentWrapper establishVpn( + LinkProperties lp, int ownerUid, Set<UidRange> vpnRange) throws Exception { final TestNetworkAgentWrapper vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp); - vpnNetworkAgent.getNetworkCapabilities().setEstablishingVpnAppUid(establishingUid); + vpnNetworkAgent.getNetworkCapabilities().setOwnerUid(ownerUid); mMockVpn.setNetworkAgent(vpnNetworkAgent); mMockVpn.connect(); mMockVpn.setUids(vpnRange); diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 114e0fa21296..0ef224a5f8ee 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -481,12 +481,14 @@ public class WifiConfiguration implements Parcelable { allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X); break; case SECURITY_TYPE_SAE: + allowedProtocols.set(WifiConfiguration.Protocol.RSN); allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE); allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); requirePMF = true; break; case SECURITY_TYPE_EAP_SUITE_B: + allowedProtocols.set(WifiConfiguration.Protocol.RSN); allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192); allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256); allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256); @@ -496,6 +498,7 @@ public class WifiConfiguration implements Parcelable { requirePMF = true; break; case SECURITY_TYPE_OWE: + allowedProtocols.set(WifiConfiguration.Protocol.RSN); allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE); allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); |