diff options
95 files changed, 2662 insertions, 1087 deletions
diff --git a/Android.bp b/Android.bp index 3dd8a0a66b14..8daee86c6ac2 100644 --- a/Android.bp +++ b/Android.bp @@ -1680,16 +1680,13 @@ filegroup { } filegroup { - name: "framework-wifistack-shared-srcs", + name: "framework-wifi-service-shared-srcs", srcs: [ ":framework-annotations", "core/java/android/os/HandlerExecutor.java", "core/java/android/util/BackupUtils.java", - "core/java/android/util/KeyValueListParser.java", "core/java/android/util/LocalLog.java", "core/java/android/util/Rational.java", - "core/java/android/util/proto/ProtoStream.java", - "core/java/android/util/proto/ProtoOutputStream.java", "core/java/com/android/internal/util/FastXmlSerializer.java", "core/java/com/android/internal/util/HexDump.java", "core/java/com/android/internal/util/IState.java", diff --git a/TEST_MAPPING b/TEST_MAPPING index 55fa5ed13d79..b1c4cad72dc9 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -7,6 +7,22 @@ "exclude-annotation": "androidx.test.filters.FlakyTest" } ] + }, + { + "name": "ExtServicesUnitTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + }, + { + "name": "TestablesTests", + "options": [ + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] } ], "postsubmit-managedprofile-stress": [ diff --git a/apex/statsd/aidl/android/os/IStatsManager.aidl b/apex/statsd/aidl/android/os/IStatsManager.aidl index 5ebb9f2e4e90..cc62f07a3750 100644 --- a/apex/statsd/aidl/android/os/IStatsManager.aidl +++ b/apex/statsd/aidl/android/os/IStatsManager.aidl @@ -240,7 +240,7 @@ interface IStatsManager { * Logs an event for watchdog rollbacks. */ oneway void sendWatchdogRollbackOccurredAtom(in int rollbackType, in String packageName, - in long packageVersionCode); + in long packageVersionCode, in int rollbackReason, in String failingPackageName); /** * Returns the most recently registered experiment IDs. 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 c9139b15f223..6fb3bc47859d 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -41,6 +41,7 @@ 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; @@ -139,6 +140,7 @@ import com.android.server.LocalServices; import com.android.server.SystemService; 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.IonMemoryUtil.IonAllocations; import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot; @@ -1750,14 +1752,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { if (statsFiles.size() != 1) { return; } - InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream( - statsFiles.get(0)); - int[] len = new int[1]; - byte[] stats = readFully(stream, len); - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, - wallClockNanos); - e.writeStorage(Arrays.copyOf(stats, len[0])); - pulledData.add(e); + unpackStreamedData(tagId, elapsedNanos, wallClockNanos, pulledData, statsFiles); new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark).delete(); new File( @@ -1773,6 +1768,52 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } + private INotificationManager mNotificationManager = + INotificationManager.Stub.asInterface( + ServiceManager.getService(Context.NOTIFICATION_SERVICE)); + + private void pullNotificationStats(int reportId, int tagId, long elapsedNanos, + long wallClockNanos, + List<StatsLogEventWrapper> pulledData) { + final long callingToken = Binder.clearCallingIdentity(); + try { + // determine last pull tine. Copy file trick from pullProcessStats? + long lastNotificationStatsNs = wallClockNanos - + TimeUnit.NANOSECONDS.convert(1, TimeUnit.DAYS); + + List<ParcelFileDescriptor> statsFiles = new ArrayList<>(); + long notificationStatsNs = mNotificationManager.pullStats( + lastNotificationStatsNs, reportId, true, statsFiles); + if (statsFiles.size() != 1) { + return; + } + unpackStreamedData(tagId, elapsedNanos, wallClockNanos, pulledData, statsFiles); + } catch (IOException e) { + Log.e(TAG, "Getting notistats failed: ", e); + + } catch (RemoteException e) { + Log.e(TAG, "Getting notistats failed: ", e); + } catch (SecurityException e) { + Log.e(TAG, "Getting notistats failed: ", e); + } finally { + Binder.restoreCallingIdentity(callingToken); + } + + } + + static void unpackStreamedData(int tagId, long elapsedNanos, long wallClockNanos, + List<StatsLogEventWrapper> pulledData, List<ParcelFileDescriptor> statsFiles) + throws IOException { + InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream( + statsFiles.get(0)); + int[] len = new int[1]; + byte[] stats = readFully(stream, len); + StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, + wallClockNanos); + e.writeStorage(Arrays.copyOf(stats, len[0])); + pulledData.add(e); + } + static byte[] readFully(InputStream stream, int[] outLen) throws IOException { int pos = 0; final int initialAvail = stream.available(); @@ -2621,6 +2662,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullAppOps(elapsedNanos, wallClockNanos, ret); break; } + case StatsLog.NOTIFICATION_REMOTE_VIEWS: { + pullNotificationStats(NotificationManagerService.REPORT_REMOTE_VIEWS, + tagId, elapsedNanos, wallClockNanos, ret); + break; + } default: Slog.w(TAG, "No such tagId data as " + tagId); return null; diff --git a/api/current.txt b/api/current.txt index 4c4895c5bcb6..d05ef8cea53a 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6834,7 +6834,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 boolean resetPassword(String, int); + 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); method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(@NonNull android.content.ComponentName); diff --git a/api/system-current.txt b/api/system-current.txt index e46c60f5ec47..217943c519af 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1331,8 +1331,22 @@ package android.app.usage { package android.bluetooth { public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile { + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void disableOptionalCodecs(@Nullable android.bluetooth.BluetoothDevice); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void enableOptionalCodecs(@Nullable android.bluetooth.BluetoothDevice); + method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothDevice getActiveDevice(); + method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothCodecStatus getCodecStatus(@Nullable android.bluetooth.BluetoothDevice); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int getOptionalCodecsEnabled(@Nullable android.bluetooth.BluetoothDevice); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setCodecConfigPreference(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothCodecConfig); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setOptionalCodecsEnabled(@Nullable android.bluetooth.BluetoothDevice, int); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int supportsOptionalCodecs(@Nullable android.bluetooth.BluetoothDevice); + field public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0; // 0x0 + field public static final int OPTIONAL_CODECS_PREF_DISABLED = 0; // 0x0 + field public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; // 0x1 + field public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1; // 0xffffffff + field public static final int OPTIONAL_CODECS_SUPPORTED = 1; // 0x1 + field public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1; // 0xffffffff } public final class BluetoothAdapter { @@ -1361,6 +1375,52 @@ package android.bluetooth { method public void onMetadataChanged(@NonNull android.bluetooth.BluetoothDevice, int, @Nullable byte[]); } + public final class BluetoothCodecConfig implements android.os.Parcelable { + ctor public BluetoothCodecConfig(int, int, int, int, int, long, long, long, long); + ctor public BluetoothCodecConfig(int); + method public int getBitsPerSample(); + method @NonNull public String getCodecName(); + method public int getCodecPriority(); + method public long getCodecSpecific1(); + method public int getCodecType(); + method public int getSampleRate(); + method public boolean isMandatoryCodec(); + field public static final int BITS_PER_SAMPLE_16 = 1; // 0x1 + field public static final int BITS_PER_SAMPLE_24 = 2; // 0x2 + field public static final int BITS_PER_SAMPLE_32 = 4; // 0x4 + field public static final int BITS_PER_SAMPLE_NONE = 0; // 0x0 + field public static final int CHANNEL_MODE_MONO = 1; // 0x1 + field public static final int CHANNEL_MODE_NONE = 0; // 0x0 + field public static final int CHANNEL_MODE_STEREO = 2; // 0x2 + field public static final int CODEC_PRIORITY_DEFAULT = 0; // 0x0 + field public static final int CODEC_PRIORITY_DISABLED = -1; // 0xffffffff + field public static final int CODEC_PRIORITY_HIGHEST = 1000000; // 0xf4240 + field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecConfig> CREATOR; + field public static final int SAMPLE_RATE_176400 = 16; // 0x10 + field public static final int SAMPLE_RATE_192000 = 32; // 0x20 + field public static final int SAMPLE_RATE_44100 = 1; // 0x1 + field public static final int SAMPLE_RATE_48000 = 2; // 0x2 + field public static final int SAMPLE_RATE_88200 = 4; // 0x4 + field public static final int SAMPLE_RATE_96000 = 8; // 0x8 + field public static final int SAMPLE_RATE_NONE = 0; // 0x0 + field public static final int SOURCE_CODEC_TYPE_AAC = 1; // 0x1 + field public static final int SOURCE_CODEC_TYPE_APTX = 2; // 0x2 + field public static final int SOURCE_CODEC_TYPE_APTX_HD = 3; // 0x3 + field public static final int SOURCE_CODEC_TYPE_INVALID = 1000000; // 0xf4240 + field public static final int SOURCE_CODEC_TYPE_LDAC = 4; // 0x4 + field public static final int SOURCE_CODEC_TYPE_MAX = 5; // 0x5 + field public static final int SOURCE_CODEC_TYPE_SBC = 0; // 0x0 + } + + public final class BluetoothCodecStatus implements android.os.Parcelable { + ctor public BluetoothCodecStatus(@Nullable android.bluetooth.BluetoothCodecConfig, @Nullable android.bluetooth.BluetoothCodecConfig[], @Nullable android.bluetooth.BluetoothCodecConfig[]); + method @Nullable public android.bluetooth.BluetoothCodecConfig getCodecConfig(); + method @Nullable public android.bluetooth.BluetoothCodecConfig[] getCodecsLocalCapabilities(); + method @Nullable public android.bluetooth.BluetoothCodecConfig[] getCodecsSelectableCapabilities(); + field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecStatus> CREATOR; + field public static final String EXTRA_CODEC_STATUS = "android.bluetooth.extra.CODEC_STATUS"; + } + public final class BluetoothDevice implements android.os.Parcelable { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess(); method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int); @@ -6624,7 +6684,7 @@ package android.os.connectivity { } public final class WifiActivityEnergyInfo implements android.os.Parcelable { - ctor public WifiActivityEnergyInfo(long, int, long, long, long, long, long); + ctor public WifiActivityEnergyInfo(long, int, long, long, long, long); method public int describeContents(); method public long getControllerEnergyUsedMicroJoules(); method public long getControllerIdleDurationMillis(); @@ -7243,6 +7303,10 @@ package android.provider { field public static final String SUB_ID = "sub_id"; } + public static final class Telephony.SimInfo { + field @NonNull public static final android.net.Uri CONTENT_URI; + } + public static final class Telephony.Sms.Intents { field public static final String ACTION_SMS_EMERGENCY_CB_RECEIVED = "android.provider.action.SMS_EMERGENCY_CB_RECEIVED"; } diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index d10a661c6d83..3c5ad4231133 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -1417,7 +1417,10 @@ Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& tra Status StatsService::sendWatchdogRollbackOccurredAtom(const int32_t rollbackTypeIn, const android::String16& packageNameIn, - const int64_t packageVersionCodeIn) { + const int64_t packageVersionCodeIn, + const int32_t rollbackReasonIn, + const android::String16& + failingPackageNameIn) { // Note: We skip the usage stats op check here since we do not have a package name. // This is ok since we are overloading the usage_stats permission. // This method only sends data, it does not receive it. @@ -1439,7 +1442,8 @@ Status StatsService::sendWatchdogRollbackOccurredAtom(const int32_t rollbackType } android::util::stats_write(android::util::WATCHDOG_ROLLBACK_OCCURRED, - rollbackTypeIn, String8(packageNameIn).string(), packageVersionCodeIn); + rollbackTypeIn, String8(packageNameIn).string(), packageVersionCodeIn, + rollbackReasonIn, String8(failingPackageNameIn).string()); // Fast return to save disk read. if (rollbackTypeIn != android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 8c98e7b96936..50b1014f4e8a 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -214,7 +214,9 @@ public: virtual Status sendWatchdogRollbackOccurredAtom( const int32_t rollbackTypeIn, const android::String16& packageNameIn, - const int64_t packageVersionCodeIn) override; + const int64_t packageVersionCodeIn, + const int32_t rollbackReasonIn, + const android::String16& failingPackageNameIn) override; /** * Binder call to get registered experiment IDs. diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 2efb78943812..f1ea4c9e0c68 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -112,7 +112,7 @@ message Atom { TouchEventReported touch_event_reported = 34; WakeupAlarmOccurred wakeup_alarm_occurred = 35; KernelWakeupReported kernel_wakeup_reported = 36; - WifiLockStateChanged wifi_lock_state_changed = 37; + WifiLockStateChanged wifi_lock_state_changed = 37 [(log_from_module) = "wifi"]; WifiSignalStrengthChanged wifi_signal_strength_changed = 38; WifiScanStateChanged wifi_scan_state_changed = 39; PhoneSignalStrengthChanged phone_signal_strength_changed = 40; @@ -356,7 +356,7 @@ message Atom { } // Pulled events will start at field 10000. - // Next: 10065 + // Next: 10067 oneof pulled { WifiBytesTransfer wifi_bytes_transfer = 10000; WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001; @@ -423,6 +423,7 @@ message Atom { SurfaceflingerStatsLayerInfo surfaceflinger_stats_layer_info = 10063; ProcessMemorySnapshot process_memory_snapshot = 10064; VmsClientStats vms_client_stats = 10065; + NotificationRemoteViews notification_remote_views = 10066; } // DO NOT USE field numbers above 100,000 in AOSP. @@ -1742,6 +1743,19 @@ message WatchdogRollbackOccurred { optional string package_name = 2; optional int32 package_version_code = 3; + + enum RollbackReasonType { + REASON_UNKNOWN = 0; + REASON_NATIVE_CRASH = 1; + REASON_EXPLICIT_HEALTH_CHECK = 2; + REASON_APP_CRASH = 3; + REASON_APP_NOT_RESPONDING = 4; + } + optional RollbackReasonType rollback_reason = 4; + + // Set by RollbackPackageHealthObserver to be the package that is failing when a rollback + // is initiated. Empty if the package is unknown. + optional string failing_package_name = 5; } /** @@ -4947,6 +4961,24 @@ message ProcStatsPkgProc { optional ProcessStatsSectionProto proc_stats_section = 1; } +// Next Tag: 2 +message PackageRemoteViewInfoProto { + optional string package_name = 1; + // add per-package additional info here (like channels) +} + +// Next Tag: 2 +message NotificationRemoteViewsProto { + repeated PackageRemoteViewInfoProto package_remote_view_info = 1; +} + +/** + * Pulled from NotificationManagerService.java + */ +message NotificationRemoteViews { + optional NotificationRemoteViewsProto notification_remote_views = 1; +} + message PowerProfileProto { optional double cpu_suspend = 1; @@ -5960,6 +5992,8 @@ message PermissionGrantRequestResultReported { IGNORED_RESTRICTED_PERMISSION = 9; // one time permission was granted by user action USER_GRANTED_ONE_TIME = 10; + // user ignored request by leaving the request screen without choosing any option + USER_IGNORED = 11; } // The result of the permission grant optional Result result = 6; diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index b5bad0530503..615af89e3186 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -281,6 +281,9 @@ std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { {{.atomTag = android::util::VMS_CLIENT_STATS}, {.additiveFields = {5, 6, 7, 8, 9, 10}, .puller = new CarStatsPuller(android::util::VMS_CLIENT_STATS)}}, + // NotiifcationRemoteViews. + {{.atomTag = android::util::NOTIFICATION_REMOTE_VIEWS}, + {.puller = new StatsCompanionServicePuller(android::util::NOTIFICATION_REMOTE_VIEWS)}}, }; StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 0957dba4eac1..86f52af1a13b 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -207,4 +207,6 @@ interface INotificationManager void setPrivateNotificationsAllowed(boolean allow); boolean getPrivateNotificationsAllowed(); + + long pullStats(long startNs, int report, boolean doAgg, out List<ParcelFileDescriptor> stats); } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 34ceb08f39bf..915e4572c035 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -3742,17 +3742,35 @@ public class DevicePolicyManager { /** * Force a new password for device unlock (the password needed to access the entire device) or * the work profile challenge on the current user. This takes effect immediately. - * <p> - * <em>For device owner and profile owners targeting SDK level - * {@link android.os.Build.VERSION_CODES#O} or above, this API is no longer available and will - * throw {@link SecurityException}. Please use the new API {@link #resetPasswordWithToken} - * instead. </em> - * <p> - * <em>Note: This API has been limited as of {@link android.os.Build.VERSION_CODES#N} for - * device admins that are not device owner and not profile owner. - * The password can now only be changed if there is currently no password set. Device owner - * and profile owner can still do this when user is unlocked and does not have a managed - * profile.</em> + * + * <p> Before {@link android.os.Build.VERSION_CODES#N}, this API is available to device admin, + * profile owner and device owner. Starting from {@link android.os.Build.VERSION_CODES#N}, + * legacy device admin (who is not also profile owner or device owner) can only call this + * API to set a new password if there is currently no password set. Profile owner and device + * owner can continue to force change an existing password as long as the target user is + * unlocked, although device owner will not be able to call this API at all if there is also a + * managed profile on the device. + * + * <p> Between {@link android.os.Build.VERSION_CODES#O}, + * {@link android.os.Build.VERSION_CODES#P} and {@link android.os.Build.VERSION_CODES#Q}, + * profile owner and devices owner targeting SDK level {@link android.os.Build.VERSION_CODES#O} + * or above who attempt to call this API will receive {@link SecurityException}; they are + * encouraged to migrate to the new {@link #resetPasswordWithToken} API instead. + * Profile owner and device owner targeting older SDK levels are not affected: they continue + * to experience the existing behaviour described in the previous paragraph. + * + * <p><em>Starting from {@link android.os.Build.VERSION_CODES#R}, this API is no longer + * supported in most cases.</em> Device owner and profile owner calling + * this API will receive {@link SecurityException} if they target SDK level + * {@link android.os.Build.VERSION_CODES#O} or above, or they will receive a silent failure + * (API returning {@code false}) if they target lower SDK level. + * For legacy device admins, this API throws {@link SecurityException} if they target SDK level + * {@link android.os.Build.VERSION_CODES#N} or above, and returns {@code false} otherwise. Only + * privileged apps holding RESET_PASSWORD permission which are part of + * the system factory image can still call this API to set a new password if there is currently + * no password set. In this case, if the device already has a password, this API will throw + * {@link SecurityException}. + * * <p> * The given password must be sufficient for the current password quality and length constraints * as returned by {@link #getPasswordQuality(ComponentName)} and @@ -3760,12 +3778,7 @@ public class DevicePolicyManager { * it will be rejected and false returned. Note that the password may be a stronger quality * (containing alphanumeric characters when the requested quality is only numeric), in which * case the currently active quality will be increased to match. - * <p> - * Calling with a null or empty password will clear any existing PIN, pattern or password if the - * current password constraints allow it. <em>Note: This will not work in - * {@link android.os.Build.VERSION_CODES#N} and later for managed profiles, or for device admins - * that are not device owner or profile owner. Once set, the password cannot be changed to null - * or empty except by these admins.</em> + * * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, this * methods does nothing. * <p> @@ -3777,11 +3790,13 @@ public class DevicePolicyManager { * @param flags May be 0 or combination of {@link #RESET_PASSWORD_REQUIRE_ENTRY} and * {@link #RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT}. * @return Returns true if the password was applied, or false if it is not acceptable for the - * current constraints or if the user has not been decrypted yet. + * current constraints. * @throws SecurityException if the calling application does not own an active administrator * that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} * @throws IllegalStateException if the calling user is locked or has a managed profile. + * @deprecated Please use {@link #resetPasswordWithToken} instead. */ + @Deprecated @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) public boolean resetPassword(String password, int flags) { throwIfParentInstance("resetPassword"); @@ -5555,7 +5570,12 @@ public class DevicePolicyManager { * device, for this user. After setting this, no applications running as this user will be able * to access any cameras on the device. * <p> - * If the caller is device owner, then the restriction will be applied to all users. + * This method can be called on the {@link DevicePolicyManager} instance, + * returned by {@link #getParentProfileInstance(ComponentName)}, where the caller must be + * the profile owner of an organization-owned managed profile. + * <p> + * If the caller is device owner or called on the parent instance, then the + * restriction will be applied to all users. * <p> * The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA} to be able to call this method; if it has @@ -5567,10 +5587,9 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA}. */ public void setCameraDisabled(@NonNull ComponentName admin, boolean disabled) { - throwIfParentInstance("setCameraDisabled"); if (mService != null) { try { - mService.setCameraDisabled(admin, disabled); + mService.setCameraDisabled(admin, disabled, mParentInstance); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -5580,11 +5599,15 @@ public class DevicePolicyManager { /** * Determine whether or not the device's cameras have been disabled for this user, * either by the calling admin, if specified, or all admins. + * <p> + * This method can be called on the {@link DevicePolicyManager} instance, + * returned by {@link #getParentProfileInstance(ComponentName)}, where the caller must be + * the profile owner of an organization-owned managed profile. + * * @param admin The name of the admin component to check, or {@code null} to check whether any admins * have disabled the camera */ public boolean getCameraDisabled(@Nullable ComponentName admin) { - throwIfParentInstance("getCameraDisabled"); return getCameraDisabled(admin, myUserId()); } @@ -5593,7 +5616,7 @@ public class DevicePolicyManager { public boolean getCameraDisabled(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getCameraDisabled(admin, userHandle); + return mService.getCameraDisabled(admin, userHandle, mParentInstance); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -7893,7 +7916,8 @@ public class DevicePolicyManager { * for the list of keys. * @throws SecurityException if {@code admin} is not a device or profile owner. */ - public void addUserRestriction(@NonNull ComponentName admin, String key) { + public void addUserRestriction(@NonNull ComponentName admin, + @UserManager.UserRestrictionKey String key) { throwIfParentInstance("addUserRestriction"); if (mService != null) { try { @@ -7915,7 +7939,8 @@ public class DevicePolicyManager { * for the list of keys. * @throws SecurityException if {@code admin} is not a device or profile owner. */ - public void clearUserRestriction(@NonNull ComponentName admin, String key) { + public void clearUserRestriction(@NonNull ComponentName admin, + @UserManager.UserRestrictionKey String key) { throwIfParentInstance("clearUserRestriction"); if (mService != null) { try { @@ -9344,7 +9369,6 @@ public class DevicePolicyManager { * <li>{@link #setPasswordExpirationTimeout}</li> * <li>{@link #getPasswordExpiration}</li> * <li>{@link #getPasswordMaximumLength}</li> - * <li>{@link #getPasswordComplexity}</li> * <li>{@link #isActivePasswordSufficient}</li> * <li>{@link #getCurrentFailedPasswordAttempts}</li> * <li>{@link #getMaximumFailedPasswordsForWipe}</li> @@ -9359,6 +9383,14 @@ public class DevicePolicyManager { * <li>{@link #getRequiredStrongAuthTimeout}</li> * <li>{@link #setRequiredStrongAuthTimeout}</li> * </ul> + * <p> + * The following methods are supported for the parent instance but can only be called by the + * profile owner of a managed profile that was created during the device provisioning flow: + * <ul> + * <li>{@link #getPasswordComplexity}</li> + * <li>{@link #setCameraDisabled}</li> + * <li>{@link #getCameraDisabled}</li> + * </ul> * * <p>The following methods can be called by the profile owner of a managed profile * on an organization-owned device: diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java index 713126ee9341..f299d456a18f 100644 --- a/core/java/android/app/admin/DevicePolicyManagerInternal.java +++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java @@ -145,15 +145,6 @@ public abstract class DevicePolicyManagerInternal { public abstract void reportSeparateProfileChallengeChanged(@UserIdInt int userId); /** - * Check whether the user could have their password reset in an untrusted manor due to there - * being an admin which can call {@link #resetPassword} to reset the password without knowledge - * of the previous password. - * - * @param userId The user in question - */ - public abstract boolean canUserHaveUntrustedCredentialReset(@UserIdInt int userId); - - /** * Return text of error message if printing is disabled. * Called by Print Service when printing is disabled by PO or DO when printing is attempted. * diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index f55026c76906..34246fa808bd 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -114,8 +114,8 @@ interface IDevicePolicyManager { boolean requestBugreport(in ComponentName who); - void setCameraDisabled(in ComponentName who, boolean disabled); - boolean getCameraDisabled(in ComponentName who, int userHandle); + void setCameraDisabled(in ComponentName who, boolean disabled, boolean parent); + boolean getCameraDisabled(in ComponentName who, int userHandle, boolean parent); void setScreenCaptureDisabled(in ComponentName who, boolean disabled); boolean getScreenCaptureDisabled(in ComponentName who, int userHandle); diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 8ed61b6c87e3..64df0e84f6dc 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -17,6 +17,7 @@ package android.bluetooth; import android.Manifest; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -32,6 +33,8 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; @@ -154,13 +157,22 @@ public final class BluetoothA2dp implements BluetoothProfile { */ public static final int STATE_NOT_PLAYING = 11; + /** @hide */ + @IntDef(prefix = "OPTIONAL_CODECS_", value = { + OPTIONAL_CODECS_SUPPORT_UNKNOWN, + OPTIONAL_CODECS_NOT_SUPPORTED, + OPTIONAL_CODECS_SUPPORTED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface OptionalCodecsSupportStatus {} + /** * We don't have a stored preference for whether or not the given A2DP sink device supports * optional codecs. * * @hide */ - @UnsupportedAppUsage + @SystemApi public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1; /** @@ -168,7 +180,7 @@ public final class BluetoothA2dp implements BluetoothProfile { * * @hide */ - @UnsupportedAppUsage + @SystemApi public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0; /** @@ -176,16 +188,25 @@ public final class BluetoothA2dp implements BluetoothProfile { * * @hide */ - @UnsupportedAppUsage + @SystemApi public static final int OPTIONAL_CODECS_SUPPORTED = 1; + /** @hide */ + @IntDef(prefix = "OPTIONAL_CODECS_PREF_", value = { + OPTIONAL_CODECS_PREF_UNKNOWN, + OPTIONAL_CODECS_PREF_DISABLED, + OPTIONAL_CODECS_PREF_ENABLED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface OptionalCodecsPreferenceStatus {} + /** - * We don't have a stored preference for whether optional codecs should be enabled or disabled - * for the given A2DP device. + * We don't have a stored preference for whether optional codecs should be enabled or + * disabled for the given A2DP device. * * @hide */ - @UnsupportedAppUsage + @SystemApi public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1; /** @@ -193,7 +214,7 @@ public final class BluetoothA2dp implements BluetoothProfile { * * @hide */ - @UnsupportedAppUsage + @SystemApi public static final int OPTIONAL_CODECS_PREF_DISABLED = 0; /** @@ -201,7 +222,7 @@ public final class BluetoothA2dp implements BluetoothProfile { * * @hide */ - @UnsupportedAppUsage + @SystemApi public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; private BluetoothAdapter mAdapter; @@ -248,13 +269,12 @@ public final class BluetoothA2dp implements BluetoothProfile { * the state. Users can get the connection state of the profile * from this intent. * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} - * permission. * * @param device Remote Bluetooth Device * @return false on immediate error, true otherwise * @hide */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) @UnsupportedAppUsage public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); @@ -289,13 +309,12 @@ public final class BluetoothA2dp implements BluetoothProfile { * {@link #STATE_DISCONNECTING} can be used to distinguish between the * two scenarios. * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} - * permission. * * @param device Remote Bluetooth Device * @return false on immediate error, true otherwise * @hide */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) @UnsupportedAppUsage public boolean disconnect(BluetoothDevice device) { if (DBG) log("disconnect(" + device + ")"); @@ -384,14 +403,12 @@ public final class BluetoothA2dp implements BluetoothProfile { * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted * with the active device. * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} - * permission. - * * @param device the remote Bluetooth device. Could be null to clear * the active device and stop streaming audio to a Bluetooth device. * @return false on immediate error, true otherwise * @hide */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) @UnsupportedAppUsage public boolean setActiveDevice(@Nullable BluetoothDevice device) { if (DBG) log("setActiveDevice(" + device + ")"); @@ -412,16 +429,13 @@ public final class BluetoothA2dp implements BluetoothProfile { /** * Get the connected device that is active. * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH} - * permission. - * * @return the connected device that is active or null if no device * is active * @hide */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @SystemApi @Nullable - @UnsupportedAppUsage + @RequiresPermission(Manifest.permission.BLUETOOTH) public BluetoothDevice getActiveDevice() { if (VDBG) log("getActiveDevice()"); try { @@ -441,7 +455,7 @@ public final class BluetoothA2dp implements BluetoothProfile { * Set priority of the profile * * <p> The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, + * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF} * * @param device Paired bluetooth device * @param priority @@ -626,8 +640,10 @@ public final class BluetoothA2dp implements BluetoothProfile { * @return the current codec status * @hide */ - @UnsupportedAppUsage - public @Nullable BluetoothCodecStatus getCodecStatus(BluetoothDevice device) { + @SystemApi + @Nullable + @RequiresPermission(Manifest.permission.BLUETOOTH) + public BluetoothCodecStatus getCodecStatus(@Nullable BluetoothDevice device) { if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")"); try { final IBluetoothA2dp service = getService(); @@ -652,9 +668,10 @@ public final class BluetoothA2dp implements BluetoothProfile { * @param codecConfig the codec configuration preference * @hide */ - @UnsupportedAppUsage - public void setCodecConfigPreference(BluetoothDevice device, - BluetoothCodecConfig codecConfig) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public void setCodecConfigPreference(@Nullable BluetoothDevice device, + @Nullable BluetoothCodecConfig codecConfig) { if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")"); try { final IBluetoothA2dp service = getService(); @@ -676,8 +693,9 @@ public final class BluetoothA2dp implements BluetoothProfile { * active A2DP Bluetooth device. * @hide */ - @UnsupportedAppUsage - public void enableOptionalCodecs(BluetoothDevice device) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public void enableOptionalCodecs(@Nullable BluetoothDevice device) { if (DBG) Log.d(TAG, "enableOptionalCodecs(" + device + ")"); enableDisableOptionalCodecs(device, true); } @@ -689,8 +707,9 @@ public final class BluetoothA2dp implements BluetoothProfile { * active A2DP Bluetooth device. * @hide */ - @UnsupportedAppUsage - public void disableOptionalCodecs(BluetoothDevice device) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public void disableOptionalCodecs(@Nullable BluetoothDevice device) { if (DBG) Log.d(TAG, "disableOptionalCodecs(" + device + ")"); enableDisableOptionalCodecs(device, false); } @@ -728,8 +747,10 @@ public final class BluetoothA2dp implements BluetoothProfile { * OPTIONAL_CODECS_SUPPORTED. * @hide */ - @UnsupportedAppUsage - public int supportsOptionalCodecs(BluetoothDevice device) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @OptionalCodecsSupportStatus + public int supportsOptionalCodecs(@Nullable BluetoothDevice device) { try { final IBluetoothA2dp service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { @@ -738,7 +759,7 @@ public final class BluetoothA2dp implements BluetoothProfile { if (service == null) Log.w(TAG, "Proxy not attached to service"); return OPTIONAL_CODECS_SUPPORT_UNKNOWN; } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e); + Log.e(TAG, "Error talking to BT service in supportsOptionalCodecs()", e); return OPTIONAL_CODECS_SUPPORT_UNKNOWN; } } @@ -751,8 +772,10 @@ public final class BluetoothA2dp implements BluetoothProfile { * OPTIONAL_CODECS_PREF_DISABLED. * @hide */ - @UnsupportedAppUsage - public int getOptionalCodecsEnabled(BluetoothDevice device) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @OptionalCodecsPreferenceStatus + public int getOptionalCodecsEnabled(@Nullable BluetoothDevice device) { try { final IBluetoothA2dp service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { @@ -761,7 +784,7 @@ public final class BluetoothA2dp implements BluetoothProfile { if (service == null) Log.w(TAG, "Proxy not attached to service"); return OPTIONAL_CODECS_PREF_UNKNOWN; } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e); + Log.e(TAG, "Error talking to BT service in getOptionalCodecsEnabled()", e); return OPTIONAL_CODECS_PREF_UNKNOWN; } } @@ -775,8 +798,10 @@ public final class BluetoothA2dp implements BluetoothProfile { * OPTIONAL_CODECS_PREF_DISABLED. * @hide */ - @UnsupportedAppUsage - public void setOptionalCodecsEnabled(BluetoothDevice device, int value) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public void setOptionalCodecsEnabled(@Nullable BluetoothDevice device, + @OptionalCodecsPreferenceStatus int value) { try { if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java index c17834aa8e52..cf3367602aa9 100755 --- a/core/java/android/bluetooth/BluetoothA2dpSink.java +++ b/core/java/android/bluetooth/BluetoothA2dpSink.java @@ -320,7 +320,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile { * Set priority of the profile * * <p> The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, + * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF} * * @param device Paired bluetooth device * @param priority diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java index 36f3a1eeba79..08d0797997b5 100644 --- a/core/java/android/bluetooth/BluetoothCodecConfig.java +++ b/core/java/android/bluetooth/BluetoothCodecConfig.java @@ -16,10 +16,15 @@ package android.bluetooth; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** @@ -29,78 +34,131 @@ import java.util.Objects; * * {@hide} */ +@SystemApi public final class BluetoothCodecConfig implements Parcelable { // Add an entry for each source codec here. // NOTE: The values should be same as those listed in the following file: // hardware/libhardware/include/hardware/bt_av.h - @UnsupportedAppUsage + + /** @hide */ + @IntDef(prefix = "SOURCE_CODEC_TYPE_", value = { + SOURCE_CODEC_TYPE_SBC, + SOURCE_CODEC_TYPE_AAC, + SOURCE_CODEC_TYPE_APTX, + SOURCE_CODEC_TYPE_APTX_HD, + SOURCE_CODEC_TYPE_LDAC, + SOURCE_CODEC_TYPE_MAX, + SOURCE_CODEC_TYPE_INVALID + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SourceCodecType {} + public static final int SOURCE_CODEC_TYPE_SBC = 0; - @UnsupportedAppUsage + public static final int SOURCE_CODEC_TYPE_AAC = 1; - @UnsupportedAppUsage + public static final int SOURCE_CODEC_TYPE_APTX = 2; - @UnsupportedAppUsage + public static final int SOURCE_CODEC_TYPE_APTX_HD = 3; - @UnsupportedAppUsage + public static final int SOURCE_CODEC_TYPE_LDAC = 4; - @UnsupportedAppUsage + public static final int SOURCE_CODEC_TYPE_MAX = 5; - @UnsupportedAppUsage + public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000; - @UnsupportedAppUsage + /** @hide */ + @IntDef(prefix = "CODEC_PRIORITY_", value = { + CODEC_PRIORITY_DISABLED, + CODEC_PRIORITY_DEFAULT, + CODEC_PRIORITY_HIGHEST + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CodecPriority {} + public static final int CODEC_PRIORITY_DISABLED = -1; - @UnsupportedAppUsage + public static final int CODEC_PRIORITY_DEFAULT = 0; - @UnsupportedAppUsage + public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000; - @UnsupportedAppUsage + + /** @hide */ + @IntDef(prefix = "SAMPLE_RATE_", value = { + SAMPLE_RATE_NONE, + SAMPLE_RATE_44100, + SAMPLE_RATE_48000, + SAMPLE_RATE_88200, + SAMPLE_RATE_96000, + SAMPLE_RATE_176400, + SAMPLE_RATE_192000 + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SampleRate {} + public static final int SAMPLE_RATE_NONE = 0; - @UnsupportedAppUsage + public static final int SAMPLE_RATE_44100 = 0x1 << 0; - @UnsupportedAppUsage + public static final int SAMPLE_RATE_48000 = 0x1 << 1; - @UnsupportedAppUsage + public static final int SAMPLE_RATE_88200 = 0x1 << 2; - @UnsupportedAppUsage + public static final int SAMPLE_RATE_96000 = 0x1 << 3; - @UnsupportedAppUsage + public static final int SAMPLE_RATE_176400 = 0x1 << 4; - @UnsupportedAppUsage + public static final int SAMPLE_RATE_192000 = 0x1 << 5; - @UnsupportedAppUsage + + /** @hide */ + @IntDef(prefix = "BITS_PER_SAMPLE_", value = { + BITS_PER_SAMPLE_NONE, + BITS_PER_SAMPLE_16, + BITS_PER_SAMPLE_24, + BITS_PER_SAMPLE_32 + }) + @Retention(RetentionPolicy.SOURCE) + public @interface BitsPerSample {} + public static final int BITS_PER_SAMPLE_NONE = 0; - @UnsupportedAppUsage + public static final int BITS_PER_SAMPLE_16 = 0x1 << 0; - @UnsupportedAppUsage + public static final int BITS_PER_SAMPLE_24 = 0x1 << 1; - @UnsupportedAppUsage + public static final int BITS_PER_SAMPLE_32 = 0x1 << 2; - @UnsupportedAppUsage + + /** @hide */ + @IntDef(prefix = "CHANNEL_MODE_", value = { + CHANNEL_MODE_NONE, + CHANNEL_MODE_MONO, + CHANNEL_MODE_STEREO + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ChannelMode {} + public static final int CHANNEL_MODE_NONE = 0; - @UnsupportedAppUsage + public static final int CHANNEL_MODE_MONO = 0x1 << 0; - @UnsupportedAppUsage + public static final int CHANNEL_MODE_STEREO = 0x1 << 1; - private final int mCodecType; - private int mCodecPriority; - private final int mSampleRate; - private final int mBitsPerSample; - private final int mChannelMode; + private final @SourceCodecType int mCodecType; + private @CodecPriority int mCodecPriority; + private final @SampleRate int mSampleRate; + private final @BitsPerSample int mBitsPerSample; + private final @ChannelMode int mChannelMode; private final long mCodecSpecific1; private final long mCodecSpecific2; private final long mCodecSpecific3; private final long mCodecSpecific4; - @UnsupportedAppUsage - public BluetoothCodecConfig(int codecType, int codecPriority, - int sampleRate, int bitsPerSample, - int channelMode, long codecSpecific1, + public BluetoothCodecConfig(@SourceCodecType int codecType, @CodecPriority int codecPriority, + @SampleRate int sampleRate, @BitsPerSample int bitsPerSample, + @ChannelMode int channelMode, long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4) { mCodecType = codecType; @@ -114,8 +172,7 @@ public final class BluetoothCodecConfig implements Parcelable { mCodecSpecific4 = codecSpecific4; } - @UnsupportedAppUsage - public BluetoothCodecConfig(int codecType) { + public BluetoothCodecConfig(@SourceCodecType int codecType) { mCodecType = codecType; mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT; mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE; @@ -144,6 +201,12 @@ public final class BluetoothCodecConfig implements Parcelable { return false; } + /** + * Returns a hash based on the config values + * + * @return a hash based on the config values + * @hide + */ @Override public int hashCode() { return Objects.hash(mCodecType, mCodecPriority, mSampleRate, @@ -155,6 +218,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Checks whether the object contains valid codec configuration. * * @return true if the object contains valid codec configuration, otherwise false. + * @hide */ public boolean isValid() { return (mSampleRate != SAMPLE_RATE_NONE) @@ -242,6 +306,12 @@ public final class BluetoothCodecConfig implements Parcelable { + ",mCodecSpecific4:" + mCodecSpecific4 + "}"; } + /** + * Always returns 0 + * + * @return 0 + * @hide + */ @Override public int describeContents() { return 0; @@ -271,6 +341,14 @@ public final class BluetoothCodecConfig implements Parcelable { } }; + /** + * Flattens the object to a parcel + * + * @param out The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. + * + * @hide + */ @Override public void writeToParcel(Parcel out, int flags) { out.writeInt(mCodecType); @@ -289,7 +367,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @return the codec name */ - public String getCodecName() { + public @NonNull String getCodecName() { switch (mCodecType) { case SOURCE_CODEC_TYPE_SBC: return "SBC"; @@ -315,8 +393,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @return the codec type */ - @UnsupportedAppUsage - public int getCodecType() { + public @SourceCodecType int getCodecType() { return mCodecType; } @@ -336,8 +413,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @return the codec priority */ - @UnsupportedAppUsage - public int getCodecPriority() { + public @CodecPriority int getCodecPriority() { return mCodecPriority; } @@ -347,9 +423,10 @@ public final class BluetoothCodecConfig implements Parcelable { * means higher priority. If 0, reset to default. * * @param codecPriority the codec priority + * @hide */ @UnsupportedAppUsage - public void setCodecPriority(int codecPriority) { + public void setCodecPriority(@CodecPriority int codecPriority) { mCodecPriority = codecPriority; } @@ -366,8 +443,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @return the codec sample rate */ - @UnsupportedAppUsage - public int getSampleRate() { + public @SampleRate int getSampleRate() { return mSampleRate; } @@ -381,8 +457,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @return the codec bits per sample */ - @UnsupportedAppUsage - public int getBitsPerSample() { + public @BitsPerSample int getBitsPerSample() { return mBitsPerSample; } @@ -394,9 +469,10 @@ public final class BluetoothCodecConfig implements Parcelable { * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_STEREO} * * @return the codec channel mode + * @hide */ @UnsupportedAppUsage - public int getChannelMode() { + public @ChannelMode int getChannelMode() { return mChannelMode; } @@ -405,7 +481,6 @@ public final class BluetoothCodecConfig implements Parcelable { * * @return a codec specific value1. */ - @UnsupportedAppUsage public long getCodecSpecific1() { return mCodecSpecific1; } @@ -414,6 +489,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Gets a codec specific value2. * * @return a codec specific value2 + * @hide */ @UnsupportedAppUsage public long getCodecSpecific2() { @@ -424,6 +500,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Gets a codec specific value3. * * @return a codec specific value3 + * @hide */ @UnsupportedAppUsage public long getCodecSpecific3() { @@ -434,6 +511,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Gets a codec specific value4. * * @return a codec specific value4 + * @hide */ @UnsupportedAppUsage public long getCodecSpecific4() { @@ -445,6 +523,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @param valueSet the value set presented by a bitmask * @return true if the valueSet contains zero or single bit, otherwise false. + * @hide */ private static boolean hasSingleBit(int valueSet) { return (valueSet == 0 || (valueSet & (valueSet - 1)) == 0); @@ -454,6 +533,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Checks whether the object contains none or single sample rate. * * @return true if the object contains none or single sample rate, otherwise false. + * @hide */ public boolean hasSingleSampleRate() { return hasSingleBit(mSampleRate); @@ -463,6 +543,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Checks whether the object contains none or single bits per sample. * * @return true if the object contains none or single bits per sample, otherwise false. + * @hide */ public boolean hasSingleBitsPerSample() { return hasSingleBit(mBitsPerSample); @@ -472,6 +553,7 @@ public final class BluetoothCodecConfig implements Parcelable { * Checks whether the object contains none or single channel mode. * * @return true if the object contains none or single channel mode, otherwise false. + * @hide */ public boolean hasSingleChannelMode() { return hasSingleBit(mChannelMode); @@ -482,6 +564,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @param other the codec config to compare against * @return true if the audio feeding parameters are same, otherwise false + * @hide */ public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) { return (other != null && other.mSampleRate == mSampleRate @@ -495,6 +578,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @param other the codec config to compare against * @return true if the audio feeding parameters are similar, otherwise false. + * @hide */ public boolean similarCodecFeedingParameters(BluetoothCodecConfig other) { if (other == null || mCodecType != other.mCodecType) { @@ -526,6 +610,7 @@ public final class BluetoothCodecConfig implements Parcelable { * * @param other the codec config to compare against * @return true if the codec specific parameters are the same, otherwise false. + * @hide */ public boolean sameCodecSpecificParameters(BluetoothCodecConfig other) { if (other == null && mCodecType != other.mCodecType) { diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java index 58a764a85bed..b6e77391da5d 100644 --- a/core/java/android/bluetooth/BluetoothCodecStatus.java +++ b/core/java/android/bluetooth/BluetoothCodecStatus.java @@ -17,7 +17,7 @@ package android.bluetooth; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -32,6 +32,7 @@ import java.util.Objects; * * {@hide} */ +@SystemApi public final class BluetoothCodecStatus implements Parcelable { /** * Extra for the codec configuration intents of the individual profiles. @@ -39,17 +40,16 @@ public final class BluetoothCodecStatus implements Parcelable { * This extra represents the current codec status of the A2DP * profile. */ - @UnsupportedAppUsage public static final String EXTRA_CODEC_STATUS = - "android.bluetooth.codec.extra.CODEC_STATUS"; + "android.bluetooth.extra.CODEC_STATUS"; private final @Nullable BluetoothCodecConfig mCodecConfig; private final BluetoothCodecConfig[] mCodecsLocalCapabilities; private final BluetoothCodecConfig[] mCodecsSelectableCapabilities; - public BluetoothCodecStatus(BluetoothCodecConfig codecConfig, - BluetoothCodecConfig[] codecsLocalCapabilities, - BluetoothCodecConfig[] codecsSelectableCapabilities) { + public BluetoothCodecStatus(@Nullable BluetoothCodecConfig codecConfig, + @Nullable BluetoothCodecConfig[] codecsLocalCapabilities, + @Nullable BluetoothCodecConfig[] codecsSelectableCapabilities) { mCodecConfig = codecConfig; mCodecsLocalCapabilities = codecsLocalCapabilities; mCodecsSelectableCapabilities = codecsSelectableCapabilities; @@ -74,6 +74,7 @@ public final class BluetoothCodecStatus implements Parcelable { * @param c1 the first array of capabilities to compare * @param c2 the second array of capabilities to compare * @return true if both arrays contain same capabilities + * @hide */ public static boolean sameCapabilities(BluetoothCodecConfig[] c1, BluetoothCodecConfig[] c2) { @@ -95,6 +96,7 @@ public final class BluetoothCodecStatus implements Parcelable { * * @param codecConfig the codec config to compare against * @return true if the codec config matches, otherwise false + * @hide */ public boolean isCodecConfigSelectable(BluetoothCodecConfig codecConfig) { if (codecConfig == null || !codecConfig.hasSingleSampleRate() @@ -125,7 +127,12 @@ public final class BluetoothCodecStatus implements Parcelable { return false; } - + /** + * Returns a hash based on the codec config and local capabilities + * + * @return a hash based on the config values + * @hide + */ @Override public int hashCode() { return Objects.hash(mCodecConfig, mCodecsLocalCapabilities, @@ -140,6 +147,12 @@ public final class BluetoothCodecStatus implements Parcelable { + "}"; } + /** + * Always returns 0 + * + * @return 0 + * @hide + */ @Override public int describeContents() { return 0; @@ -165,6 +178,14 @@ public final class BluetoothCodecStatus implements Parcelable { } }; + /** + * Flattens the object to a parcel + * + * @param out The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. + * + * @hide + */ @Override public void writeToParcel(Parcel out, int flags) { out.writeTypedObject(mCodecConfig, 0); @@ -177,7 +198,6 @@ public final class BluetoothCodecStatus implements Parcelable { * * @return the current codec configuration */ - @UnsupportedAppUsage public @Nullable BluetoothCodecConfig getCodecConfig() { return mCodecConfig; } @@ -187,8 +207,7 @@ public final class BluetoothCodecStatus implements Parcelable { * * @return an array with the codecs local capabilities */ - @UnsupportedAppUsage - public BluetoothCodecConfig[] getCodecsLocalCapabilities() { + public @Nullable BluetoothCodecConfig[] getCodecsLocalCapabilities() { return mCodecsLocalCapabilities; } @@ -197,8 +216,7 @@ public final class BluetoothCodecStatus implements Parcelable { * * @return an array with the codecs selectable capabilities */ - @UnsupportedAppUsage - public BluetoothCodecConfig[] getCodecsSelectableCapabilities() { + public @Nullable BluetoothCodecConfig[] getCodecsSelectableCapabilities() { return mCodecsSelectableCapabilities; } } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 9e9cd9218a0f..137f53782124 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -24,6 +24,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.StringDef; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -1112,6 +1113,82 @@ public class UserManager { */ public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending"; + /** + * List of key values that can be passed into the various user restriction related methods + * in {@link UserManager} & {@link DevicePolicyManager}. + * Note: This is slightly different from the real set of user restrictions listed in {@link + * com.android.server.pm.UserRestrictionsUtils#USER_RESTRICTIONS}. For example + * {@link #KEY_RESTRICTIONS_PENDING} is not a real user restriction, but is a a legitimate + * value that can be passed into {@link #hasUserRestriction(String)}. + * @hide + */ + @StringDef(value = { + DISALLOW_MODIFY_ACCOUNTS, + DISALLOW_CONFIG_WIFI, + DISALLOW_CONFIG_LOCALE, + DISALLOW_INSTALL_APPS, + DISALLOW_UNINSTALL_APPS, + DISALLOW_SHARE_LOCATION, + DISALLOW_AIRPLANE_MODE, + DISALLOW_CONFIG_BRIGHTNESS, + DISALLOW_AMBIENT_DISPLAY, + DISALLOW_CONFIG_SCREEN_TIMEOUT, + DISALLOW_INSTALL_UNKNOWN_SOURCES, + DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, + DISALLOW_CONFIG_BLUETOOTH, + DISALLOW_BLUETOOTH, + DISALLOW_BLUETOOTH_SHARING, + DISALLOW_USB_FILE_TRANSFER, + DISALLOW_CONFIG_CREDENTIALS, + DISALLOW_REMOVE_USER, + DISALLOW_REMOVE_MANAGED_PROFILE, + DISALLOW_DEBUGGING_FEATURES, + DISALLOW_CONFIG_VPN, + DISALLOW_CONFIG_LOCATION, + DISALLOW_CONFIG_DATE_TIME, + DISALLOW_CONFIG_TETHERING, + DISALLOW_NETWORK_RESET, + DISALLOW_FACTORY_RESET, + DISALLOW_ADD_USER, + DISALLOW_ADD_MANAGED_PROFILE, + ENSURE_VERIFY_APPS, + DISALLOW_CONFIG_CELL_BROADCASTS, + DISALLOW_CONFIG_MOBILE_NETWORKS, + DISALLOW_APPS_CONTROL, + DISALLOW_MOUNT_PHYSICAL_MEDIA, + DISALLOW_UNMUTE_MICROPHONE, + DISALLOW_ADJUST_VOLUME, + DISALLOW_OUTGOING_CALLS, + DISALLOW_SMS, + DISALLOW_FUN, + DISALLOW_CREATE_WINDOWS, + DISALLOW_SYSTEM_ERROR_DIALOGS, + DISALLOW_CROSS_PROFILE_COPY_PASTE, + DISALLOW_OUTGOING_BEAM, + DISALLOW_WALLPAPER, + DISALLOW_SET_WALLPAPER, + DISALLOW_SAFE_BOOT, + DISALLOW_RECORD_AUDIO, + DISALLOW_RUN_IN_BACKGROUND, + DISALLOW_CAMERA, + DISALLOW_UNMUTE_DEVICE, + DISALLOW_DATA_ROAMING, + DISALLOW_SET_USER_ICON, + DISALLOW_OEM_UNLOCK, + DISALLOW_UNIFIED_PASSWORD, + ALLOW_PARENT_PROFILE_APP_LINKING, + DISALLOW_AUTOFILL, + DISALLOW_CONTENT_CAPTURE, + DISALLOW_CONTENT_SUGGESTIONS, + DISALLOW_USER_SWITCH, + DISALLOW_SHARE_INTO_MANAGED_PROFILE, + DISALLOW_PRINTING, + DISALLOW_CONFIG_PRIVATE_DNS, + KEY_RESTRICTIONS_PENDING, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface UserRestrictionKey {} + private static final String ACTION_CREATE_USER = "android.os.action.CREATE_USER"; /** @@ -2026,7 +2103,8 @@ public class UserManager { @SystemApi @UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) - public int getUserRestrictionSource(String restrictionKey, UserHandle userHandle) { + public int getUserRestrictionSource(@UserRestrictionKey String restrictionKey, + UserHandle userHandle) { try { return mService.getUserRestrictionSource(restrictionKey, userHandle.getIdentifier()); } catch (RemoteException re) { @@ -2045,7 +2123,7 @@ public class UserManager { @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public List<EnforcingUser> getUserRestrictionSources( - String restrictionKey, UserHandle userHandle) { + @UserRestrictionKey String restrictionKey, UserHandle userHandle) { try { return mService.getUserRestrictionSources(restrictionKey, userHandle.getIdentifier()); } catch (RemoteException re) { @@ -2091,7 +2169,8 @@ public class UserManager { * @param userHandle the UserHandle of the user for whom to retrieve the restrictions. */ @UnsupportedAppUsage - public boolean hasBaseUserRestriction(String restrictionKey, UserHandle userHandle) { + public boolean hasBaseUserRestriction(@UserRestrictionKey String restrictionKey, + UserHandle userHandle) { try { return mService.hasBaseUserRestriction(restrictionKey, userHandle.getIdentifier()); } catch (RemoteException re) { @@ -2162,7 +2241,7 @@ public class UserManager { * @param restrictionKey The string key representing the restriction. * @return {@code true} if the current user has the given restriction, {@code false} otherwise. */ - public boolean hasUserRestriction(String restrictionKey) { + public boolean hasUserRestriction(@UserRestrictionKey String restrictionKey) { return hasUserRestrictionForUser(restrictionKey, Process.myUserHandle()); } @@ -2174,7 +2253,8 @@ public class UserManager { * @param userHandle the UserHandle of the user for whom to retrieve the restrictions. */ @UnsupportedAppUsage - public boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) { + public boolean hasUserRestriction(@UserRestrictionKey String restrictionKey, + UserHandle userHandle) { return hasUserRestrictionForUser(restrictionKey, userHandle); } @@ -2194,7 +2274,7 @@ public class UserManager { @RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) - public boolean hasUserRestrictionForUser(@NonNull String restrictionKey, + public boolean hasUserRestrictionForUser(@NonNull @UserRestrictionKey String restrictionKey, @NonNull UserHandle userHandle) { try { return mService.hasUserRestriction(restrictionKey, userHandle.getIdentifier()); @@ -2207,7 +2287,7 @@ public class UserManager { * @hide * Returns whether any user on the device has the given user restriction set. */ - public boolean hasUserRestrictionOnAnyUser(String restrictionKey) { + public boolean hasUserRestrictionOnAnyUser(@UserRestrictionKey String restrictionKey) { try { return mService.hasUserRestrictionOnAnyUser(restrictionKey); } catch (RemoteException re) { diff --git a/core/java/android/os/connectivity/WifiActivityEnergyInfo.java b/core/java/android/os/connectivity/WifiActivityEnergyInfo.java index 7db003d9853c..664b6c87d339 100644 --- a/core/java/android/os/connectivity/WifiActivityEnergyInfo.java +++ b/core/java/android/os/connectivity/WifiActivityEnergyInfo.java @@ -19,9 +19,13 @@ package android.os.connectivity; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.app.ActivityThread; +import android.content.Context; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.os.PowerProfile; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -72,7 +76,6 @@ public final class WifiActivityEnergyInfo implements Parcelable { * @param scanDurationMillis Cumulative milliseconds when radio is awake due to scan. * @param idleDurationMillis Cumulative milliseconds when radio is awake but not transmitting or * receiving. - * @param energyUsedMicroJoules Cumulative energy consumed by Wifi, in microjoules. */ public WifiActivityEnergyInfo( long timeSinceBootMillis, @@ -80,14 +83,33 @@ public final class WifiActivityEnergyInfo implements Parcelable { long txDurationMillis, long rxDurationMillis, long scanDurationMillis, - long idleDurationMillis, - long energyUsedMicroJoules) { + long idleDurationMillis) { mTimeSinceBootMillis = timeSinceBootMillis; mStackState = stackState; mControllerTxDurationMillis = txDurationMillis; mControllerRxDurationMillis = rxDurationMillis; mControllerScanDurationMillis = scanDurationMillis; mControllerIdleDurationMillis = idleDurationMillis; + + final Context context = ActivityThread.currentActivityThread().getSystemContext(); + if (context == null) { + mControllerEnergyUsedMicroJoules = 0L; + return; + } + // Calculate energy used using PowerProfile. + PowerProfile powerProfile = new PowerProfile(context); + final double rxIdleCurrent = powerProfile.getAveragePower( + PowerProfile.POWER_WIFI_CONTROLLER_IDLE); + final double rxCurrent = powerProfile.getAveragePower( + PowerProfile.POWER_WIFI_CONTROLLER_RX); + final double txCurrent = powerProfile.getAveragePower( + PowerProfile.POWER_WIFI_CONTROLLER_TX); + final double voltage = powerProfile.getAveragePower( + PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0; + final long energyUsedMicroJoules = (long) ((mControllerTxDurationMillis * txCurrent + + mControllerRxDurationMillis * rxCurrent + + mControllerIdleDurationMillis * rxIdleCurrent) + * voltage); mControllerEnergyUsedMicroJoules = energyUsedMicroJoules; } @@ -113,9 +135,8 @@ public final class WifiActivityEnergyInfo implements Parcelable { long rxTime = in.readLong(); long scanTime = in.readLong(); long idleTime = in.readLong(); - long energyUsed = in.readLong(); return new WifiActivityEnergyInfo(timestamp, stackState, - txTime, rxTime, scanTime, idleTime, energyUsed); + txTime, rxTime, scanTime, idleTime); } public WifiActivityEnergyInfo[] newArray(int size) { return new WifiActivityEnergyInfo[size]; @@ -130,7 +151,6 @@ public final class WifiActivityEnergyInfo implements Parcelable { out.writeLong(mControllerRxDurationMillis); out.writeLong(mControllerScanDurationMillis); out.writeLong(mControllerIdleDurationMillis); - out.writeLong(mControllerEnergyUsedMicroJoules); } @Override diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index b91d69f6dc2c..2fa3386bccb8 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -159,6 +159,8 @@ public final class MediaStore { public static final String SCAN_FILE_CALL = "scan_file"; /** {@hide} */ public static final String SCAN_VOLUME_CALL = "scan_volume"; + /** {@hide} */ + public static final String SUICIDE_CALL = "suicide"; /** * Extra used with {@link #SCAN_FILE_CALL} or {@link #SCAN_VOLUME_CALL} to indicate that @@ -3980,6 +3982,16 @@ public final class MediaStore { } /** @hide */ + public static void suicide(Context context) { + final ContentResolver resolver = context.getContentResolver(); + try (ContentProviderClient client = resolver + .acquireUnstableContentProviderClient(AUTHORITY)) { + client.call(SUICIDE_CALL, null, null); + } catch (Exception ignored) { + } + } + + /** @hide */ @TestApi public static Uri scanFile(Context context, File file) { return scan(context, SCAN_FILE_CALL, file, false); diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 22f90f62b114..70c8e5d311bd 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -4837,4 +4837,23 @@ public final class Telephony { public static final Uri CONTENT_URI = Uri.parse("content://carrier_id/all"); } } + + /** + * Contains SIM Information + * @hide + */ + @SystemApi + public static final class SimInfo { + /** + * Not instantiable. + * @hide + */ + private SimInfo() {} + + /** + * The {@code content://} style URI for this provider. + */ + @NonNull + public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo"); + } } diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java index 64e15cfb7948..8cb5b05df685 100644 --- a/core/java/android/util/StatsLog.java +++ b/core/java/android/util/StatsLog.java @@ -179,6 +179,8 @@ public final class StatsLog extends StatsLogInternal { * @param rollbackType state of the rollback. * @param packageName package name being rolled back. * @param packageVersionCode version of the package being rolled back. + * @param rollbackReason reason the package is being rolled back. + * @param failingPackageName the package name causing the failure. * * @return True if the log request was sent to statsd. * @@ -186,7 +188,7 @@ public final class StatsLog extends StatsLogInternal { */ @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS}) public static boolean logWatchdogRollbackOccurred(int rollbackType, String packageName, - long packageVersionCode) { + long packageVersionCode, int rollbackReason, String failingPackageName) { synchronized (sLogLock) { try { IStatsManager service = getIStatsManagerLocked(); @@ -198,7 +200,7 @@ public final class StatsLog extends StatsLogInternal { } service.sendWatchdogRollbackOccurredAtom(rollbackType, packageName, - packageVersionCode); + packageVersionCode, rollbackReason, failingPackageName); return true; } catch (RemoteException e) { sService = null; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index afa661e26d4c..3171306fc568 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1646,7 +1646,7 @@ public final class ViewRootImpl implements ViewParent, mBlastSurfaceControl, width, height); } - mBlastBufferQueue.update(mSurfaceControl, width, height); + mBlastBufferQueue.update(mBlastSurfaceControl, width, height); mTransaction.show(mBlastSurfaceControl) .reparent(mBlastSurfaceControl, mSurfaceControl) diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index c571737cec8f..7cec440dd80b 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -3473,18 +3473,10 @@ public class RemoteViews implements Parcelable, Filter { return applyAsync(context, parent, executor, listener, null); } - private CancellationSignal startTaskOnExecutor(AsyncApplyTask task, Executor executor) { - CancellationSignal cancelSignal = new CancellationSignal(); - cancelSignal.setOnCancelListener(task); - - task.executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor); - return cancelSignal; - } - /** @hide */ public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor, OnViewAppliedListener listener, OnClickHandler handler) { - return startTaskOnExecutor(getAsyncApplyTask(context, parent, listener, handler), executor); + return getAsyncApplyTask(context, parent, listener, handler).startTaskOnExecutor(executor); } private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent, @@ -3495,6 +3487,7 @@ public class RemoteViews implements Parcelable, Filter { private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree> implements CancellationSignal.OnCancelListener { + final CancellationSignal mCancelSignal = new CancellationSignal(); final RemoteViews mRV; final ViewGroup mParent; final Context mContext; @@ -3545,6 +3538,7 @@ public class RemoteViews implements Parcelable, Filter { @Override protected void onPostExecute(ViewTree viewTree) { + mCancelSignal.setOnCancelListener(null); if (mError == null) { if (mListener != null) { mListener.onViewInflated(viewTree.mRoot); @@ -3581,6 +3575,13 @@ public class RemoteViews implements Parcelable, Filter { @Override public void onCancel() { cancel(true); + mCancelSignal.setOnCancelListener(null); + } + + private CancellationSignal startTaskOnExecutor(Executor executor) { + mCancelSignal.setOnCancelListener(this); + executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor); + return mCancelSignal; } } @@ -3646,8 +3647,8 @@ public class RemoteViews implements Parcelable, Filter { } } - return startTaskOnExecutor(new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(), - context, listener, handler, v), executor); + return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(), + context, listener, handler, v).startTaskOnExecutor(executor); } private void performApply(View v, ViewGroup parent, OnClickHandler handler) { diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index fd3cd42b07a1..a21187165c65 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -30,8 +30,10 @@ import android.os.SystemProperties; import android.os.Trace; import android.util.Log; import android.util.Slog; + import com.android.internal.logging.AndroidConfig; import com.android.server.NetworkManagementSocketTagger; + import dalvik.system.RuntimeHooks; import dalvik.system.VMRuntime; @@ -374,9 +376,6 @@ public class RuntimeInit { // leftover running threads to crash before the process actually exits. nativeSetExitWithoutCleanup(true); - // We want to be fairly aggressive about heap utilization, to avoid - // holding on to a lot of memory that isn't needed. - VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); final Arguments args = new Arguments(argv); diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 897b982406dc..13cc98be5d5a 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -43,7 +43,7 @@ interface ILockSettings { long getLong(in String key, in long defaultValue, in int userId); @UnsupportedAppUsage String getString(in String key, in String defaultValue, in int userId); - boolean setLockCredential(in LockscreenCredential credential, in LockscreenCredential savedCredential, int userId, boolean allowUntrustedChange); + boolean setLockCredential(in LockscreenCredential credential, in LockscreenCredential savedCredential, int userId); void resetKeyStore(int userId); VerifyCredentialResponse checkCredential(in LockscreenCredential credential, int userId, in ICheckCredentialProgressCallback progressCallback); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index b534213ec859..cff39f120dd7 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -636,35 +636,16 @@ public class LockPatternUtils { * * @param newCredential The new credential to save * @param savedCredential The current credential - * @param userId the user whose lockscreen credential is to be changed - * - * @return whether this method saved the new password successfully or not. This flow will fail - * and return false if the given credential is wrong. - * @throws RuntimeException if password change encountered an unrecoverable error. - */ - public boolean setLockCredential(@NonNull LockscreenCredential newCredential, - @NonNull LockscreenCredential savedCredential, int userId) { - return setLockCredential(newCredential, savedCredential, userId, false); - } - - /** - * Save a new lockscreen credential. - * <p> This method will fail (returning {@code false}) if the previously saved pattern provided - * is incorrect and allowUntrustedChange is false, or if the lockscreen verification is still - * being throttled. - * @param newCredential The new credential to save - * @param savedCredential The current credential * @param userHandle the user whose lockscreen credential is to be changed - * @param allowUntrustedChange whether we want to allow saving a new pattern if the existing - * credentialt being provided is incorrect. * * @return whether this method saved the new password successfully or not. This flow will fail - * and return false if the given credential is wrong and allowUntrustedChange is false. + * and return false if the given credential is wrong. * @throws RuntimeException if password change encountered an unrecoverable error. + * @throws UnsupportedOperationException secure lockscreen is not supported on this device. + * @throws IllegalArgumentException if new credential is too short. */ public boolean setLockCredential(@NonNull LockscreenCredential newCredential, - @NonNull LockscreenCredential savedCredential, int userHandle, - boolean allowUntrustedChange) { + @NonNull LockscreenCredential savedCredential, int userHandle) { if (!hasSecureLockScreen()) { throw new UnsupportedOperationException( "This operation requires the lock screen feature."); @@ -672,8 +653,7 @@ public class LockPatternUtils { newCredential.checkLength(); try { - if (!getLockSettings().setLockCredential( - newCredential, savedCredential, userHandle, allowUntrustedChange)) { + if (!getLockSettings().setLockCredential(newCredential, savedCredential, userHandle)) { return false; } } catch (RemoteException e) { diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java index dc4f09a2af6f..13bfc1bf72b8 100644 --- a/core/java/com/android/server/BootReceiver.java +++ b/core/java/com/android/server/BootReceiver.java @@ -66,10 +66,15 @@ import org.xmlpull.v1.XmlSerializer; public class BootReceiver extends BroadcastReceiver { private static final String TAG = "BootReceiver"; + private static final String TAG_TRUNCATED = "[[TRUNCATED]]\n"; + // Maximum size of a logged event (files get truncated if they're longer). // Give userdebug builds a larger max to capture extra debug, esp. for last_kmsg. private static final int LOG_SIZE = SystemProperties.getInt("ro.debuggable", 0) == 1 ? 98304 : 65536; + private static final int LASTK_LOG_SIZE = + SystemProperties.getInt("ro.debuggable", 0) == 1 ? 196608 : 65536; + private static final int GMSCORE_LASTK_LOG_SIZE = 196608; private static final File TOMBSTONE_DIR = new File("/data/tombstones"); private static final String TAG_TOMBSTONE = "SYSTEM_TOMBSTONE"; @@ -224,12 +229,12 @@ public class BootReceiver extends BroadcastReceiver { if (db != null) db.addText("SYSTEM_BOOT", headers); // Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile()) - addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter, - "/proc/last_kmsg", -LOG_SIZE, "SYSTEM_LAST_KMSG"); - addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter, - "/sys/fs/pstore/console-ramoops", -LOG_SIZE, "SYSTEM_LAST_KMSG"); - addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter, - "/sys/fs/pstore/console-ramoops-0", -LOG_SIZE, "SYSTEM_LAST_KMSG"); + addLastkToDropBox(db, timestamps, headers, lastKmsgFooter, + "/proc/last_kmsg", -LASTK_LOG_SIZE, "SYSTEM_LAST_KMSG"); + addLastkToDropBox(db, timestamps, headers, lastKmsgFooter, + "/sys/fs/pstore/console-ramoops", -LASTK_LOG_SIZE, "SYSTEM_LAST_KMSG"); + addLastkToDropBox(db, timestamps, headers, lastKmsgFooter, + "/sys/fs/pstore/console-ramoops-0", -LASTK_LOG_SIZE, "SYSTEM_LAST_KMSG"); addFileToDropBox(db, timestamps, headers, "/cache/recovery/log", -LOG_SIZE, "SYSTEM_RECOVERY_LOG"); addFileToDropBox(db, timestamps, headers, "/cache/recovery/last_kmsg", @@ -278,6 +283,23 @@ public class BootReceiver extends BroadcastReceiver { sTombstoneObserver.startWatching(); } + private static void addLastkToDropBox( + DropBoxManager db, HashMap<String, Long> timestamps, + String headers, String footers, String filename, int maxSize, + String tag) throws IOException { + int extraSize = headers.length() + TAG_TRUNCATED.length() + footers.length(); + // GMSCore will do 2nd truncation to be 192KiB + // LASTK_LOG_SIZE + extraSize must be less than GMSCORE_LASTK_LOG_SIZE + if (LASTK_LOG_SIZE + extraSize > GMSCORE_LASTK_LOG_SIZE) { + if (GMSCORE_LASTK_LOG_SIZE > extraSize) { + maxSize = -(GMSCORE_LASTK_LOG_SIZE - extraSize); + } else { + maxSize = 0; + } + } + addFileWithFootersToDropBox(db, timestamps, headers, footers, filename, maxSize, tag); + } + private static void addFileToDropBox( DropBoxManager db, HashMap<String, Long> timestamps, String headers, String filename, int maxSize, String tag) throws IOException { @@ -301,7 +323,7 @@ public class BootReceiver extends BroadcastReceiver { timestamps.put(filename, fileTime); - String fileContents = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n"); + String fileContents = FileUtils.readTextFile(file, maxSize, TAG_TRUNCATED); String text = headers + fileContents + footers; // Create an additional report for system server native crashes, with a special tag. if (tag.equals(TAG_TOMBSTONE) && fileContents.contains(">>> system_server <<<")) { @@ -345,7 +367,7 @@ public class BootReceiver extends BroadcastReceiver { timestamps.put(tag, fileTime); - String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n"); + String log = FileUtils.readTextFile(file, maxSize, TAG_TRUNCATED); StringBuilder sb = new StringBuilder(); for (String line : log.split("\n")) { if (line.contains("audit")) { @@ -370,7 +392,7 @@ public class BootReceiver extends BroadcastReceiver { long fileTime = file.lastModified(); if (fileTime <= 0) return; // File does not exist - String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n"); + String log = FileUtils.readTextFile(file, maxSize, TAG_TRUNCATED); Pattern pattern = Pattern.compile(FS_STAT_PATTERN); String lines[] = log.split("\n"); int lineNumber = 0; diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 378e125a3a3e..97451a2c4cfd 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -648,6 +648,7 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX]; std::string fingerprintBuf; char jdwpProviderBuf[sizeof("-XjdwpProvider:") - 1 + PROPERTY_VALUE_MAX]; + char opaqueJniIds[sizeof("-Xopaque-jni-ids:") - 1 + PROPERTY_VALUE_MAX]; char bootImageBuf[sizeof("-Ximage:") - 1 + PROPERTY_VALUE_MAX]; // Read if we are using the profile configuration, do this at the start since the last ART args @@ -839,6 +840,14 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool p "default"); } + // Only pass an explicit opaque-jni-ids to apps forked from zygote + if (zygote) { + parseRuntimeOption("dalvik.vm.opaque-jni-ids", + opaqueJniIds, + "-Xopaque-jni-ids:", + "swapable"); + } + parseRuntimeOption("dalvik.vm.lockprof.threshold", lockProfThresholdBuf, "-Xlockprofthreshold:"); diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto index 1ec05fb5e9fc..ecb4193a2c6c 100644 --- a/core/proto/android/service/notification.proto +++ b/core/proto/android/service/notification.proto @@ -264,3 +264,14 @@ message ZenPolicyProto { optional Sender priority_calls = 16; optional Sender priority_messages = 17; } + +// Next Tag: 2 +message PackageRemoteViewInfoProto { + optional string package_name = 1; + // add per-package additional info here (like channels) +} + +// Next Tag: 2 +message NotificationRemoteViewsProto { + repeated PackageRemoteViewInfoProto package_remote_view_info = 1; +}
\ No newline at end of file diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index cf3f51d6599a..322cbd798203 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -204,7 +204,7 @@ applications that come with the platform <permission name="android.permission.UPDATE_DEVICE_STATS"/> </privapp-permissions> - <privapp-permissions package="com.android.providers.media"> + <privapp-permissions package="com.android.providers.media.module"> <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.MANAGE_USERS"/> <permission name="android.permission.USE_RESERVED_DISK"/> @@ -369,4 +369,7 @@ applications that come with the platform <permission name="android.permission.REBOOT"/> <permission name="android.permission.MANAGE_DYNAMIC_SYSTEM"/> </privapp-permissions> + <privapp-permissions package="com.android.settings"> + <permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/> + </privapp-permissions> </permissions> diff --git a/media/java/android/media/tv/tuner/FilterSettings.java b/media/java/android/media/tv/tuner/FilterSettings.java new file mode 100644 index 000000000000..d5f100341dc6 --- /dev/null +++ b/media/java/android/media/tv/tuner/FilterSettings.java @@ -0,0 +1,383 @@ +/* + * Copyright 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.media.tv.tuner; + +import android.annotation.Nullable; +import android.hardware.tv.tuner.V1_0.Constants; +import android.media.tv.tuner.TunerConstants.FilterSettingsType; + +import java.util.List; + +/** + * Demux Filter settings. + * + * @hide + */ +public abstract class FilterSettings { + @Nullable + protected final Settings mSettings; + + protected FilterSettings(Settings settings) { + mSettings = settings; + } + + /** + * Gets filter settings type + */ + @FilterSettingsType public abstract int getType(); + + // TODO: more builders and getters + + /** + * Filter Settings for a TS filter. + */ + public static class TsFilterSettings extends FilterSettings { + private int mTpid; + + private TsFilterSettings(Settings settings, int tpid) { + super(settings); + mTpid = tpid; + } + + @Override + public int getType() { + return TunerConstants.FILTER_SETTINGS_TS; + } + + /** + * Creates a new builder. + */ + public static Builder newBuilder() { + return new Builder(); + } + + /** + * Builder for TsFilterSettings. + */ + public static class Builder { + private Settings mSettings; + private int mTpid; + + /** + * Sets settings. + */ + public Builder setSettings(Settings settings) { + mSettings = settings; + return this; + } + + /** + * Sets TPID. + */ + public Builder setTpid(int tpid) { + mTpid = tpid; + return this; + } + + /** + * Builds a TsFilterSettings instance. + */ + public TsFilterSettings build() { + return new TsFilterSettings(mSettings, mTpid); + } + } + } + + /** + * Filter Settings for a MMTP filter. + */ + public static class MmtpFilterSettings extends FilterSettings { + private int mMmtpPid; + + public MmtpFilterSettings(Settings settings) { + super(settings); + } + + @Override + public int getType() { + return TunerConstants.FILTER_SETTINGS_MMTP; + } + } + + + /** + * Filter Settings for a IP filter. + */ + public static class IpFilterSettings extends FilterSettings { + private byte[] mSrcIpAddress; + private byte[] mDstIpAddress; + private int mSrcPort; + private int mDstPort; + private boolean mPassthrough; + + public IpFilterSettings(Settings settings) { + super(settings); + } + + @Override + public int getType() { + return TunerConstants.FILTER_SETTINGS_IP; + } + } + + + /** + * Filter Settings for a TLV filter. + */ + public static class TlvFilterSettings extends FilterSettings { + private int mPacketType; + private boolean mIsCompressedIpPacket; + private boolean mPassthrough; + + public TlvFilterSettings(Settings settings) { + super(settings); + } + + @Override + public int getType() { + return TunerConstants.FILTER_SETTINGS_TLV; + } + } + + + /** + * Filter Settings for a ALP filter. + */ + public static class AlpFilterSettings extends FilterSettings { + private int mPacketType; + private int mLengthType; + + public AlpFilterSettings(Settings settings) { + super(settings); + } + + @Override + public int getType() { + return TunerConstants.FILTER_SETTINGS_ALP; + } + } + + + /** + * Settings for filters of different subtypes. + */ + public abstract static class Settings { + protected final int mType; + + protected Settings(int type) { + mType = type; + } + + /** + * Gets filter settings type. + * @return + */ + int getType() { + return mType; + } + } + + /** + * Filter Settings for Section data according to ISO/IEC 13818-1. + */ + public static class SectionSettings extends Settings { + + private SectionSettings(int mainType) { + super(SectionSettings.findType(mainType)); + } + + private static int findType(int mainType) { + switch (mainType) { + case TunerConstants.FILTER_SETTINGS_TS: + return Constants.DemuxTsFilterType.SECTION; + case TunerConstants.FILTER_SETTINGS_MMTP: + return Constants.DemuxMmtpFilterType.SECTION; + case TunerConstants.FILTER_SETTINGS_IP: + return Constants.DemuxIpFilterType.SECTION; + case TunerConstants.FILTER_SETTINGS_TLV: + return Constants.DemuxTlvFilterType.SECTION; + case TunerConstants.FILTER_SETTINGS_ALP: + return Constants.DemuxAlpFilterType.SECTION; + } + // UNDEFINED + return 0; + } + } + + /** + * Bits Settings for Section Filter. + */ + public static class SectionSettingsWithSectionBits extends SectionSettings { + private List<Byte> mFilter; + private List<Byte> mMask; + private List<Byte> mMode; + + private SectionSettingsWithSectionBits(int mainType) { + super(mainType); + } + } + + /** + * Table information for Section Filter. + */ + public static class SectionSettingsWithTableInfo extends SectionSettings { + private int mTableId; + private int mVersion; + + private SectionSettingsWithTableInfo(int mainType) { + super(mainType); + } + } + + /** + * Filter Settings for a PES Data. + */ + public static class PesSettings extends Settings { + private int mStreamId; + private boolean mIsRaw; + + private PesSettings(int mainType, int streamId, boolean isRaw) { + super(PesSettings.findType(mainType)); + mStreamId = streamId; + mIsRaw = isRaw; + } + + private static int findType(int mainType) { + switch (mainType) { + case TunerConstants.FILTER_SETTINGS_TS: + return Constants.DemuxTsFilterType.PES; + case TunerConstants.FILTER_SETTINGS_MMTP: + return Constants.DemuxMmtpFilterType.PES; + } + // UNDEFINED + return 0; + } + + /** + * Creates a builder for PesSettings. + */ + public static Builder newBuilder(int mainType) { + return new Builder(mainType); + } + + /** + * Builder for PesSettings. + */ + public static class Builder { + private final int mMainType; + private int mStreamId; + private boolean mIsRaw; + + public Builder(int mainType) { + mMainType = mainType; + } + + /** + * Sets stream ID. + */ + public Builder setStreamId(int streamId) { + mStreamId = streamId; + return this; + } + + /** + * Sets whether it's raw. + * true if the filter send onFilterStatus instead of onFilterEvent. + */ + public Builder setIsRaw(boolean isRaw) { + mIsRaw = isRaw; + return this; + } + + /** + * Builds a PesSettings instance. + */ + public PesSettings build() { + return new PesSettings(mMainType, mStreamId, mIsRaw); + } + } + } + + /** + * Filter Settings for a Video and Audio. + */ + public static class AvSettings extends Settings { + private boolean mIsPassthrough; + + private AvSettings(int mainType, boolean isAudio) { + super(AvSettings.findType(mainType, isAudio)); + } + + private static int findType(int mainType, boolean isAudio) { + switch (mainType) { + case TunerConstants.FILTER_SETTINGS_TS: + return isAudio + ? Constants.DemuxTsFilterType.AUDIO + : Constants.DemuxTsFilterType.VIDEO; + case TunerConstants.FILTER_SETTINGS_MMTP: + return isAudio + ? Constants.DemuxMmtpFilterType.AUDIO + : Constants.DemuxMmtpFilterType.VIDEO; + } + // UNDEFINED + return 0; + } + } + + /** + * Filter Settings for a Download. + */ + public static class DownloadSettings extends Settings { + private int mDownloadId; + + public DownloadSettings(int mainType) { + super(DownloadSettings.findType(mainType)); + } + + private static int findType(int mainType) { + if (mainType == TunerConstants.FILTER_SETTINGS_MMTP) { + return Constants.DemuxMmtpFilterType.DOWNLOAD; + } + // UNDEFINED + return 0; + } + } + + /** + * The Settings for the record in DVR. + */ + public static class RecordSettings extends Settings { + private int mIndexType; + private int mIndexMask; + + public RecordSettings(int mainType) { + super(RecordSettings.findType(mainType)); + } + + private static int findType(int mainType) { + switch (mainType) { + case TunerConstants.FILTER_SETTINGS_TS: + return Constants.DemuxTsFilterType.RECORD; + case TunerConstants.FILTER_SETTINGS_MMTP: + return Constants.DemuxMmtpFilterType.RECORD; + } + // UNDEFINED + return 0; + } + } + +} diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 82cef2e43307..6537f6fb5a2b 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -243,9 +243,11 @@ public final class Tuner implements AutoCloseable { private FilterCallback mCallback; int mId; + private native int nativeConfigureFilter(int type, int subType, FilterSettings settings); private native boolean nativeStartFilter(); private native boolean nativeStopFilter(); private native boolean nativeFlushFilter(); + private native int nativeRead(byte[] buffer, int offset, int size); private Filter(int id) { mId = id; @@ -258,6 +260,14 @@ public final class Tuner implements AutoCloseable { } } + public int configure(FilterSettings settings) { + int subType = -1; + if (settings.mSettings != null) { + subType = settings.mSettings.getType(); + } + return nativeConfigureFilter(settings.getType(), subType, settings); + } + public boolean start() { return nativeStartFilter(); } @@ -269,6 +279,11 @@ public final class Tuner implements AutoCloseable { public boolean flush() { return nativeFlushFilter(); } + + public int read(@NonNull byte[] buffer, int offset, int size) { + size = Math.min(size, buffer.length - offset); + return nativeRead(buffer, offset, size); + } } private Filter openFilter(int type, int subType, int bufferSize, FilterCallback cb) { diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java index 458cb1678ded..f2d5e939f532 100644 --- a/media/java/android/media/tv/tuner/TunerConstants.java +++ b/media/java/android/media/tv/tuner/TunerConstants.java @@ -90,6 +90,17 @@ final class TunerConstants { public static final int FRONTEND_SETTINGS_ISDBS3 = 8; public static final int FRONTEND_SETTINGS_ISDBT = 9; + @Retention(RetentionPolicy.SOURCE) + @IntDef({FILTER_SETTINGS_TS, FILTER_SETTINGS_MMTP, FILTER_SETTINGS_IP, FILTER_SETTINGS_TLV, + FILTER_SETTINGS_ALP}) + public @interface FilterSettingsType {} + + public static final int FILTER_SETTINGS_TS = Constants.DemuxFilterMainType.TS; + public static final int FILTER_SETTINGS_MMTP = Constants.DemuxFilterMainType.MMTP; + public static final int FILTER_SETTINGS_IP = Constants.DemuxFilterMainType.IP; + public static final int FILTER_SETTINGS_TLV = Constants.DemuxFilterMainType.TLV; + public static final int FILTER_SETTINGS_ALP = Constants.DemuxFilterMainType.ALP; + private TunerConstants() { } } diff --git a/media/jni/Android.bp b/media/jni/Android.bp index 12b3e6735d81..4ca23a1084a2 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -135,6 +135,8 @@ cc_library_shared { shared_libs: [ "android.hardware.tv.tuner@1.0", "libandroid_runtime", + "libcutils", + "libfmq", "libhidlbase", "liblog", "libutils", diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index 5216906d5ec5..a0be12ebecfc 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -28,8 +28,12 @@ using ::android::hardware::Void; using ::android::hardware::hidl_vec; using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType; +using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; +using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings; using ::android::hardware::tv::tuner::V1_0::DemuxMmtpPid; +using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; using ::android::hardware::tv::tuner::V1_0::DemuxTpid; +using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings; using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType; using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSettings; using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSifStandard; @@ -112,6 +116,26 @@ void FilterCallback::setFilter(const jobject filter) { mFilter = env->NewWeakGlobalRef(filter); } +/////////////// Filter /////////////////////// + +Filter::Filter(sp<IFilter> sp, jweak obj) : mFilterSp(sp), mFilterObj(obj) {} + +Filter::~Filter() { + EventFlag::deleteEventFlag(&mFilterMQEventFlag); +} + +int Filter::close() { + Result r = mFilterSp->close(); + if (r == Result::SUCCESS) { + EventFlag::deleteEventFlag(&mFilterMQEventFlag); + } + return (int)r; +} + +sp<IFilter> Filter::getIFilter() { + return mFilterSp; +} + /////////////// FrontendCallback /////////////////////// FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {} @@ -211,6 +235,7 @@ jobject JTuner::openFrontendById(int id) { fe->setCallback(feCb); jint jId = (jint) id; + JNIEnv *env = AndroidRuntime::getJNIEnv(); // TODO: add more fields to frontend return env->NewObject( @@ -327,18 +352,18 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { } } - sp<IFilter> filterSp; + sp<IFilter> iFilterSp; sp<FilterCallback> callback = new FilterCallback(); mDemux->openFilter(type, bufferSize, callback, [&](Result, const sp<IFilter>& filter) { - filterSp = filter; + iFilterSp = filter; }); - if (filterSp == NULL) { + if (iFilterSp == NULL) { ALOGD("Failed to open filter, type = %d", type.mainType); return NULL; } int fId; - filterSp->getId([&](Result, uint32_t filterId) { + iFilterSp->getId([&](Result, uint32_t filterId) { fId = filterId; }); @@ -350,6 +375,7 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { mObject, (jint) fId); + sp<Filter> filterSp = new Filter(iFilterSp, filterObj); filterSp->incStrong(filterObj); env->SetLongField(filterObj, gFields.filterContext, (jlong)filterSp.get()); @@ -432,7 +458,7 @@ static DemuxPid getDemuxPid(int pidType, int pid) { static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject settings) { FrontendSettings frontendSettings; jclass clazz = env->FindClass("android/media/tv/tuner/FrontendSettings"); - jfieldID freqField = env->GetFieldID(clazz, "frequency", "I"); + jfieldID freqField = env->GetFieldID(clazz, "mFrequency", "I"); uint32_t freq = static_cast<uint32_t>(env->GetIntField(clazz, freqField)); // TODO: handle the other 8 types of settings @@ -455,8 +481,8 @@ static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject setti return frontendSettings; } -static sp<IFilter> getFilter(JNIEnv *env, jobject filter) { - return (IFilter *)env->GetLongField(filter, gFields.filterContext); +static sp<Filter> getFilter(JNIEnv *env, jobject filter) { + return (Filter *)env->GetLongField(filter, gFields.filterContext); } static sp<IDvr> getDvr(JNIEnv *env, jobject dvr) { @@ -542,8 +568,100 @@ static jobject android_media_tv_Tuner_open_filter( return tuner->openFilter(filterType, bufferSize); } +static DemuxFilterSettings getFilterSettings( + JNIEnv *env, int type, int subtype, jobject filterSettingsObj) { + DemuxFilterSettings filterSettings; + // TODO: more setting types + jobject settingsObj = + env->GetObjectField( + filterSettingsObj, + env->GetFieldID( + env->FindClass("android/media/tv/tuner/FilterSettings"), + "mSettings", + "Landroid/media/tv/tuner/FilterSettings$Settings;")); + if (type == (int)DemuxFilterMainType::TS) { + // DemuxTsFilterSettings + jclass clazz = env->FindClass("android/media/tv/tuner/FilterSettings$TsFilterSettings"); + int tpid = env->GetIntField(filterSettingsObj, env->GetFieldID(clazz, "mTpid", "I")); + if (subtype == (int)DemuxTsFilterType::PES) { + // DemuxFilterPesDataSettings + jclass settingClazz = + env->FindClass("android/media/tv/tuner/FilterSettings$PesSettings"); + int streamId = env->GetIntField( + settingsObj, env->GetFieldID(settingClazz, "mStreamId", "I")); + bool isRaw = (bool)env->GetBooleanField( + settingsObj, env->GetFieldID(settingClazz, "mIsRaw", "Z")); + DemuxFilterPesDataSettings filterPesDataSettings { + .streamId = static_cast<uint16_t>(streamId), + .isRaw = isRaw, + }; + DemuxTsFilterSettings tsFilterSettings { + .tpid = static_cast<uint16_t>(tpid), + }; + tsFilterSettings.filterSettings.pesData(filterPesDataSettings); + filterSettings.ts(tsFilterSettings); + } + } + return filterSettings; +} + +static int copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jint offset, int size) { + ALOGD("copyData, size=%d, offset=%d", size, offset); + + int available = filter->mFilterMQ->availableToRead(); + ALOGD("copyData, available=%d", available); + size = std::min(size, available); + + jboolean isCopy; + jbyte *dst = env->GetByteArrayElements(buffer, &isCopy); + ALOGD("copyData, isCopy=%d", isCopy); + if (dst == nullptr) { + ALOGD("Failed to GetByteArrayElements"); + return 0; + } + + if (filter->mFilterMQ->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) { + env->ReleaseByteArrayElements(buffer, dst, 0); + filter->mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); + } else { + ALOGD("Failed to read FMQ"); + env->ReleaseByteArrayElements(buffer, dst, 0); + return 0; + } + return size; +} + +static int android_media_tv_Tuner_configure_filter( + JNIEnv *env, jobject filter, int type, int subtype, jobject settings) { + ALOGD("configure filter type=%d, subtype=%d", type, subtype); + sp<Filter> filterSp = getFilter(env, filter); + sp<IFilter> iFilterSp = filterSp->getIFilter(); + if (iFilterSp == NULL) { + ALOGD("Failed to configure filter: filter not found"); + return (int)Result::INVALID_STATE; + } + DemuxFilterSettings filterSettings = getFilterSettings(env, type, subtype, settings); + Result res = iFilterSp->configure(filterSettings); + MQDescriptorSync<uint8_t> filterMQDesc; + if (res == Result::SUCCESS && filterSp->mFilterMQ == NULL) { + Result getQueueDescResult = Result::UNKNOWN_ERROR; + iFilterSp->getQueueDesc( + [&](Result r, const MQDescriptorSync<uint8_t>& desc) { + filterMQDesc = desc; + getQueueDescResult = r; + ALOGD("getFilterQueueDesc"); + }); + if (getQueueDescResult == Result::SUCCESS) { + filterSp->mFilterMQ = std::make_unique<FilterMQ>(filterMQDesc, true); + EventFlag::createEventFlag( + filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag)); + } + } + return (int)res; +} + static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) { - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (filterSp == NULL) { ALOGD("Failed to start filter: filter not found"); return false; @@ -552,7 +670,7 @@ static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) { } static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) { - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (filterSp == NULL) { ALOGD("Failed to stop filter: filter not found"); return false; @@ -561,7 +679,7 @@ static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) { } static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) { - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (filterSp == NULL) { ALOGD("Failed to flush filter: filter not found"); return false; @@ -569,6 +687,16 @@ static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) { return filterSp->flush() == Result::SUCCESS; } +static int android_media_tv_Tuner_read_filter_fmq( + JNIEnv *env, jobject filter, jbyteArray buffer, jint offset, jint size) { + sp<Filter> filterSp = getFilter(env, filter); + if (filterSp == NULL) { + ALOGD("Failed to read filter FMQ: filter not found"); + return 0; + } + return copyData(env, filterSp, buffer, offset, size); +} + static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) { sp<JTuner> tuner = getTuner(env, thiz); return tuner->openDescrambler(); @@ -580,7 +708,7 @@ static bool android_media_tv_Tuner_add_pid( if (descramblerSp == NULL) { return false; } - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); Result result = descramblerSp->addPid(getDemuxPid((int)pidType, (int)pid), filterSp); return result == Result::SUCCESS; } @@ -591,7 +719,7 @@ static bool android_media_tv_Tuner_remove_pid( if (descramblerSp == NULL) { return false; } - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); Result result = descramblerSp->removePid(getDemuxPid((int)pidType, (int)pid), filterSp); return result == Result::SUCCESS; } @@ -603,7 +731,7 @@ static jobject android_media_tv_Tuner_open_dvr(JNIEnv *env, jobject thiz, jint t static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr); - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (dvrSp == NULL || filterSp == NULL) { return false; } @@ -613,7 +741,7 @@ static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobje static bool android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr); - sp<IFilter> filterSp = getFilter(env, filter); + sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (dvrSp == NULL || filterSp == NULL) { return false; } @@ -670,9 +798,12 @@ static const JNINativeMethod gTunerMethods[] = { }; static const JNINativeMethod gFilterMethods[] = { + { "nativeConfigureFilter", "(IILandroid/media/tv/tuner/FilterSettings;)I", + (void *)android_media_tv_Tuner_configure_filter }, { "nativeStartFilter", "()Z", (void *)android_media_tv_Tuner_start_filter }, { "nativeStopFilter", "()Z", (void *)android_media_tv_Tuner_stop_filter }, { "nativeFlushFilter", "()Z", (void *)android_media_tv_Tuner_flush_filter }, + { "nativeRead", "([BII)I", (void *)android_media_tv_Tuner_read_filter_fmq }, }; static const JNINativeMethod gDescramblerMethods[] = { diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index f856791e2618..467acb8cdbdd 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -18,13 +18,18 @@ #define _ANDROID_MEDIA_TV_TUNER_H_ #include <android/hardware/tv/tuner/1.0/ITuner.h> +#include <fmq/MessageQueue.h> #include <unordered_map> #include <utils/RefBase.h> #include "jni.h" +using ::android::hardware::EventFlag; +using ::android::hardware::MQDescriptorSync; +using ::android::hardware::MessageQueue; using ::android::hardware::Return; using ::android::hardware::hidl_vec; +using ::android::hardware::kSynchronizedReadWrite; using ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent; using ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus; using ::android::hardware::tv::tuner::V1_0::DemuxFilterType; @@ -51,6 +56,8 @@ using ::android::hardware::tv::tuner::V1_0::LnbId; using ::android::hardware::tv::tuner::V1_0::PlaybackStatus; using ::android::hardware::tv::tuner::V1_0::RecordStatus; +using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; + namespace android { struct LnbCallback : public ILnbCallback { @@ -91,6 +98,17 @@ struct FrontendCallback : public IFrontendCallback { FrontendId mId; }; +struct Filter : public RefBase { + Filter(sp<IFilter> sp, jweak obj); + ~Filter(); + int close(); + sp<IFilter> getIFilter(); + sp<IFilter> mFilterSp; + std::unique_ptr<FilterMQ> mFilterMQ; + EventFlag* mFilterMQEventFlag; + jweak mFilterObj; +}; + struct JTuner : public RefBase { JTuner(JNIEnv *env, jobject thiz); sp<ITuner> getTunerService(); diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp index 79e4d8ae6e26..c8f0ff10ca3f 100644 --- a/media/jni/soundpool/StreamManager.cpp +++ b/media/jni/soundpool/StreamManager.cpp @@ -38,7 +38,7 @@ static constexpr bool kStealActiveStream_OldestFirst = true; // kPlayOnCallingThread = true prior to R. // Changing to false means calls to play() are almost instantaneous instead of taking around // ~10ms to launch the AudioTrack. It is perhaps 100x faster. -static constexpr bool kPlayOnCallingThread = true; +static constexpr bool kPlayOnCallingThread = false; // Amount of time for a StreamManager thread to wait before closing. static constexpr int64_t kWaitTimeBeforeCloseNs = 9 * NANOS_PER_SECOND; @@ -170,7 +170,6 @@ int32_t StreamManager::queueForPlay(const std::shared_ptr<Sound> &sound, if (stream->getSoundID() == soundID) { ALOGV("%s: found soundID %d in restart queue", __func__, soundID); newStream = stream; - fromAvailableQueue = false; break; } else if (newStream == nullptr) { ALOGV("%s: found stream in restart queue", __func__); diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java index 45430197fdd8..291cdd5ea3d8 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java @@ -35,6 +35,7 @@ import android.view.ViewStub; import androidx.recyclerview.widget.GridLayoutManager; +import com.android.internal.widget.LockPatternUtils; import com.android.systemui.R; import com.android.systemui.car.CarServiceProvider; import com.android.systemui.dagger.qualifiers.MainResources; @@ -135,8 +136,9 @@ public class FullscreenUserSwitcher { /* isAddUser= */ false, /* isForeground= */ true); - // If the initial user has trusted device, display the unlock dialog on the keyguard. - if (hasTrustedDevice(initialUser)) { + // If the initial user has screen lock and trusted device, display the unlock dialog on the + // keyguard. + if (hasScreenLock(initialUser) && hasTrustedDevice(initialUser)) { mUnlockDialogHelper.showUnlockDialogAfterDelay(initialUser, mOnHideListener); } else { @@ -178,7 +180,7 @@ public class FullscreenUserSwitcher { */ private void onUserSelected(UserGridRecyclerView.UserRecord record) { mSelectedUser = record; - if (hasTrustedDevice(record.mInfo.id)) { + if (hasScreenLock(record.mInfo.id) && hasTrustedDevice(record.mInfo.id)) { mUnlockDialogHelper.showUnlockDialog(record.mInfo.id, mOnHideListener); return; } @@ -216,6 +218,12 @@ public class FullscreenUserSwitcher { } + private boolean hasScreenLock(int uid) { + LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); + return lockPatternUtils.getCredentialTypeForUser(uid) + != LockPatternUtils.CREDENTIAL_TYPE_NONE; + } + private boolean hasTrustedDevice(int uid) { if (mEnrollmentManager == null) { // car service not ready, so it cannot be available. return false; diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING index 26ec5726a4a2..9f13a7b861a0 100644 --- a/packages/SystemUI/TEST_MAPPING +++ b/packages/SystemUI/TEST_MAPPING @@ -9,12 +9,6 @@ "include-filter": "android.platform.test.scenario.sysui" }, { - "include-filter": "android.platform.test.scenario.quicksettings" - }, - { - "include-filter": "android.platform.test.scenario.notification" - }, - { "include-annotation": "android.platform.test.scenario.annotation.Scenario" }, { diff --git a/packages/SystemUI/res/layout/bubble_menu_view.xml b/packages/SystemUI/res/layout/bubble_menu_view.xml new file mode 100644 index 000000000000..24608d3e9611 --- /dev/null +++ b/packages/SystemUI/res/layout/bubble_menu_view.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<com.android.systemui.bubbles.BubbleMenuView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="match_parent" + android:layout_width="match_parent" + android:background="#66000000" + android:visibility="gone" + android:id="@+id/bubble_menu_container"> + + <FrameLayout + android:layout_height="@dimen/individual_bubble_size" + android:layout_width="wrap_content" + android:background="#FFFFFF" + android:id="@+id/bubble_menu_view"> + + <ImageView + android:id="@*android:id/icon" + android:layout_width="@dimen/global_actions_grid_item_icon_width" + android:layout_height="@dimen/global_actions_grid_item_icon_height" + android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin" + android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin" + android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin" + android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin" + android:scaleType="centerInside" + android:tint="@color/global_actions_text" + /> + </FrameLayout> +</com.android.systemui.bubbles.BubbleMenuView> diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml new file mode 100644 index 000000000000..27db294a98d8 --- /dev/null +++ b/packages/SystemUI/res/values-television/config.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources> + <!-- SystemUI Services: The classes of the stuff to start. --> + <string-array name="config_systemUIServiceComponents" translatable="false"> + <item>com.android.systemui.volume.VolumeUI</item> + <item>com.android.systemui.stackdivider.Divider</item> + <item>com.android.systemui.statusbar.tv.TvStatusBar</item> + <item>com.android.systemui.usb.StorageNotification</item> + <item>com.android.systemui.power.PowerUI</item> + <item>com.android.systemui.media.RingtonePlayer</item> + <item>com.android.systemui.keyboard.KeyboardUI</item> + <item>com.android.systemui.pip.PipUI</item> + <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item> + <item>@string/config_systemUIVendorServiceComponent</item> + <item>com.android.systemui.SliceBroadcastRelayHandler</item> + <item>com.android.systemui.SizeCompatModeActivityController</item> + <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item> + </string-array> +</resources> diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index dbb193669083..19381940543e 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -44,13 +44,19 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.UserIdInt; import android.app.ActivityManager.RunningTaskInfo; +import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.RemoteInput; import android.content.Context; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.content.pm.ShortcutManager; import android.content.res.Configuration; import android.graphics.Rect; +import android.net.Uri; +import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; import android.service.notification.NotificationListenerService.RankingMap; @@ -69,6 +75,7 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.util.ScreenshotHelper; import com.android.systemui.R; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -86,6 +93,7 @@ import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.ZenModeController; import java.io.FileDescriptor; @@ -93,8 +101,10 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Singleton; @@ -138,6 +148,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi @Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer; private final NotificationGroupManager mNotificationGroupManager; private final Lazy<ShadeController> mShadeController; + private final RemoteInputUriController mRemoteInputUriController; + private Handler mHandler = new Handler() {}; private BubbleData mBubbleData; @Nullable private BubbleStackView mStackView; @@ -155,6 +167,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi private final StatusBarWindowController mStatusBarWindowController; private final ZenModeController mZenModeController; private StatusBarStateListener mStatusBarStateListener; + private final ScreenshotHelper mScreenshotHelper; + private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; private IStatusBarService mBarService; @@ -192,6 +206,16 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } /** + * Listener for handling bubble screenshot events. + */ + public interface BubbleScreenshotListener { + /** + * Called to trigger taking a screenshot and sending the result to a bubble. + */ + void onBubbleScreenshot(Bubble bubble); + } + + /** * Listens for the current state of the status bar and updates the visibility state * of bubbles as needed. */ @@ -226,10 +250,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager, NotificationGroupManager groupManager, - NotificationEntryManager entryManager) { + NotificationEntryManager entryManager, + RemoteInputUriController remoteInputUriController) { this(context, statusBarWindowController, statusBarStateController, shadeController, data, null /* synchronizer */, configurationController, interruptionStateProvider, - zenModeController, notifUserManager, groupManager, entryManager); + zenModeController, notifUserManager, groupManager, entryManager, + remoteInputUriController); } public BubbleController(Context context, @@ -243,11 +269,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager, NotificationGroupManager groupManager, - NotificationEntryManager entryManager) { + NotificationEntryManager entryManager, + RemoteInputUriController remoteInputUriController) { mContext = context; mNotificationInterruptionStateProvider = interruptionStateProvider; mNotifUserManager = notifUserManager; mZenModeController = zenModeController; + mRemoteInputUriController = remoteInputUriController; mZenModeController.addCallback(new ZenModeController.Callback() { @Override public void onZenChanged(int zen) { @@ -320,6 +348,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi }); mUserCreatedBubbles = new HashSet<>(); + + mScreenshotHelper = new ScreenshotHelper(context); } /** @@ -337,6 +367,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (mExpandListener != null) { mStackView.setExpandListener(mExpandListener); } + if (mBubbleScreenshotListener != null) { + mStackView.setBubbleScreenshotListener(mBubbleScreenshotListener); + } } } @@ -1058,4 +1091,71 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } } } + + // TODO: Copied from RemoteInputView. Consolidate RemoteInput intent logic. + private Intent prepareRemoteInputFromData(String contentType, Uri data, + RemoteInput remoteInput, NotificationEntry entry) { + HashMap<String, Uri> results = new HashMap<>(); + results.put(contentType, data); + mRemoteInputUriController.grantInlineReplyUriPermission(entry.getSbn(), data); + Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + RemoteInput.addDataResultToIntent(remoteInput, fillInIntent, results); + + return fillInIntent; + } + + // TODO: Copied from RemoteInputView. Consolidate RemoteInput intent logic. + private void sendRemoteInput(Intent intent, NotificationEntry entry, + PendingIntent pendingIntent) { + // Tell ShortcutManager that this package has been "activated". ShortcutManager + // will reset the throttling for this package. + // Strictly speaking, the intent receiver may be different from the notification publisher, + // but that's an edge case, and also because we can't always know which package will receive + // an intent, so we just reset for the publisher. + mContext.getSystemService(ShortcutManager.class).onApplicationActive( + entry.getSbn().getPackageName(), + entry.getSbn().getUser().getIdentifier()); + + try { + pendingIntent.send(mContext, 0, intent); + } catch (PendingIntent.CanceledException e) { + Log.i(TAG, "Unable to send remote input result", e); + } + } + + private void sendScreenshotToBubble(Bubble bubble) { + // delay allows the bubble menu to disappear before the screenshot + // done here because we already have a Handler to delay with. + // TODO: Hide bubble + menu UI from screenshots entirely instead of just delaying. + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + mScreenshotHelper.takeScreenshot( + android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN, + true /* hasStatus */, + true /* hasNav */, + mHandler, + new Consumer<Uri>() { + @Override + public void accept(Uri uri) { + if (uri != null) { + NotificationEntry entry = bubble.getEntry(); + Pair<RemoteInput, Notification.Action> pair = entry.getSbn() + .getNotification().findRemoteInputActionPair(false); + RemoteInput remoteInput = pair.first; + Notification.Action action = pair.second; + Intent dataIntent = prepareRemoteInputFromData("image/png", uri, + remoteInput, entry); + sendRemoteInput(dataIntent, entry, action.actionIntent); + mBubbleData.setSelectedBubble(bubble); + mBubbleData.setExpanded(true); + } + } + }); + } + }, 200); + } + + private final BubbleScreenshotListener mBubbleScreenshotListener = + bubble -> sendScreenshotToBubble(bubble); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java index e138d9387ca6..8299f2261b8e 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java @@ -68,6 +68,9 @@ public class BubbleExperimentConfig { private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps"; + private static final String ALLOW_BUBBLE_MENU = "allow_bubble_screenshot_menu"; + private static final boolean ALLOW_BUBBLE_MENU_DEFAULT = false; + /** * When true, if a notification has the information necessary to bubble (i.e. valid * contentIntent and an icon or image), then a {@link android.app.Notification.BubbleMetadata} @@ -123,6 +126,16 @@ public class BubbleExperimentConfig { } /** + * When true, show a menu when a bubble is long-pressed, which will allow the user to take + * actions on that bubble. + */ + static boolean allowBubbleScreenshotMenu(Context context) { + return Settings.Secure.getInt(context.getContentResolver(), + ALLOW_BUBBLE_MENU, + ALLOW_BUBBLE_MENU_DEFAULT ? 1 : 0) != 0; + } + + /** * If {@link #allowAnyNotifToBubble(Context)} is true, this method creates and adds * {@link android.app.Notification.BubbleMetadata} to the notification entry as long as * the notification has necessary info for BubbleMetadata. diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java new file mode 100644 index 000000000000..e8eb72e8392f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java @@ -0,0 +1,81 @@ +/* + * 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 com.android.systemui.bubbles; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.android.systemui.R; + +/** + * Menu which allows users to take actions on bubbles, ex. screenshots. + */ +public class BubbleMenuView extends FrameLayout { + private FrameLayout mMenu; + private boolean mShowing = false; + + public BubbleMenuView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public BubbleMenuView(Context context) { + super(context); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mMenu = findViewById(R.id.bubble_menu_view); + ImageView icon = findViewById(com.android.internal.R.id.icon); + icon.setImageDrawable(mContext.getDrawable(com.android.internal.R.drawable.ic_screenshot)); + } + + /** + * Get the bubble menu view. + */ + public View getMenuView() { + return mMenu; + } + + /** + * Checks whether the bubble menu is currently displayed. + */ + public boolean isShowing() { + return mShowing; + } + + /** + * Show the bubble menu at the specified position on the screen. + */ + public void show(float x, float y) { + mShowing = true; + this.setVisibility(VISIBLE); + mMenu.setTranslationX(x); + mMenu.setTranslationY(y); + } + + /** + * Hide the bubble menu. + */ + public void hide() { + mShowing = false; + this.setVisibility(GONE); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 29de2f049690..29a4bb1fca84 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -110,6 +110,7 @@ public class BubbleStackView extends FrameLayout { /** How long to wait, in milliseconds, before hiding the flyout. */ @VisibleForTesting static final int FLYOUT_HIDE_AFTER = 5000; + private BubbleController.BubbleScreenshotListener mBubbleScreenshotListener; /** * Interface to synchronize {@link View} state and the screen. @@ -163,6 +164,7 @@ public class BubbleStackView extends FrameLayout { private ExpandedAnimationController mExpandedAnimationController; private FrameLayout mExpandedViewContainer; + @Nullable private BubbleMenuView mBubbleMenuView; private BubbleFlyoutView mFlyout; /** Runnable that fades out the flyout and then sets it to GONE. */ @@ -194,6 +196,7 @@ public class BubbleStackView extends FrameLayout { private int mPointerHeight; private int mStatusBarHeight; private int mImeOffset; + private int mBubbleMenuOffset = 252; private BubbleIconFactory mBubbleIconFactory; private Bubble mExpandedBubble; private boolean mIsExpanded; @@ -492,6 +495,9 @@ public class BubbleStackView extends FrameLayout { mDesaturateAndDarkenPaint.setColorFilter(new ColorMatrixColorFilter(animatedMatrix)); mDesaturateAndDarkenTargetView.setLayerPaint(mDesaturateAndDarkenPaint); }); + + mInflater.inflate(R.layout.bubble_menu_view, this); + mBubbleMenuView = findViewById(R.id.bubble_menu_container); } private void setUpFlyout() { @@ -683,6 +689,13 @@ public class BubbleStackView extends FrameLayout { } /** + * Sets the screenshot listener. + */ + public void setBubbleScreenshotListener(BubbleController.BubbleScreenshotListener listener) { + mBubbleScreenshotListener = listener; + } + + /** * Whether the stack of bubbles is expanded or not. */ public boolean isExpanded() { @@ -870,6 +883,12 @@ public class BubbleStackView extends FrameLayout { public View getTargetView(MotionEvent event) { float x = event.getRawX(); float y = event.getRawY(); + if (mBubbleMenuView.isShowing()) { + if (isIntersecting(mBubbleMenuView.getMenuView(), x, y)) { + return mBubbleMenuView; + } + return null; + } if (mIsExpanded) { if (isIntersecting(mBubbleContainer, x, y)) { // Could be tapping or dragging a bubble while expanded @@ -1074,6 +1093,7 @@ public class BubbleStackView extends FrameLayout { return; } + hideBubbleMenu(); mStackAnimationController.cancelStackPositionAnimations(); mBubbleContainer.setActiveController(mStackAnimationController); hideFlyoutImmediate(); @@ -1473,6 +1493,11 @@ public class BubbleStackView extends FrameLayout { @Override public void getBoundsOnScreen(Rect outRect) { + // If the bubble menu is open, the entire screen should capture touch events. + if (mBubbleMenuView.isShowing()) { + outRect.set(0, 0, getWidth(), getHeight()); + return; + } if (!mIsExpanded) { if (mBubbleContainer.getChildCount() > 0) { mBubbleContainer.getChildAt(0).getBoundsOnScreen(outRect); @@ -1700,4 +1725,43 @@ public class BubbleStackView extends FrameLayout { } return bubbles; } + + /** + * Show the bubble menu, positioned relative to the stack. + */ + public void showBubbleMenu() { + PointF currentPos = mStackAnimationController.getStackPosition(); + float yPos = currentPos.y; + float xPos = currentPos.x; + if (mStackAnimationController.isStackOnLeftSide()) { + xPos += mBubbleSize; + } else { + //TODO: Use the width of the menu instead of this fixed offset. Offset used for now + // because menu width isn't correct the first time the menu is shown. + xPos -= mBubbleMenuOffset; + } + + mBubbleMenuView.show(xPos, yPos); + } + + /** + * Hide the bubble menu. + */ + public void hideBubbleMenu() { + mBubbleMenuView.hide(); + } + + /** + * Determines whether the bubble menu is currently showing. + */ + public boolean isShowingBubbleMenu() { + return mBubbleMenuView.isShowing(); + } + + /** + * Take a screenshot and send it to the specified bubble. + */ + public void sendScreenshotToBubble(Bubble bubble) { + mBubbleScreenshotListener.onBubbleScreenshot(bubble); + } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java index 44e013a34f54..b1d205c79c99 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java @@ -57,6 +57,7 @@ class BubbleTouchHandler implements View.OnTouchListener { private final PointF mViewPositionOnTouchDown = new PointF(); private final BubbleStackView mStack; private final BubbleData mBubbleData; + private final Context mContext; private BubbleController mController = Dependency.get(BubbleController.class); @@ -75,6 +76,7 @@ class BubbleTouchHandler implements View.OnTouchListener { mTouchSlopSquared = touchSlop * touchSlop; mBubbleData = bubbleData; mStack = stackView; + mContext = context; } @Override @@ -91,15 +93,24 @@ class BubbleTouchHandler implements View.OnTouchListener { // anything, collapse the stack. if (action == MotionEvent.ACTION_OUTSIDE || mTouchedView == null) { mBubbleData.setExpanded(false); + mStack.hideBubbleMenu(); resetForNextGesture(); return false; } + if (mTouchedView instanceof BubbleMenuView) { + mStack.hideBubbleMenu(); + resetForNextGesture(); + mStack.sendScreenshotToBubble(mBubbleData.getSelectedBubble()); + return false; + } + if (!(mTouchedView instanceof BadgedImageView) && !(mTouchedView instanceof BubbleStackView) && !(mTouchedView instanceof BubbleFlyoutView)) { // Not touching anything touchable, but we shouldn't collapse (e.g. touching edge // of expanded view). + mStack.hideBubbleMenu(); resetForNextGesture(); return false; } @@ -132,6 +143,10 @@ class BubbleTouchHandler implements View.OnTouchListener { break; case MotionEvent.ACTION_MOVE: + // block all further touch inputs once the menu is open + if (mStack.isShowingBubbleMenu()) { + return true; + } trackMovement(event); final float deltaX = rawX - mTouchDown.x; final float deltaY = rawY - mTouchDown.y; @@ -148,6 +163,13 @@ class BubbleTouchHandler implements View.OnTouchListener { } else { mStack.onBubbleDragged(mTouchedView, viewX, viewY); } + } else { + float touchTime = event.getEventTime() - event.getDownTime(); + if (touchTime > ViewConfiguration.getLongPressTimeout() && !mStack.isExpanded() + && BubbleExperimentConfig.allowBubbleScreenshotMenu(mContext)) { + mStack.showBubbleMenu(); + return true; + } } final boolean currentlyInDismissTarget = mStack.isInDismissTarget(event); @@ -171,6 +193,10 @@ class BubbleTouchHandler implements View.OnTouchListener { break; case MotionEvent.ACTION_UP: + if (mStack.isShowingBubbleMenu()) { + resetForNextGesture(); + return true; + } trackMovement(event); mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000); final float velX = mVelocityTracker.getXVelocity(); @@ -261,7 +287,6 @@ class BubbleTouchHandler implements View.OnTouchListener { mVelocityTracker.recycle(); mVelocityTracker = null; } - mTouchedView = null; mMovedEnough = false; mInDismissTarget = false; diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 4c707f45efc1..ae43aa2f4118 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -82,6 +82,7 @@ import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.InjectionInflationController; @@ -153,6 +154,8 @@ public class BubbleControllerTest extends SysuiTestCase { private Resources mResources; @Mock private Lazy<ShadeController> mShadeController; + @Mock + private RemoteInputUriController mRemoteInputUriController; private SuperStatusBarViewFactory mSuperStatusBarViewFactory; private BubbleData mBubbleData; @@ -212,7 +215,8 @@ public class BubbleControllerTest extends SysuiTestCase { mZenModeController, mLockscreenUserManager, mNotificationGroupManager, - mNotificationEntryManager); + mNotificationEntryManager, + mRemoteInputUriController); mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener); mBubbleController.setExpandListener(mBubbleExpandListener); @@ -708,11 +712,13 @@ public class BubbleControllerTest extends SysuiTestCase { ZenModeController zenModeController, NotificationLockscreenUserManager lockscreenUserManager, NotificationGroupManager groupManager, - NotificationEntryManager entryManager) { + NotificationEntryManager entryManager, + RemoteInputUriController remoteInputUriController) { super(context, statusBarWindowController, statusBarStateController, shadeController, data, Runnable::run, configurationController, interruptionStateProvider, - zenModeController, lockscreenUserManager, groupManager, entryManager); + zenModeController, lockscreenUserManager, groupManager, entryManager, + remoteInputUriController); } } diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index e79a2897d86a..840b7af19890 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -16,6 +16,7 @@ package com.android.server; +import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.NETWORK_SETTINGS; import static android.Manifest.permission.OBSERVE_NETWORK_POLICY; import static android.Manifest.permission.SHUTDOWN; @@ -737,7 +738,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub { // @Override public String[] listInterfaces() { - NetworkStack.checkNetworkStackPermission(mContext); + // TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these + // APIs. + NetworkStack.checkNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL); try { return mNetdService.interfaceGetList(); } catch (RemoteException | ServiceSpecificException e) { @@ -787,7 +790,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public InterfaceConfiguration getInterfaceConfig(String iface) { - NetworkStack.checkNetworkStackPermission(mContext); + // TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these + // APIs. + NetworkStack.checkNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL); final InterfaceConfigurationParcel result; try { result = mNetdService.interfaceGetCfg(iface); @@ -805,7 +810,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) { - NetworkStack.checkNetworkStackPermission(mContext); + // TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these + // APIs. + NetworkStack.checkNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL); LinkAddress linkAddr = cfg.getLinkAddress(); if (linkAddr == null || linkAddr.getAddress() == null) { throw new IllegalStateException("Null LinkAddress given"); diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index 12debbff3e90..521b39305d9d 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -57,6 +57,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; @@ -81,6 +82,22 @@ public class PackageWatchdog { static final String PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED = "watchdog_explicit_health_check_enabled"; + public static final int FAILURE_REASON_UNKNOWN = 0; + public static final int FAILURE_REASON_NATIVE_CRASH = 1; + public static final int FAILURE_REASON_EXPLICIT_HEALTH_CHECK = 2; + public static final int FAILURE_REASON_APP_CRASH = 3; + public static final int FAILURE_REASON_APP_NOT_RESPONDING = 4; + + @IntDef(prefix = { "FAILURE_REASON_" }, value = { + FAILURE_REASON_UNKNOWN, + FAILURE_REASON_NATIVE_CRASH, + FAILURE_REASON_EXPLICIT_HEALTH_CHECK, + FAILURE_REASON_APP_CRASH, + FAILURE_REASON_APP_NOT_RESPONDING + }) + @Retention(RetentionPolicy.SOURCE) + public @interface FailureReasons {} + // Duration to count package failures before it resets to 0 @VisibleForTesting static final int DEFAULT_TRIGGER_FAILURE_DURATION_MS = @@ -305,14 +322,15 @@ public class PackageWatchdog { } /** - * Called when a process fails either due to a crash or ANR. + * Called when a process fails due to a crash, ANR or explicit health check. * * <p>For each package contained in the process, one registered observer with the least user * impact will be notified for mitigation. * * <p>This method could be called frequently if there is a severe problem on the device. */ - public void onPackageFailure(List<VersionedPackage> packages) { + public void onPackageFailure(List<VersionedPackage> packages, + @FailureReasons int failureReason) { mLongTaskHandler.post(() -> { synchronized (mLock) { if (mAllObservers.isEmpty()) { @@ -343,7 +361,7 @@ public class PackageWatchdog { // Execute action with least user impact if (currentObserverToNotify != null) { - currentObserverToNotify.execute(versionedPackage); + currentObserverToNotify.execute(versionedPackage, failureReason); } } } @@ -414,7 +432,7 @@ public class PackageWatchdog { * * @return {@code true} if action was executed successfully, {@code false} otherwise */ - boolean execute(VersionedPackage versionedPackage); + boolean execute(VersionedPackage versionedPackage, @FailureReasons int failureReason); // TODO(b/120598832): Ensure uniqueness? /** @@ -659,7 +677,8 @@ public class PackageWatchdog { while (it.hasNext()) { VersionedPackage versionedPkg = it.next().mPackage; Slog.i(TAG, "Explicit health check failed for package " + versionedPkg); - registeredObserver.execute(versionedPkg); + registeredObserver.execute(versionedPkg, + PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK); } } } @@ -770,7 +789,7 @@ public class PackageWatchdog { final List<VersionedPackage> pkgList = Collections.singletonList(pkg); final long failureCount = getTriggerFailureCount(); for (int i = 0; i < failureCount; i++) { - onPackageFailure(pkgList); + onPackageFailure(pkgList, FAILURE_REASON_EXPLICIT_HEALTH_CHECK); } }); } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 51e1718d4c98..83a7341923fa 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -446,7 +446,8 @@ class AppErrors { RescueParty.noteAppCrash(mContext, r.uid); } - mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode()); + mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode(), + PackageWatchdog.FAILURE_REASON_APP_CRASH); } final int relaunchReason = r != null @@ -900,7 +901,8 @@ class AppErrors { } // Notify PackageWatchdog without the lock held if (packageList != null) { - mPackageWatchdog.onPackageFailure(packageList); + mPackageWatchdog.onPackageFailure(packageList, + PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING); } } diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index 38030c248139..cf996a50d5c7 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -125,7 +125,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { // Keep the last WiFi stats so we can compute a delta. @GuardedBy("mWorkerLock") private WifiActivityEnergyInfo mLastInfo = - new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0, 0); + new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0); /** * Timestamp at which all external stats were last collected in diff --git a/services/core/java/com/android/server/integrity/model/BitInputStream.java b/services/core/java/com/android/server/integrity/model/BitInputStream.java index 09bc7e8b9861..e768fe6626ac 100644 --- a/services/core/java/com/android/server/integrity/model/BitInputStream.java +++ b/services/core/java/com/android/server/integrity/model/BitInputStream.java @@ -16,15 +16,29 @@ package com.android.server.integrity.model; +import java.io.IOException; +import java.io.InputStream; + /** A wrapper class for reading a stream of bits. */ public class BitInputStream { - private byte[] mRuleBytes; private long mBitPointer; + private boolean mReadFromStream; + + private byte[] mRuleBytes; + private InputStream mRuleInputStream; + + private byte mCurrentRuleByte; public BitInputStream(byte[] ruleBytes) { this.mRuleBytes = ruleBytes; this.mBitPointer = 0; + this.mReadFromStream = false; + } + + public BitInputStream(InputStream ruleInputStream) { + this.mRuleInputStream = ruleInputStream; + this.mReadFromStream = true; } /** @@ -33,34 +47,43 @@ public class BitInputStream { * @param numOfBits The number of bits to read. * @return The value read from the stream. */ - public int getNext(int numOfBits) { + public int getNext(int numOfBits) throws IOException { int component = 0; int count = 0; - int idx = (int) (mBitPointer / 8); - int offset = 7 - (int) (mBitPointer % 8); - while (count++ < numOfBits) { - if (idx >= mRuleBytes.length) { - throw new IllegalArgumentException(String.format("Invalid byte index: %d", idx)); + if (mBitPointer % 8 == 0) { + mCurrentRuleByte = getNextByte(); } + int offset = 7 - (int) (mBitPointer % 8); component <<= 1; - component |= (mRuleBytes[idx] >>> offset) & 1; + component |= (mCurrentRuleByte >>> offset) & 1; - offset--; - if (offset == -1) { - idx++; - offset = 7; - } + mBitPointer++; } - mBitPointer += numOfBits; return component; } /** Check if there are bits left in the stream. */ - public boolean hasNext() { - return mBitPointer / 8 < mRuleBytes.length; + public boolean hasNext() throws IOException { + if (mReadFromStream) { + return mRuleInputStream.available() > 0; + } else { + return mBitPointer / 8 < mRuleBytes.length; + } + } + + private byte getNextByte() throws IOException { + if (mReadFromStream) { + return (byte) mRuleInputStream.read(); + } else { + int idx = (int) (mBitPointer / 8); + if (idx >= mRuleBytes.length) { + throw new IllegalArgumentException(String.format("Invalid byte index: %d", idx)); + } + return mRuleBytes[idx]; + } } } 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 8aa0751af11c..3ef45a637bc1 100644 --- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java +++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java @@ -36,6 +36,7 @@ import android.content.integrity.Rule; import com.android.server.integrity.model.BitInputStream; +import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -56,15 +57,14 @@ public class RuleBinaryParser implements RuleParser { @Override public List<Rule> parse(InputStream inputStream) throws RuleParseException { try { - byte[] ruleBytes = new byte[inputStream.available()]; - inputStream.read(ruleBytes); - return parse(ruleBytes); + BitInputStream bitInputStream = new BitInputStream(inputStream); + return parseRules(bitInputStream); } catch (Exception e) { throw new RuleParseException(e.getMessage(), e); } } - private List<Rule> parseRules(BitInputStream bitInputStream) { + private List<Rule> parseRules(BitInputStream bitInputStream) throws IOException { List<Rule> parsedRules = new ArrayList<>(); // Read the rule binary file format version. @@ -79,7 +79,7 @@ public class RuleBinaryParser implements RuleParser { return parsedRules; } - private Rule parseRule(BitInputStream bitInputStream) { + private Rule parseRule(BitInputStream bitInputStream) throws IOException { Formula formula = parseFormula(bitInputStream); int effect = bitInputStream.getNext(EFFECT_BITS); @@ -90,7 +90,7 @@ public class RuleBinaryParser implements RuleParser { return new Rule(formula, effect); } - private Formula parseFormula(BitInputStream bitInputStream) { + private Formula parseFormula(BitInputStream bitInputStream) throws IOException { int separator = bitInputStream.getNext(SEPARATOR_BITS); switch (separator) { case ATOMIC_FORMULA_START: @@ -105,7 +105,7 @@ public class RuleBinaryParser implements RuleParser { } } - private CompoundFormula parseCompoundFormula(BitInputStream bitInputStream) { + private CompoundFormula parseCompoundFormula(BitInputStream bitInputStream) throws IOException { int connector = bitInputStream.getNext(CONNECTOR_BITS); List<Formula> formulas = new ArrayList<>(); @@ -118,7 +118,7 @@ public class RuleBinaryParser implements RuleParser { return new CompoundFormula(connector, formulas); } - private AtomicFormula parseAtomicFormula(BitInputStream bitInputStream) { + private AtomicFormula parseAtomicFormula(BitInputStream bitInputStream) throws IOException { int key = bitInputStream.getNext(KEY_BITS); int operator = bitInputStream.getNext(OPERATOR_BITS); 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 b988fd4c40f1..fdbb7d9df293 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java @@ -127,7 +127,7 @@ public class RuleBinarySerializer implements RuleSerializer { bitOutputStream.setNext(SEPARATOR_BITS, ATOMIC_FORMULA_START); bitOutputStream.setNext(KEY_BITS, atomicFormula.getKey()); - if (atomicFormula instanceof AtomicFormula.StringAtomicFormula) { + if (atomicFormula.getTag() == AtomicFormula.STRING_ATOMIC_FORMULA_TAG) { AtomicFormula.StringAtomicFormula stringAtomicFormula = (AtomicFormula.StringAtomicFormula) atomicFormula; bitOutputStream.setNext(OPERATOR_BITS, AtomicFormula.EQ); @@ -135,7 +135,7 @@ public class RuleBinarySerializer implements RuleSerializer { stringAtomicFormula.getValue(), stringAtomicFormula.getIsHashedValue(), bitOutputStream); - } else if (atomicFormula instanceof AtomicFormula.IntAtomicFormula) { + } else if (atomicFormula.getTag() == AtomicFormula.INT_ATOMIC_FORMULA_TAG) { AtomicFormula.IntAtomicFormula intAtomicFormula = (AtomicFormula.IntAtomicFormula) atomicFormula; bitOutputStream.setNext(OPERATOR_BITS, intAtomicFormula.getOperator()); @@ -143,7 +143,7 @@ public class RuleBinarySerializer implements RuleSerializer { String.valueOf(intAtomicFormula.getValue()), /* isHashedValue= */ false, bitOutputStream); - } else if (atomicFormula instanceof AtomicFormula.BooleanAtomicFormula) { + } else if (atomicFormula.getTag() == AtomicFormula.BOOLEAN_ATOMIC_FORMULA_TAG) { AtomicFormula.BooleanAtomicFormula booleanAtomicFormula = (AtomicFormula.BooleanAtomicFormula) atomicFormula; bitOutputStream.setNext(OPERATOR_BITS, AtomicFormula.EQ); 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 72068ceeb4f0..cfe50c6c8ac9 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java @@ -127,7 +127,7 @@ public class RuleXmlSerializer implements RuleSerializer { xmlSerializer.startTag(NAMESPACE, ATOMIC_FORMULA_TAG); serializeAttributeValue( KEY_ATTRIBUTE, String.valueOf(atomicFormula.getKey()), xmlSerializer); - if (atomicFormula instanceof AtomicFormula.StringAtomicFormula) { + if (atomicFormula.getTag() == AtomicFormula.STRING_ATOMIC_FORMULA_TAG) { serializeAttributeValue( VALUE_ATTRIBUTE, ((AtomicFormula.StringAtomicFormula) atomicFormula).getValue(), @@ -137,7 +137,7 @@ public class RuleXmlSerializer implements RuleSerializer { String.valueOf( ((AtomicFormula.StringAtomicFormula) atomicFormula).getIsHashedValue()), xmlSerializer); - } else if (atomicFormula instanceof AtomicFormula.IntAtomicFormula) { + } else if (atomicFormula.getTag() == AtomicFormula.INT_ATOMIC_FORMULA_TAG) { serializeAttributeValue( OPERATOR_ATTRIBUTE, String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getOperator()), @@ -146,7 +146,7 @@ public class RuleXmlSerializer implements RuleSerializer { VALUE_ATTRIBUTE, String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getValue()), xmlSerializer); - } else if (atomicFormula instanceof AtomicFormula.BooleanAtomicFormula) { + } else if (atomicFormula.getTag() == AtomicFormula.BOOLEAN_ATOMIC_FORMULA_TAG) { serializeAttributeValue( VALUE_ATTRIBUTE, String.valueOf(((AtomicFormula.BooleanAtomicFormula) atomicFormula).getValue()), diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 83b62159f9b0..ec4aedd01cea 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -379,7 +379,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!"); try (LockscreenCredential unifiedProfilePassword = generateRandomProfilePassword()) { setLockCredentialInternal(unifiedProfilePassword, managedUserPassword, managedUserId, - false, /* isLockTiedToParent= */ true); + /* isLockTiedToParent= */ true); tieProfileLockToParent(managedUserId, unifiedProfilePassword); } } @@ -1473,17 +1473,12 @@ public class LockSettingsService extends ILockSettings.Stub { setLockCredentialInternal(LockscreenCredential.createNone(), profilePasswordMap.get(managedUserId), managedUserId, - false, /* isLockTiedToParent= */ true); + /* isLockTiedToParent= */ true); + mStorage.removeChildProfileLock(managedUserId); + removeKeystoreProfileKey(managedUserId); } else { - Slog.wtf(TAG, "clear tied profile challenges, but no password supplied."); - // Attempt an untrusted reset by supplying an empty credential. - setLockCredentialInternal(LockscreenCredential.createNone(), - LockscreenCredential.createNone(), - managedUserId, - true, /* isLockTiedToParent= */ true); + Slog.wtf(TAG, "Attempt to clear tied challenge, but no password supplied."); } - mStorage.removeChildProfileLock(managedUserId); - removeKeystoreProfileKey(managedUserId); } } } @@ -1567,7 +1562,7 @@ public class LockSettingsService extends ILockSettings.Stub { // should call setLockCredentialInternal. @Override public boolean setLockCredential(LockscreenCredential credential, - LockscreenCredential savedCredential, int userId, boolean allowUntrustedChange) { + LockscreenCredential savedCredential, int userId) { if (!mLockPatternUtils.hasSecureLockScreen()) { throw new UnsupportedOperationException( @@ -1576,7 +1571,7 @@ public class LockSettingsService extends ILockSettings.Stub { checkWritePermission(userId); synchronized (mSeparateChallengeLock) { if (!setLockCredentialInternal(credential, savedCredential, - userId, allowUntrustedChange, /* isLockTiedToParent= */ false)) { + userId, /* isLockTiedToParent= */ false)) { return false; } setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null); @@ -1598,14 +1593,13 @@ public class LockSettingsService extends ILockSettings.Stub { * credentials are being tied to its parent's credentials. */ private boolean setLockCredentialInternal(LockscreenCredential credential, - LockscreenCredential savedCredential, int userId, - boolean allowUntrustedChange, boolean isLockTiedToParent) { + LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) { Preconditions.checkNotNull(credential); Preconditions.checkNotNull(savedCredential); synchronized (mSpManager) { if (isSyntheticPasswordBasedCredentialLocked(userId)) { return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId, - allowUntrustedChange, isLockTiedToParent); + isLockTiedToParent); } } @@ -1653,7 +1647,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (shouldMigrateToSyntheticPasswordLocked(userId)) { initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential, userId); return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId, - allowUntrustedChange, isLockTiedToParent); + isLockTiedToParent); } } if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId); @@ -2075,7 +2069,7 @@ public class LockSettingsService extends ILockSettings.Stub { } if (shouldReEnroll) { setLockCredentialInternal(credential, credential, - userId, false, /* isLockTiedToParent= */ false); + userId, /* isLockTiedToParent= */ false); } else { // Now that we've cleared of all required GK migration, let's do the final // migration to synthetic password. @@ -2210,7 +2204,6 @@ public class LockSettingsService extends ILockSettings.Stub { Slog.i(TAG, "RemoveUser: " + userId); mSpManager.removeUser(userId); mStrongAuth.removeUser(userId); - tryRemoveUserFromSpCacheLater(userId); final KeyStore ks = KeyStore.getInstance(); ks.onUserRemoved(userId); @@ -2471,25 +2464,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } - /** - * A user's synthetic password does not change so it must be cached in certain circumstances to - * enable untrusted credential reset. - * - * Untrusted credential reset will be removed in a future version (b/68036371) at which point - * this cache is no longer needed as the SP will always be known when changing the user's - * credential. - */ - @GuardedBy("mSpManager") - private SparseArray<AuthenticationToken> mSpCache = new SparseArray<>(); - private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) { - // Preemptively cache the SP and then try to remove it in a handler. - Slog.i(TAG, "Caching SP for user " + userId); - synchronized (mSpManager) { - mSpCache.put(userId, auth); - } - tryRemoveUserFromSpCacheLater(userId); - if (mInjector.isGsiRunning()) { Slog.w(TAG, "AuthSecret disabled in GSI"); return; @@ -2510,42 +2485,6 @@ public class LockSettingsService extends ILockSettings.Stub { } } - private void tryRemoveUserFromSpCacheLater(@UserIdInt int userId) { - mHandler.post(() -> { - if (!shouldCacheSpForUser(userId)) { - // The transition from 'should not cache' to 'should cache' can only happen if - // certain admin apps are installed after provisioning e.g. via adb. This is not - // a common case and we do not seamlessly support; it may result in the SP not - // being cached when it is needed. The cache can be re-populated by verifying - // the credential again. - Slog.i(TAG, "Removing SP from cache for user " + userId); - synchronized (mSpManager) { - mSpCache.remove(userId); - } - } - }); - } - - /** Do not hold any of the locks from this service when calling. */ - private boolean shouldCacheSpForUser(@UserIdInt int userId) { - // Before the user setup has completed, an admin could be installed that requires the SP to - // be cached (see below). - if (Settings.Secure.getIntForUser(mContext.getContentResolver(), - Settings.Secure.USER_SETUP_COMPLETE, 0, userId) == 0) { - return true; - } - - // If the user has an admin which can perform an untrusted credential reset, the SP needs to - // be cached. If there isn't a DevicePolicyManager then there can't be an admin in the first - // place so caching is not necessary. - final DevicePolicyManagerInternal dpmi = LocalServices.getService( - DevicePolicyManagerInternal.class); - if (dpmi == null) { - return false; - } - return dpmi.canUserHaveUntrustedCredentialReset(userId); - } - /** * Precondition: vold and keystore unlocked. * @@ -2579,8 +2518,8 @@ public class LockSettingsService extends ILockSettings.Stub { * This could also happen during an untrusted reset to clear password. * * 3. credentialhash == null and credential != null - * This is the untrusted credential reset, OR the user sets a new lockscreen password - * FOR THE FIRST TIME on a SP-enabled device. New credential and new SID will be created + * The user sets a new lockscreen password FOR THE FIRST TIME on a SP-enabled device. + * New credential and new SID will be created */ @GuardedBy("mSpManager") @VisibleForTesting @@ -2905,8 +2844,7 @@ public class LockSettingsService extends ILockSettings.Stub { */ @GuardedBy("mSpManager") private boolean spBasedSetLockCredentialInternalLocked(LockscreenCredential credential, - LockscreenCredential savedCredential, int userId, - boolean allowUntrustedChange, boolean isLockTiedToParent) { + LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) { if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId); if (savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) { // get credential from keystore when managed profile has unified lock @@ -2927,50 +2865,24 @@ public class LockSettingsService extends ILockSettings.Stub { VerifyCredentialResponse response = authResult.gkResponse; AuthenticationToken auth = authResult.authToken; - // If existing credential is provided, the existing credential must match. - if (!savedCredential.isNone() && auth == null) { - Slog.w(TAG, "Failed to enroll: incorrect credential"); - return false; - } - boolean untrustedReset = false; - if (auth != null) { - onAuthTokenKnownForUser(userId, auth); - } else if (response == null) { - throw new IllegalStateException("Password change failed."); - } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) { - // We are performing an untrusted credential change, by DevicePolicyManager or other - // internal callers that don't provide the existing credential - Slog.w(TAG, "Untrusted credential change invoked"); - // Try to get a cached auth token, so we can keep SP unchanged. - auth = mSpCache.get(userId); - if (!allowUntrustedChange) { - throw new IllegalStateException("Untrusted credential change was invoked but it was" - + " not allowed. This is likely a bug. Auth token is null: " - + Boolean.toString(auth == null)); - } - untrustedReset = true; - } else /* responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ { - Slog.w(TAG, "Rate limit exceeded, so password was not changed."); - return false; - } - if (auth != null) { - if (untrustedReset) { - // Force change the current SID to mantain existing behaviour that an untrusted - // reset leads to a change of SID. If the untrusted reset is for clearing the - // current password, the nuking of the SID will be done in - // setLockCredentialWithAuthTokenLocked next - mSpManager.newSidForUser(getGateKeeperService(), auth, userId); + if (auth == null) { + if (response == null + || response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) { + Slog.w(TAG, "Failed to enroll: incorrect credential."); + return false; } - setLockCredentialWithAuthTokenLocked(credential, auth, userId); - mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId); - } else { - throw new IllegalStateException( - "Untrusted credential reset not possible without cached SP"); - // Could call initializeSyntheticPasswordLocked(null, credential, credentialType, - // requestedQuality, userId) instead if we still allow untrusted reset that changes - // synthetic password. That would invalidate existing escrow tokens though. + if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { + Slog.w(TAG, "Failed to enroll: rate limit exceeded."); + return false; + } + // Should not be reachable, but just in case. + throw new IllegalStateException("password change failed"); } + + onAuthTokenKnownForUser(userId, auth); + setLockCredentialWithAuthTokenLocked(credential, auth, userId); + mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId); sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent); return true; } @@ -3125,11 +3037,10 @@ public class LockSettingsService extends ILockSettings.Stub { + "verification."); return false; } + onAuthTokenKnownForUser(userId, result.authToken); long oldHandle = getSyntheticPasswordHandleLocked(userId); setLockCredentialWithAuthTokenLocked(credential, result.authToken, userId); mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId); - - onAuthTokenKnownForUser(userId, result.authToken); return true; } @@ -3248,8 +3159,6 @@ public class LockSettingsService extends ILockSettings.Stub { private class DeviceProvisionedObserver extends ContentObserver { private final Uri mDeviceProvisionedUri = Settings.Global.getUriFor( Settings.Global.DEVICE_PROVISIONED); - private final Uri mUserSetupCompleteUri = Settings.Secure.getUriFor( - Settings.Secure.USER_SETUP_COMPLETE); private boolean mRegistered; @@ -3267,8 +3176,6 @@ public class LockSettingsService extends ILockSettings.Stub { reportDeviceSetupComplete(); clearFrpCredentialIfOwnerNotSecure(); } - } else if (mUserSetupCompleteUri.equals(uri)) { - tryRemoveUserFromSpCacheLater(userId); } } @@ -3320,8 +3227,6 @@ public class LockSettingsService extends ILockSettings.Stub { if (register) { mContext.getContentResolver().registerContentObserver(mDeviceProvisionedUri, false, this); - mContext.getContentResolver().registerContentObserver(mUserSetupCompleteUri, - false, this, UserHandle.USER_ALL); } else { mContext.getContentResolver().unregisterContentObserver(this); } diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index e9a8085950b0..c53647d053bc 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -136,8 +136,13 @@ public class SyntheticPasswordManager { "android-synthetic-password-personalization-context".getBytes(); static class AuthenticationResult { - public AuthenticationToken authToken; - public VerifyCredentialResponse gkResponse; + // Non-null if password/token passes verification, null otherwise + @Nullable public AuthenticationToken authToken; + // OK: password / token passes verification, user has a lockscreen + // null: user does not have a lockscreen (but password / token passes verification) + // ERROR: password / token fails verification + // RETRY: password / token verification is throttled at the moment. + @Nullable public VerifyCredentialResponse gkResponse; } /** diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index d0ad47d3d7a6..12afef2cf950 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -171,6 +171,7 @@ import android.os.IDeviceIdleController; import android.os.IInterface; import android.os.Looper; import android.os.Message; +import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; @@ -292,6 +293,9 @@ public class NotificationManagerService extends SystemService { public static final boolean ENABLE_CHILD_NOTIFICATIONS = SystemProperties.getBoolean("debug.child_notifs", true); + // pullStats report request: undecorated remote view stats + public static final int REPORT_REMOTE_VIEWS = 0x01; + static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean( "debug.notification.interruptiveness", false); @@ -4080,6 +4084,8 @@ public class NotificationManagerService extends SystemService { try { if (filter.stats) { dumpJson(pw, filter); + } else if (filter.rvStats) { + dumpRemoteViewStats(pw, filter); } else if (filter.proto) { dumpProto(fd, filter); } else if (filter.criticalPriority) { @@ -4556,6 +4562,49 @@ public class NotificationManagerService extends SystemService { new NotificationShellCmd(NotificationManagerService.this) .exec(this, in, out, err, args, callback, resultReceiver); } + + /** + * Get stats committed after startNs + * + * @param startNs Report stats committed after this time in nanoseconds. + * @param report Indicatess which section to include in the stats. + * @param doAgg Whether to aggregate the stats or keep them separated. + * @param out List of protos of individual commits or one representing the + * aggregate. + * @return the report time in nanoseconds, or 0 on error. + */ + @Override + public long pullStats(long startNs, int report, boolean doAgg, + List<ParcelFileDescriptor> out) { + checkCallerIsSystemOrShell(); + long startMs = TimeUnit.MILLISECONDS.convert(startNs, TimeUnit.NANOSECONDS); + + final long identity = Binder.clearCallingIdentity(); + try { + switch (report) { + case REPORT_REMOTE_VIEWS: + Slog.e(TAG, "pullStats REPORT_REMOTE_VIEWS from: " + + startMs + " wtih " + doAgg); + PulledStats stats = mUsageStats.remoteViewStats(startMs, doAgg); + if (stats != null) { + out.add(stats.toParcelFileDescriptor(report)); + Slog.e(TAG, "exiting pullStats with: " + out.size()); + long endNs = TimeUnit.NANOSECONDS + .convert(stats.endTimeMs(), TimeUnit.MILLISECONDS); + return endNs; + } + Slog.e(TAG, "null stats for: " + report); + } + } catch (IOException e) { + + Slog.e(TAG, "exiting pullStats: on error", e); + return 0; + } finally { + Binder.restoreCallingIdentity(identity); + } + Slog.e(TAG, "exiting pullStats: bad request"); + return 0; + } }; @VisibleForTesting @@ -4773,6 +4822,15 @@ public class NotificationManagerService extends SystemService { pw.println(dump); } + private void dumpRemoteViewStats(PrintWriter pw, @NonNull DumpFilter filter) { + PulledStats stats = mUsageStats.remoteViewStats(filter.since, true); + if (stats == null) { + pw.println("no remote view stats reported."); + return; + } + stats.dump(REPORT_REMOTE_VIEWS, pw, filter); + } + private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) { final ProtoOutputStream proto = new ProtoOutputStream(fd); synchronized (mNotificationLock) { @@ -9084,6 +9142,7 @@ public class NotificationManagerService extends SystemService { public boolean zen; public long since; public boolean stats; + public boolean rvStats; public boolean redact = true; public boolean proto = false; public boolean criticalPriority = false; @@ -9119,6 +9178,14 @@ public class NotificationManagerService extends SystemService { } else { filter.since = 0; } + } else if ("--remote-view-stats".equals(a)) { + filter.rvStats = true; + if (ai < args.length-1) { + ai++; + filter.since = Long.parseLong(args[ai]); + } else { + filter.since = 0; + } } else if (PRIORITY_ARG.equals(a)) { // Bugreport will call the service twice with priority arguments, first to dump // critical sections and then non critical ones. Set approriate filters diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java index fe3d0eb3e469..ac8d1a9a9ad4 100644 --- a/services/core/java/com/android/server/notification/NotificationUsageStats.java +++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java @@ -149,6 +149,7 @@ public class NotificationUsageStats { stats.numPostedByApp++; stats.updateInterarrivalEstimate(now); stats.countApiUse(notification); + stats.numUndecoratedRemoteViews += (isUndecoratedRemoteView(notification) ? 1 : 0); } releaseAggregatedStatsLocked(aggregatedStatsArray); if (ENABLE_SQLITE_LOG) { @@ -157,6 +158,13 @@ public class NotificationUsageStats { } /** + * Does this notification use RemoveViews without a platform decoration? + */ + protected static boolean isUndecoratedRemoteView(NotificationRecord notification) { + return (notification.getNotification().getNotificationStyle() == null); + } + + /** * Called when a notification has been updated. */ public synchronized void registerUpdatedByApp(NotificationRecord notification, @@ -337,6 +345,15 @@ public class NotificationUsageStats { return dump; } + public PulledStats remoteViewStats(long startMs, boolean aggregate) { + if (ENABLE_SQLITE_LOG) { + if (aggregate) { + return mSQLiteLog.remoteViewAggStats(startMs); + } + } + return null; + } + public synchronized void dump(PrintWriter pw, String indent, DumpFilter filter) { if (ENABLE_AGGREGATED_IN_MEMORY_STATS) { for (AggregatedStats as : mStats.values()) { @@ -414,6 +431,7 @@ public class NotificationUsageStats { public int numRateViolations; public int numAlertViolations; public int numQuotaViolations; + public int numUndecoratedRemoteViews; public long mLastAccessTime; public int numImagesRemoved; @@ -685,6 +703,8 @@ public class NotificationUsageStats { output.append(indentPlusTwo).append(noisyImportance.toString()).append("\n"); output.append(indentPlusTwo).append(quietImportance.toString()).append("\n"); output.append(indentPlusTwo).append(finalImportance.toString()).append("\n"); + output.append(indentPlusTwo); + output.append("numUndecorateRVs=").append(numUndecoratedRemoteViews).append("\n"); output.append(indent).append("}"); return output.toString(); } @@ -1044,7 +1064,7 @@ public class NotificationUsageStats { private static final int MSG_DISMISS = 4; private static final String DB_NAME = "notification_log.db"; - private static final int DB_VERSION = 5; + private static final int DB_VERSION = 7; /** Age in ms after which events are pruned from the DB. */ private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L; // 1 week @@ -1077,6 +1097,7 @@ public class NotificationUsageStats { private static final String COL_FIRST_EXPANSIONTIME_MS = "first_expansion_time_ms"; private static final String COL_AIRTIME_EXPANDED_MS = "expansion_airtime_ms"; private static final String COL_EXPAND_COUNT = "expansion_count"; + private static final String COL_UNDECORATED = "undecorated"; private static final int EVENT_TYPE_POST = 1; @@ -1102,12 +1123,20 @@ public class NotificationUsageStats { "COUNT(*) AS cnt, " + "SUM(" + COL_MUTED + ") as muted, " + "SUM(" + COL_NOISY + ") as noisy, " + - "SUM(" + COL_DEMOTED + ") as demoted " + + "SUM(" + COL_DEMOTED + ") as demoted, " + + "SUM(" + COL_UNDECORATED + ") as undecorated " + "FROM " + TAB_LOG + " " + "WHERE " + COL_EVENT_TYPE + "=" + EVENT_TYPE_POST + " AND " + COL_EVENT_TIME + " > %d " + " GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG; + private static final String UNDECORATED_QUERY = "SELECT " + + COL_PKG + ", " + + "MAX(" + COL_EVENT_TIME + ") as max_time " + + "FROM " + TAB_LOG + " " + + "WHERE " + COL_UNDECORATED + "> 0 " + + " AND " + COL_EVENT_TIME + " > %d " + + "GROUP BY " + COL_PKG; public SQLiteLog(Context context) { HandlerThread backgroundThread = new HandlerThread("notification-sqlite-log", @@ -1163,7 +1192,8 @@ public class NotificationUsageStats { COL_AIRTIME_MS + " INT," + COL_FIRST_EXPANSIONTIME_MS + " INT," + COL_AIRTIME_EXPANDED_MS + " INT," + - COL_EXPAND_COUNT + " INT" + + COL_EXPAND_COUNT + " INT," + + COL_UNDECORATED + " INT" + ")"); } @@ -1273,6 +1303,7 @@ public class NotificationUsageStats { } else { putPosttimeVisibility(r, cv); } + cv.put(COL_UNDECORATED, (isUndecoratedRemoteView(r) ? 1 : 0)); SQLiteDatabase db = mHelper.getWritableDatabase(); if (db.insert(TAB_LOG, null, cv) < 0) { Log.wtf(TAG, "Error while trying to insert values: " + cv); @@ -1353,5 +1384,22 @@ public class NotificationUsageStats { } return dump; } + + public PulledStats remoteViewAggStats(long startMs) { + PulledStats stats = new PulledStats(startMs); + SQLiteDatabase db = mHelper.getReadableDatabase(); + String q = String.format(UNDECORATED_QUERY, startMs); + Cursor cursor = db.rawQuery(q, null); + try { + for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { + String pkg = cursor.getString(0); + long maxTimeMs = cursor.getLong(1); + stats.addUndecoratedPackage(pkg, maxTimeMs); + } + } finally { + cursor.close(); + } + return stats; + } } } diff --git a/services/core/java/com/android/server/notification/PulledStats.java b/services/core/java/com/android/server/notification/PulledStats.java new file mode 100644 index 000000000000..ada890a10361 --- /dev/null +++ b/services/core/java/com/android/server/notification/PulledStats.java @@ -0,0 +1,129 @@ +/* + * 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 com.android.server.notification; + +import static com.android.server.notification.NotificationManagerService.REPORT_REMOTE_VIEWS; + +import android.os.ParcelFileDescriptor; +import android.service.notification.NotificationRemoteViewsProto; +import android.service.notification.PackageRemoteViewInfoProto; +import android.util.Slog; +import android.util.proto.ProtoOutputStream; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +public class PulledStats { + static final String TAG = "PulledStats"; + + private final long mTimePeriodStartMs; + private long mTimePeriodEndMs; + private List<String> mUndecoratedPackageNames; + + public PulledStats(long startMs) { + mTimePeriodEndMs = mTimePeriodStartMs = startMs; + mUndecoratedPackageNames = new ArrayList<>(); + } + + ParcelFileDescriptor toParcelFileDescriptor(int report) + throws IOException { + final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); + switch(report) { + case REPORT_REMOTE_VIEWS: + Thread thr = new Thread("NotificationManager pulled metric output") { + public void run() { + try { + FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream( + fds[1]); + final ProtoOutputStream proto = new ProtoOutputStream(fout); + writeToProto(report, proto); + proto.flush(); + fout.close(); + } catch (IOException e) { + Slog.w(TAG, "Failure writing pipe", e); + } + } + }; + thr.start(); + break; + + default: + Slog.w(TAG, "Unknown pulled stats request: " + report); + break; + } + return fds[0]; + } + + /* + * @return the most recent timestamp in the report, as nanoseconds. + */ + public long endTimeMs() { + return mTimePeriodEndMs; + } + + public void dump(int report, PrintWriter pw, NotificationManagerService.DumpFilter filter) { + switch(report) { + case REPORT_REMOTE_VIEWS: + pw.print(" Packages with undecordated notifications ("); + pw.print(mTimePeriodStartMs); + pw.print(" - "); + pw.print(mTimePeriodEndMs); + pw.println("):"); + if (mUndecoratedPackageNames.size() == 0) { + pw.println(" none"); + } else { + for (String pkg : mUndecoratedPackageNames) { + if (!filter.filtered || pkg.equals(filter.pkgFilter)) { + pw.println(" " + pkg); + } + } + } + break; + + default: + pw.println("Unknown pulled stats request: " + report); + break; + } + } + + @VisibleForTesting + void writeToProto(int report, ProtoOutputStream proto) { + switch(report) { + case REPORT_REMOTE_VIEWS: + for (String pkg: mUndecoratedPackageNames) { + long token = proto.start(NotificationRemoteViewsProto.PACKAGE_REMOTE_VIEW_INFO); + proto.write(PackageRemoteViewInfoProto.PACKAGE_NAME, pkg); + proto.end(token); + } + break; + + default: + Slog.w(TAG, "Unknown pulled stats request: " + report); + break; + } + } + + public void addUndecoratedPackage(String packageName, long timestampMs) { + mUndecoratedPackageNames.add(packageName); + mTimePeriodEndMs = Math.max(mTimePeriodEndMs, timestampMs); + } +} diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index 1222d9a29baf..2b4b409f329a 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -36,6 +36,7 @@ import android.os.Environment; import android.os.RemoteException; import android.os.ServiceManager; import android.sysprop.ApexProperties; +import android.util.Singleton; import android.util.Slog; import com.android.internal.annotations.GuardedBy; @@ -65,22 +66,31 @@ abstract class ApexManager { static final int MATCH_ACTIVE_PACKAGE = 1 << 0; static final int MATCH_FACTORY_PACKAGE = 1 << 1; + private static final Singleton<ApexManager> sApexManagerSingleton = + new Singleton<ApexManager>() { + @Override + protected ApexManager create() { + if (ApexProperties.updatable().orElse(false)) { + try { + return new ApexManagerImpl(IApexService.Stub.asInterface( + ServiceManager.getServiceOrThrow("apexservice"))); + } catch (ServiceManager.ServiceNotFoundException e) { + throw new IllegalStateException( + "Required service apexservice not available"); + } + } else { + return new ApexManagerFlattenedApex(); + } + } + }; + /** * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerFlattenedApex} * depending on whether this device supports APEX, i.e. {@link ApexProperties#updatable()} * evaluates to {@code true}. */ - static ApexManager create(Context systemContext) { - if (ApexProperties.updatable().orElse(false)) { - try { - return new ApexManagerImpl(systemContext, IApexService.Stub.asInterface( - ServiceManager.getServiceOrThrow("apexservice"))); - } catch (ServiceManager.ServiceNotFoundException e) { - throw new IllegalStateException("Required service apexservice not available"); - } - } else { - return new ApexManagerFlattenedApex(); - } + static ApexManager getInstance() { + return sApexManagerSingleton.get(); } /** @@ -101,7 +111,7 @@ abstract class ApexManager { */ abstract List<ActiveApexInfo> getActiveApexInfos(); - abstract void systemReady(); + abstract void systemReady(Context context); /** * Retrieves information about an APEX package. @@ -248,7 +258,6 @@ abstract class ApexManager { @VisibleForTesting static class ApexManagerImpl extends ApexManager { private final IApexService mApexService; - private final Context mContext; private final Object mLock = new Object(); /** * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code @@ -260,8 +269,7 @@ abstract class ApexManager { @GuardedBy("mLock") private List<PackageInfo> mAllPackagesCache; - ApexManagerImpl(Context context, IApexService apexService) { - mContext = context; + ApexManagerImpl(IApexService apexService) { mApexService = apexService; } @@ -302,14 +310,14 @@ abstract class ApexManager { } @Override - void systemReady() { - mContext.registerReceiver(new BroadcastReceiver() { + void systemReady(Context context) { + context.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Post populateAllPackagesCacheIfNeeded to a background thread, since it's // expensive to run it in broadcast handler thread. BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded()); - mContext.unregisterReceiver(this); + context.unregisterReceiver(this); } }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); } @@ -643,7 +651,7 @@ abstract class ApexManager { } @Override - void systemReady() { + void systemReady(Context context) { // No-op } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 3d4247e761b5..fcaf5e1d912a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2605,7 +2605,7 @@ public class PackageManagerService extends IPackageManager.Stub mProtectedPackages = new ProtectedPackages(mContext); - mApexManager = ApexManager.create(mContext); + mApexManager = ApexManager.getInstance(); mAppsFilter = mInjector.getAppsFilter(); mDirsToScanAsSystem = new ArrayList<>(); @@ -20371,7 +20371,7 @@ public class PackageManagerService extends IPackageManager.Stub storage.registerListener(mStorageListener); mInstallerService.systemReady(); - mApexManager.systemReady(); + mApexManager.systemReady(mContext); mPackageDexOptimizer.systemReady(); mInjector.getStorageManagerInternal().addExternalStoragePolicy( diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java index 83891f60d4f7..a62616623cb5 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -16,6 +16,13 @@ package com.android.server.rollback; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN; + +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.Context; @@ -41,6 +48,7 @@ import android.util.StatsLog; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.server.PackageWatchdog; +import com.android.server.PackageWatchdog.FailureReasons; import com.android.server.PackageWatchdog.PackageHealthObserver; import com.android.server.PackageWatchdog.PackageHealthObserverImpact; @@ -106,10 +114,11 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } @Override - public boolean execute(VersionedPackage failedPackage) { + public boolean execute(VersionedPackage failedPackage, @FailureReasons int rollbackReason) { RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); VersionedPackage moduleMetadataPackage = getModuleMetadataPackage(); RollbackInfo rollback = getAvailableRollback(rollbackManager, failedPackage); + int reasonToLog = mapFailureReasonToMetric(rollbackReason); if (rollback == null) { Slog.w(TAG, "Expected rollback but no valid rollback found for package: [ " @@ -119,7 +128,8 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } logEvent(moduleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE, + reasonToLog, failedPackage.getPackageName()); LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> { int status = result.getIntExtra(RollbackManager.EXTRA_STATUS, RollbackManager.STATUS_FAILURE); @@ -136,11 +146,13 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve moduleMetadataPackage); } else { logEvent(moduleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, + reasonToLog, failedPackage.getPackageName()); } } else { logEvent(moduleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + reasonToLog, failedPackage.getPackageName()); } }); @@ -219,12 +231,14 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } if (sessionInfo.isStagedSessionApplied()) { logEvent(oldModuleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, + WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); } else if (sessionInfo.isStagedSessionReady()) { // TODO: What do for staged session ready but not applied } else { logEvent(oldModuleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); } } @@ -303,12 +317,16 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve saveLastStagedRollbackId(rollbackId); logEvent(moduleMetadataPackage, StatsLog - .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED); + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED, + WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, + ""); mContext.getSystemService(PowerManager.class).reboot("Rollback staged install"); } else if (sessionInfo.isStagedSessionFailed() && markStagedSessionHandled(rollbackId)) { logEvent(moduleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, + ""); mContext.unregisterReceiver(listener); } } @@ -355,11 +373,12 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve return rollbackId; } - private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type) { + private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type, + int rollbackReason, @NonNull String failingPackageName) { Slog.i(TAG, "Watchdog event occurred of type: " + type); if (moduleMetadataPackage != null) { StatsLog.logWatchdogRollbackOccurred(type, moduleMetadataPackage.getPackageName(), - moduleMetadataPackage.getVersionCode()); + moduleMetadataPackage.getVersionCode(), rollbackReason, failingPackageName); } } @@ -371,7 +390,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve mNumberOfNativeCrashPollsRemaining--; // Check if native watchdog reported a crash if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) { - execute(getModuleMetadataPackage()); + execute(getModuleMetadataPackage(), PackageWatchdog.FAILURE_REASON_NATIVE_CRASH); // we stop polling after an attempt to execute rollback, regardless of whether the // attempt succeeds or not } else { @@ -392,4 +411,20 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve + "and mitigate native crashes"); mHandler.post(()->checkAndMitigateNativeCrashes()); } + + private int mapFailureReasonToMetric(@FailureReasons int failureReason) { + switch (failureReason) { + case PackageWatchdog.FAILURE_REASON_NATIVE_CRASH: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH; + case PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK; + case PackageWatchdog.FAILURE_REASON_APP_CRASH: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH; + case PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING; + default: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN; + } + } + } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5d796055dcc7..83c854bae4b5 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -620,10 +620,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // TODO: Make this final int mTargetSdk; - // Set to true when this app creates a surface while in the middle of an animation. In that - // case do not clear allDrawn until the animation completes. - boolean deferClearAllDrawn; - // Is this window's surface needed? This is almost like visible, except // it will sometimes be true a little earlier: when the activity record has // been shown, but is still waiting for its app transition to execute @@ -771,10 +767,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.print(" primaryColor="); pw.println(Integer.toHexString(taskDescription.getPrimaryColor())); pw.print(prefix + " backgroundColor="); - pw.println(Integer.toHexString(taskDescription.getBackgroundColor())); - pw.print(prefix + " statusBarColor="); - pw.println(Integer.toHexString(taskDescription.getStatusBarColor())); - pw.print(prefix + " navigationBarColor="); + pw.print(Integer.toHexString(taskDescription.getBackgroundColor())); + pw.print(" statusBarColor="); + pw.print(Integer.toHexString(taskDescription.getStatusBarColor())); + pw.print(" navigationBarColor="); pw.println(Integer.toHexString(taskDescription.getNavigationBarColor())); } } @@ -847,14 +843,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.println(requestedVrComponent); } super.dump(pw, prefix, dumpAll); - pw.print(" visible="); pw.print(mVisible); - if (appToken != null) { - pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction); + if (mVoiceInteraction) { + pw.println(prefix + "mVoiceInteraction=true"); } - pw.print(prefix); pw.print(" mOccludesParent="); pw.print(mOccludesParent); + pw.print(prefix); pw.print("mOccludesParent="); pw.print(mOccludesParent); pw.print(" mOrientation="); pw.println(mOrientation); pw.println(prefix + "mVisibleRequested=" + mVisibleRequested - + " mClientVisible=" + mClientVisible + + " mVisible=" + mVisible + " mClientVisible=" + mClientVisible + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "") + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible); if (paused) { @@ -901,7 +896,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay); } if (lastVisibleTime != 0 || nowVisible) { - pw.print(prefix); pw.print(" nowVisible="); pw.print(nowVisible); + pw.print(prefix); pw.print("nowVisible="); pw.print(nowVisible); pw.print(" lastVisibleTime="); if (lastVisibleTime == 0) pw.print("0"); else TimeUtils.formatDuration(lastVisibleTime, now, pw); @@ -3235,7 +3230,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // to move that animation to the new one. if (fromActivity.allDrawn) { allDrawn = true; - deferClearAllDrawn = fromActivity.deferClearAllDrawn; } if (fromActivity.firstWindowDrawn) { firstWindowDrawn = true; @@ -3719,7 +3713,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void clearAllDrawn() { allDrawn = false; - deferClearAllDrawn = false; } /** diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index e9ad0d361b07..d7f4b34ba56d 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -389,7 +389,6 @@ public class AppTransitionController { // this guy's animations regardless of whether it's // gotten drawn. wtoken.allDrawn = true; - wtoken.deferClearAllDrawn = false; // Ensure that apps that are mid-starting are also scheduled to have their // starting windows removed after the animation is complete if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) { diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index c42029155bd0..175fccbdd0ba 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -439,10 +439,6 @@ class WindowStateAnimator { if (!mWin.mActivityRecord.isAnimating(TRANSITION)) { mWin.mActivityRecord.clearAllDrawn(); - } else { - // Currently animating, persist current state of allDrawn until animation - // is complete. - mWin.mActivityRecord.deferClearAllDrawn = true; } } diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index f81713ed4385..53edf9d3086a 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -280,10 +280,11 @@ class WindowToken extends WindowContainer<WindowState> { super.dump(pw, prefix, dumpAll); pw.print(prefix); pw.print("windows="); pw.println(mChildren); pw.print(prefix); pw.print("windowType="); pw.print(windowType); - pw.print(" hasVisible="); pw.println(hasVisible); + pw.print(" hasVisible="); pw.print(hasVisible); if (waitingToShow) { - pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow); + pw.print(" waitingToShow=true"); } + pw.println(); } @Override diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index cb599be82aa6..ee0449d95e00 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -4345,6 +4345,40 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + /** + * Get the list of active admins for an affected user: + * <ul> + * <li>The active admins associated with the userHandle itself</li> + * <li>The parent active admins for each managed profile associated with the userHandle</li> + * </ul> + * + * @param userHandle the affected user for whom to get the active admins + * @param parent whether the parent active admins should be included in the list of active + * admins or not + * @return the list of active admins for the affected user + */ + private List<ActiveAdmin> getActiveAdminsForAffectedUser(int userHandle, boolean parent) { + if (!parent) { + return getUserDataUnchecked(userHandle).mAdminList; + } + ArrayList<ActiveAdmin> admins = new ArrayList<>(); + for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) { + DevicePolicyData policy = getUserData(userInfo.id); + if (!userInfo.isManagedProfile()) { + admins.addAll(policy.mAdminList); + } else { + // For managed profiles, policies set on the parent profile will be included + for (int i = 0; i < policy.mAdminList.size(); i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (admin.hasParentActiveAdmin()) { + admins.add(admin.getParentActiveAdmin()); + } + } + } + } + return admins; + } + private boolean isSeparateProfileChallengeEnabled(int userHandle) { long ident = mInjector.binderClearCallingIdentity(); try { @@ -5096,118 +5130,58 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private boolean canPOorDOCallResetPassword(ActiveAdmin admin, @UserIdInt int userId) { - // Only if the admins targets a pre-O SDK - return getTargetSdk(admin.info.getPackageName(), userId) < Build.VERSION_CODES.O; - } - - /* PO or DO could do an untrusted reset in certain conditions. */ - private boolean canUserHaveUntrustedCredentialReset(@UserIdInt int userId) { - synchronized (getLockObject()) { - // An active DO or PO might be able to fo an untrusted credential reset - for (final ActiveAdmin admin : getUserData(userId).mAdminList) { - if (!isActiveAdminWithPolicyForUserLocked(admin, - DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, userId)) { - continue; - } - if (canPOorDOCallResetPassword(admin, userId)) { - return true; - } - } - return false; + private boolean setPasswordPrivileged(@NonNull String password, int flags, int callingUid) { + // Only allow setting password on an unsecured user + if (isLockScreenSecureUnchecked(UserHandle.getUserId(callingUid))) { + throw new SecurityException("Cannot change current password"); } + return resetPasswordInternal(password, 0, null, flags, callingUid); } + @Override - public boolean resetPassword(String passwordOrNull, int flags) throws RemoteException { + public boolean resetPassword(@Nullable String password, int flags) throws RemoteException { if (!mLockPatternUtils.hasSecureLockScreen()) { Slog.w(LOG_TAG, "Cannot reset password when the device has no lock screen"); return false; } - + if (password == null) password = ""; final int callingUid = mInjector.binderGetCallingUid(); final int userHandle = mInjector.userHandleGetCallingUserId(); - String password = passwordOrNull != null ? passwordOrNull : ""; - - // Password resetting to empty/null is not allowed for managed profiles. - if (TextUtils.isEmpty(password)) { - enforceNotManagedProfile(userHandle, "clear the active password"); + // As of R, only privlleged caller holding RESET_PASSWORD can call resetPassword() to + // set password to an unsecured user. + if (mContext.checkCallingPermission(permission.RESET_PASSWORD) + == PackageManager.PERMISSION_GRANTED) { + return setPasswordPrivileged(password, flags, callingUid); } synchronized (getLockObject()) { - // If caller has PO (or DO) it can change the password, so see if that's the case first. + // If caller has PO (or DO) throw or fail silently depending on its target SDK level. ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked( null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, callingUid); - final boolean preN; if (admin != null) { - if (!canPOorDOCallResetPassword(admin, userHandle)) { - throw new SecurityException("resetPassword() is deprecated for DPC targeting O" - + " or later"); - } - preN = getTargetSdk(admin.info.getPackageName(), - userHandle) <= android.os.Build.VERSION_CODES.M; - } else { - // Otherwise, make sure the caller has any active admin with the right policy or - // the required permission. - admin = getActiveAdminOrCheckPermissionForCallerLocked( - null, - DeviceAdminInfo.USES_POLICY_RESET_PASSWORD, - android.Manifest.permission.RESET_PASSWORD); - // Cannot be preN if admin is null because an exception would have been - // thrown before getting here - preN = admin == null ? false : getTargetSdk(admin.info.getPackageName(), - userHandle) <= android.os.Build.VERSION_CODES.M; - - // As of N, password resetting to empty/null is not allowed anymore. - // TODO Should we allow DO/PO to set an empty password? - if (TextUtils.isEmpty(password)) { - if (!preN) { - throw new SecurityException("Cannot call with null password"); - } else { - Slog.e(LOG_TAG, "Cannot call with null password"); - return false; - } - } - // As of N, password cannot be changed by the admin if it is already set. - if (isLockScreenSecureUnchecked(userHandle)) { - if (!preN) { - throw new SecurityException("Cannot change current password"); - } else { - Slog.e(LOG_TAG, "Cannot change current password"); - return false; - } - } - } - // Do not allow to reset password when current user has a managed profile - if (!isManagedProfile(userHandle)) { - for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) { - if (userInfo.isManagedProfile()) { - if (!preN) { - throw new IllegalStateException( - "Cannot reset password on user has managed profile"); - } else { - Slog.e(LOG_TAG, "Cannot reset password on user has managed profile"); - return false; - } - } - } - } - // Do not allow to reset password when user is locked - if (!mUserManager.isUserUnlocked(userHandle)) { - if (!preN) { - throw new IllegalStateException("Cannot reset password when user is locked"); - } else { - Slog.e(LOG_TAG, "Cannot reset password when user is locked"); + if (getTargetSdk(admin.info.getPackageName(), userHandle) < Build.VERSION_CODES.O) { + Slog.e(LOG_TAG, "DPC can no longer call resetPassword()"); return false; } + throw new SecurityException("Device admin can no longer call resetPassword()"); } - } - return resetPasswordInternal(password, 0, null, flags, callingUid, userHandle); + // Legacy device admin cannot call resetPassword either + admin = getActiveAdminForCallerLocked( + null, DeviceAdminInfo.USES_POLICY_RESET_PASSWORD, false); + if (getTargetSdk(admin.info.getPackageName(), + userHandle) <= android.os.Build.VERSION_CODES.M) { + Slog.e(LOG_TAG, "Device admin can no longer call resetPassword()"); + return false; + } + throw new SecurityException("Device admin can no longer call resetPassword()"); + } } private boolean resetPasswordInternal(String password, long tokenHandle, byte[] token, - int flags, int callingUid, int userHandle) { + int flags, int callingUid) { + final int userHandle = UserHandle.getUserId(callingUid); synchronized (getLockObject()) { final PasswordMetrics minMetrics = getPasswordMinimumMetrics(userHandle); final List<PasswordValidationError> validationErrors; @@ -5245,21 +5219,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // Don't do this with the lock held, because it is going to call // back in to the service. final long ident = mInjector.binderClearCallingIdentity(); - final boolean result; final LockscreenCredential newCredential = LockscreenCredential.createPasswordOrNone(password); try { - if (token == null) { - // This is the legacy reset password for DPM. Here we want to be able to override - // the old device password without necessarily knowing it. - mLockPatternUtils.setLockCredential( - newCredential, - LockscreenCredential.createNone(), - userHandle, /*allowUntrustedChange */true); - result = true; + if (tokenHandle == 0 || token == null) { + if (!mLockPatternUtils.setLockCredential(newCredential, + LockscreenCredential.createNone(), userHandle)) { + return false; + } } else { - result = mLockPatternUtils.setLockCredentialWithToken(newCredential, tokenHandle, - token, userHandle); + if (!mLockPatternUtils.setLockCredentialWithToken(newCredential, tokenHandle, + token, userHandle)) { + return false; + } } boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0; if (requireEntry) { @@ -5276,7 +5248,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } finally { mInjector.binderRestoreCallingIdentity(ident); } - return result; + return true; } private boolean isLockScreenSecureUnchecked(int userId) { @@ -7769,22 +7741,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * Disables all device cameras according to the specified admin. */ @Override - public void setCameraDisabled(ComponentName who, boolean disabled) { + public void setCameraDisabled(ComponentName who, boolean disabled, boolean parent) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); - final int userHandle = mInjector.userHandleGetCallingUserId(); + int userHandle = mInjector.userHandleGetCallingUserId(); synchronized (getLockObject()) { ActiveAdmin ap = getActiveAdminForCallerLocked(who, - DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA); + DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent); + if (parent) { + enforceProfileOwnerOfOrganizationOwnedDevice(ap); + } if (ap.disableCamera != disabled) { ap.disableCamera = disabled; saveSettingsLocked(userHandle); } } // Tell the user manager that the restrictions have changed. - pushUserRestrictions(userHandle); + pushUserRestrictions(parent ? getProfileParentId(userHandle) : userHandle); DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_CAMERA_DISABLED) .setAdmin(who) @@ -7797,18 +7772,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * active admins. */ @Override - public boolean getCameraDisabled(ComponentName who, int userHandle) { - return getCameraDisabled(who, userHandle, /* mergeDeviceOwnerRestriction= */ true); + public boolean getCameraDisabled(ComponentName who, int userHandle, boolean parent) { + return getCameraDisabled(who, userHandle, /* mergeDeviceOwnerRestriction= */ true, parent); } private boolean getCameraDisabled(ComponentName who, int userHandle, - boolean mergeDeviceOwnerRestriction) { + boolean mergeDeviceOwnerRestriction, boolean parent) { if (!mHasFeature) { return false; } + if (parent) { + ActiveAdmin ap = getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent); + enforceProfileOwnerOfOrganizationOwnedDevice(ap); + } synchronized (getLockObject()) { if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent); return (admin != null) ? admin.disableCamera : false; } // First, see if DO has set it. If so, it's device-wide. @@ -7818,13 +7798,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return true; } } - - // Then check each device admin on the user. - DevicePolicyData policy = getUserData(userHandle); + // Return the strictest policy across all participating admins. + List<ActiveAdmin> admins = getActiveAdminsForAffectedUser(userHandle, parent); // Determine whether or not the device camera is disabled for any active admins. - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); + for (ActiveAdmin admin: admins) { if (admin.disableCamera) { return true; } @@ -8636,6 +8613,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return null; } + @GuardedBy("getLockObject()") + ActiveAdmin getProfileOwnerOfOrganizationOwnedDeviceLocked(int userHandle) { + final long ident = mInjector.binderClearCallingIdentity(); + try { + for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) { + if (userInfo.isManagedProfile()) { + if (getProfileOwner(userInfo.id) != null + && canProfileOwnerAccessDeviceIds(userInfo.id)) { + ComponentName who = getProfileOwner(userInfo.id); + return getActiveAdminUncheckedLocked(who, userInfo.id); + } + } + } + } finally { + mInjector.binderRestoreCallingIdentity(ident); + } + return null; + } + @Override public String getProfileOwnerName(int userHandle) { if (!mHasFeature) { @@ -10323,7 +10319,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private void pushUserRestrictions(int userId) { synchronized (getLockObject()) { final boolean isDeviceOwner = mOwners.isDeviceOwnerUserId(userId); - final Bundle userRestrictions; + Bundle userRestrictions = null; final int restrictionOwnerType; if (isDeviceOwner) { @@ -10335,42 +10331,60 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { addOrRemoveDisableCameraRestriction(userRestrictions, deviceOwner); restrictionOwnerType = UserManagerInternal.OWNER_TYPE_DEVICE_OWNER; } else { - final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId); - userRestrictions = profileOwner != null ? profileOwner.userRestrictions : null; - addOrRemoveDisableCameraRestriction(userRestrictions, userId); + final ActiveAdmin profileOwnerOfOrganizationOwnedDevice = + getProfileOwnerOfOrganizationOwnedDeviceLocked(userId); - if (isProfileOwnerOfOrganizationOwnedDevice(profileOwner)) { + // If profile owner of an organization owned device, the restrictions will be + // pushed to the parent instance. + if (profileOwnerOfOrganizationOwnedDevice != null && !isManagedProfile(userId)) { restrictionOwnerType = UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE; - } else if (profileOwner != null) { - restrictionOwnerType = UserManagerInternal.OWNER_TYPE_PROFILE_OWNER; + final ActiveAdmin parent = profileOwnerOfOrganizationOwnedDevice + .getParentActiveAdmin(); + userRestrictions = parent.userRestrictions; + userRestrictions = addOrRemoveDisableCameraRestriction(userRestrictions, + parent); } else { - restrictionOwnerType = UserManagerInternal.OWNER_TYPE_NO_OWNER; + final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId); + + if (profileOwner != null) { + userRestrictions = profileOwner.userRestrictions; + restrictionOwnerType = UserManagerInternal.OWNER_TYPE_PROFILE_OWNER; + } else { + restrictionOwnerType = UserManagerInternal.OWNER_TYPE_NO_OWNER; + } + userRestrictions = addOrRemoveDisableCameraRestriction( + userRestrictions, userId); } } - mUserManagerInternal.setDevicePolicyUserRestrictions(userId, userRestrictions, restrictionOwnerType); } } - private void addOrRemoveDisableCameraRestriction(Bundle userRestrictions, ActiveAdmin admin) { - if (userRestrictions == null) return; + private Bundle addOrRemoveDisableCameraRestriction(Bundle userRestrictions, ActiveAdmin admin) { + if (userRestrictions == null) { + userRestrictions = new Bundle(); + } if (admin.disableCamera) { userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true); } else { userRestrictions.remove(UserManager.DISALLOW_CAMERA); } + return userRestrictions; } - private void addOrRemoveDisableCameraRestriction(Bundle userRestrictions, int userId) { - if (userRestrictions == null) return; + private Bundle addOrRemoveDisableCameraRestriction(Bundle userRestrictions, int userId) { + if (userRestrictions == null) { + userRestrictions = new Bundle(); + } if (getCameraDisabled(/* who= */ null, userId, /* mergeDeviceOwnerRestriction= */ false)) { userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true); } else { userRestrictions.remove(UserManager.DISALLOW_CAMERA); } + return userRestrictions; } @Override @@ -11673,11 +11687,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public boolean canUserHaveUntrustedCredentialReset(@UserIdInt int userId) { - return DevicePolicyManagerService.this.canUserHaveUntrustedCredentialReset(userId); - } - - @Override public CharSequence getPrintingDisabledReasonForUser(@UserIdInt int userId) { synchronized (getLockObject()) { if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_PRINTING, @@ -13890,7 +13899,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (policy.mPasswordTokenHandle != 0) { final String password = passwordOrNull != null ? passwordOrNull : ""; return resetPasswordInternal(password, policy.mPasswordTokenHandle, token, - flags, mInjector.binderGetCallingUid(), userHandle); + flags, mInjector.binderGetCallingUid()); } else { Slog.w(LOG_TAG, "No saved token handle"); } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 7508343b7130..21cacd45dcb5 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -448,10 +448,6 @@ public final class SystemServer { // Mmmmmm... more memory! VMRuntime.getRuntime().clearGrowthLimit(); - // The system server has to run all of the time, so it needs to be - // as efficient as possible with its memory usage. - VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); - // Some devices rely on runtime fingerprint generation, so make sure // we've defined it before booting further. Build.ensureFingerprintProperty(); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java index c5fb0bde579f..5f1f3083361b 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java @@ -23,7 +23,6 @@ import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManagerInternal; import android.content.pm.PackageManager; -import android.content.pm.UserInfo; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; @@ -39,6 +38,9 @@ import java.util.Map; import java.util.Set; public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { + + private static final String USER_TYPE_EMPTY = ""; + private DpmMockContext mContext; @Override @@ -52,9 +54,10 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { } public void testMigration() throws Exception { - final File user10dir = getServices().addUser(10, 0); - final File user11dir = getServices().addUser(11, UserInfo.FLAG_MANAGED_PROFILE); - getServices().addUser(12, 0); + final File user10dir = getServices().addUser(10, 0, USER_TYPE_EMPTY); + final File user11dir = getServices().addUser(11, 0, + UserManager.USER_TYPE_PROFILE_MANAGED); + getServices().addUser(12, 0, USER_TYPE_EMPTY); setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); setUpPackageManagerForAdmin(admin2, UserHandle.getUid(10, 123)); @@ -273,7 +276,8 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { // Test setting default restrictions for managed profile. public void testMigration3_managedProfileOwner() throws Exception { // Create a managed profile user. - final File user10dir = getServices().addUser(10, UserInfo.FLAG_MANAGED_PROFILE); + final File user10dir = getServices().addUser(10, 0, + UserManager.USER_TYPE_PROFILE_MANAGED); // Profile owner package for managed profile user. setUpPackageManagerForAdmin(admin1, UserHandle.getUid(10, 123)); // Set up fake UserManager to make it look like a managed profile. diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 06b8716c0926..43d8f927a57e 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -151,6 +151,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { private DpmMockContext mServiceContext; private DpmMockContext mAdmin1Context; public DevicePolicyManager dpm; + public DevicePolicyManager parentDpm; public DevicePolicyManagerServiceTestable dpms; /* @@ -240,6 +241,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm = new DevicePolicyManagerTestable(mContext, dpms); + parentDpm = new DevicePolicyManagerTestable(mServiceContext, dpms, + /* parentInstance= */true); + mContext.binder.restoreCallingIdentity(ident); } @@ -269,7 +273,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { anyString(), any(UserHandle.class)); // Add the first secondary user. - getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0); + getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, + UserManager.USER_TYPE_FULL_SECONDARY); } private void setAsProfileOwner(ComponentName admin) { @@ -330,7 +335,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testLoadAdminData_noAdmins() throws Exception { final int ANOTHER_USER_ID = 15; - getServices().addUser(ANOTHER_USER_ID, 0); + getServices().addUser(ANOTHER_USER_ID, 0, ""); initializeDpms(); @@ -477,7 +482,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int ANOTHER_USER_ID = 100; final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 20456); - getServices().addUser(ANOTHER_USER_ID, 0); // Add one more user. + getServices().addUser(ANOTHER_USER_ID, 0, ""); // Add one more user. // Set up pacakge manager for the other user. setUpPackageManagerForAdmin(admin2, ANOTHER_ADMIN_UID); @@ -1343,7 +1348,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int ANOTHER_USER_ID = 100; final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 456); - getServices().addUser(ANOTHER_USER_ID, 0); // Add one more user. + getServices().addUser(ANOTHER_USER_ID, 0, ""); // Add one more user. mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); @@ -1961,35 +1966,30 @@ public class DevicePolicyManagerTest extends DpmTestBase { // TODO Make sure restrictions are written to the file. } + // TODO: (b/138709470) test addUserRestriction as PO of an organization-owned device public void testSetUserRestriction_asPoOfOrgOwnedDevice() throws Exception { - setupProfileOwner(); + final int MANAGED_PROFILE_USER_ID = DpmMockContext.CALLER_USER_HANDLE; + final int MANAGED_PROFILE_ADMIN_UID = + UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID); + mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - final long ident = mServiceContext.binder.clearCallingIdentity(); - configureContextForAccess(mServiceContext, true); + addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); + configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE); - mServiceContext.binder.callingUid = - UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, - DpmMockContext.CALLER_MANAGED_PROVISIONING_UID); - try { - runAsCaller(mServiceContext, dpms, dpm -> { - dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1); - }); - } finally { - mServiceContext.binder.restoreCallingIdentity(ident); - } + when(getServices().userManager.getProfileParent(MANAGED_PROFILE_USER_ID)) + .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); - dpm.addUserRestriction(admin1, UserManager.DISALLOW_CONFIG_DATE_TIME); + parentDpm.setCameraDisabled(admin1, true); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( - eq(DpmMockContext.CALLER_USER_HANDLE), - MockUtils.checkUserRestrictions(UserManager.DISALLOW_CONFIG_DATE_TIME), + eq(UserHandle.USER_SYSTEM), + MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA), eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE)); reset(getServices().userManagerInternal); - dpm.setCameraDisabled(admin1, true); + parentDpm.setCameraDisabled(admin1, false); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( - eq(DpmMockContext.CALLER_USER_HANDLE), - MockUtils.checkUserRestrictions(UserManager.DISALLOW_CONFIG_DATE_TIME, - UserManager.DISALLOW_CAMERA), + eq(UserHandle.USER_SYSTEM), + MockUtils.checkUserRestrictions(), eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE)); reset(getServices().userManagerInternal); } @@ -3861,7 +3861,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Add a secondary user, it should never talk with. final int ANOTHER_USER_ID = 36; - getServices().addUser(ANOTHER_USER_ID, 0); + getServices().addUser(ANOTHER_USER_ID, 0, UserManager.USER_TYPE_FULL_SECONDARY); // Since the managed profile is not affiliated, they should not be allowed to talk to each // other. @@ -5206,8 +5206,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } public void testRevertProfileOwnership_adminAndProfileMigrated() throws Exception { - getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, UserInfo.FLAG_MANAGED_PROFILE, - UserHandle.USER_SYSTEM); + getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, + UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM); DpmTestUtils.writeInputStreamToFile( getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated), getProfileOwnerPoliciesFile()); @@ -5218,8 +5218,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } public void testRevertProfileOwnership_profileNotMigrated() throws Exception { - getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, UserInfo.FLAG_MANAGED_PROFILE, - UserHandle.USER_SYSTEM); + getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, + UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM); DpmTestUtils.writeInputStreamToFile( getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated), getProfileOwnerPoliciesFile()); @@ -5230,8 +5230,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { } public void testRevertProfileOwnership_adminAndProfileNotMigrated() throws Exception { - getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, UserInfo.FLAG_MANAGED_PROFILE, - UserHandle.USER_SYSTEM); + getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0, + UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM); DpmTestUtils.writeInputStreamToFile( getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_not_migrated), getProfileOwnerPoliciesFile()); @@ -5405,11 +5405,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY); setAsProfileOwner(admin1); - new DevicePolicyManagerTestable( - mServiceContext, - dpms, - /* parentInstance= */ true) - .getPasswordComplexity(); + parentDpm.getPasswordComplexity(); assertEquals(PASSWORD_COMPLEXITY_NONE, dpm.getPasswordComplexity()); } @@ -5685,7 +5681,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { private void addManagedProfile( ComponentName admin, int adminUid, ComponentName copyFromAdmin) throws Exception { final int userId = UserHandle.getUserId(adminUid); - getServices().addUser(userId, UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_SYSTEM); + getServices().addUser(userId, 0, UserManager.USER_TYPE_PROFILE_MANAGED, + UserHandle.USER_SYSTEM); mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS); setUpPackageManagerForFakeAdmin(admin, adminUid, copyFromAdmin); dpm.setActiveAdmin(admin, false, userId); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index 6a0d9265f594..7a2350eb4402 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -185,8 +185,8 @@ public class MockSystemServices { // Add the system user with a fake profile group already set up (this can happen in the real // world if a managed profile is added and then removed). - systemUserDataDir = - addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY, UserHandle.USER_SYSTEM); + systemUserDataDir = addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY, + UserManager.USER_TYPE_FULL_SYSTEM, UserHandle.USER_SYSTEM); // System user is always running. setUserRunning(UserHandle.USER_SYSTEM, true); @@ -208,26 +208,21 @@ public class MockSystemServices { mBroadcastReceivers.removeIf(r -> r.receiver == receiver); } - public File addUser(int userId, int flags) { - return addUser(userId, flags, UserInfo.NO_PROFILE_GROUP_ID); + public File addUser(int userId, int flags, String type) { + return addUser(userId, flags, type, UserInfo.NO_PROFILE_GROUP_ID); } - public File addUser(int userId, int flags, int profileGroupId) { + public File addUser(int userId, int flags, String type, int profileGroupId) { // Set up (default) UserInfo for CALLER_USER_HANDLE. final UserInfo uh = new UserInfo(userId, "user" + userId, flags); + + uh.userType = type; uh.profileGroupId = profileGroupId; when(userManager.getUserInfo(eq(userId))).thenReturn(uh); - mUserInfos.add(uh); when(userManager.getUsers()).thenReturn(mUserInfos); when(userManager.getUsers(anyBoolean())).thenReturn(mUserInfos); when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(true); - when(userManager.getUserInfo(anyInt())).thenAnswer( - invocation -> { - final int userId1 = (int) invocation.getArguments()[0]; - return getUserInfo(userId1); - } - ); when(userManager.getProfileParent(anyInt())).thenAnswer( invocation -> { final int userId1 = (int) invocation.getArguments()[0]; @@ -308,7 +303,7 @@ public class MockSystemServices { */ public void addUsers(int... userIds) { for (final int userId : userIds) { - addUser(userId, 0); + addUser(userId, 0, ""); } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java deleted file mode 100644 index d1c2fd0fa9dd..000000000000 --- a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2018 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.locksettings; - -import static com.android.server.testutils.TestUtils.assertExpectException; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.os.RemoteException; -import android.platform.test.annotations.Presubmit; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import com.android.internal.widget.LockscreenCredential; -import com.android.internal.widget.VerifyCredentialResponse; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; - -import java.util.ArrayList; - -/** - * Run the synthetic password tests with caching enabled. - * - * By default, those tests run without caching. Untrusted credential reset depends on caching so - * this class included those tests. - */ -@SmallTest -@Presubmit -@RunWith(AndroidJUnit4.class) -public class CachedSyntheticPasswordTests extends SyntheticPasswordTests { - - @Before - public void enableSpCache() throws Exception { - enableSpCaching(true); - } - - private void enableSpCaching(boolean enable) { - when(mDevicePolicyManagerInternal - .canUserHaveUntrustedCredentialReset(anyInt())).thenReturn(enable); - } - - @Test - public void testSyntheticPasswordClearCredentialUntrusted() throws RemoteException { - final LockscreenCredential password = newPassword("password"); - final LockscreenCredential newPassword = newPassword("newpassword"); - - initializeCredentialUnderSP(password, PRIMARY_USER_ID); - long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); - // clear password - mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, true); - assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); - - // set a new password - mService.setLockCredential(newPassword, nonePassword(), PRIMARY_USER_ID, - false); - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - newPassword, 0, PRIMARY_USER_ID) - .getResponseCode()); - assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); - } - - @Test - public void testSyntheticPasswordChangeCredentialUntrusted() throws RemoteException { - final LockscreenCredential password = newPassword("password"); - final LockscreenCredential newPassword = newPassword("newpassword"); - - initializeCredentialUnderSP(password, PRIMARY_USER_ID); - long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); - // Untrusted change password - mService.setLockCredential(newPassword, nonePassword(), PRIMARY_USER_ID, - true); - assertNotEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); - assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); - - // Verify the password - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - newPassword, 0, PRIMARY_USER_ID).getResponseCode()); - } - - @Test - public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException { - final LockscreenCredential password = newPassword("password"); - final LockscreenCredential newPassword = newPassword("newpassword"); - - initializeCredentialUnderSP(password, PRIMARY_USER_ID); - // Untrusted change password - mService.setLockCredential(newPassword, nonePassword(), PRIMARY_USER_ID, - true); - - // Verify the password - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - newPassword, 0, PRIMARY_USER_ID) - .getResponseCode()); - - // Ensure the same secret was passed each time - ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class); - verify(mAuthSecretService, atLeastOnce()).primaryUserCredential(secret.capture()); - assertEquals(1, secret.getAllValues().stream().distinct().count()); - } - - @Test - public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException { - final LockscreenCredential password = newPassword("password"); - final LockscreenCredential newPassword = newPassword("newpassword"); - - // Disable caching for this test - enableSpCaching(false); - - initializeCredentialUnderSP(password, PRIMARY_USER_ID); - flushHandlerTasks(); - - long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); - // Untrusted change password - assertExpectException( - IllegalStateException.class, - /* messageRegex= */ "Untrusted credential reset not possible without cached SP", - () -> mService.setLockCredential(newPassword, nonePassword(), - PRIMARY_USER_ID, true)); - assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); - - // Verify the new password doesn't work but the old one still does - assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential( - newPassword, 0, PRIMARY_USER_ID) - .getResponseCode()); - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - password, 0, PRIMARY_USER_ID) - .getResponseCode()); - } - -} diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java index 8c8edfad231f..abfda7725b7d 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java @@ -93,7 +93,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), sid); assertFalse(mService.setLockCredential(newPassword("newpwd"), newPassword("badpwd"), - PRIMARY_USER_ID, false)); + PRIMARY_USER_ID)); assertVerifyCredentials(PRIMARY_USER_ID, newPassword("password"), sid); } @@ -101,7 +101,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { public void testClearPasswordPrimaryUser() throws RemoteException { initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), 1234); assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"), - PRIMARY_USER_ID, false)); + PRIMARY_USER_ID)); assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); } @@ -111,7 +111,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { final LockscreenCredential firstUnifiedPassword = newPassword("pwd-1"); final LockscreenCredential secondUnifiedPassword = newPassword("pwd-2"); assertTrue(mService.setLockCredential(firstUnifiedPassword, - nonePassword(), PRIMARY_USER_ID, false)); + nonePassword(), PRIMARY_USER_ID)); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID); @@ -146,15 +146,14 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mStorageManager.setIgnoreBadUnlock(true); // Change primary password and verify that profile SID remains assertTrue(mService.setLockCredential( - secondUnifiedPassword, firstUnifiedPassword, PRIMARY_USER_ID, false)); + secondUnifiedPassword, firstUnifiedPassword, PRIMARY_USER_ID)); mStorageManager.setIgnoreBadUnlock(false); assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID)); // Clear unified challenge assertTrue(mService.setLockCredential(nonePassword(), - secondUnifiedPassword, PRIMARY_USER_ID, - false)); + secondUnifiedPassword, PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID)); @@ -166,7 +165,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { final LockscreenCredential profilePassword = newPassword("profile"); assertTrue(mService.setLockCredential(primaryPassword, nonePassword(), - PRIMARY_USER_ID, false)); + PRIMARY_USER_ID)); /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new * credential as part of verifyCredential() before the new credential is committed in * StorageManager. So we relax the check in our mock StorageManager to allow that. @@ -174,7 +173,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mStorageManager.setIgnoreBadUnlock(true); assertTrue(mService.setLockCredential(profilePassword, nonePassword(), - MANAGED_PROFILE_USER_ID, false)); + MANAGED_PROFILE_USER_ID)); mStorageManager.setIgnoreBadUnlock(false); final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); @@ -201,7 +200,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { // Change primary credential and make sure we don't affect profile mStorageManager.setIgnoreBadUnlock(true); assertTrue(mService.setLockCredential( - newPassword("pwd"), primaryPassword, PRIMARY_USER_ID, false)); + newPassword("pwd"), primaryPassword, PRIMARY_USER_ID)); mStorageManager.setIgnoreBadUnlock(false); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( profilePassword, 0, MANAGED_PROFILE_USER_ID) @@ -214,8 +213,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( newPassword("password"), nonePassword(), - PRIMARY_USER_ID, - false)); + PRIMARY_USER_ID)); verify(mRecoverableKeyStoreManager) .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, "password".getBytes(), @@ -228,8 +226,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( newPattern("12345"), nonePassword(), - MANAGED_PROFILE_USER_ID, - false)); + MANAGED_PROFILE_USER_ID)); verify(mRecoverableKeyStoreManager) .lockScreenSecretChanged(CREDENTIAL_TYPE_PATTERN, "12345".getBytes(), @@ -247,8 +244,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( newPassword("newPassword"), newPattern("12345"), - MANAGED_PROFILE_USER_ID, - false)); + MANAGED_PROFILE_USER_ID)); verify(mRecoverableKeyStoreManager) .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, "newPassword".getBytes(), @@ -263,8 +259,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( newPattern("12345"), nonePassword(), - PRIMARY_USER_ID, - false)); + PRIMARY_USER_ID)); verify(mRecoverableKeyStoreManager, never()) .lockScreenSecretChanged( @@ -284,8 +279,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( newCredential, oldCredential, - PRIMARY_USER_ID, - false)); + PRIMARY_USER_ID)); verify(mRecoverableKeyStoreManager) .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, newCredential.getCredential(), @@ -305,8 +299,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( nonePassword(), newPassword("oldPassword"), - PRIMARY_USER_ID, - false)); + PRIMARY_USER_ID)); verify(mRecoverableKeyStoreManager) .lockScreenSecretChanged(CREDENTIAL_TYPE_NONE, null, PRIMARY_USER_ID); @@ -322,7 +315,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { 1234); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); - mService.setLockCredential(nonePassword(), newPattern("123654"), PRIMARY_USER_ID, false); + mService.setLockCredential(nonePassword(), newPattern("123654"), PRIMARY_USER_ID); // Verify fingerprint is removed verify(mFingerprintManager).remove(any(), eq(PRIMARY_USER_ID), any()); @@ -343,8 +336,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( profilePassword, nonePassword(), - MANAGED_PROFILE_USER_ID, - false)); + MANAGED_PROFILE_USER_ID)); verify(mRecoverableKeyStoreManager) .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, profilePassword.getCredential(), @@ -390,8 +382,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { assertTrue(mService.setLockCredential( pattern, nonePassword(), - MANAGED_PROFILE_USER_ID, - false)); + MANAGED_PROFILE_USER_ID)); reset(mRecoverableKeyStoreManager); mService.verifyCredential(pattern, 1, MANAGED_PROFILE_USER_ID); @@ -426,7 +417,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { private void testCreateCredential(int userId, LockscreenCredential credential) throws RemoteException { - assertTrue(mService.setLockCredential(credential, nonePassword(), userId, false)); + assertTrue(mService.setLockCredential(credential, nonePassword(), userId)); assertVerifyCredentials(userId, credential, -1); } @@ -435,7 +426,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mHasSecureLockScreen = false; try { - mService.setLockCredential(credential, null, userId, false); + mService.setLockCredential(credential, null, userId); fail("An exception should have been thrown."); } catch (UnsupportedOperationException e) { // Success - the exception was expected. @@ -448,7 +439,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { LockscreenCredential oldCredential) throws RemoteException { final long sid = 1234; initializeStorageWithCredential(userId, oldCredential, sid); - assertTrue(mService.setLockCredential(newCredential, oldCredential, userId, false)); + assertTrue(mService.setLockCredential(newCredential, oldCredential, userId)); assertVerifyCredentials(userId, newCredential, sid); } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java index 27af9e2dfd6f..4b3f7b5d08ef 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java @@ -48,7 +48,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_setPin() { - mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID); assertEquals(CREDENTIAL_TYPE_PIN, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, @@ -57,7 +57,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_setPattern() { - mService.setLockCredential(newPattern("4321"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPattern("4321"), nonePassword(), PRIMARY_USER_ID); assertEquals(CREDENTIAL_TYPE_PATTERN, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, @@ -66,7 +66,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_setPassword() { - mService.setLockCredential(newPassword("4321"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPassword("4321"), nonePassword(), PRIMARY_USER_ID); assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, @@ -75,8 +75,8 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_changeCredential() { - mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID, false); - mService.setLockCredential(newPattern("5678"), newPassword("1234"), PRIMARY_USER_ID, false); + mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID); + mService.setLockCredential(newPattern("5678"), newPassword("1234"), PRIMARY_USER_ID); assertEquals(CREDENTIAL_TYPE_PATTERN, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, @@ -85,16 +85,16 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_removeCredential() { - mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID); assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(USER_FRP)); - mService.setLockCredential(nonePassword(), newPassword("1234"), PRIMARY_USER_ID, false); + mService.setLockCredential(nonePassword(), newPassword("1234"), PRIMARY_USER_ID); assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(USER_FRP)); } @Test public void testFrpCredential_cannotVerifyAfterProvsioning() { - mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID); mSettings.setDeviceProvisioned(true); assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, @@ -103,7 +103,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_legacyPinTypePersistentData() { - mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID); PersistentData data = mStorage.readPersistentDataBlock(); // Tweak the existing persistent data to make it look like one with legacy credential type assertEquals(CREDENTIAL_TYPE_PIN, data.payload[3]); @@ -119,7 +119,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { @Test public void testFrpCredential_legacyPasswordTypePersistentData() { - mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID); PersistentData data = mStorage.readPersistentDataBlock(); // Tweak the existing persistent data to make it look like one with legacy credential type assertEquals(CREDENTIAL_TYPE_PASSWORD, data.payload[3]); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index 49858482fdf6..d6ef2d459769 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -106,7 +106,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { final LockscreenCredential password = newPassword("testPasswordMigration-password"); disableSyntheticPassword(); - assertTrue(mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID, false)); + assertTrue(mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID)); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); enableSyntheticPassword(); @@ -128,7 +128,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { protected void initializeCredentialUnderSP(LockscreenCredential password, int userId) throws RemoteException { enableSyntheticPassword(); - mService.setLockCredential(password, nonePassword(), userId, false); + mService.setLockCredential(password, nonePassword(), userId); assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(userId)); assertTrue(mService.isSyntheticPasswordBasedCredential(userId)); } @@ -140,7 +140,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { initializeCredentialUnderSP(password, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); - mService.setLockCredential(newPassword, password, PRIMARY_USER_ID, false); + mService.setLockCredential(newPassword, password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( newPassword, 0, PRIMARY_USER_ID) .getResponseCode()); @@ -170,12 +170,11 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { initializeCredentialUnderSP(password, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); // clear password - mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, false); + mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID); assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); // set a new password - mService.setLockCredential(badPassword, nonePassword(), - PRIMARY_USER_ID, false); + mService.setLockCredential(badPassword, nonePassword(), PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( badPassword, 0, PRIMARY_USER_ID) .getResponseCode()); @@ -188,7 +187,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { LockscreenCredential badPassword = newPassword("new"); initializeCredentialUnderSP(password, PRIMARY_USER_ID); - mService.setLockCredential(badPassword, password, PRIMARY_USER_ID, false); + mService.setLockCredential(badPassword, password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( badPassword, 0, PRIMARY_USER_ID) .getResponseCode()); @@ -245,7 +244,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException { LockscreenCredential password = newPassword("getASyntheticPassword"); initializeCredentialUnderSP(password, PRIMARY_USER_ID); - mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, false); + mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID); reset(mAuthSecretService); mService.onUnlockUser(PRIMARY_USER_ID); @@ -257,7 +256,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testManagedProfileUnifiedChallengeMigration() throws RemoteException { LockscreenCredential UnifiedPassword = newPassword("unified-pwd"); disableSyntheticPassword(); - mService.setLockCredential(UnifiedPassword, nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(UnifiedPassword, nonePassword(), PRIMARY_USER_ID); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID); @@ -292,9 +291,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { LockscreenCredential primaryPassword = newPassword("primary"); LockscreenCredential profilePassword = newPassword("profile"); disableSyntheticPassword(); - mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID, false); - mService.setLockCredential(profilePassword, nonePassword(), - MANAGED_PROFILE_USER_ID, false); + mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID); + mService.setLockCredential(profilePassword, nonePassword(), MANAGED_PROFILE_USER_ID); final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID); byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); @@ -404,7 +402,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode(); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.setLockCredential(pattern, password, PRIMARY_USER_ID, false); + mService.setLockCredential(pattern, password, PRIMARY_USER_ID); mLocalService.setLockCredentialWithToken(newPassword, handle, token, PRIMARY_USER_ID); @@ -433,7 +431,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { // initialized but the user currently has no password initializeCredentialUnderSP(newPassword("password"), PRIMARY_USER_ID); assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"), - PRIMARY_USER_ID, false)); + PRIMARY_USER_ID)); assertTrue(mService.isSyntheticPasswordBasedCredential(PRIMARY_USER_ID)); long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); @@ -449,7 +447,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { LockscreenCredential password = newPassword("password"); // Set up pre-SP user password disableSyntheticPassword(); - mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID); enableSyntheticPassword(); long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); @@ -507,11 +505,11 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { @Test public void testGetHashFactorPrimaryUser() throws RemoteException { LockscreenCredential password = newPassword("password"); - mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID); byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID); assertNotNull(hashFactor); - mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, false); + mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID); byte[] newHashFactor = mService.getHashFactor(nonePassword(), PRIMARY_USER_ID); assertNotNull(newHashFactor); // Hash factor should never change after password change/removal @@ -521,7 +519,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { @Test public void testGetHashFactorManagedProfileUnifiedChallenge() throws RemoteException { LockscreenCredential pattern = newPattern("1236"); - mService.setLockCredential(pattern, nonePassword(), PRIMARY_USER_ID, false); + mService.setLockCredential(pattern, nonePassword(), PRIMARY_USER_ID); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID)); } @@ -530,9 +528,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testGetHashFactorManagedProfileSeparateChallenge() throws RemoteException { LockscreenCredential primaryPassword = newPassword("primary"); LockscreenCredential profilePassword = newPassword("profile"); - mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID, false); - mService.setLockCredential(profilePassword, nonePassword(), - MANAGED_PROFILE_USER_ID, false); + mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID); + mService.setLockCredential(profilePassword, nonePassword(), MANAGED_PROFILE_USER_ID); assertNotNull( mService.getHashFactor(profilePassword, MANAGED_PROFILE_USER_ID)); } diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java index 178f38aac0b7..fb9c68a5b70d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java @@ -68,7 +68,7 @@ public class ApexManagerTest { @Before public void setUp() throws RemoteException { mContext = InstrumentationRegistry.getInstrumentation().getContext(); - mApexManager = new ApexManager.ApexManagerImpl(mContext, mApexService); + mApexManager = new ApexManager.ApexManagerImpl(mApexService); } @Test diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp index 92198fa8cb0c..f608babd062c 100644 --- a/services/tests/uiservicestests/Android.bp +++ b/services/tests/uiservicestests/Android.bp @@ -20,6 +20,7 @@ android_test { "androidx.test.rules", "hamcrest-library", "mockito-target-inline-minus-junit4", "platform-test-annotations", + "platformprotosnano", "hamcrest-library", "testables", "truth-prebuilt", diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PulledStatsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PulledStatsTest.java new file mode 100644 index 000000000000..f685c68f4160 --- /dev/null +++ b/services/tests/uiservicestests/src/com/android/server/notification/PulledStatsTest.java @@ -0,0 +1,113 @@ +/* + * 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 com.android.server.notification; + +import static com.android.server.notification.NotificationManagerService.REPORT_REMOTE_VIEWS; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotSame; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.service.notification.nano.NotificationRemoteViewsProto; +import android.test.MoreAsserts; +import android.util.proto.ProtoOutputStream; + +import androidx.test.filters.SmallTest; + +import com.android.server.UiServiceTestCase; + +import com.google.protobuf.nano.InvalidProtocolBufferNanoException; + +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.List; + +@SmallTest +public class PulledStatsTest extends UiServiceTestCase { + + @Test + public void testPulledStats_Empty() { + PulledStats stats = new PulledStats(0L); + assertEquals(0L, stats.endTimeMs()); + } + + @Test + public void testPulledStats_UnknownReport() { + PulledStats stats = new PulledStats(0L); + stats.addUndecoratedPackage("foo", 456); + stats.addUndecoratedPackage("bar", 123); + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + final ProtoOutputStream proto = new ProtoOutputStream(bytes); + stats.writeToProto(1023123, proto); // a very large number + proto.flush(); + + // expect empty output in response to an unrecognized request + assertEquals(0L, bytes.size()); + } + + @Test + public void testPulledStats_RemoteViewReportPackages() { + List<String> expectedPkgs = new ArrayList<>(2); + expectedPkgs.add("foo"); + expectedPkgs.add("bar"); + + PulledStats stats = new PulledStats(0L); + for(String pkg: expectedPkgs) { + stats.addUndecoratedPackage(pkg, 111); + } + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + final ProtoOutputStream protoStream = new ProtoOutputStream(bytes); + stats.writeToProto(REPORT_REMOTE_VIEWS, protoStream); + protoStream.flush(); + + try { + NotificationRemoteViewsProto proto = + NotificationRemoteViewsProto.parseFrom(bytes.toByteArray()); + List<String> actualPkgs = new ArrayList<>(2); + for(int i = 0 ; i < proto.packageRemoteViewInfo.length; i++) { + actualPkgs.add(proto.packageRemoteViewInfo[i].packageName); + } + assertEquals(2, actualPkgs.size()); + assertTrue("missing packages", actualPkgs.containsAll(expectedPkgs)); + assertTrue("unexpected packages", expectedPkgs.containsAll(actualPkgs)); + } catch (InvalidProtocolBufferNanoException e) { + e.printStackTrace(); + fail("writeToProto generated unparsable output"); + } + + } + @Test + public void testPulledStats_RemoteViewReportEndTime() { + List<String> expectedPkgs = new ArrayList<>(2); + expectedPkgs.add("foo"); + expectedPkgs.add("bar"); + + PulledStats stats = new PulledStats(0L); + long t = 111; + for(String pkg: expectedPkgs) { + t += 1000; + stats.addUndecoratedPackage(pkg, t); + } + assertEquals(t, stats.endTimeMs()); + } + +} diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java index e34824c57fb2..1996dd4f6545 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java +++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java @@ -236,7 +236,7 @@ public class UsageStatsDatabase { return false; } } - } catch (IOException e) { + } catch (Exception e) { Slog.e(TAG, "Failed to check-in", e); return false; } @@ -744,7 +744,7 @@ public class UsageStatsDatabase { IntervalStats stats = new IntervalStats(); readLocked(f, stats); return stats; - } catch (IOException e) { + } catch (Exception e) { Slog.e(TAG, "Failed to read usage stats file", e); } } @@ -862,7 +862,7 @@ public class UsageStatsDatabase { if (beginTime < stats.endTime) { combiner.combine(stats, false, results); } - } catch (IOException e) { + } catch (Exception e) { Slog.e(TAG, "Failed to read usage stats file", e); // We continue so that we return results that are not // corrupt. @@ -1009,7 +1009,8 @@ public class UsageStatsDatabase { } } - private void writeLocked(AtomicFile file, IntervalStats stats) throws IOException { + private void writeLocked(AtomicFile file, IntervalStats stats) + throws IOException, RuntimeException { if (mCurrentVersion <= 3) { Slog.wtf(TAG, "Attempting to write UsageStats as XML with version " + mCurrentVersion); return; @@ -1018,7 +1019,7 @@ public class UsageStatsDatabase { } private static void writeLocked(AtomicFile file, IntervalStats stats, int version, - PackagesTokenData packagesTokenData) throws IOException { + PackagesTokenData packagesTokenData) throws IOException, RuntimeException { FileOutputStream fos = file.startWrite(); try { writeLocked(fos, stats, version, packagesTokenData); @@ -1031,7 +1032,7 @@ public class UsageStatsDatabase { } private static void writeLocked(OutputStream out, IntervalStats stats, int version, - PackagesTokenData packagesTokenData) throws IOException { + PackagesTokenData packagesTokenData) throws RuntimeException { switch (version) { case 1: case 2: @@ -1041,7 +1042,7 @@ public class UsageStatsDatabase { case 4: try { UsageStatsProto.write(out, stats); - } catch (IOException | IllegalArgumentException e) { + } catch (Exception e) { Slog.e(TAG, "Unable to write interval stats to proto.", e); } break; @@ -1049,7 +1050,7 @@ public class UsageStatsDatabase { stats.obfuscateData(packagesTokenData); try { UsageStatsProtoV2.write(out, stats); - } catch (IOException | IllegalArgumentException e) { + } catch (Exception e) { Slog.e(TAG, "Unable to write interval stats to proto.", e); } break; @@ -1060,7 +1061,8 @@ public class UsageStatsDatabase { } } - private void readLocked(AtomicFile file, IntervalStats statsOut) throws IOException { + private void readLocked(AtomicFile file, IntervalStats statsOut) + throws IOException, RuntimeException { if (mCurrentVersion <= 3) { Slog.wtf(TAG, "Reading UsageStats as XML; current database version: " + mCurrentVersion); @@ -1072,7 +1074,7 @@ public class UsageStatsDatabase { * Returns {@code true} if any stats were omitted while reading, {@code false} otherwise. */ private static boolean readLocked(AtomicFile file, IntervalStats statsOut, int version, - PackagesTokenData packagesTokenData) throws IOException { + PackagesTokenData packagesTokenData) throws IOException, RuntimeException { boolean dataOmitted = false; try { FileInputStream in = file.openRead(); @@ -1098,7 +1100,7 @@ public class UsageStatsDatabase { * Returns {@code true} if any stats were omitted while reading, {@code false} otherwise. */ private static boolean readLocked(InputStream in, IntervalStats statsOut, int version, - PackagesTokenData packagesTokenData) throws IOException { + PackagesTokenData packagesTokenData) throws RuntimeException { boolean dataOmitted = false; switch (version) { case 1: @@ -1114,14 +1116,14 @@ public class UsageStatsDatabase { case 4: try { UsageStatsProto.read(in, statsOut); - } catch (IOException e) { + } catch (Exception e) { Slog.e(TAG, "Unable to read interval stats from proto.", e); } break; case 5: try { UsageStatsProtoV2.read(in, statsOut); - } catch (IOException e) { + } catch (Exception e) { Slog.e(TAG, "Unable to read interval stats from proto.", e); } dataOmitted = statsOut.deobfuscateData(packagesTokenData); @@ -1145,7 +1147,7 @@ public class UsageStatsDatabase { try (FileInputStream in = new AtomicFile(mPackageMappingsFile).openRead()) { UsageStatsProtoV2.readObfuscatedData(in, mPackagesTokenData); - } catch (IOException e) { + } catch (Exception e) { Slog.e(TAG, "Failed to read the obfuscated packages mapping file.", e); return; } @@ -1174,7 +1176,7 @@ public class UsageStatsDatabase { UsageStatsProtoV2.writeObfuscatedData(fos, mPackagesTokenData); file.finishWrite(fos); fos = null; - } catch (IOException | IllegalArgumentException e) { + } catch (Exception e) { Slog.e(TAG, "Unable to write obfuscated data to proto.", e); } finally { file.failWrite(fos); @@ -1414,8 +1416,8 @@ public class UsageStatsDatabase { try { stats.beginTime = in.readLong(); readLocked(in, stats, version, mPackagesTokenData); - } catch (IOException ioe) { - Slog.d(TAG, "DeSerializing IntervalStats Failed", ioe); + } catch (Exception e) { + Slog.d(TAG, "DeSerializing IntervalStats Failed", e); stats = null; } return stats; diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 064922386773..c900f386b438 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -653,18 +653,20 @@ public class UsageStatsService extends SystemService implements } Arrays.sort(pendingEventsFiles); - for (int i = 0; i < pendingEventsFiles.length; i++) { + final int numFiles = pendingEventsFiles.length; + for (int i = 0; i < numFiles; i++) { final AtomicFile af = new AtomicFile(pendingEventsFiles[i]); + final LinkedList<Event> tmpEvents = new LinkedList<>(); try { try (FileInputStream in = af.openRead()) { - UsageStatsProtoV2.readPendingEvents(in, pendingEvents); + UsageStatsProtoV2.readPendingEvents(in, tmpEvents); } - } catch (IOException e) { - // Even if one file read fails, exit here to keep all events in order on disk - - // they will be read and processed the next time user is unlocked. + // only add to the pending events if the read was successful + pendingEvents.addAll(tmpEvents); + } catch (Exception e) { + // Most likely trying to read a corrupted file - log the failure and continue + // reading the other pending event files. Slog.e(TAG, "Could not read " + pendingEventsFiles[i] + " for user " + userId); - pendingEvents.clear(); - return; } } } @@ -691,7 +693,7 @@ public class UsageStatsService extends SystemService implements af.finishWrite(fos); fos = null; pendingEvents.clear(); - } catch (IOException | IllegalArgumentException e) { + } catch (Exception e) { Slog.e(TAG, "Failed to write " + pendingEventsFile.getAbsolutePath() + " for user " + userId); } finally { diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index ace2131835c0..cf705f466e48 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -54,6 +54,7 @@ import android.os.ParcelUuid; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.provider.Telephony.SimInfo; import android.telephony.euicc.EuiccManager; import android.telephony.ims.ImsMmTelManager; import android.util.DisplayMetrics; @@ -129,7 +130,7 @@ public class SubscriptionManager { /** @hide */ @UnsupportedAppUsage - public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo"); + public static final Uri CONTENT_URI = SimInfo.CONTENT_URI; /** * Generates a content {@link Uri} used to receive updates on simInfo change diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml index d433df56bc00..d1da47f0f9d8 100644 --- a/tests/FlickerTests/AndroidTest.xml +++ b/tests/FlickerTests/AndroidTest.xml @@ -25,6 +25,6 @@ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> <option name="directory-keys" value="/sdcard/flicker" /> <option name="collect-on-run-ended-only" value="true" /> - <option name="clean-up" value="false" /> + <option name="clean-up" value="true" /> </metrics_collector> </configuration> diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index e30878157a26..ef8facec9752 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -118,7 +118,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // The failed packages should be the same as the registered ones to ensure registration is // done successfully @@ -135,7 +136,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION); raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE), - new VersionedPackage(APP_B, VERSION_CODE))); + new VersionedPackage(APP_B, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // The failed packages should be the same as the registered ones to ensure registration is // done successfully @@ -151,7 +153,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION); watchdog.unregisterHealthObserver(observer); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // We should have no failed packages to ensure unregistration is done successfully assertThat(observer.mHealthCheckFailedPackages).isEmpty(); @@ -167,7 +170,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION); watchdog.unregisterHealthObserver(observer2); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // observer1 should receive failed packages as intended. assertThat(observer1.mHealthCheckFailedPackages).containsExactly(APP_A); @@ -183,7 +187,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION); moveTimeForwardAndDispatch(SHORT_DURATION); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // We should have no failed packages for the fatal failure is raised after expiration assertThat(observer.mHealthCheckFailedPackages).isEmpty(); @@ -199,7 +204,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), LONG_DURATION); moveTimeForwardAndDispatch(SHORT_DURATION); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // We should have no failed packages for the fatal failure is raised after expiration assertThat(observer1.mHealthCheckFailedPackages).isEmpty(); @@ -226,7 +232,8 @@ public class PackageWatchdogTest { moveTimeForwardAndDispatch((SHORT_DURATION / 2) + 1); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify that we receive failed packages as expected for APP_A not expired assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A); @@ -252,7 +259,8 @@ public class PackageWatchdogTest { watchdog2.registerHealthObserver(observer2); raiseFatalFailureAndDispatch(watchdog2, Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE), - new VersionedPackage(APP_B, VERSION_CODE))); + new VersionedPackage(APP_B, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // We should receive failed packages as expected to ensure observers are persisted and // resumed correctly @@ -274,7 +282,8 @@ public class PackageWatchdogTest { // Then fail APP_A below the threshold for (int i = 0; i < watchdog.getTriggerFailureCount() - 1; i++) { - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); } // Run handler so package failures are dispatched to observers @@ -301,7 +310,8 @@ public class PackageWatchdogTest { // Then fail APP_C (not observed) above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_C, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_C, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify that observers are not notified assertThat(observer1.mHealthCheckFailedPackages).isEmpty(); @@ -331,7 +341,8 @@ public class PackageWatchdogTest { // Then fail APP_A (different version) above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, differentVersionCode))); + Arrays.asList(new VersionedPackage(APP_A, differentVersionCode)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify that observers are not notified assertThat(observer.mHealthCheckFailedPackages).isEmpty(); @@ -368,7 +379,8 @@ public class PackageWatchdogTest { Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE), new VersionedPackage(APP_B, VERSION_CODE), new VersionedPackage(APP_C, VERSION_CODE), - new VersionedPackage(APP_D, VERSION_CODE))); + new VersionedPackage(APP_D, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify least impact observers are notifed of package failures List<String> observerNonePackages = observerNone.mMitigatedPackages; @@ -411,7 +423,8 @@ public class PackageWatchdogTest { // Then fail APP_A above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify only observerFirst is notifed assertThat(observerFirst.mMitigatedPackages).containsExactly(APP_A); @@ -424,7 +437,8 @@ public class PackageWatchdogTest { // Then fail APP_A again above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify only observerSecond is notifed cos it has least impact assertThat(observerSecond.mMitigatedPackages).containsExactly(APP_A); @@ -437,7 +451,8 @@ public class PackageWatchdogTest { // Then fail APP_A again above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify only observerFirst is notifed cos it has the only action assertThat(observerFirst.mMitigatedPackages).containsExactly(APP_A); @@ -450,7 +465,8 @@ public class PackageWatchdogTest { // Then fail APP_A again above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify no observer is notified cos no actions left assertThat(observerFirst.mMitigatedPackages).isEmpty(); @@ -474,7 +490,8 @@ public class PackageWatchdogTest { // Then fail APP_A above the threshold raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // Verify only one observer is notifed assertThat(observer1.mMitigatedPackages).containsExactly(APP_A); @@ -746,13 +763,15 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION); // Fail APP_A below the threshold which should not trigger package failures for (int i = 0; i < PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT - 1; i++) { - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); } mTestLooper.dispatchAll(); assertThat(observer.mHealthCheckFailedPackages).isEmpty(); // One more to trigger the package failure - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A); } @@ -773,20 +792,24 @@ public class PackageWatchdogTest { TestObserver observer = new TestObserver(OBSERVER_NAME_1); watchdog.startObservingHealth(observer, Arrays.asList(APP_A, APP_B), Long.MAX_VALUE); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS + 1); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); // We shouldn't receive APP_A since the interval of 2 failures is greater than // DEFAULT_TRIGGER_FAILURE_DURATION_MS. assertThat(observer.mHealthCheckFailedPackages).isEmpty(); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS - 1); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); // We should receive APP_B since the interval of 2 failures is less than @@ -809,7 +832,8 @@ public class PackageWatchdogTest { // small timeouts. moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS - 100); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // We should receive APP_A since the observer hasn't expired assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A); @@ -827,7 +851,8 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer, Arrays.asList(APP_A), -1); moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS + 1); raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); // We should receive nothing since the observer has expired assertThat(observer.mHealthCheckFailedPackages).isEmpty(); @@ -850,22 +875,59 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer, Arrays.asList(APP_A), Long.MAX_VALUE); // Raise 2 failures at t=0 and t=900 respectively - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); moveTimeForwardAndDispatch(900); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); // Raise 2 failures at t=1100 moveTimeForwardAndDispatch(200); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); mTestLooper.dispatchAll(); // We should receive APP_A since there are 3 failures within 1000ms window assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A); } + /** Test that observers execute correctly for different failure reasons */ + @Test + public void testFailureReasons() { + PackageWatchdog watchdog = createWatchdog(); + TestObserver observer1 = new TestObserver(OBSERVER_NAME_1); + TestObserver observer2 = new TestObserver(OBSERVER_NAME_2); + TestObserver observer3 = new TestObserver(OBSERVER_NAME_3); + TestObserver observer4 = new TestObserver(OBSERVER_NAME_4); + + watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.startObservingHealth(observer2, Arrays.asList(APP_B), SHORT_DURATION); + watchdog.startObservingHealth(observer3, Arrays.asList(APP_C), SHORT_DURATION); + watchdog.startObservingHealth(observer4, Arrays.asList(APP_D), SHORT_DURATION); + + raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A, + VERSION_CODE)), PackageWatchdog.FAILURE_REASON_NATIVE_CRASH); + raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_B, + VERSION_CODE)), PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK); + raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_C, + VERSION_CODE)), PackageWatchdog.FAILURE_REASON_APP_CRASH); + raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_D, + VERSION_CODE)), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING); + + assertThat(observer1.getLastFailureReason()).isEqualTo( + PackageWatchdog.FAILURE_REASON_NATIVE_CRASH); + assertThat(observer2.getLastFailureReason()).isEqualTo( + PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK); + assertThat(observer3.getLastFailureReason()).isEqualTo( + PackageWatchdog.FAILURE_REASON_APP_CRASH); + assertThat(observer4.getLastFailureReason()).isEqualTo( + PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING); + } + private void adoptShellPermissions(String... permissions) { InstrumentationRegistry .getInstrumentation() @@ -900,9 +962,9 @@ public class PackageWatchdogTest { /** Trigger package failures above the threshold. */ private void raiseFatalFailureAndDispatch(PackageWatchdog watchdog, - List<VersionedPackage> packages) { + List<VersionedPackage> packages, int failureReason) { for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { - watchdog.onPackageFailure(packages); + watchdog.onPackageFailure(packages, failureReason); } mTestLooper.dispatchAll(); } @@ -936,6 +998,7 @@ public class PackageWatchdogTest { private static class TestObserver implements PackageHealthObserver { private final String mName; private int mImpact; + private int mLastFailureReason; final List<String> mHealthCheckFailedPackages = new ArrayList<>(); final List<String> mMitigatedPackages = new ArrayList<>(); @@ -954,14 +1017,19 @@ public class PackageWatchdogTest { return mImpact; } - public boolean execute(VersionedPackage versionedPackage) { + public boolean execute(VersionedPackage versionedPackage, int failureReason) { mMitigatedPackages.add(versionedPackage.getPackageName()); + mLastFailureReason = failureReason; return true; } public String getName() { return mName; } + + public int getLastFailureReason() { + return mLastFailureReason; + } } private static class TestController extends ExplicitHealthCheckController { diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp index 6c3bcf039be1..bb541fe2490b 100644 --- a/tools/aapt2/java/JavaClassGenerator.cpp +++ b/tools/aapt2/java/JavaClassGenerator.cpp @@ -304,9 +304,11 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res auto documentation_remove_iter = std::remove_if(documentation_attrs.begin(), documentation_attrs.end(), [&](StyleableAttr entry) -> bool { - StringPiece attr_comment_line = entry.symbol.value().attribute->GetComment(); - return SkipSymbol(entry.symbol) || attr_comment_line.contains("@removed") - || attr_comment_line.contains("@hide"); + if (SkipSymbol(entry.symbol)) { + return true; + } + const StringPiece attr_comment_line = entry.symbol.value().attribute->GetComment(); + return attr_comment_line.contains("@removed") || attr_comment_line.contains("@hide"); }); documentation_attrs.erase(documentation_remove_iter, documentation_attrs.end()); diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp index 4899fbd3b669..d45c4e7efb12 100644 --- a/tools/stats_log_api_gen/java_writer.cpp +++ b/tools/stats_log_api_gen/java_writer.cpp @@ -83,7 +83,7 @@ static int write_java_methods( // Print method body. string indent(""); if (DEFAULT_MODULE_NAME != moduleName) { - fprintf(out, " if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n"); + fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {\n"); indent = " "; } @@ -116,16 +116,19 @@ static int write_java_methods( fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(), argIndex); break; case JAVA_TYPE_BYTE_ARRAY: - fprintf(out, "%s builder.writeByteArray(arg%d);\n", - indent.c_str(), argIndex); + fprintf(out, "%s builder.writeByteArray(null == arg%d ? new byte[0] : arg%d);\n", + indent.c_str(), argIndex, argIndex); break; case JAVA_TYPE_ATTRIBUTION_CHAIN: { const char* uidName = attributionDecl.fields.front().name.c_str(); const char* tagName = attributionDecl.fields.back().name.c_str(); - fprintf(out, "%s builder.writeAttributionChain(%s, %s);\n", - indent.c_str(), uidName, tagName); + fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str()); + fprintf(out, "%s null == %s ? new int[0] : %s,\n", + indent.c_str(), uidName, uidName); + fprintf(out, "%s null == %s ? new String[0] : %s);\n", + indent.c_str(), tagName, tagName); break; } case JAVA_TYPE_KEY_VALUE_PAIR: diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index fccbcf7c101f..b52880e29e30 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -44,7 +44,6 @@ import android.net.wifi.WifiNetworkSuggestion; import android.os.Messenger; import android.os.ResultReceiver; import android.os.WorkSource; -import android.os.connectivity.WifiActivityEnergyInfo; /** * Interface that allows controlling and querying Wi-Fi connectivity. @@ -55,8 +54,6 @@ interface IWifiManager { long getSupportedFeatures(); - WifiActivityEnergyInfo reportActivityInfo(); - oneway void getWifiActivityEnergyInfoAsync(in IOnWifiActivityEnergyInfoListener listener); ParceledListSlice getConfiguredNetworks(String packageName, String featureId); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 0108d5aa936c..86c398b770b7 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -2379,25 +2379,6 @@ public class WifiManager { } /** - * Return the record of {@link WifiActivityEnergyInfo} object that - * has the activity and energy info. This can be used to ascertain what - * the controller has been up to, since the last sample. - * - * @return a record with {@link WifiActivityEnergyInfo} or null if - * report is unavailable or unsupported - * @hide - */ - public WifiActivityEnergyInfo getControllerActivityEnergyInfo() { - try { - synchronized(this) { - return mService.reportActivityInfo(); - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Interface for Wi-Fi activity energy info listener. Should be implemented by applications and * set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}. * diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java index e78104d3da38..9fd29ae8d14a 100644 --- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java +++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java @@ -23,12 +23,10 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.app.ActivityThread; import android.net.MacAddress; import android.net.wifi.hotspot2.PasspointConfiguration; import android.os.Parcel; import android.os.Parcelable; -import android.os.Process; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -46,7 +44,6 @@ import java.util.Objects; * {@link WifiManager#addNetworkSuggestions(List)}. */ public final class WifiNetworkSuggestion implements Parcelable { - /** * Builder used to create {@link WifiNetworkSuggestion} objects. */ @@ -563,9 +560,7 @@ public final class WifiNetworkSuggestion implements Parcelable { mPasspointConfiguration, mIsAppInteractionRequired, mIsUserInteractionRequired, - mIsUserAllowed, - Process.myUid(), - ActivityThread.currentApplication().getApplicationContext().getOpPackageName()); + mIsUserAllowed); } } @@ -592,19 +587,6 @@ public final class WifiNetworkSuggestion implements Parcelable { * @hide */ public final boolean isUserInteractionRequired; - - /** - * The UID of the process initializing this network suggestion. - * @hide - */ - public final int suggestorUid; - - /** - * The package name of the process initializing this network suggestion. - * @hide - */ - public final String suggestorPackageName; - /** * Whether app share credential with the user, allow user use provided credential to * connect network manually. @@ -619,8 +601,6 @@ public final class WifiNetworkSuggestion implements Parcelable { this.isAppInteractionRequired = false; this.isUserInteractionRequired = false; this.isUserAllowedToManuallyConnect = true; - this.suggestorUid = -1; - this.suggestorPackageName = null; } /** @hide */ @@ -628,18 +608,14 @@ public final class WifiNetworkSuggestion implements Parcelable { @Nullable PasspointConfiguration passpointConfiguration, boolean isAppInteractionRequired, boolean isUserInteractionRequired, - boolean isUserAllowedToManuallyConnect, - int suggestorUid, @NonNull String suggestorPackageName) { + boolean isUserAllowedToManuallyConnect) { checkNotNull(networkConfiguration); - checkNotNull(suggestorPackageName); this.wifiConfiguration = networkConfiguration; this.passpointConfiguration = passpointConfiguration; this.isAppInteractionRequired = isAppInteractionRequired; this.isUserInteractionRequired = isUserInteractionRequired; this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect; - this.suggestorUid = suggestorUid; - this.suggestorPackageName = suggestorPackageName; } public static final @NonNull Creator<WifiNetworkSuggestion> CREATOR = @@ -651,9 +627,7 @@ public final class WifiNetworkSuggestion implements Parcelable { in.readParcelable(null), // PasspointConfiguration in.readBoolean(), // isAppInteractionRequired in.readBoolean(), // isUserInteractionRequired - in.readBoolean(), // isSharedCredentialWithUser - in.readInt(), // suggestorUid - in.readString() // suggestorPackageName + in.readBoolean() // isSharedCredentialWithUser ); } @@ -675,15 +649,12 @@ public final class WifiNetworkSuggestion implements Parcelable { dest.writeBoolean(isAppInteractionRequired); dest.writeBoolean(isUserInteractionRequired); dest.writeBoolean(isUserAllowedToManuallyConnect); - dest.writeInt(suggestorUid); - dest.writeString(suggestorPackageName); } @Override public int hashCode() { return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.BSSID, - wifiConfiguration.allowedKeyManagement, wifiConfiguration.FQDN, - suggestorUid, suggestorPackageName); + wifiConfiguration.allowedKeyManagement, wifiConfiguration.FQDN); } /** @@ -706,23 +677,19 @@ public final class WifiNetworkSuggestion implements Parcelable { && TextUtils.equals(this.wifiConfiguration.BSSID, lhs.wifiConfiguration.BSSID) && Objects.equals(this.wifiConfiguration.allowedKeyManagement, lhs.wifiConfiguration.allowedKeyManagement) - && TextUtils.equals(this.wifiConfiguration.FQDN, lhs.wifiConfiguration.FQDN) - && this.suggestorUid == lhs.suggestorUid - && TextUtils.equals(this.suggestorPackageName, lhs.suggestorPackageName); + && TextUtils.equals(this.wifiConfiguration.FQDN, lhs.wifiConfiguration.FQDN); } @Override public String toString() { - StringBuilder sb = new StringBuilder("WifiNetworkSuggestion [") - .append(", SSID=").append(wifiConfiguration.SSID) + StringBuilder sb = new StringBuilder("WifiNetworkSuggestion[ ") + .append("SSID=").append(wifiConfiguration.SSID) .append(", BSSID=").append(wifiConfiguration.BSSID) .append(", FQDN=").append(wifiConfiguration.FQDN) .append(", isAppInteractionRequired=").append(isAppInteractionRequired) .append(", isUserInteractionRequired=").append(isUserInteractionRequired) .append(", isUserAllowedToManuallyConnect=").append(isUserAllowedToManuallyConnect) - .append(", suggestorUid=").append(suggestorUid) - .append(", suggestorPackageName=").append(suggestorPackageName) - .append("]"); + .append(" ]"); return sb.toString(); } } diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java index 65a6c4d051cd..81bf81e40199 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java @@ -19,6 +19,7 @@ package android.net.wifi.aware; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; @@ -396,6 +397,17 @@ public class WifiAwareManager { } /** @hide */ + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + public void requestMacAddresses(int uid, List<Integer> peerIds, + IWifiAwareMacAddressProvider callback) { + try { + mService.requestMacAddresses(uid, peerIds, callback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ public NetworkSpecifier createNetworkSpecifier(int clientId, int role, int sessionId, @NonNull PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase) { if (VDBG) { diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java index 367cfa069e74..2c27037d29aa 100644 --- a/wifi/java/com/android/server/wifi/BaseWifiService.java +++ b/wifi/java/com/android/server/wifi/BaseWifiService.java @@ -76,11 +76,14 @@ public class BaseWifiService extends IWifiManager.Stub { throw new UnsupportedOperationException(); } - @Override + /** @deprecated use {@link #getWifiActivityEnergyInfoAsync} instead */ + @Deprecated public WifiActivityEnergyInfo reportActivityInfo() { throw new UnsupportedOperationException(); } + /** @deprecated use {@link #getWifiActivityEnergyInfoAsync} instead */ + @Deprecated public void requestActivityInfo(ResultReceiver result) { throw new UnsupportedOperationException(); } diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index de4514997b1c..f92d38c982b8 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -161,7 +161,7 @@ public class WifiManagerTest { mRunnable.run(); } }; - mWifiActivityEnergyInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0, 0); + mWifiActivityEnergyInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0); } /** @@ -1708,18 +1708,6 @@ public class WifiManagerTest { } /** - * Test behavior of {@link WifiManager#getControllerActivityEnergyInfo()} - */ - @Test - public void testGetControllerActivityEnergyInfo() throws Exception { - WifiActivityEnergyInfo activityEnergyInfo = - new WifiActivityEnergyInfo(5, 3, 3, 5, 5, 5, 5); - when(mWifiService.reportActivityInfo()).thenReturn(activityEnergyInfo); - - assertEquals(activityEnergyInfo, mWifiManager.getControllerActivityEnergyInfo()); - } - - /** * Tests that passing a null Executor to {@link WifiManager#getWifiActivityEnergyInfoAsync} * throws an exception. */ diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java index 8a5a0fd6805b..04aaa0bbcad0 100644 --- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java +++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java @@ -22,7 +22,6 @@ import android.net.MacAddress; import android.net.wifi.hotspot2.PasspointConfiguration; import android.net.wifi.hotspot2.PasspointTestUtils; import android.os.Parcel; -import android.os.Process; import androidx.test.filters.SmallTest; @@ -35,8 +34,6 @@ import org.junit.Test; public class WifiNetworkSuggestionTest { private static final int TEST_UID = 45677; private static final int TEST_UID_OTHER = 45673; - private static final String TEST_PACKAGE_NAME = "com.test.packagename"; - private static final String TEST_PACKAGE_NAME_OTHER = "com.test.packagenameother"; private static final String TEST_SSID = "\"Test123\""; private static final String TEST_BSSID = "12:12:12:12:12:12"; private static final String TEST_SSID_1 = "\"Test1234\""; @@ -55,7 +52,6 @@ public class WifiNetworkSuggestionTest { .setIsAppInteractionRequired(true) .build(); - assertEquals(Process.myUid(), suggestion.suggestorUid); assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID); assertTrue(suggestion.wifiConfiguration.allowedKeyManagement .get(WifiConfiguration.KeyMgmt.NONE)); @@ -448,7 +444,7 @@ public class WifiNetworkSuggestionTest { configuration.BSSID = TEST_BSSID; configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion( - configuration, null, false, true, true, TEST_UID, TEST_PACKAGE_NAME); + configuration, null, false, true, true); Parcel parcelW = Parcel.obtain(); suggestion.writeToParcel(parcelW, 0); @@ -515,16 +511,14 @@ public class WifiNetworkSuggestionTest { configuration.BSSID = TEST_BSSID; configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); WifiNetworkSuggestion suggestion = - new WifiNetworkSuggestion(configuration, null, true, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration, null, true, false, true); WifiConfiguration configuration1 = new WifiConfiguration(); configuration1.SSID = TEST_SSID; configuration1.BSSID = TEST_BSSID; configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); WifiNetworkSuggestion suggestion1 = - new WifiNetworkSuggestion(configuration1, null, false, true, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration1, null, false, true, true); assertEquals(suggestion, suggestion1); assertEquals(suggestion.hashCode(), suggestion1.hashCode()); @@ -540,15 +534,13 @@ public class WifiNetworkSuggestionTest { configuration.SSID = TEST_SSID; configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); WifiNetworkSuggestion suggestion = - new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration, null, false, false, true); WifiConfiguration configuration1 = new WifiConfiguration(); configuration1.SSID = TEST_SSID_1; configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); WifiNetworkSuggestion suggestion1 = - new WifiNetworkSuggestion(configuration1, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration1, null, false, false, true); assertNotEquals(suggestion, suggestion1); } @@ -564,15 +556,13 @@ public class WifiNetworkSuggestionTest { configuration.BSSID = TEST_BSSID; configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); WifiNetworkSuggestion suggestion = - new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration, null, false, false, true); WifiConfiguration configuration1 = new WifiConfiguration(); configuration1.SSID = TEST_SSID; configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); WifiNetworkSuggestion suggestion1 = - new WifiNetworkSuggestion(configuration1, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration1, null, false, false, true); assertNotEquals(suggestion, suggestion1); } @@ -587,57 +577,18 @@ public class WifiNetworkSuggestionTest { configuration.SSID = TEST_SSID; configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); WifiNetworkSuggestion suggestion = - new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration, null, false, false, true); WifiConfiguration configuration1 = new WifiConfiguration(); configuration1.SSID = TEST_SSID; configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); WifiNetworkSuggestion suggestion1 = - new WifiNetworkSuggestion(configuration1, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); + new WifiNetworkSuggestion(configuration1, null, false, false, true); assertNotEquals(suggestion, suggestion1); } /** - * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same - * SSID, BSSID and key mgmt, but different UID. - */ - @Test - public void testWifiNetworkSuggestionEqualsFailsWhenUidIsDifferent() { - WifiConfiguration configuration = new WifiConfiguration(); - configuration.SSID = TEST_SSID; - configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); - WifiNetworkSuggestion suggestion = - new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID, - TEST_PACKAGE_NAME); - - WifiNetworkSuggestion suggestion1 = - new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID_OTHER, - TEST_PACKAGE_NAME); - - assertNotEquals(suggestion, suggestion1); - } - - /** - * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same - * SSID, BSSID and key mgmt, but different package name. - */ - @Test - public void testWifiNetworkSuggestionEqualsFailsWhenPackageNameIsDifferent() { - WifiConfiguration configuration = new WifiConfiguration(); - configuration.SSID = TEST_SSID; - configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); - WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion( - configuration, null, false, false, true, TEST_UID, TEST_PACKAGE_NAME); - - WifiNetworkSuggestion suggestion1 = new WifiNetworkSuggestion( - configuration, null, false, false, true, TEST_UID, TEST_PACKAGE_NAME_OTHER); - - assertNotEquals(suggestion, suggestion1); - } - /** * Check NetworkSuggestion equals returns {@code true} for 2 Passpoint network suggestions with * same FQDN. */ |