Merge "Disable falsing when resting on a Dock."
diff --git a/Android.bp b/Android.bp
index 4b82e1d..e1f5abd9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -284,6 +284,7 @@
name: "framework-aidl-export-defaults",
aidl: {
export_include_dirs: [
+ "apex/media/java",
"core/java",
"drm/java",
"graphics/java",
@@ -291,7 +292,6 @@
"location/java",
"lowpan/java",
"media/java",
- "media/apex/java",
"media/mca/effect/java",
"media/mca/filterfw/java",
"media/mca/filterpacks/java",
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 78e72bf..4d1ac0e 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -6,6 +6,7 @@
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
cmds/hid/
cmds/input/
+ core/jni/
libs/input/
[Hook Scripts]
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 1ec96ec..9310762 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -81,7 +81,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Preconditions;
import com.android.server.AppStateTracker;
import com.android.server.DeviceIdleInternal;
import com.android.server.FgThread;
@@ -117,6 +116,7 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -1283,7 +1283,7 @@
super(context);
mLocalPM = LocalServices.getService(PackageManagerInternal.class);
- mActivityManagerInternal = Preconditions.checkNotNull(
+ mActivityManagerInternal = Objects.requireNonNull(
LocalServices.getService(ActivityManagerInternal.class));
mHandler = new JobHandler(context.getMainLooper());
@@ -1389,7 +1389,7 @@
controller.onSystemServicesReady();
}
- mAppStateTracker = Preconditions.checkNotNull(
+ mAppStateTracker = Objects.requireNonNull(
LocalServices.getService(AppStateTracker.class));
// Register br for package removals and user removals.
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index 8b61006..aa3d74a 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -23,7 +23,6 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Preconditions;
import com.android.server.AppStateTracker;
import com.android.server.AppStateTracker.Listener;
import com.android.server.LocalServices;
@@ -32,6 +31,7 @@
import com.android.server.job.StateControllerProto;
import com.android.server.job.StateControllerProto.BackgroundJobsController.TrackedJob;
+import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -59,7 +59,7 @@
public BackgroundJobsController(JobSchedulerService service) {
super(service);
- mAppStateTracker = Preconditions.checkNotNull(
+ mAppStateTracker = Objects.requireNonNull(
LocalServices.getService(AppStateTracker.class));
mAppStateTracker.addListener(mForceAppStandbyListener);
}
diff --git a/apex/media/Android.bp b/apex/media/Android.bp
new file mode 100644
index 0000000..6bd0086
--- /dev/null
+++ b/apex/media/Android.bp
@@ -0,0 +1,120 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_library {
+ name: "updatable-media",
+
+ srcs: [
+ ":updatable-media-srcs",
+ ],
+
+ aidl: {
+ export_include_dirs: [
+ "java",
+ ],
+
+ // It would be great if we don't need to add include_dirs for public
+ // parcelable classes. Find a better way.
+ include_dirs: [
+ // To refer:
+ // android.os.Bundle
+ // android.os.ResultReceiver
+ "frameworks/base/core/java",
+ ],
+ },
+
+ permitted_packages: [
+ "android.media",
+ ],
+
+ installable: true,
+
+ // TODO: build against stable API surface. Use core_platform for now to avoid
+ // link-check failure with exoplayer building against "current".
+ sdk_version: "core_platform",
+ libs: [
+ // The order matters. android_system_* library should come later.
+ "framework_media_annotation",
+ "android_system_stubs_current",
+ ],
+
+ static_libs: [
+ "exoplayer2-core"
+ ],
+ jarjar_rules: "jarjar_rules.txt",
+
+ plugins: ["java_api_finder"],
+}
+
+filegroup {
+ name: "updatable-media-srcs",
+ srcs: [
+ ":mediaparser-srcs",
+ ":mediasession2-srcs",
+ ],
+}
+
+filegroup {
+ name: "mediasession2-srcs",
+ srcs: [
+ "java/android/media/Controller2Link.java",
+ "java/android/media/IMediaController2.aidl",
+ "java/android/media/IMediaSession2.aidl",
+ "java/android/media/IMediaSession2Service.aidl",
+ "java/android/media/MediaConstants.java",
+ "java/android/media/MediaController2.java",
+ "java/android/media/MediaSession2.java",
+ "java/android/media/MediaSession2Service.java",
+ "java/android/media/Session2Command.java",
+ "java/android/media/Session2CommandGroup.java",
+ "java/android/media/Session2Link.java",
+ "java/android/media/Session2Token.java",
+ ],
+ path: "java",
+}
+
+filegroup {
+ name: "mediaparser-srcs",
+ srcs: [
+ "java/android/media/MediaParser.java"
+ ],
+ path: "java"
+}
+
+droidstubs {
+ name: "updatable-media-stubs",
+ srcs: [
+ ":updatable-media-srcs",
+ ":framework-media-annotation-srcs",
+ ],
+ defaults: [ "framework-module-stubs-defaults-systemapi" ],
+ aidl: {
+ // TODO(b/135922046) remove this
+ include_dirs: ["frameworks/base/core/java"],
+ },
+ sdk_version: "system_current",
+}
+
+java_library {
+ name: "updatable_media_stubs",
+ srcs: [":updatable-media-stubs"],
+ sdk_version: "system_current",
+}
+
+java_library {
+ name: "framework_media_annotation",
+ srcs: [":framework-media-annotation-srcs"],
+ installable: false,
+ sdk_version: "core_current",
+}
diff --git a/apex/media/OWNERS b/apex/media/OWNERS
new file mode 100644
index 0000000..0ac750c
--- /dev/null
+++ b/apex/media/OWNERS
@@ -0,0 +1,4 @@
+andrewlewis@google.com
+dwkang@google.com
+marcone@google.com
+sungsoo@google.com
diff --git a/media/jarjar_rules.txt b/apex/media/jarjar_rules.txt
similarity index 100%
rename from media/jarjar_rules.txt
rename to apex/media/jarjar_rules.txt
diff --git a/media/apex/java/android/media/BufferingParams.java b/apex/media/java/android/media/BufferingParams.java
similarity index 97%
rename from media/apex/java/android/media/BufferingParams.java
rename to apex/media/java/android/media/BufferingParams.java
index 943f142..04af028 100644
--- a/media/apex/java/android/media/BufferingParams.java
+++ b/apex/media/java/android/media/BufferingParams.java
@@ -16,13 +16,9 @@
package android.media;
-import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
/**
* Structure for source buffering management params.
*
diff --git a/media/apex/java/android/media/Controller2Link.aidl b/apex/media/java/android/media/Controller2Link.aidl
similarity index 100%
rename from media/apex/java/android/media/Controller2Link.aidl
rename to apex/media/java/android/media/Controller2Link.aidl
diff --git a/media/apex/java/android/media/Controller2Link.java b/apex/media/java/android/media/Controller2Link.java
similarity index 100%
rename from media/apex/java/android/media/Controller2Link.java
rename to apex/media/java/android/media/Controller2Link.java
diff --git a/media/apex/java/android/media/DataSourceCallback.java b/apex/media/java/android/media/DataSourceCallback.java
similarity index 100%
rename from media/apex/java/android/media/DataSourceCallback.java
rename to apex/media/java/android/media/DataSourceCallback.java
diff --git a/media/apex/java/android/media/IMediaController2.aidl b/apex/media/java/android/media/IMediaController2.aidl
similarity index 100%
rename from media/apex/java/android/media/IMediaController2.aidl
rename to apex/media/java/android/media/IMediaController2.aidl
diff --git a/media/apex/java/android/media/IMediaSession2.aidl b/apex/media/java/android/media/IMediaSession2.aidl
similarity index 100%
rename from media/apex/java/android/media/IMediaSession2.aidl
rename to apex/media/java/android/media/IMediaSession2.aidl
diff --git a/media/apex/java/android/media/IMediaSession2Service.aidl b/apex/media/java/android/media/IMediaSession2Service.aidl
similarity index 100%
rename from media/apex/java/android/media/IMediaSession2Service.aidl
rename to apex/media/java/android/media/IMediaSession2Service.aidl
diff --git a/media/apex/java/android/media/MediaConstants.java b/apex/media/java/android/media/MediaConstants.java
similarity index 100%
rename from media/apex/java/android/media/MediaConstants.java
rename to apex/media/java/android/media/MediaConstants.java
diff --git a/media/apex/java/android/media/MediaController2.java b/apex/media/java/android/media/MediaController2.java
similarity index 100%
rename from media/apex/java/android/media/MediaController2.java
rename to apex/media/java/android/media/MediaController2.java
diff --git a/media/apex/java/android/media/MediaParser.java b/apex/media/java/android/media/MediaParser.java
similarity index 100%
rename from media/apex/java/android/media/MediaParser.java
rename to apex/media/java/android/media/MediaParser.java
diff --git a/media/apex/java/android/media/MediaSession2.java b/apex/media/java/android/media/MediaSession2.java
similarity index 100%
rename from media/apex/java/android/media/MediaSession2.java
rename to apex/media/java/android/media/MediaSession2.java
diff --git a/media/apex/java/android/media/MediaSession2Service.java b/apex/media/java/android/media/MediaSession2Service.java
similarity index 100%
rename from media/apex/java/android/media/MediaSession2Service.java
rename to apex/media/java/android/media/MediaSession2Service.java
diff --git a/media/apex/java/android/media/ProxyDataSourceCallback.java b/apex/media/java/android/media/ProxyDataSourceCallback.java
similarity index 100%
rename from media/apex/java/android/media/ProxyDataSourceCallback.java
rename to apex/media/java/android/media/ProxyDataSourceCallback.java
diff --git a/media/apex/java/android/media/RoutingDelegate.java b/apex/media/java/android/media/RoutingDelegate.java
similarity index 100%
rename from media/apex/java/android/media/RoutingDelegate.java
rename to apex/media/java/android/media/RoutingDelegate.java
diff --git a/media/apex/java/android/media/Session2Command.aidl b/apex/media/java/android/media/Session2Command.aidl
similarity index 100%
rename from media/apex/java/android/media/Session2Command.aidl
rename to apex/media/java/android/media/Session2Command.aidl
diff --git a/media/apex/java/android/media/Session2Command.java b/apex/media/java/android/media/Session2Command.java
similarity index 100%
rename from media/apex/java/android/media/Session2Command.java
rename to apex/media/java/android/media/Session2Command.java
diff --git a/media/apex/java/android/media/Session2CommandGroup.java b/apex/media/java/android/media/Session2CommandGroup.java
similarity index 98%
rename from media/apex/java/android/media/Session2CommandGroup.java
rename to apex/media/java/android/media/Session2CommandGroup.java
index 0ee5f62..13aabfc 100644
--- a/media/apex/java/android/media/Session2CommandGroup.java
+++ b/apex/media/java/android/media/Session2CommandGroup.java
@@ -38,8 +38,8 @@
public final class Session2CommandGroup implements Parcelable {
private static final String TAG = "Session2CommandGroup";
- public static final @android.annotation.NonNull Parcelable.Creator<Session2CommandGroup> CREATOR =
- new Parcelable.Creator<Session2CommandGroup>() {
+ public static final @android.annotation.NonNull Parcelable.Creator<Session2CommandGroup>
+ CREATOR = new Parcelable.Creator<Session2CommandGroup>() {
@Override
public Session2CommandGroup createFromParcel(Parcel in) {
return new Session2CommandGroup(in);
diff --git a/media/apex/java/android/media/Session2Link.java b/apex/media/java/android/media/Session2Link.java
similarity index 100%
rename from media/apex/java/android/media/Session2Link.java
rename to apex/media/java/android/media/Session2Link.java
diff --git a/media/apex/java/android/media/Session2Token.aidl b/apex/media/java/android/media/Session2Token.aidl
similarity index 100%
rename from media/apex/java/android/media/Session2Token.aidl
rename to apex/media/java/android/media/Session2Token.aidl
diff --git a/media/apex/java/android/media/Session2Token.java b/apex/media/java/android/media/Session2Token.java
similarity index 95%
rename from media/apex/java/android/media/Session2Token.java
rename to apex/media/java/android/media/Session2Token.java
index 6eb76b1..aae2e1b 100644
--- a/media/apex/java/android/media/Session2Token.java
+++ b/apex/media/java/android/media/Session2Token.java
@@ -52,17 +52,18 @@
public final class Session2Token implements Parcelable {
private static final String TAG = "Session2Token";
- public static final @android.annotation.NonNull Creator<Session2Token> CREATOR = new Creator<Session2Token>() {
- @Override
- public Session2Token createFromParcel(Parcel p) {
- return new Session2Token(p);
- }
+ public static final @android.annotation.NonNull Creator<Session2Token> CREATOR =
+ new Creator<Session2Token>() {
+ @Override
+ public Session2Token createFromParcel(Parcel p) {
+ return new Session2Token(p);
+ }
- @Override
- public Session2Token[] newArray(int size) {
- return new Session2Token[size];
- }
- };
+ @Override
+ public Session2Token[] newArray(int size) {
+ return new Session2Token[size];
+ }
+ };
/**
* @hide
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 7ed51ca..e4f7300 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -23,7 +23,6 @@
import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
-import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
@@ -1848,7 +1847,7 @@
int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
PowerProfile powerProfile = new PowerProfile(mContext);
- checkNotNull(powerProfile);
+ Objects.requireNonNull(powerProfile);
StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
wallClockNanos);
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
index f3bf909..24b7978 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
@@ -95,6 +95,12 @@
return;
}
sStatsd = IStatsd.Stub.asInterface(ServiceManager.getService("stats"));
+ if (sStatsd == null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to get stats service.");
+ }
+ return;
+ }
// Assume statsd is ready since this is called form statscompanion, link to statsd.
try {
sStatsd.asBinder().linkToDeath((IBinder.DeathRecipient) () -> {
diff --git a/api/current.txt b/api/current.txt
index c734db5..fca72b1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -610,6 +610,7 @@
field public static final int fastScrollTextColor = 16843609; // 0x1010359
field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
+ field public static final int featureId = 16844301; // 0x101060d
field public static final int fillAfter = 16843197; // 0x10101bd
field public static final int fillAlpha = 16843980; // 0x10104cc
field public static final int fillBefore = 16843196; // 0x10101bc
@@ -1331,6 +1332,7 @@
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsAssist = 16844016; // 0x10104f0
+ field public static final int supportsInlineSuggestions = 16844302; // 0x101060e
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
field public static final int supportsLocalInteraction = 16844047; // 0x101050f
field public static final int supportsMultipleDisplays = 16844182; // 0x1010596
@@ -4498,7 +4500,6 @@
method public int describeContents();
method @Nullable public String getFeatureId();
method @NonNull public String getMessage();
- method @Nullable public String getNotingPackageName();
method @IntRange(from=0) public int getNotingUid();
method @NonNull public String getOp();
method @IntRange(from=0) public long getTime();
diff --git a/api/system-current.txt b/api/system-current.txt
index 405aab3..2edef24 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -111,6 +111,7 @@
field public static final String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
field public static final String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
+ field public static final String MANAGE_ONE_TIME_PERMISSION_SESSIONS = "android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS";
field public static final String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
@@ -4099,6 +4100,10 @@
method public android.media.AudioRecord.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
}
+ public final class AudioRecordingConfiguration implements android.os.Parcelable {
+ method public int getClientUid();
+ }
+
public class HwAudioSource {
method public boolean isPlaying();
method public void start();
@@ -5693,6 +5698,7 @@
@Deprecated public class WifiConfiguration implements android.os.Parcelable {
method @Deprecated public int getAuthType();
method @Deprecated @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
+ method @Deprecated @NonNull public android.net.IpConfiguration getIpConfiguration();
method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus getNetworkSelectionStatus();
method @Deprecated @NonNull public String getPrintableSsid();
method @Deprecated @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
@@ -7242,8 +7248,8 @@
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToLuiApp(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromLuiApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
- method @RequiresPermission(allOf={android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void startOneTimePermissionSession(@NonNull String, long, int, int);
- method @RequiresPermission(allOf={android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void stopOneTimePermissionSession(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void stopOneTimePermissionSession(@NonNull String);
}
public static final class PermissionManager.SplitPermissionInfo {
@@ -9763,6 +9769,8 @@
}
public class ServiceState implements android.os.Parcelable {
+ method @NonNull public android.telephony.ServiceState createLocationInfoSanitizedCopy(boolean);
+ method public void fillInNotifierBundle(@NonNull android.os.Bundle);
method public int getDataRegistrationState();
method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int);
method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList();
@@ -9771,6 +9779,7 @@
method public int getNrFrequencyRange();
method @Nullable public String getOperatorAlphaLongRaw();
method @Nullable public String getOperatorAlphaShortRaw();
+ method @NonNull public static android.telephony.ServiceState newFromBundle(@NonNull android.os.Bundle);
field public static final int ROAMING_TYPE_DOMESTIC = 2; // 0x2
field public static final int ROAMING_TYPE_INTERNATIONAL = 3; // 0x3
field public static final int ROAMING_TYPE_NOT_ROAMING = 0; // 0x0
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 887d17c..7b96ce9 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -196,18 +196,6 @@
"libcutils",
"libstatslog",
],
- target: {
- android: {
- shared_libs: [
- "libutils",
- ],
- },
- host: {
- static_libs: [
- "libutils",
- ],
- },
- },
}
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index f9f11b2..109785f 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -152,6 +152,10 @@
return false;
}
+bool HashableDimensionKey::operator!=(const HashableDimensionKey& that) const {
+ return !((*this) == that);
+}
+
bool HashableDimensionKey::operator==(const HashableDimensionKey& that) const {
if (mValues.size() != that.getValues().size()) {
return false;
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index b9b86ce..654e135 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -71,6 +71,8 @@
std::string toString() const;
+ bool operator!=(const HashableDimensionKey& that) const;
+
bool operator==(const HashableDimensionKey& that) const;
bool operator<(const HashableDimensionKey& that) const;
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 68a51ef..c569bc1 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -284,6 +284,10 @@
FRIEND_TEST(DurationMetricE2eTest, TestWithCondition);
FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedCondition);
FRIEND_TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition);
+
+ FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState);
+ FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions);
+ FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions);
};
} // namespace statsd
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index 16c936c..6d2bd04 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -85,5 +85,5 @@
optional bool allow_from_any_uid = 50003 [default = false];
- optional string log_from_module = 50004;
-}
\ No newline at end of file
+ optional string module = 50004;
+}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 2270974..19b9709 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -112,9 +112,9 @@
TouchEventReported touch_event_reported = 34;
WakeupAlarmOccurred wakeup_alarm_occurred = 35;
KernelWakeupReported kernel_wakeup_reported = 36;
- WifiLockStateChanged wifi_lock_state_changed = 37 [(log_from_module) = "wifi"];
- WifiSignalStrengthChanged wifi_signal_strength_changed = 38 [(log_from_module) = "wifi"];
- WifiScanStateChanged wifi_scan_state_changed = 39 [(log_from_module) = "wifi"];
+ WifiLockStateChanged wifi_lock_state_changed = 37 [(module) = "wifi"];
+ WifiSignalStrengthChanged wifi_signal_strength_changed = 38 [(module) = "wifi"];
+ WifiScanStateChanged wifi_scan_state_changed = 39 [(module) = "wifi"];
PhoneSignalStrengthChanged phone_signal_strength_changed = 40;
SettingChanged setting_changed = 41;
ActivityForegroundStateChanged activity_foreground_state_changed = 42;
@@ -128,7 +128,7 @@
AppStartFullyDrawn app_start_fully_drawn = 50;
LmkKillOccurred lmk_kill_occurred = 51;
PictureInPictureStateChanged picture_in_picture_state_changed = 52;
- WifiMulticastLockStateChanged wifi_multicast_lock_state_changed = 53 [(log_from_module) = "wifi"];
+ WifiMulticastLockStateChanged wifi_multicast_lock_state_changed = 53 [(module) = "wifi"];
LmkStateChanged lmk_state_changed = 54;
AppStartMemoryStateCaptured app_start_memory_state_captured = 55;
ShutdownSequenceReported shutdown_sequence_reported = 56;
@@ -182,39 +182,27 @@
FlagFlipUpdateOccurred flag_flip_update_occurred = 101;
BinaryPushStateChanged binary_push_state_changed = 102;
DevicePolicyEvent device_policy_event = 103;
- DocsUIFileOperationCanceledReported docs_ui_file_op_canceled =
- 104 [(log_from_module) = "docsui"];
- DocsUIFileOperationCopyMoveModeReported
- docs_ui_file_op_copy_move_mode_reported =
- 105 [(log_from_module) = "docsui"];
- DocsUIFileOperationFailureReported docs_ui_file_op_failure =
- 106 [(log_from_module) = "docsui"];
- DocsUIFileOperationReported docs_ui_provider_file_op =
- 107 [(log_from_module) = "docsui"];
- DocsUIInvalidScopedAccessRequestReported
- docs_ui_invalid_scoped_access_request =
- 108 [(log_from_module) = "docsui"];
- DocsUILaunchReported docs_ui_launch_reported =
- 109 [(log_from_module) = "docsui"];
- DocsUIRootVisitedReported docs_ui_root_visited =
- 110 [(log_from_module) = "docsui"];
- DocsUIStartupMsReported docs_ui_startup_ms =
- 111 [(log_from_module) = "docsui"];
- DocsUIUserActionReported docs_ui_user_action_reported =
- 112 [(log_from_module) = "docsui"];
+ DocsUIFileOperationCanceledReported docs_ui_file_op_canceled = 104 [(module) = "docsui"];
+ DocsUIFileOperationCopyMoveModeReported docs_ui_file_op_copy_move_mode_reported =
+ 105 [(module) = "docsui"];
+ DocsUIFileOperationFailureReported docs_ui_file_op_failure = 106 [(module) = "docsui"];
+ DocsUIFileOperationReported docs_ui_provider_file_op = 107 [(module) = "docsui"];
+ DocsUIInvalidScopedAccessRequestReported docs_ui_invalid_scoped_access_request =
+ 108 [(module) = "docsui"];
+ DocsUILaunchReported docs_ui_launch_reported = 109 [(module) = "docsui"];
+ DocsUIRootVisitedReported docs_ui_root_visited = 110 [(module) = "docsui"];
+ DocsUIStartupMsReported docs_ui_startup_ms = 111 [(module) = "docsui"];
+ DocsUIUserActionReported docs_ui_user_action_reported = 112 [(module) = "docsui"];
WifiEnabledStateChanged wifi_enabled_state_changed = 113;
WifiRunningStateChanged wifi_running_state_changed = 114;
AppCompacted app_compacted = 115;
- NetworkDnsEventReported network_dns_event_reported = 116 [(log_from_module) = "resolv"];
+ NetworkDnsEventReported network_dns_event_reported = 116 [(module) = "resolv"];
DocsUIPickerLaunchedFromReported docs_ui_picker_launched_from_reported =
- 117 [(log_from_module) = "docsui"];
- DocsUIPickResultReported docs_ui_pick_result_reported =
- 118 [(log_from_module) = "docsui"];
- DocsUISearchModeReported docs_ui_search_mode_reported =
- 119 [(log_from_module) = "docsui"];
- DocsUISearchTypeReported docs_ui_search_type_reported =
- 120 [(log_from_module) = "docsui"];
- DataStallEvent data_stall_event = 121 [(log_from_module) = "network_stack"];
+ 117 [(module) = "docsui"];
+ DocsUIPickResultReported docs_ui_pick_result_reported = 118 [(module) = "docsui"];
+ DocsUISearchModeReported docs_ui_search_mode_reported = 119 [(module) = "docsui"];
+ DocsUISearchTypeReported docs_ui_search_type_reported = 120 [(module) = "docsui"];
+ DataStallEvent data_stall_event = 121 [(module) = "network_stack"];
RescuePartyResetReported rescue_party_reset_reported = 122;
SignedConfigReported signed_config_reported = 123;
GnssNiEventReported gnss_ni_event_reported = 124;
@@ -264,7 +252,7 @@
ScreenTimeoutExtensionReported screen_timeout_extension_reported = 168;
ProcessStartTime process_start_time = 169;
PermissionGrantRequestResultReported permission_grant_request_result_reported =
- 170 [(log_from_module) = "permissioncontroller"];
+ 170 [(module) = "permissioncontroller"];
BluetoothSocketConnectionStateChanged bluetooth_socket_connection_state_changed = 171;
DeviceIdentifierAccessDenied device_identifier_access_denied = 172;
BubbleDeveloperErrorReported bubble_developer_error_reported = 173;
@@ -273,21 +261,21 @@
AssistGestureProgressReported assist_gesture_progress_reported = 176;
TouchGestureClassified touch_gesture_classified = 177;
HiddenApiUsed hidden_api_used = 178 [(allow_from_any_uid) = true];
- StyleUIChanged style_ui_changed = 179 [(log_from_module) = "style"];
+ StyleUIChanged style_ui_changed = 179 [(module) = "style"];
PrivacyIndicatorsInteracted privacy_indicators_interacted =
- 180 [(log_from_module) = "permissioncontroller"];
+ 180 [(module) = "permissioncontroller"];
AppInstallOnExternalStorageReported app_install_on_external_storage_reported = 181;
- NetworkStackReported network_stack_reported = 182 [(log_from_module) = "network_stack"];
+ NetworkStackReported network_stack_reported = 182 [(module) = "network_stack"];
AppMovedStorageReported app_moved_storage_reported = 183;
BiometricEnrolled biometric_enrolled = 184;
SystemServerWatchdogOccurred system_server_watchdog_occurred = 185;
TombStoneOccurred tomb_stone_occurred = 186;
BluetoothClassOfDeviceReported bluetooth_class_of_device_reported = 187;
IntelligenceEventReported intelligence_event_reported =
- 188 [(log_from_module) = "intelligence"];
+ 188 [(module) = "intelligence"];
ThermalThrottlingSeverityStateChanged thermal_throttling_severity_state_changed = 189;
RoleRequestResultReported role_request_result_reported =
- 190 [(log_from_module) = "permissioncontroller"];
+ 190 [(module) = "permissioncontroller"];
MediametricsAudiopolicyReported mediametrics_audiopolicy_reported = 191;
MediametricsAudiorecordReported mediametrics_audiorecord_reported = 192;
MediametricsAudiothreadReported mediametrics_audiothread_reported = 193;
@@ -301,36 +289,32 @@
MediametricsDrmManagerReported mediametrics_drmmanager_reported = 201;
CarPowerStateChanged car_power_state_changed = 203;
GarageModeInfo garage_mode_info = 204;
- TestAtomReported test_atom_reported = 205 [(log_from_module) = "cts"];
+ TestAtomReported test_atom_reported = 205 [(module) = "cts"];
ContentCaptureCallerMismatchReported content_capture_caller_mismatch_reported = 206;
ContentCaptureServiceEvents content_capture_service_events = 207;
ContentCaptureSessionEvents content_capture_session_events = 208;
ContentCaptureFlushed content_capture_flushed = 209;
LocationManagerApiUsageReported location_manager_api_usage_reported = 210;
ReviewPermissionsFragmentResultReported review_permissions_fragment_result_reported =
- 211 [(log_from_module) = "permissioncontroller"];
+ 211 [(module) = "permissioncontroller"];
RuntimePermissionsUpgradeResult runtime_permissions_upgrade_result =
- 212 [(log_from_module) = "permissioncontroller"];
+ 212 [(module) = "permissioncontroller"];
GrantPermissionsActivityButtonActions grant_permissions_activity_button_actions =
- 213 [(log_from_module) = "permissioncontroller"];
+ 213 [(module) = "permissioncontroller"];
LocationAccessCheckNotificationAction location_access_check_notification_action =
- 214 [(log_from_module) = "permissioncontroller"];
+ 214 [(module) = "permissioncontroller"];
AppPermissionFragmentActionReported app_permission_fragment_action_reported =
- 215 [(log_from_module) = "permissioncontroller"];
+ 215 [(module) = "permissioncontroller"];
AppPermissionFragmentViewed app_permission_fragment_viewed =
- 216 [(log_from_module) = "permissioncontroller"];
+ 216 [(module) = "permissioncontroller"];
AppPermissionsFragmentViewed app_permissions_fragment_viewed =
- 217 [(log_from_module) = "permissioncontroller"];
+ 217 [(module) = "permissioncontroller"];
PermissionAppsFragmentViewed permission_apps_fragment_viewed =
- 218 [(log_from_module) = "permissioncontroller"];
- TextSelectionEvent text_selection_event =
- 219 [(log_from_module) = "textclassifier"];
- TextLinkifyEvent text_linkify_event =
- 220 [(log_from_module) = "textclassifier"];
- ConversationActionsEvent conversation_actions_event =
- 221 [(log_from_module) = "textclassifier"];
- LanguageDetectionEvent language_detection_event =
- 222 [(log_from_module) = "textclassifier"];
+ 218 [(module) = "permissioncontroller"];
+ TextSelectionEvent text_selection_event = 219 [(module) = "textclassifier"];
+ TextLinkifyEvent text_linkify_event = 220 [(module) = "textclassifier"];
+ ConversationActionsEvent conversation_actions_event = 221 [(module) = "textclassifier"];
+ LanguageDetectionEvent language_detection_event = 222 [(module) = "textclassifier"];
ExclusionRectStateChanged exclusion_rect_state_changed = 223;
BackGesture back_gesture_reported_reported = 224;
UpdateEngineUpdateAttemptReported update_engine_update_attempt_reported = 225;
@@ -338,21 +322,17 @@
CameraActionEvent camera_action_event = 227;
AppCompatibilityChangeReported app_compatibility_change_reported =
228 [(allow_from_any_uid) = true];
- PerfettoUploaded perfetto_uploaded =
- 229 [(log_from_module) = "perfetto"];
+ PerfettoUploaded perfetto_uploaded = 229 [(module) = "perfetto"];
VmsClientConnectionStateChanged vms_client_connection_state_changed = 230;
GpsLocationStatusReported gps_location_status_reported = 231;
GpsTimeToFirstFixReported gps_time_to_first_fix_reported = 232;
- MediaProviderScanEvent media_provider_scan_event =
- 233 [(log_from_module) = "mediaprovider"];
- MediaProviderDeletionEvent media_provider_deletion_event =
- 234 [(log_from_module) = "mediaprovider"];
+ MediaProviderScanEvent media_provider_scan_event = 233 [(module) = "mediaprovider"];
+ MediaProviderDeletionEvent media_provider_deletion_event = 234 [(module) = "mediaprovider"];
MediaProviderPermissionEvent media_provider_permission_event =
- 235 [(log_from_module) = "mediaprovider"];
- MediaProviderSchemaChange media_provider_schema_change =
- 236 [(log_from_module) = "mediaprovider"];
+ 235 [(module) = "mediaprovider"];
+ MediaProviderSchemaChange media_provider_schema_change = 236 [(module) = "mediaprovider"];
MediaProviderIdleMaintenance media_provider_idle_maintenance =
- 237 [(log_from_module) = "mediaprovider"];
+ 237 [(module) = "mediaprovider"];
}
// Pulled events will start at field 10000.
@@ -6711,6 +6691,9 @@
// App is not doing pre-rotation correctly.
optional bool false_prerotation = 7;
+
+ // App creates GLESv1 context.
+ optional bool gles_1_in_use = 8;
}
/*
diff --git a/cmds/statsd/src/external/GpuStatsPuller.cpp b/cmds/statsd/src/external/GpuStatsPuller.cpp
index d38b87f..3229ba8 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.cpp
+++ b/cmds/statsd/src/external/GpuStatsPuller.cpp
@@ -103,6 +103,7 @@
}
if (!event->write(info.cpuVulkanInUse)) return false;
if (!event->write(info.falsePrerotation)) return false;
+ if (!event->write(info.gles1InUse)) return false;
event->init();
data->emplace_back(event);
}
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index c1f95ee..21ffff3 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -277,8 +277,8 @@
void CountMetricProducer::onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKey, bool condition,
- const LogEvent& event) {
+ const ConditionKey& conditionKey, bool condition, const LogEvent& event,
+ const map<int, HashableDimensionKey>& statePrimaryKeys) {
int64_t eventTimeNs = event.GetElapsedTimestampNs();
flushIfNeededLocked(eventTimeNs);
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 7b6c7e0..a4711e8 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -59,8 +59,8 @@
protected:
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKey, bool condition,
- const LogEvent& event) override;
+ const ConditionKey& conditionKey, bool condition, const LogEvent& event,
+ const std::map<int, HashableDimensionKey>& statePrimaryKeys) override;
private:
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index fee5e6e..35c6d37 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -541,8 +541,8 @@
void DurationMetricProducer::onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKeys, bool condition,
- const LogEvent& event) {
+ const ConditionKey& conditionKeys, bool condition, const LogEvent& event,
+ const map<int, HashableDimensionKey>& statePrimaryKeys) {
ALOGW("Not used in duration tracker.");
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 7457d7f..45908fb 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -59,8 +59,8 @@
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKeys, bool condition,
- const LogEvent& event) override;
+ const ConditionKey& conditionKeys, bool condition, const LogEvent& event,
+ const std::map<int, HashableDimensionKey>& statePrimaryKeys) override;
private:
void handleStartEvent(const MetricDimensionKey& eventKey, const ConditionKey& conditionKeys,
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 32eb077..6833f8d 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -143,8 +143,8 @@
void EventMetricProducer::onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKey, bool condition,
- const LogEvent& event) {
+ const ConditionKey& conditionKey, bool condition, const LogEvent& event,
+ const map<int, HashableDimensionKey>& statePrimaryKeys) {
if (!condition) {
return;
}
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index dca37e8..e8f2119 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -47,8 +47,8 @@
private:
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKey, bool condition,
- const LogEvent& event) override;
+ const ConditionKey& conditionKey, bool condition, const LogEvent& event,
+ const std::map<int, HashableDimensionKey>& statePrimaryKeys) override;
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 4ab6ec3..4ab6fd4 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -449,8 +449,8 @@
void GaugeMetricProducer::onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKey, bool condition,
- const LogEvent& event) {
+ const ConditionKey& conditionKey, bool condition, const LogEvent& event,
+ const map<int, HashableDimensionKey>& statePrimaryKeys) {
if (condition == false) {
return;
}
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 12dcaa4..284bcc5 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -95,8 +95,8 @@
protected:
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKey, bool condition,
- const LogEvent& event) override;
+ const ConditionKey& conditionKey, bool condition, const LogEvent& event,
+ const std::map<int, HashableDimensionKey>& statePrimaryKeys) override;
private:
void onDumpReportLocked(const int64_t dumpTimeNs,
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index cf1d2f3..5c29cb3 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -133,8 +133,8 @@
HashableDimensionKey dimensionInWhat;
filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
MetricDimensionKey metricKey(dimensionInWhat, stateValuesKey);
- onMatchedLogEventInternalLocked(
- matcherIndex, metricKey, conditionKey, condition, event);
+ onMatchedLogEventInternalLocked(matcherIndex, metricKey, conditionKey, condition, event,
+ statePrimaryKeys);
}
bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) {
@@ -269,6 +269,7 @@
FieldValue* value) {
if (!StateManager::getInstance().getStateValue(atomId, queryKey, value)) {
value->mValue = Value(StateTracker::kStateUnknown);
+ value->mField.setTag(atomId);
ALOGW("StateTracker not found for state atom %d", atomId);
return;
}
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 30675fc..99f0c64 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -330,8 +330,8 @@
*/
virtual void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKey, bool condition,
- const LogEvent& event) = 0;
+ const ConditionKey& conditionKey, bool condition, const LogEvent& event,
+ const map<int, HashableDimensionKey>& statePrimaryKeys) = 0;
// Consume the parsed stats log entry that already matched the "what" of the metric.
virtual void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event);
@@ -475,6 +475,10 @@
FRIEND_TEST(StatsLogProcessorTest,
TestActivationOnBootMultipleActivationsDifferentActivationTypes);
FRIEND_TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart);
+
+ FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState);
+ FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions);
+ FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 1fda696..6d20822 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -289,6 +289,10 @@
FRIEND_TEST(DurationMetricE2eTest, TestWithCondition);
FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedCondition);
FRIEND_TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition);
+
+ FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState);
+ FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions);
+ FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index d8f399f..d2db6e9 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -66,6 +66,7 @@
const int FIELD_ID_DIMENSION_IN_WHAT = 1;
const int FIELD_ID_BUCKET_INFO = 3;
const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
+const int FIELD_ID_SLICE_BY_STATE = 6;
// for ValueBucketInfo
const int FIELD_ID_VALUE_INDEX = 1;
const int FIELD_ID_VALUE_LONG = 2;
@@ -146,6 +147,14 @@
mConditionSliced = true;
}
+ for (const auto& stateLink : metric.state_link()) {
+ Metric2State ms;
+ ms.stateAtomId = stateLink.state_atom_id();
+ translateFieldMatcher(stateLink.fields_in_what(), &ms.metricFields);
+ translateFieldMatcher(stateLink.fields_in_state(), &ms.stateFields);
+ mMetric2StateLinks.push_back(ms);
+ }
+
int64_t numBucketsForward = calcBucketsForwardCount(startTimeNs);
mCurrentBucketNum += numBucketsForward;
@@ -181,6 +190,33 @@
}
}
+void ValueMetricProducer::onStateChanged(int64_t eventTimeNs, int32_t atomId,
+ const HashableDimensionKey& primaryKey, int oldState,
+ int newState) {
+ VLOG("ValueMetric %lld onStateChanged time %lld, State %d, key %s, %d -> %d",
+ (long long)mMetricId, (long long)eventTimeNs, atomId, primaryKey.toString().c_str(),
+ oldState, newState);
+ // If condition is not true, we do not need to pull for this state change.
+ if (mCondition != ConditionState::kTrue) {
+ return;
+ }
+ bool isEventLate = eventTimeNs < mCurrentBucketStartTimeNs;
+ if (isEventLate) {
+ VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
+ (long long)mCurrentBucketStartTimeNs);
+ invalidateCurrentBucket(eventTimeNs, BucketDropReason::EVENT_IN_WRONG_BUCKET);
+ return;
+ }
+ mStateChangePrimaryKey.first = atomId;
+ mStateChangePrimaryKey.second = primaryKey;
+ if (mIsPulled) {
+ pullAndMatchEventsLocked(eventTimeNs);
+ }
+ mStateChangePrimaryKey.first = 0;
+ mStateChangePrimaryKey.second = DEFAULT_DIMENSION_KEY;
+ flushIfNeededLocked(eventTimeNs);
+}
+
void ValueMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
const int64_t eventTime) {
VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
@@ -281,6 +317,14 @@
FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
}
+ // Then fill slice_by_state.
+ for (auto state : dimensionKey.getStateValuesKey().getValues()) {
+ uint64_t stateToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+ FIELD_ID_SLICE_BY_STATE);
+ writeStateToProto(state, protoOutput);
+ protoOutput->end(stateToken);
+ }
+
// Then fill bucket_info (ValueBucketInfo).
for (const auto& bucket : pair.second) {
uint64_t bucketInfoToken = protoOutput->start(
@@ -300,7 +344,7 @@
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_CONDITION_TRUE_NS,
(long long)bucket.mConditionTrueNs);
}
- for (int i = 0; i < (int)bucket.valueIndex.size(); i ++) {
+ for (int i = 0; i < (int)bucket.valueIndex.size(); i++) {
int index = bucket.valueIndex[i];
const Value& value = bucket.values[i];
uint64_t valueToken = protoOutput->start(
@@ -358,9 +402,10 @@
}
void ValueMetricProducer::resetBase() {
- for (auto& slice : mCurrentSlicedBucket) {
- for (auto& interval : slice.second) {
- interval.hasBase = false;
+ for (auto& slice : mCurrentBaseInfo) {
+ for (auto& baseInfo : slice.second) {
+ baseInfo.hasBase = false;
+ baseInfo.hasCurrentState = false;
}
}
mHasGlobalBase = false;
@@ -558,14 +603,20 @@
onMatchedLogEventLocked(mWhatMatcherIndex, localCopy);
}
}
- // If the new pulled data does not contains some keys we track in our intervals, we need to
- // reset the base.
+ // If a key that is:
+ // 1. Tracked in mCurrentSlicedBucket and
+ // 2. A superset of the current mStateChangePrimaryKey
+ // was not found in the new pulled data (i.e. not in mMatchedDimensionInWhatKeys)
+ // then we need to reset the base.
for (auto& slice : mCurrentSlicedBucket) {
- bool presentInPulledData = mMatchedMetricDimensionKeys.find(slice.first)
- != mMatchedMetricDimensionKeys.end();
- if (!presentInPulledData) {
- for (auto& interval : slice.second) {
- interval.hasBase = false;
+ const auto& whatKey = slice.first.getDimensionKeyInWhat();
+ bool presentInPulledData =
+ mMatchedMetricDimensionKeys.find(whatKey) != mMatchedMetricDimensionKeys.end();
+ if (!presentInPulledData && whatKey.contains(mStateChangePrimaryKey.second)) {
+ auto it = mCurrentBaseInfo.find(whatKey);
+ for (auto& baseInfo : it->second) {
+ baseInfo.hasBase = false;
+ baseInfo.hasCurrentState = false;
}
}
}
@@ -674,17 +725,30 @@
return false;
}
-void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIndex,
- const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKey,
- bool condition, const LogEvent& event) {
+void ValueMetricProducer::onMatchedLogEventInternalLocked(
+ const size_t matcherIndex, const MetricDimensionKey& eventKey,
+ const ConditionKey& conditionKey, bool condition, const LogEvent& event,
+ const map<int, HashableDimensionKey>& statePrimaryKeys) {
+ auto whatKey = eventKey.getDimensionKeyInWhat();
+ auto stateKey = eventKey.getStateValuesKey();
+
+ // Skip this event if a state changed occurred for a different primary key.
+ auto it = statePrimaryKeys.find(mStateChangePrimaryKey.first);
+ // Check that both the atom id and the primary key are equal.
+ if (it != statePrimaryKeys.end() && it->second != mStateChangePrimaryKey.second) {
+ VLOG("ValueMetric skip event with primary key %s because state change primary key "
+ "is %s",
+ it->second.toString().c_str(), mStateChangePrimaryKey.second.toString().c_str());
+ return;
+ }
+
int64_t eventTimeNs = event.GetElapsedTimestampNs();
if (eventTimeNs < mCurrentBucketStartTimeNs) {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
(long long)mCurrentBucketStartTimeNs);
return;
}
- mMatchedMetricDimensionKeys.insert(eventKey);
+ mMatchedMetricDimensionKeys.insert(whatKey);
if (!mIsPulled) {
// We cannot flush without doing a pull first.
@@ -709,10 +773,26 @@
if (hitGuardRailLocked(eventKey)) {
return;
}
- vector<Interval>& multiIntervals = mCurrentSlicedBucket[eventKey];
- if (multiIntervals.size() < mFieldMatchers.size()) {
+ vector<BaseInfo>& baseInfos = mCurrentBaseInfo[whatKey];
+ if (baseInfos.size() < mFieldMatchers.size()) {
VLOG("Resizing number of intervals to %d", (int)mFieldMatchers.size());
- multiIntervals.resize(mFieldMatchers.size());
+ baseInfos.resize(mFieldMatchers.size());
+ }
+
+ for (auto baseInfo : baseInfos) {
+ if (!baseInfo.hasCurrentState) {
+ baseInfo.currentState = DEFAULT_DIMENSION_KEY;
+ baseInfo.hasCurrentState = true;
+ }
+ }
+
+ // We need to get the intervals stored with the previous state key so we can
+ // close these value intervals.
+ const auto oldStateKey = baseInfos[0].currentState;
+ vector<Interval>& intervals = mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)];
+ if (intervals.size() < mFieldMatchers.size()) {
+ VLOG("Resizing number of intervals to %d", (int)mFieldMatchers.size());
+ intervals.resize(mFieldMatchers.size());
}
// We only use anomaly detection under certain cases.
@@ -725,7 +805,8 @@
for (int i = 0; i < (int)mFieldMatchers.size(); i++) {
const Matcher& matcher = mFieldMatchers[i];
- Interval& interval = multiIntervals[i];
+ BaseInfo& baseInfo = baseInfos[i];
+ Interval& interval = intervals[i];
interval.valueIndex = i;
Value value;
if (!getDoubleOrLong(event, matcher, value)) {
@@ -736,60 +817,61 @@
interval.seenNewData = true;
if (mUseDiff) {
- if (!interval.hasBase) {
+ if (!baseInfo.hasBase) {
if (mHasGlobalBase && mUseZeroDefaultBase) {
// The bucket has global base. This key does not.
// Optionally use zero as base.
- interval.base = (value.type == LONG ? ZERO_LONG : ZERO_DOUBLE);
- interval.hasBase = true;
+ baseInfo.base = (value.type == LONG ? ZERO_LONG : ZERO_DOUBLE);
+ baseInfo.hasBase = true;
} else {
// no base. just update base and return.
- interval.base = value;
- interval.hasBase = true;
+ baseInfo.base = value;
+ baseInfo.hasBase = true;
// If we're missing a base, do not use anomaly detection on incomplete data
useAnomalyDetection = false;
- // Continue (instead of return) here in order to set interval.base and
- // interval.hasBase for other intervals
+ // Continue (instead of return) here in order to set baseInfo.base and
+ // baseInfo.hasBase for other baseInfos
continue;
}
}
+
Value diff;
switch (mValueDirection) {
case ValueMetric::INCREASING:
- if (value >= interval.base) {
- diff = value - interval.base;
+ if (value >= baseInfo.base) {
+ diff = value - baseInfo.base;
} else if (mUseAbsoluteValueOnReset) {
diff = value;
} else {
VLOG("Unexpected decreasing value");
StatsdStats::getInstance().notePullDataError(mPullTagId);
- interval.base = value;
+ baseInfo.base = value;
// If we've got bad data, do not use anomaly detection
useAnomalyDetection = false;
continue;
}
break;
case ValueMetric::DECREASING:
- if (interval.base >= value) {
- diff = interval.base - value;
+ if (baseInfo.base >= value) {
+ diff = baseInfo.base - value;
} else if (mUseAbsoluteValueOnReset) {
diff = value;
} else {
VLOG("Unexpected increasing value");
StatsdStats::getInstance().notePullDataError(mPullTagId);
- interval.base = value;
+ baseInfo.base = value;
// If we've got bad data, do not use anomaly detection
useAnomalyDetection = false;
continue;
}
break;
case ValueMetric::ANY:
- diff = value - interval.base;
+ diff = value - baseInfo.base;
break;
default:
break;
}
- interval.base = value;
+ baseInfo.base = value;
value = diff;
}
@@ -814,12 +896,13 @@
interval.hasValue = true;
}
interval.sampleSize += 1;
+ baseInfo.currentState = stateKey;
}
// Only trigger the tracker if all intervals are correct
if (useAnomalyDetection) {
// TODO: propgate proper values down stream when anomaly support doubles
- long wholeBucketVal = multiIntervals[0].value.long_value;
+ long wholeBucketVal = intervals[0].value.long_value;
auto prev = mCurrentFullBucket.find(eventKey);
if (prev != mCurrentFullBucket.end()) {
wholeBucketVal += prev->second;
@@ -953,6 +1036,7 @@
} else {
it++;
}
+ // TODO: remove mCurrentBaseInfo entries when obsolete
}
mCurrentBucketIsInvalid = false;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 4eae99b..19fb694 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -83,11 +83,14 @@
flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
};
+ void onStateChanged(int64_t eventTimeNs, int32_t atomId, const HashableDimensionKey& primaryKey,
+ int oldState, int newState) override;
+
protected:
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKey, bool condition,
- const LogEvent& event) override;
+ const ConditionKey& conditionKey, bool condition, const LogEvent& event,
+ const std::map<int, HashableDimensionKey>& statePrimaryKeys) override;
private:
void onDumpReportLocked(const int64_t dumpTimeNs,
@@ -144,7 +147,10 @@
std::vector<Matcher> mFieldMatchers;
// Value fields for matching.
- std::set<MetricDimensionKey> mMatchedMetricDimensionKeys;
+ std::set<HashableDimensionKey> mMatchedMetricDimensionKeys;
+
+ // Holds the atom id, primary key pair from a state change.
+ pair<int32_t, HashableDimensionKey> mStateChangePrimaryKey;
// tagId for pulled data. -1 if this is not pulled
const int mPullTagId;
@@ -156,10 +162,6 @@
typedef struct {
// Index in multi value aggregation.
int valueIndex;
- // Holds current base value of the dimension. Take diff and update if necessary.
- Value base;
- // Whether there is a base to diff to.
- bool hasBase;
// Current value, depending on the aggregation type.
Value value;
// Number of samples collected.
@@ -171,8 +173,21 @@
bool seenNewData = false;
} Interval;
+ typedef struct {
+ // Holds current base value of the dimension. Take diff and update if necessary.
+ Value base;
+ // Whether there is a base to diff to.
+ bool hasBase;
+ // Last seen state value(s).
+ HashableDimensionKey currentState;
+ // Whether this dimensions in what key has a current state key.
+ bool hasCurrentState;
+ } BaseInfo;
+
std::unordered_map<MetricDimensionKey, std::vector<Interval>> mCurrentSlicedBucket;
+ std::unordered_map<HashableDimensionKey, std::vector<BaseInfo>> mCurrentBaseInfo;
+
std::unordered_map<MetricDimensionKey, int64_t> mCurrentFullBucket;
// Save the past buckets and we can clear when the StatsLogReport is dumped.
@@ -285,6 +300,9 @@
FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate);
FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput);
FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue);
+ FRIEND_TEST(ValueMetricProducerTest, TestSlicedState);
+ FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMap);
+ FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions);
FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey);
FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase);
FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures);
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 2ad8217..73c1212 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -18,11 +18,12 @@
#include "Log.h"
#include "metrics_manager_util.h"
-#include "MetricProducer.h"
#include <inttypes.h>
#include "atoms_info.h"
+#include "FieldValue.h"
+#include "MetricProducer.h"
#include "condition/CombinationConditionTracker.h"
#include "condition/SimpleConditionTracker.h"
#include "condition/StateConditionTracker.h"
@@ -173,6 +174,14 @@
return true;
}
+bool handleMetricWithStateLink(const FieldMatcher& stateMatcher,
+ const vector<Matcher>& dimensionsInWhat) {
+ vector<Matcher> stateMatchers;
+ translateFieldMatcher(stateMatcher, &stateMatchers);
+
+ return subsetDimensions(stateMatchers, dimensionsInWhat);
+}
+
// Validates a metricActivation and populates state.
// EventActivationMap and EventDeactivationMap are supplied to a MetricProducer
// to provide the producer with state about its activators and deactivators.
@@ -669,18 +678,41 @@
}
}
+ std::vector<int> slicedStateAtoms;
+ unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
+ if (metric.slice_by_state_size() > 0) {
+ if (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap,
+ allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
+ return false;
+ }
+ } else {
+ if (metric.state_link_size() > 0) {
+ ALOGW("ValueMetric has a MetricStateLink but doesn't have a sliced state");
+ return false;
+ }
+ }
+
+ // Check that all metric state links are a subset of dimensions_in_what fields.
+ std::vector<Matcher> dimensionsInWhat;
+ translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
+ for (const auto& stateLink : metric.state_link()) {
+ if (!handleMetricWithStateLink(stateLink.fields_in_what(), dimensionsInWhat)) {
+ return false;
+ }
+ }
+
unordered_map<int, shared_ptr<Activation>> eventActivationMap;
unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
- bool success = handleMetricActivation(config, metric.id(), metricIndex,
- metricToActivationMap, logTrackerMap, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation, eventActivationMap,
- eventDeactivationMap);
+ bool success = handleMetricActivation(
+ config, metric.id(), metricIndex, metricToActivationMap, logTrackerMap,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation, eventActivationMap, eventDeactivationMap);
if (!success) return false;
sp<MetricProducer> valueProducer = new ValueMetricProducer(
key, metric, conditionIndex, wizard, trackerIndex, matcherWizard, pullTagId,
timeBaseTimeNs, currentTimeNs, pullerManager, eventActivationMap,
- eventDeactivationMap);
+ eventDeactivationMap, slicedStateAtoms, stateGroupMap);
allMetricProducers.push_back(valueProducer);
}
diff --git a/cmds/statsd/src/state/StateManager.cpp b/cmds/statsd/src/state/StateManager.cpp
index 80d3983..ea776fa 100644
--- a/cmds/statsd/src/state/StateManager.cpp
+++ b/cmds/statsd/src/state/StateManager.cpp
@@ -28,13 +28,17 @@
return sStateManager;
}
+void StateManager::clear() {
+ mStateTrackers.clear();
+}
+
void StateManager::onLogEvent(const LogEvent& event) {
if (mStateTrackers.find(event.GetTagId()) != mStateTrackers.end()) {
mStateTrackers[event.GetTagId()]->onLogEvent(event);
}
}
-bool StateManager::registerListener(int32_t atomId, wp<StateListener> listener) {
+bool StateManager::registerListener(const int32_t atomId, wp<StateListener> listener) {
// Check if state tracker already exists.
if (mStateTrackers.find(atomId) == mStateTrackers.end()) {
// Create a new state tracker iff atom is a state atom.
@@ -50,7 +54,7 @@
return true;
}
-void StateManager::unregisterListener(int32_t atomId, wp<StateListener> listener) {
+void StateManager::unregisterListener(const int32_t atomId, wp<StateListener> listener) {
std::unique_lock<std::mutex> lock(mMutex);
// Hold the sp<> until the lock is released so that ~StateTracker() is
@@ -74,7 +78,7 @@
lock.unlock();
}
-bool StateManager::getStateValue(int32_t atomId, const HashableDimensionKey& key,
+bool StateManager::getStateValue(const int32_t atomId, const HashableDimensionKey& key,
FieldValue* output) const {
auto it = mStateTrackers.find(atomId);
if (it != mStateTrackers.end()) {
diff --git a/cmds/statsd/src/state/StateManager.h b/cmds/statsd/src/state/StateManager.h
index a6053e6..8bc2461 100644
--- a/cmds/statsd/src/state/StateManager.h
+++ b/cmds/statsd/src/state/StateManager.h
@@ -40,30 +40,33 @@
// Returns a pointer to the single, shared StateManager object.
static StateManager& getInstance();
+ // Unregisters all listeners and removes all trackers from StateManager.
+ void clear();
+
// Notifies the correct StateTracker of an event.
void onLogEvent(const LogEvent& event);
// Returns true if atomId is being tracked and is associated with a state
// atom. StateManager notifies the correct StateTracker to register listener.
// If the correct StateTracker does not exist, a new StateTracker is created.
- bool registerListener(int32_t atomId, wp<StateListener> listener);
+ bool registerListener(const int32_t atomId, wp<StateListener> listener);
// Notifies the correct StateTracker to unregister a listener
// and removes the tracker if it no longer has any listeners.
- void unregisterListener(int32_t atomId, wp<StateListener> listener);
+ void unregisterListener(const int32_t atomId, wp<StateListener> listener);
// Returns true if the StateTracker exists and queries for the
// original state value mapped to the given query key. The state value is
// stored and output in a FieldValue class.
// Returns false if the StateTracker doesn't exist.
- bool getStateValue(int32_t atomId, const HashableDimensionKey& queryKey,
+ bool getStateValue(const int32_t atomId, const HashableDimensionKey& queryKey,
FieldValue* output) const;
inline int getStateTrackersCount() const {
return mStateTrackers.size();
}
- inline int getListenersCount(int32_t atomId) const {
+ inline int getListenersCount(const int32_t atomId) const {
auto it = mStateTrackers.find(atomId);
if (it != mStateTrackers.end()) {
return it->second->getListenersCount();
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 8b4d781..c45274e 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -147,12 +147,14 @@
message ValueMetricData {
optional DimensionsValue dimensions_in_what = 1;
- optional DimensionsValue dimensions_in_condition = 2 [deprecated = true];
+ repeated StateValue slice_by_state = 6;
repeated ValueBucketInfo bucket_info = 3;
repeated DimensionsValue dimension_leaf_values_in_what = 4;
+ optional DimensionsValue dimensions_in_condition = 2 [deprecated = true];
+
repeated DimensionsValue dimension_leaf_values_in_condition = 5 [deprecated = true];
}
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index a22805b..736aa9b 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -290,12 +290,14 @@
optional FieldMatcher dimensions_in_what = 5;
- optional FieldMatcher dimensions_in_condition = 9 [deprecated = true];
+ repeated int64 slice_by_state = 18;
optional TimeUnit bucket = 6;
repeated MetricConditionLink links = 7;
+ repeated MetricStateLink state_link = 19;
+
enum AggregationType {
SUM = 1;
MIN = 2;
@@ -325,6 +327,8 @@
optional int32 max_pull_delay_sec = 16 [default = 10];
optional bool split_bucket_for_app_upgrade = 17 [default = true];
+
+ optional FieldMatcher dimensions_in_condition = 9 [deprecated = true];
}
message Alert {
diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
index 0f51c1b..15fc468 100644
--- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
@@ -27,9 +27,6 @@
#ifdef __ANDROID__
-const int SCREEN_STATE_ATOM_ID = android::util::SCREEN_STATE_CHANGED;
-const int UID_PROCESS_STATE_ATOM_ID = android::util::UID_PROCESS_STATE_CHANGED;
-
/**
* Test a count metric that has one slice_by_state with no primary fields.
*
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index fb878dc7..e8d2ec5 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -369,6 +369,168 @@
EXPECT_EQ(1, bucketInfo.values_size());
}
+/**
+ * Test initialization of a simple value metric that is sliced by a state.
+ *
+ * ValueCpuUserTimePerScreenState
+ */
+TEST(ValueMetricE2eTest, TestInitWithSlicedState) {
+ // Create config.
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto pulledAtomMatcher =
+ CreateSimpleAtomMatcher("TestMatcher", android::util::SUBSYSTEM_SLEEP_STATE);
+ *config.add_atom_matcher() = pulledAtomMatcher;
+
+ auto screenState = CreateScreenState();
+ *config.add_state() = screenState;
+
+ // Create value metric that slices by screen state without a map.
+ int64_t metricId = 123456;
+ auto valueMetric = config.add_value_metric();
+ valueMetric->set_id(metricId);
+ valueMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ valueMetric->set_what(pulledAtomMatcher.id());
+ *valueMetric->mutable_value_field() =
+ CreateDimensions(android::util::CPU_TIME_PER_UID, {2 /* user_time_micros */});
+ valueMetric->add_slice_by_state(screenState.id());
+ valueMetric->set_max_pull_delay_sec(INT_MAX);
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000LL;
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ // Check that StateTrackers were initialized correctly.
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+
+ // Check that ValueMetricProducer was initialized correctly.
+ EXPECT_EQ(1U, processor->mMetricsManagers.size());
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(1, metricsManager->mAllMetricProducers.size());
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_EQ(1, metricProducer->mSlicedStateAtoms.size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, metricProducer->mSlicedStateAtoms.at(0));
+ EXPECT_EQ(0, metricProducer->mStateGroupMap.size());
+}
+
+/**
+ * Test initialization of a value metric that is sliced by state and has
+ * dimensions_in_what.
+ *
+ * ValueCpuUserTimePerUidPerUidProcessState
+ */
+TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions) {
+ // Create config.
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto cpuTimePerUidMatcher =
+ CreateSimpleAtomMatcher("CpuTimePerUidMatcher", android::util::CPU_TIME_PER_UID);
+ *config.add_atom_matcher() = cpuTimePerUidMatcher;
+
+ auto uidProcessState = CreateUidProcessState();
+ *config.add_state() = uidProcessState;
+
+ // Create value metric that slices by screen state with a complete map.
+ int64_t metricId = 123456;
+ auto valueMetric = config.add_value_metric();
+ valueMetric->set_id(metricId);
+ valueMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ valueMetric->set_what(cpuTimePerUidMatcher.id());
+ *valueMetric->mutable_value_field() =
+ CreateDimensions(android::util::CPU_TIME_PER_UID, {2 /* user_time_micros */});
+ *valueMetric->mutable_dimensions_in_what() =
+ CreateDimensions(android::util::CPU_TIME_PER_UID, {1 /* uid */});
+ valueMetric->add_slice_by_state(uidProcessState.id());
+ MetricStateLink* stateLink = valueMetric->add_state_link();
+ stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+ auto fieldsInWhat = stateLink->mutable_fields_in_what();
+ *fieldsInWhat = CreateDimensions(android::util::CPU_TIME_PER_UID, {1 /* uid */});
+ auto fieldsInState = stateLink->mutable_fields_in_state();
+ *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
+ valueMetric->set_max_pull_delay_sec(INT_MAX);
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ // Check that StateTrackers were initialized correctly.
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
+
+ // Check that ValueMetricProducer was initialized correctly.
+ EXPECT_EQ(1U, processor->mMetricsManagers.size());
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(1, metricsManager->mAllMetricProducers.size());
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_EQ(1, metricProducer->mSlicedStateAtoms.size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, metricProducer->mSlicedStateAtoms.at(0));
+ EXPECT_EQ(0, metricProducer->mStateGroupMap.size());
+}
+
+/**
+ * Test initialization of a value metric that is sliced by state and has
+ * dimensions_in_what.
+ *
+ * ValueCpuUserTimePerUidPerUidProcessState
+ */
+TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions) {
+ // Create config.
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto cpuTimePerUidMatcher =
+ CreateSimpleAtomMatcher("CpuTimePerUidMatcher", android::util::CPU_TIME_PER_UID);
+ *config.add_atom_matcher() = cpuTimePerUidMatcher;
+
+ auto uidProcessState = CreateUidProcessState();
+ *config.add_state() = uidProcessState;
+
+ // Create value metric that slices by screen state with a complete map.
+ int64_t metricId = 123456;
+ auto valueMetric = config.add_value_metric();
+ valueMetric->set_id(metricId);
+ valueMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ valueMetric->set_what(cpuTimePerUidMatcher.id());
+ *valueMetric->mutable_value_field() =
+ CreateDimensions(android::util::CPU_TIME_PER_UID, {2 /* user_time_micros */});
+ valueMetric->add_slice_by_state(uidProcessState.id());
+ MetricStateLink* stateLink = valueMetric->add_state_link();
+ stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+ auto fieldsInWhat = stateLink->mutable_fields_in_what();
+ *fieldsInWhat = CreateDimensions(android::util::CPU_TIME_PER_UID, {1 /* uid */});
+ auto fieldsInState = stateLink->mutable_fields_in_state();
+ *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
+ valueMetric->set_max_pull_delay_sec(INT_MAX);
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ // No StateTrackers are initialized.
+ EXPECT_EQ(0, StateManager::getInstance().getStateTrackersCount());
+
+ // Config initialization fails.
+ EXPECT_EQ(0, processor->mMetricsManagers.size());
+}
+
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
index 6abdfa3..ae92705 100644
--- a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
+++ b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
@@ -58,8 +58,9 @@
static const int32_t GLES_VERSION = 3;
static const bool CPU_VULKAN_IN_USE = true;
static const bool FALSE_PREROTATION = true;
+static const bool GLES_1_IN_USE = true;
static const size_t NUMBER_OF_VALUES_GLOBAL = 13;
-static const size_t NUMBER_OF_VALUES_APP = 7;
+static const size_t NUMBER_OF_VALUES_APP = 8;
// clang-format on
class MockGpuStatsPuller : public GpuStatsPuller {
@@ -153,6 +154,7 @@
EXPECT_TRUE(event->write(int64VectorToProtoByteString(angleDriverLoadingTime)));
EXPECT_TRUE(event->write(CPU_VULKAN_IN_USE));
EXPECT_TRUE(event->write(FALSE_PREROTATION));
+ EXPECT_TRUE(event->write(GLES_1_IN_USE));
event->init();
inData.emplace_back(event);
MockGpuStatsPuller mockPuller(android::util::GPU_STATS_APP_INFO, &inData);
@@ -172,6 +174,7 @@
outData[0]->getValues()[4].mValue.str_value);
EXPECT_EQ(CPU_VULKAN_IN_USE, outData[0]->getValues()[5].mValue.int_value);
EXPECT_EQ(FALSE_PREROTATION, outData[0]->getValues()[6].mValue.int_value);
+ EXPECT_EQ(GLES_1_IN_USE, outData[0]->getValues()[7].mValue.int_value);
}
} // namespace statsd
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index da0a672..92e8241 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -148,6 +148,26 @@
return valueProducer;
}
+ static sp<ValueMetricProducer> createValueProducerWithState(
+ sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
+ vector<int32_t> slicedStateAtoms,
+ unordered_map<int, unordered_map<int, int64_t>> stateGroupMap) {
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+ sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
+ kConfigKey, metric, -1 /* no condition */, wizard, logEventMatcherIndex,
+ eventMatcherWizard, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager, {},
+ {}, slicedStateAtoms, stateGroupMap);
+ return valueProducer;
+ }
+
static ValueMetric createMetric() {
ValueMetric metric;
metric.set_id(metricId);
@@ -163,8 +183,13 @@
metric.set_condition(StringToId("SCREEN_ON"));
return metric;
}
-};
+ static ValueMetric createMetricWithState(string state) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.add_slice_by_state(StringToId(state));
+ return metric;
+ }
+};
/*
* Tests that the first bucket works correctly
@@ -253,10 +278,12 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::Interval curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(11, curInterval.base.long_value);
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(11, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(8, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
@@ -273,9 +300,10 @@
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(23, curInterval.base.long_value);
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(23, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(12, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
@@ -294,9 +322,10 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(36, curInterval.base.long_value);
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(36, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(13, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
@@ -394,9 +423,8 @@
}));
sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
- kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, logEventMatcherIndex,
+ eventMatcherWizard, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -411,9 +439,10 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(11, curInterval.base.long_value);
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(11, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(8, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
@@ -430,8 +459,8 @@
// No new data seen, so data has been cleared.
EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(11, curInterval.base.long_value);
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(11, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(8, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
@@ -447,10 +476,11 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
// the base was reset
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(36, curInterval.base.long_value);
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(36, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer->mPastBuckets.begin()->second.size());
@@ -482,9 +512,10 @@
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(11, curInterval.base.long_value);
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(11, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
@@ -498,8 +529,9 @@
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(10, curInterval.base.long_value);
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(10, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
@@ -515,8 +547,9 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(36, curInterval.base.long_value);
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(36, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(26, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
@@ -549,9 +582,10 @@
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(11, curInterval.base.long_value);
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(11, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
@@ -565,8 +599,9 @@
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(10, curInterval.base.long_value);
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(10, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
@@ -579,8 +614,9 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(36, curInterval.base.long_value);
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(36, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(26, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
@@ -633,9 +669,10 @@
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
// startUpdated:false sum:0 start:100
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(100, curInterval.base.long_value);
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
@@ -652,8 +689,9 @@
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(110, curInterval.base.long_value);
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(110, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(10, curInterval.value.long_value);
@@ -663,9 +701,10 @@
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(20, curInterval.value.long_value);
- EXPECT_EQ(false, curInterval.hasBase);
+ EXPECT_EQ(false, curBaseInfo.hasBase);
valueProducer->onConditionChanged(true, bucket3StartTimeNs + 1);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10, 20}, {bucketSizeNs - 8, 1});
@@ -879,6 +918,7 @@
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1066,10 +1106,11 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
// startUpdated:true sum:0 start:11
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(11, curInterval.base.long_value);
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(11, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
@@ -1084,9 +1125,10 @@
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
// tartUpdated:false sum:12
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(23, curInterval.base.long_value);
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(23, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
@@ -1103,9 +1145,10 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs);
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
// startUpdated:false sum:12
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(36, curInterval.base.long_value);
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(36, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
}
@@ -1148,16 +1191,18 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(100, curInterval.base.long_value);
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
// pull on bucket boundary come late, condition change happens before it
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
- EXPECT_EQ(false, curInterval.hasBase);
+ EXPECT_EQ(false, curBaseInfo.hasBase);
// Now the alarm is delivered.
// since the condition turned to off before this pull finish, it has no effect
@@ -1167,7 +1212,8 @@
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(false, curInterval.hasBase);
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
}
@@ -1220,9 +1266,10 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
// startUpdated:false sum:0 start:100
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(100, curInterval.base.long_value);
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
@@ -1231,15 +1278,17 @@
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(false, curInterval.hasBase);
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
// condition changed to true again, before the pull alarm is delivered
valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(130, curInterval.base.long_value);
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(130, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
// Now the alarm is delivered, but it is considered late, the data will be used
@@ -1249,8 +1298,9 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 50);
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(140, curInterval.base.long_value);
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(140, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(10, curInterval.value.long_value);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
@@ -1477,8 +1527,9 @@
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer.mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(10, curInterval.base.long_value);
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(10, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
@@ -1497,8 +1548,9 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(15, curInterval.base.long_value);
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(15, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 15);
@@ -1508,8 +1560,9 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(15, curInterval.base.long_value);
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(15, curBaseInfo.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
@@ -1550,27 +1603,29 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval0 =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
- ValueMetricProducer::Interval curInterval1 =
- valueProducer.mCurrentSlicedBucket.begin()->second[1];
- EXPECT_EQ(true, curInterval0.hasBase);
- EXPECT_EQ(10, curInterval0.base.long_value);
- EXPECT_EQ(false, curInterval0.hasValue);
- EXPECT_EQ(true, curInterval1.hasBase);
- EXPECT_EQ(20, curInterval1.base.long_value);
- EXPECT_EQ(false, curInterval1.hasValue);
+ ValueMetricProducer::Interval curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(10, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(20, curBaseInfo.base.long_value);
+ EXPECT_EQ(false, curInterval.hasValue);
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval0 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curInterval1 = valueProducer.mCurrentSlicedBucket.begin()->second[1];
- EXPECT_EQ(true, curInterval0.hasValue);
- EXPECT_EQ(5, curInterval0.value.long_value);
- EXPECT_EQ(true, curInterval1.hasValue);
- EXPECT_EQ(2, curInterval1.value.long_value);
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(5, curInterval.value.long_value);
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(2, curInterval.value.long_value);
// no change in first value field
shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
@@ -1580,14 +1635,17 @@
event3->init();
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval0 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curInterval1 = valueProducer.mCurrentSlicedBucket.begin()->second[1];
- EXPECT_EQ(true, curInterval0.hasBase);
- EXPECT_EQ(15, curInterval0.base.long_value);
- EXPECT_EQ(true, curInterval0.hasValue);
- EXPECT_EQ(true, curInterval1.hasBase);
- EXPECT_EQ(25, curInterval1.base.long_value);
- EXPECT_EQ(true, curInterval1.hasValue);
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(15, curBaseInfo.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(25, curBaseInfo.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 15);
event4->write(1);
@@ -1596,14 +1654,16 @@
event4->init();
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval0 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
- curInterval1 = valueProducer.mCurrentSlicedBucket.begin()->second[1];
- EXPECT_EQ(true, curInterval0.hasBase);
- EXPECT_EQ(15, curInterval0.base.long_value);
- EXPECT_EQ(true, curInterval0.hasValue);
- EXPECT_EQ(true, curInterval1.hasBase);
- EXPECT_EQ(29, curInterval1.base.long_value);
- EXPECT_EQ(true, curInterval1.hasValue);
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(15, curBaseInfo.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+ curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(29, curBaseInfo.base.long_value);
+ EXPECT_EQ(true, curInterval.hasValue);
valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
@@ -1650,9 +1710,11 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
auto iter = valueProducer->mCurrentSlicedBucket.begin();
auto& interval1 = iter->second[0];
+ auto iterBase = valueProducer->mCurrentBaseInfo.begin();
+ auto& baseInfo1 = iterBase->second[0];
EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
- EXPECT_EQ(true, interval1.hasBase);
- EXPECT_EQ(3, interval1.base.long_value);
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(3, baseInfo1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
@@ -1672,8 +1734,8 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
- EXPECT_EQ(true, interval1.hasBase);
- EXPECT_EQ(11, interval1.base.long_value);
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(11, baseInfo1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(8, interval1.value.long_value);
@@ -1683,11 +1745,19 @@
break;
}
}
+ auto itBase = valueProducer->mCurrentBaseInfo.begin();
+ for (; itBase != valueProducer->mCurrentBaseInfo.end(); it++) {
+ if (itBase != iterBase) {
+ break;
+ }
+ }
EXPECT_TRUE(it != iter);
+ EXPECT_TRUE(itBase != iterBase);
auto& interval2 = it->second[0];
+ auto& baseInfo2 = itBase->second[0];
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
- EXPECT_EQ(true, interval2.hasBase);
- EXPECT_EQ(4, interval2.base.long_value);
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(4, baseInfo2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_EQ(4, interval2.value.long_value);
@@ -1725,11 +1795,13 @@
ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- auto iter = valueProducer->mCurrentSlicedBucket.begin();
- auto& interval1 = iter->second[0];
- EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
- EXPECT_EQ(true, interval1.hasBase);
- EXPECT_EQ(3, interval1.base.long_value);
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ auto& interval1 = it->second[0];
+ auto& baseInfo1 =
+ valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0];
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(3, baseInfo1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
@@ -1749,22 +1821,31 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
- EXPECT_EQ(true, interval1.hasBase);
- EXPECT_EQ(11, interval1.base.long_value);
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(11, baseInfo1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(8, interval1.value.long_value);
- auto it = valueProducer->mCurrentSlicedBucket.begin();
- for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
- if (it != iter) {
+ auto it2 = valueProducer->mCurrentSlicedBucket.begin();
+ for (; it2 != valueProducer->mCurrentSlicedBucket.end(); it2++) {
+ if (it2 != it) {
break;
}
}
- EXPECT_TRUE(it != iter);
- auto& interval2 = it->second[0];
- EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
- EXPECT_EQ(true, interval2.hasBase);
- EXPECT_EQ(4, interval2.base.long_value);
+ // auto itBase = valueProducer->mCurrentBaseInfo.begin();
+ // for (; itBase != valueProducer->mCurrentBaseInfo.end(); it++) {
+ // if (itBase != iterBase) {
+ // break;
+ // }
+ // }
+ EXPECT_TRUE(it2 != it);
+ // EXPECT_TRUE(itBase != iterBase);
+ auto& interval2 = it2->second[0];
+ auto& baseInfo2 =
+ valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0];
+ EXPECT_EQ(2, it2->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(4, baseInfo2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_EQ(4, interval2.value.long_value);
EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
@@ -1779,8 +1860,8 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- EXPECT_EQ(true, interval2.hasBase);
- EXPECT_EQ(5, interval2.base.long_value);
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(5, baseInfo2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
@@ -1799,17 +1880,24 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
- auto it1 = std::next(valueProducer->mCurrentSlicedBucket.begin())->second[0];
- EXPECT_EQ(true, it1.hasBase);
- EXPECT_EQ(13, it1.base.long_value);
- EXPECT_EQ(false, it1.hasValue);
- EXPECT_EQ(8, it1.value.long_value);
- auto it2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, it2.hasBase);
- EXPECT_EQ(5, it2.base.long_value);
- EXPECT_EQ(false, it2.hasValue);
- EXPECT_EQ(5, it2.value.long_value);
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ it2 = std::next(valueProducer->mCurrentSlicedBucket.begin());
+ interval1 = it->second[0];
+ interval2 = it2->second[0];
+ baseInfo1 = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0];
+ baseInfo2 = valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0];
+
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(5, baseInfo1.base.long_value);
+ EXPECT_EQ(false, interval1.hasValue);
+ EXPECT_EQ(5, interval1.value.long_value);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(13, baseInfo2.base.long_value);
+ EXPECT_EQ(false, interval2.hasValue);
+ EXPECT_EQ(8, interval2.value.long_value);
+
EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
}
@@ -1839,9 +1927,11 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
auto iter = valueProducer->mCurrentSlicedBucket.begin();
auto& interval1 = iter->second[0];
+ auto iterBase = valueProducer->mCurrentBaseInfo.begin();
+ auto& baseInfo1 = iterBase->second[0];
EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
- EXPECT_EQ(true, interval1.hasBase);
- EXPECT_EQ(3, interval1.base.long_value);
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(3, baseInfo1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
vector<shared_ptr<LogEvent>> allData;
@@ -1860,8 +1950,8 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
- EXPECT_EQ(true, interval1.hasBase);
- EXPECT_EQ(11, interval1.base.long_value);
+ EXPECT_EQ(true, baseInfo1.hasBase);
+ EXPECT_EQ(11, baseInfo1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(8, interval1.value.long_value);
EXPECT_FALSE(interval1.seenNewData);
@@ -1873,11 +1963,19 @@
break;
}
}
+ auto itBase = valueProducer->mCurrentBaseInfo.begin();
+ for (; itBase != valueProducer->mCurrentBaseInfo.end(); it++) {
+ if (itBase != iterBase) {
+ break;
+ }
+ }
EXPECT_TRUE(it != iter);
+ EXPECT_TRUE(itBase != iterBase);
auto& interval2 = it->second[0];
+ auto& baseInfo2 = itBase->second[0];
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
- EXPECT_EQ(true, interval2.hasBase);
- EXPECT_EQ(4, interval2.base.long_value);
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(4, baseInfo2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_FALSE(interval2.seenNewData);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
@@ -1890,12 +1988,13 @@
event1->init();
allData.push_back(event1);
valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
- // Only one interval left. One was trimmed.
+ // Only one interval left. One was trimmed.
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
- EXPECT_EQ(true, interval2.hasBase);
- EXPECT_EQ(5, interval2.base.long_value);
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(5, baseInfo2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_FALSE(interval2.seenNewData);
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
@@ -1909,8 +2008,9 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, interval2.hasBase);
- EXPECT_EQ(14, interval2.base.long_value);
+ baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, baseInfo2.hasBase);
+ EXPECT_EQ(14, baseInfo2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_FALSE(interval2.seenNewData);
ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
@@ -1946,14 +2046,15 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(100, curInterval.base.long_value);
+ ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
vector<shared_ptr<LogEvent>> allData;
valueProducer->onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- EXPECT_EQ(false, curInterval.hasBase);
+ EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(false, valueProducer->mHasGlobalBase);
}
@@ -1983,8 +2084,9 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(100, curInterval.base.long_value);
+ ValueMetricProducer::BaseInfo& curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
@@ -1993,7 +2095,7 @@
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(false, curInterval.hasBase);
+ EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, valueProducer->mHasGlobalBase);
}
@@ -2035,7 +2137,8 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(false, curInterval.hasBase);
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(false, valueProducer->mHasGlobalBase);
}
@@ -2118,8 +2221,9 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(100, curInterval.base.long_value);
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(100, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
}
@@ -2181,8 +2285,9 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(140, curInterval.base.long_value);
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(140, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
@@ -2222,7 +2327,8 @@
// First onConditionChanged
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
for (int i = 0; i < 2000; i++) {
- shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
+ shared_ptr<LogEvent> event =
+ make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
event->write(i);
event->write(i);
event->init();
@@ -2338,8 +2444,9 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(140, curInterval.base.long_value);
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(140, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
@@ -2429,7 +2536,8 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(false, curInterval.hasBase);
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(false, valueProducer->mHasGlobalBase);
@@ -2523,7 +2631,8 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
@@ -2531,7 +2640,8 @@
valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(false, curInterval.hasBase);
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(false, valueProducer->mHasGlobalBase);
}
@@ -2579,7 +2689,8 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval& curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
@@ -2589,9 +2700,10 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
// Data is empty, base should be reset.
- EXPECT_EQ(false, curInterval.hasBase);
- EXPECT_EQ(5, curInterval.base.long_value);
+ EXPECT_EQ(false, curBaseInfo.hasBase);
+ EXPECT_EQ(5, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
@@ -2638,12 +2750,14 @@
// Key 1 should be reset since in not present in the most pull.
EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
auto iterator = valueProducer->mCurrentSlicedBucket.begin();
- EXPECT_EQ(true, iterator->second[0].hasBase);
- EXPECT_EQ(2, iterator->second[0].base.long_value);
+ auto baseInfoIter = valueProducer->mCurrentBaseInfo.begin();
+ EXPECT_EQ(true, baseInfoIter->second[0].hasBase);
+ EXPECT_EQ(2, baseInfoIter->second[0].base.long_value);
EXPECT_EQ(false, iterator->second[0].hasValue);
iterator++;
- EXPECT_EQ(false, iterator->second[0].hasBase);
- EXPECT_EQ(1, iterator->second[0].base.long_value);
+ baseInfoIter++;
+ EXPECT_EQ(false, baseInfoIter->second[0].hasBase);
+ EXPECT_EQ(1, baseInfoIter->second[0].base.long_value);
EXPECT_EQ(false, iterator->second[0].hasValue);
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
@@ -2715,8 +2829,9 @@
valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(true, curInterval.hasBase);
- EXPECT_EQ(5, curInterval.base.long_value);
+ auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(true, curBaseInfo.hasBase);
+ EXPECT_EQ(5, curBaseInfo.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
valueProducer->onConditionChanged(false, bucket3StartTimeNs + 10);
@@ -2827,6 +2942,7 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(2, curInterval.value.long_value);
@@ -2918,8 +3034,7 @@
ProtoOutputStream output;
std::set<string> strSet;
- valueProducer.onDumpReport(bucketStartTimeNs + 10,
- true /* include recent buckets */, true,
+ valueProducer.onDumpReport(bucketStartTimeNs + 10, true /* include recent buckets */, true,
FAST, &strSet, &output);
StatsLogReport report = outputStreamToProto(&output);
@@ -2970,9 +3085,8 @@
ProtoOutputStream output;
std::set<string> strSet;
- valueProducer.onDumpReport(bucket4StartTimeNs,
- false /* include recent buckets */, true,
- FAST, &strSet, &output);
+ valueProducer.onDumpReport(bucket4StartTimeNs, false /* include recent buckets */, true, FAST,
+ &strSet, &output);
StatsLogReport report = outputStreamToProto(&output);
// Previous bucket is part of the report.
@@ -3023,8 +3137,7 @@
ProtoOutputStream output;
std::set<string> strSet;
- valueProducer.onDumpReport(bucketStartTimeNs + 10,
- true /* include recent buckets */, true,
+ valueProducer.onDumpReport(bucketStartTimeNs + 10, true /* include recent buckets */, true,
NO_TIME_CONSTRAINTS, &strSet, &output);
StatsLogReport report = outputStreamToProto(&output);
@@ -3058,15 +3171,15 @@
// condition becomes true
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- data->push_back(ValueMetricProducerTestHelper::createEvent(
- bucketStartTimeNs + 30, 10));
+ data->push_back(
+ ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs + 30, 10));
return true;
}))
// condition becomes false
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- data->push_back(ValueMetricProducerTestHelper::createEvent(
- bucketStartTimeNs + 50, 20));
+ data->push_back(
+ ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs + 50, 20));
return true;
}));
sp<ValueMetricProducer> valueProducer =
@@ -3079,11 +3192,11 @@
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(false, curInterval.hasBase);
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(20, curInterval.value.long_value);
-
// Now the alarm is delivered. Condition is off though.
vector<shared_ptr<LogEvent>> allData;
allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 110));
@@ -3091,7 +3204,8 @@
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {50 - 8});
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(false, curInterval.hasBase);
+ curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
}
@@ -3104,8 +3218,8 @@
// condition becomes true
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- data->push_back(ValueMetricProducerTestHelper::createEvent(
- bucketStartTimeNs + 30, 10));
+ data->push_back(
+ ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs + 30, 10));
return true;
}));
sp<ValueMetricProducer> valueProducer =
@@ -3122,7 +3236,8 @@
assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs - 8});
ValueMetricProducer::Interval curInterval =
valueProducer->mCurrentSlicedBucket.begin()->second[0];
- EXPECT_EQ(false, curInterval.hasBase);
+ ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+ EXPECT_EQ(false, curBaseInfo.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
}
@@ -3153,8 +3268,8 @@
// condition becomes true
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- data->push_back(ValueMetricProducerTestHelper::createEvent(
- bucketStartTimeNs + 30, 10));
+ data->push_back(
+ ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs + 30, 10));
return true;
}))
.WillOnce(Return(false));
@@ -3768,6 +3883,725 @@
EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 200), dropEvent.drop_time_millis());
}
+/*
+ * Test metric with a simple sliced state
+ * - Increasing values
+ * - Using diff
+ * - Second field is value field
+ */
+TEST(ValueMetricProducerTest, TestSlicedState) {
+ // Set up ValueMetricProducer.
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithState("SCREEN_STATE");
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // ValueMetricProducer initialized.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+ event->write("field1");
+ event->write(3);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ // Screen state change to ON.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 5);
+ event->write("field1");
+ event->write(5);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ // Screen state change to OFF.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ event->write("field1");
+ event->write(9);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ // Screen state change to ON.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 15);
+ event->write("field1");
+ event->write(21);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ // Dump report requested.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 50);
+ event->write("field1");
+ event->write(30);
+ event->init();
+ data->push_back(event);
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithState(
+ pullerManager, metric, {android::util::SCREEN_STATE_CHANGED}, {});
+
+ // Set up StateManager and check that StateTrackers are initialized.
+ StateManager::getInstance().clear();
+ StateManager::getInstance().registerListener(SCREEN_STATE_ATOM_ID, valueProducer);
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+
+ // Bucket status after metric initialized.
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {}
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(3, itBase->second[0].base.long_value);
+ // Value for dimension, state key {{}, kStateUnknown}
+ EXPECT_EQ(false, it->second[0].hasValue);
+
+ // Bucket status after screen state change kStateUnknown->ON.
+ auto screenEvent = CreateScreenStateChangedEvent(
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 5);
+ StateManager::getInstance().onLogEvent(*screenEvent);
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {}
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(5, itBase->second[0].base.long_value);
+ // Value for dimension, state key {{}, kStateUnknown}
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(2, it->second[0].value.long_value);
+
+ // Bucket status after screen state change ON->OFF.
+ screenEvent = CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 10);
+ StateManager::getInstance().onLogEvent(*screenEvent);
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {}
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(9, itBase->second[0].base.long_value);
+ // Value for dimension, state key {{}, ON}
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(4, it->second[0].value.long_value);
+ // Value for dimension, state key {{}, kStateUnknown}
+ it++;
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(2, it->second[0].value.long_value);
+
+ // Bucket status after screen state change OFF->ON.
+ screenEvent = CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 15);
+ StateManager::getInstance().onLogEvent(*screenEvent);
+ EXPECT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {}
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(21, itBase->second[0].base.long_value);
+ // Value for dimension, state key {{}, OFF}
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(12, it->second[0].value.long_value);
+ // Value for dimension, state key {{}, ON}
+ it++;
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(4, it->second[0].value.long_value);
+ // Value for dimension, state key {{}, kStateUnknown}
+ it++;
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(2, it->second[0].value.long_value);
+
+ // Start dump report and check output.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer->onDumpReport(bucketStartTimeNs + 50, true /* include recent buckets */, true,
+ NO_TIME_CONSTRAINTS, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ EXPECT_EQ(3, report.value_metrics().data_size());
+
+ auto data = report.value_metrics().data(0);
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
+
+ data = report.value_metrics().data(1);
+ EXPECT_EQ(1, report.value_metrics().data(1).bucket_info_size());
+ EXPECT_EQ(13, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
+
+ data = report.value_metrics().data(2);
+ EXPECT_EQ(1, report.value_metrics().data(2).bucket_info_size());
+ EXPECT_EQ(12, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
+}
+
+/*
+ * Test metric with sliced state with map
+ * - Increasing values
+ * - Using diff
+ * - Second field is value field
+ */
+TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
+ // Set up ValueMetricProducer.
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithState("SCREEN_STATE_ONOFF");
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // ValueMetricProducer initialized.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+ event->write("field1");
+ event->write(3);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ // Screen state change to ON.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 5);
+ event->write("field1");
+ event->write(5);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ // Screen state change to VR.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ event->write("field1");
+ event->write(9);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ // Screen state change to OFF.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 15);
+ event->write("field1");
+ event->write(21);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ // Dump report requested.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 50);
+ event->write("field1");
+ event->write(30);
+ event->init();
+ data->push_back(event);
+ return true;
+ }));
+
+ const StateMap& stateMap = CreateScreenStateOnOffMap();
+ const StateMap_StateGroup screenOnGroup = stateMap.group(0);
+ const StateMap_StateGroup screenOffGroup = stateMap.group(1);
+
+ unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
+ for (auto group : stateMap.group()) {
+ for (auto value : group.value()) {
+ stateGroupMap[SCREEN_STATE_ATOM_ID][value] = group.group_id();
+ }
+ }
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithState(
+ pullerManager, metric, {android::util::SCREEN_STATE_CHANGED}, stateGroupMap);
+
+ // Set up StateManager and check that StateTrackers are initialized.
+ StateManager::getInstance().clear();
+ StateManager::getInstance().registerListener(SCREEN_STATE_ATOM_ID, valueProducer);
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+
+ // Bucket status after metric initialized.
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {}
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(3, itBase->second[0].base.long_value);
+ // Value for dimension, state key {{}, {}}
+ EXPECT_EQ(false, it->second[0].hasValue);
+
+ // Bucket status after screen state change kStateUnknown->ON.
+ auto screenEvent = CreateScreenStateChangedEvent(
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 5);
+ StateManager::getInstance().onLogEvent(*screenEvent);
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {}
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(5, itBase->second[0].base.long_value);
+ // Value for dimension, state key {{}, kStateUnknown}
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(2, it->second[0].value.long_value);
+
+ // Bucket status after screen state change ON->VR (also ON).
+ screenEvent = CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_VR,
+ bucketStartTimeNs + 10);
+ StateManager::getInstance().onLogEvent(*screenEvent);
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {}
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(9, itBase->second[0].base.long_value);
+ // Value for dimension, state key {{}, ON GROUP}
+ EXPECT_EQ(screenOnGroup.group_id(),
+ it->first.getStateValuesKey().getValues()[0].mValue.long_value);
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(4, it->second[0].value.long_value);
+ // Value for dimension, state key {{}, kStateUnknown}
+ it++;
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(2, it->second[0].value.long_value);
+
+ // Bucket status after screen state change VR->OFF.
+ screenEvent = CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+ bucketStartTimeNs + 15);
+ StateManager::getInstance().onLogEvent(*screenEvent);
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {}
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(21, itBase->second[0].base.long_value);
+ // Value for dimension, state key {{}, ON GROUP}
+ EXPECT_EQ(screenOnGroup.group_id(),
+ it->first.getStateValuesKey().getValues()[0].mValue.long_value);
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(16, it->second[0].value.long_value);
+ // Value for dimension, state key {{}, kStateUnknown}
+ it++;
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(2, it->second[0].value.long_value);
+
+ // Start dump report and check output.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer->onDumpReport(bucketStartTimeNs + 50, true /* include recent buckets */, true,
+ NO_TIME_CONSTRAINTS, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ EXPECT_EQ(3, report.value_metrics().data_size());
+
+ auto data = report.value_metrics().data(0);
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
+
+ data = report.value_metrics().data(1);
+ EXPECT_EQ(1, report.value_metrics().data(1).bucket_info_size());
+ EXPECT_EQ(16, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(screenOnGroup.group_id(), data.slice_by_state(0).group_id());
+
+ data = report.value_metrics().data(2);
+ EXPECT_EQ(1, report.value_metrics().data(2).bucket_info_size());
+ EXPECT_EQ(9, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(screenOffGroup.group_id(), data.slice_by_state(0).group_id());
+}
+
+/*
+ * Test metric that slices by state with a primary field and has dimensions
+ * - Increasing values
+ * - Using diff
+ * - Second field is value field
+ */
+TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
+ // Set up ValueMetricProducer.
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithState("UID_PROCESS_STATE");
+ metric.mutable_dimensions_in_what()->set_field(tagId);
+ metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+
+ MetricStateLink* stateLink = metric.add_state_link();
+ stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+ auto fieldsInWhat = stateLink->mutable_fields_in_what();
+ *fieldsInWhat = CreateDimensions(tagId, {1 /* uid */});
+ auto fieldsInState = stateLink->mutable_fields_in_state();
+ *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // ValueMetricProducer initialized.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+ event->write(2 /* uid */);
+ event->write(7);
+ event->init();
+ data->push_back(event);
+
+ event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+ event->write(1 /* uid */);
+ event->write(3);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ // Uid 1 process state change from kStateUnknown -> Foreground
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
+ event->write(1 /* uid */);
+ event->write(6);
+ event->init();
+ data->push_back(event);
+
+ // This event should be skipped.
+ event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
+ event->write(2 /* uid */);
+ event->write(8);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ // Uid 2 process state change from kStateUnknown -> Background
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 40);
+ event->write(2 /* uid */);
+ event->write(9);
+ event->init();
+ data->push_back(event);
+
+ // This event should be skipped.
+ event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 40);
+ event->write(1 /* uid */);
+ event->write(12);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ // Uid 1 process state change from Foreground -> Background
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20);
+ event->write(1 /* uid */);
+ event->write(13);
+ event->init();
+ data->push_back(event);
+
+ // This event should be skipped.
+ event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20);
+ event->write(2 /* uid */);
+ event->write(11);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ // Uid 1 process state change from Background -> Foreground
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 40);
+ event->write(1 /* uid */);
+ event->write(17);
+ event->init();
+ data->push_back(event);
+
+ // This event should be skipped.
+ event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 40);
+ event->write(2 /* uid */);
+ event->write(15);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ // Dump report pull.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 50);
+ event->write(2 /* uid */);
+ event->write(20);
+ event->init();
+ data->push_back(event);
+
+ event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 50);
+ event->write(1 /* uid */);
+ event->write(21);
+ event->init();
+ data->push_back(event);
+ return true;
+ }));
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithState(
+ pullerManager, metric, {UID_PROCESS_STATE_ATOM_ID}, {});
+
+ // Set up StateManager and check that StateTrackers are initialized.
+ StateManager::getInstance().clear();
+ StateManager::getInstance().registerListener(UID_PROCESS_STATE_ATOM_ID, valueProducer);
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
+
+ // Bucket status after metric initialized.
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {uid 1}.
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(3, itBase->second[0].base.long_value);
+ // Value for dimension, state key {{uid 1}, kStateUnknown}
+ // TODO(tsaichristine): test equality of state values key
+ // EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(false, it->second[0].hasValue);
+ // Base for dimension key {uid 2}
+ it++;
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(7, itBase->second[0].base.long_value);
+ // Value for dimension, state key {{uid 2}, kStateUnknown}
+ // EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(false, it->second[0].hasValue);
+
+ // Bucket status after uid 1 process state change kStateUnknown -> Foreground.
+ auto uidProcessEvent = CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, bucketStartTimeNs + 20);
+ StateManager::getInstance().onLogEvent(*uidProcessEvent);
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {uid 1}.
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(6, itBase->second[0].base.long_value);
+ // Value for key {uid 1, kStateUnknown}.
+ // EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(3, it->second[0].value.long_value);
+
+ // Base for dimension key {uid 2}
+ it++;
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(7, itBase->second[0].base.long_value);
+ // Value for key {uid 2, kStateUnknown}
+ EXPECT_EQ(false, it->second[0].hasValue);
+
+ // Bucket status after uid 2 process state change kStateUnknown -> Background.
+ uidProcessEvent = CreateUidProcessStateChangedEvent(
+ 2 /* uid */, android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, bucketStartTimeNs + 40);
+ StateManager::getInstance().onLogEvent(*uidProcessEvent);
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {uid 1}.
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(6, itBase->second[0].base.long_value);
+ // Value for key {uid 1, kStateUnknown}.
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(3, it->second[0].value.long_value);
+
+ // Base for dimension key {uid 2}
+ it++;
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(9, itBase->second[0].base.long_value);
+ // Value for key {uid 2, kStateUnknown}
+ // EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(2, it->second[0].value.long_value);
+
+ // Pull at end of first bucket.
+ vector<shared_ptr<LogEvent>> allData;
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs);
+ event->write(1 /* uid */);
+ event->write(10);
+ event->init();
+ allData.push_back(event);
+
+ event = make_shared<LogEvent>(tagId, bucket2StartTimeNs);
+ event->write(2 /* uid */);
+ event->write(15);
+ event->init();
+ allData.push_back(event);
+
+ valueProducer->onDataPulled(allData, /** succeeds */ true, bucket2StartTimeNs + 1);
+
+ // Buckets flushed after end of first bucket.
+ // None of the buckets should have a value.
+ EXPECT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(4UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
+ // Base for dimension key {uid 2}.
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(15, itBase->second[0].base.long_value);
+ // Value for key {uid 2, BACKGROUND}.
+ EXPECT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(1006, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(false, it->second[0].hasValue);
+
+ // Base for dimension key {uid 1}
+ it++;
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(10, itBase->second[0].base.long_value);
+ // Value for key {uid 1, kStateUnknown}
+ EXPECT_EQ(0, it->first.getStateValuesKey().getValues().size());
+ // EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(false, it->second[0].hasValue);
+
+ // Value for key {uid 1, FOREGROUND}
+ it++;
+ EXPECT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(1005, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(false, it->second[0].hasValue);
+
+ // Value for key {uid 2, kStateUnknown}
+ it++;
+ EXPECT_EQ(false, it->second[0].hasValue);
+
+ // Bucket status after uid 1 process state change from Foreground -> Background.
+ uidProcessEvent = CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, bucket2StartTimeNs + 20);
+ StateManager::getInstance().onLogEvent(*uidProcessEvent);
+
+ EXPECT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(4UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
+ // Base for dimension key {uid 2}.
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(15, itBase->second[0].base.long_value);
+ // Value for key {uid 2, BACKGROUND}.
+ EXPECT_EQ(false, it->second[0].hasValue);
+ // Base for dimension key {uid 1}
+ it++;
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(13, itBase->second[0].base.long_value);
+ // Value for key {uid 1, kStateUnknown}
+ EXPECT_EQ(false, it->second[0].hasValue);
+ // Value for key {uid 1, FOREGROUND}
+ it++;
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(1005, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(3, it->second[0].value.long_value);
+ // Value for key {uid 2, kStateUnknown}
+ it++;
+ EXPECT_EQ(false, it->second[0].hasValue);
+
+ // Bucket status after uid 1 process state change Background->Foreground.
+ uidProcessEvent = CreateUidProcessStateChangedEvent(
+ 1 /* uid */, android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, bucket2StartTimeNs + 40);
+ StateManager::getInstance().onLogEvent(*uidProcessEvent);
+
+ EXPECT_EQ(5UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
+ // Base for dimension key {uid 2}
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(true, itBase->second[0].hasBase);
+ EXPECT_EQ(15, itBase->second[0].base.long_value);
+ EXPECT_EQ(false, it->second[0].hasValue);
+
+ it++;
+ EXPECT_EQ(false, it->second[0].hasValue);
+
+ // Base for dimension key {uid 1}
+ it++;
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(17, itBase->second[0].base.long_value);
+ // Value for key {uid 1, BACKGROUND}
+ EXPECT_EQ(1006, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(4, it->second[0].value.long_value);
+ // Value for key {uid 1, FOREGROUND}
+ it++;
+ EXPECT_EQ(1005, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, it->second[0].hasValue);
+ EXPECT_EQ(3, it->second[0].value.long_value);
+
+ // Start dump report and check output.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer->onDumpReport(bucket2StartTimeNs + 50, true /* include recent buckets */, true,
+ NO_TIME_CONSTRAINTS, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ EXPECT_EQ(5, report.value_metrics().data_size());
+
+ auto data = report.value_metrics().data(0);
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(4, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ data.slice_by_state(0).value());
+
+ data = report.value_metrics().data(1);
+ EXPECT_EQ(1, report.value_metrics().data(1).bucket_info_size());
+ EXPECT_EQ(2, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
+
+ data = report.value_metrics().data(2);
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ data.slice_by_state(0).value());
+ EXPECT_EQ(2, report.value_metrics().data(2).bucket_info_size());
+ EXPECT_EQ(4, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
+ EXPECT_EQ(7, report.value_metrics().data(2).bucket_info(1).values(0).value_long());
+
+ data = report.value_metrics().data(3);
+ EXPECT_EQ(1, report.value_metrics().data(3).bucket_info_size());
+ EXPECT_EQ(3, report.value_metrics().data(3).bucket_info(0).values(0).value_long());
+
+ data = report.value_metrics().data(4);
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ data.slice_by_state(0).value());
+ EXPECT_EQ(2, report.value_metrics().data(4).bucket_info_size());
+ EXPECT_EQ(6, report.value_metrics().data(4).bucket_info(0).values(0).value_long());
+ EXPECT_EQ(5, report.value_metrics().data(4).bucket_info(1).values(0).value_long());
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp
index 395167b..26a3733 100644
--- a/cmds/statsd/tests/state/StateTracker_test.cpp
+++ b/cmds/statsd/tests/state/StateTracker_test.cpp
@@ -146,6 +146,7 @@
TEST(StateManagerTest, TestStateManagerGetInstance) {
sp<TestStateListener> listener1 = new TestStateListener();
StateManager& mgr = StateManager::getInstance();
+ mgr.clear();
mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
EXPECT_EQ(1, mgr.getStateTrackersCount());
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 010c194..9bdfeeb 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -30,6 +30,9 @@
using android::util::ProtoReader;
using google::protobuf::RepeatedPtrField;
+const int SCREEN_STATE_ATOM_ID = android::util::SCREEN_STATE_CHANGED;
+const int UID_PROCESS_STATE_ATOM_ID = android::util::UID_PROCESS_STATE_CHANGED;
+
// Converts a ProtoOutputStream to a StatsLogReport proto.
StatsLogReport outputStreamToProto(ProtoOutputStream* proto);
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index 652669c..4d0acb3 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -14142,7 +14142,6 @@
HSPLandroid/telephony/ServiceState;->copyFrom(Landroid/telephony/ServiceState;)V
HSPLandroid/telephony/ServiceState;->describeContents()I
HSPLandroid/telephony/ServiceState;->equals(Ljava/lang/Object;)Z
-HSPLandroid/telephony/ServiceState;->fillInNotifierBundle(Landroid/os/Bundle;)V
HSPLandroid/telephony/ServiceState;->getCdmaDefaultRoamingIndicator()I
HSPLandroid/telephony/ServiceState;->getCdmaEriIconIndex()I
HSPLandroid/telephony/ServiceState;->getCdmaEriIconMode()I
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 08f8734..a4f6f57 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3659,7 +3659,7 @@
r.activity, Looper.myLooper());
}
r.activity.onGetDirectActions(cancellationSignal, (actions) -> {
- Preconditions.checkNotNull(actions);
+ Objects.requireNonNull(actions);
Preconditions.checkCollectionElementsNotNull(actions, "actions");
if (!actions.isEmpty()) {
final int actionCount = actions.size();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 86a5c76..b5ac37b 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -51,6 +51,7 @@
import android.util.ArraySet;
import android.util.LongSparseArray;
import android.util.LongSparseLongArray;
+import android.util.Pools;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -1159,8 +1160,6 @@
})
private @interface ShouldCollectNoteOp {}
- // Warning: If an permission is added here it also has to be added to
- // com.android.packageinstaller.permission.utils.EventLogger
private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = {
// RUNTIME PERMISSIONS
// Contacts
@@ -2045,7 +2044,7 @@
* transaction. Not set if this thread is currently not executing a two way binder transaction.
*
* @see #startNotedAppOpsCollection
- * @see #markAppOpNoted
+ * @see #getNotedOpCollectionMode
*/
private static final ThreadLocal<Integer> sBinderThreadCallingUid = new ThreadLocal<>();
@@ -2053,7 +2052,8 @@
* If a thread is currently executing a two-way binder transaction, this stores the op-codes of
* the app-ops that were noted during this transaction.
*
- * @see #markAppOpNoted
+ * @see #getNotedOpCollectionMode
+ * @see #collectNotedOpSync
*/
private static final ThreadLocal<ArrayMap<String, long[]>> sAppOpsNotedInThisBinderTransaction =
new ThreadLocal<>();
@@ -2341,15 +2341,31 @@
*/
@TestApi
@SystemApi
- @Immutable
- @DataClass(genHiddenConstructor = true)
+ // @DataClass(genHiddenConstructor = true, genHiddenCopyConstructor = true)
+ // genHiddenCopyConstructor does not work for @hide @SystemApi classes
public static final class OpEventProxyInfo implements Parcelable {
/** UID of the proxy app that noted the op */
- private final @IntRange(from = 0) int mUid;
+ private @IntRange(from = 0) int mUid;
/** Package of the proxy that noted the op */
- private final @Nullable String mPackageName;
+ private @Nullable String mPackageName;
/** ID of the feature of the proxy that noted the op */
- private final @Nullable String mFeatureId;
+ private @Nullable String mFeatureId;
+
+ /**
+ * Reinit existing object with new state.
+ *
+ * @param uid UID of the proxy app that noted the op
+ * @param packageName Package of the proxy that noted the op
+ * @param featureId ID of the feature of the proxy that noted the op
+ *
+ * @hide
+ */
+ public void reinit(@IntRange(from = 0) int uid, @Nullable String packageName,
+ @Nullable String featureId) {
+ mUid = Preconditions.checkArgumentNonnegative(uid);
+ mPackageName = packageName;
+ mFeatureId = featureId;
+ }
@@ -2393,6 +2409,18 @@
}
/**
+ * Copy constructor
+ *
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public OpEventProxyInfo(@NonNull OpEventProxyInfo orig) {
+ mUid = orig.mUid;
+ mPackageName = orig.mPackageName;
+ mFeatureId = orig.mFeatureId;
+ }
+
+ /**
* UID of the proxy app that noted the op
*/
@DataClass.Generated.Member
@@ -2471,14 +2499,15 @@
}
};
+ /*
@DataClass.Generated(
- time = 1576194071700L,
+ time = 1576814974615L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
- inputSignatures = "private final @android.annotation.IntRange(from=0L) int mUid\nprivate final @android.annotation.Nullable java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nclass OpEventProxyInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+ inputSignatures = "private @android.annotation.IntRange(from=0L) int mUid\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.Nullable java.lang.String mFeatureId\npublic void reinit(int,java.lang.String,java.lang.String)\nclass OpEventProxyInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genHiddenCopyConstructor=true)")
@Deprecated
private void __metadata() {}
-
+ */
//@formatter:on
// End of generated code
@@ -2490,15 +2519,48 @@
*
* @hide
*/
- @Immutable
//@DataClass codegen verifier is broken
public static final class NoteOpEvent implements Parcelable {
/** Time of noteOp event */
- public final @IntRange(from = 0) long noteTime;
+ private @IntRange(from = 0) long mNoteTime;
/** The duration of this event (in case this is a startOp event, -1 otherwise). */
- public final @IntRange(from = -1) long duration;
+ private @IntRange(from = -1) long mDuration;
/** Proxy information of the noteOp event */
- public final @Nullable OpEventProxyInfo proxy;
+ private @Nullable OpEventProxyInfo mProxy;
+
+ /**
+ * Reinit existing object with new state.
+ *
+ * @param noteTime Time of noteOp event
+ * @param duration The duration of this event (in case this is a startOp event,
+ * -1 otherwise).
+ * @param proxy Proxy information of the noteOp event
+ * @param proxyPool The pool to release previous {@link OpEventProxyInfo} to
+ */
+ public void reinit(@IntRange(from = 0) long noteTime,
+ @IntRange(from = -1) long duration,
+ @Nullable OpEventProxyInfo proxy,
+ @NonNull Pools.Pool<OpEventProxyInfo> proxyPool) {
+ mNoteTime = Preconditions.checkArgumentNonnegative(noteTime);
+ mDuration = Preconditions.checkArgumentInRange(duration, -1L, Long.MAX_VALUE,
+ "duration");
+
+ if (mProxy != null) {
+ proxyPool.release(mProxy);
+ }
+ mProxy = proxy;
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @hide
+ */
+ public NoteOpEvent(@NonNull NoteOpEvent original) {
+ this(original.mNoteTime, original.mDuration,
+ original.mProxy != null ? new OpEventProxyInfo(original.mProxy) : null);
+ }
+
// Code below generated by codegen v1.0.14.
@@ -2529,19 +2591,43 @@
@IntRange(from = 0) long noteTime,
@IntRange(from = -1) long duration,
@Nullable OpEventProxyInfo proxy) {
- this.noteTime = noteTime;
+ this.mNoteTime = noteTime;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, noteTime,
+ IntRange.class, null, mNoteTime,
"from", 0);
- this.duration = duration;
+ this.mDuration = duration;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, duration,
+ IntRange.class, null, mDuration,
"from", -1);
- this.proxy = proxy;
+ this.mProxy = proxy;
// onConstructed(); // You can define this method to get a callback
}
+ /**
+ * Time of noteOp event
+ */
+ @DataClass.Generated.Member
+ public @IntRange(from = 0) long getNoteTime() {
+ return mNoteTime;
+ }
+
+ /**
+ * The duration of this event (in case this is a startOp event, -1 otherwise).
+ */
+ @DataClass.Generated.Member
+ public @IntRange(from = -1) long getDuration() {
+ return mDuration;
+ }
+
+ /**
+ * Proxy information of the noteOp event
+ */
+ @DataClass.Generated.Member
+ public @Nullable OpEventProxyInfo getProxy() {
+ return mProxy;
+ }
+
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -2549,11 +2635,11 @@
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
- if (proxy != null) flg |= 0x4;
+ if (mProxy != null) flg |= 0x4;
dest.writeByte(flg);
- dest.writeLong(noteTime);
- dest.writeLong(duration);
- if (proxy != null) dest.writeTypedObject(proxy, flags);
+ dest.writeLong(mNoteTime);
+ dest.writeLong(mDuration);
+ if (mProxy != null) dest.writeTypedObject(mProxy, flags);
}
@Override
@@ -2568,20 +2654,19 @@
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
- long _noteTime = in.readLong();
- long _duration = in.readLong();
- OpEventProxyInfo _proxy = (flg & 0x4) == 0 ? null : (OpEventProxyInfo) in.readTypedObject(
- OpEventProxyInfo.CREATOR);
+ long noteTime = in.readLong();
+ long duration = in.readLong();
+ OpEventProxyInfo proxy = (flg & 0x4) == 0 ? null : (OpEventProxyInfo) in.readTypedObject(OpEventProxyInfo.CREATOR);
- this.noteTime = _noteTime;
+ this.mNoteTime = noteTime;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, noteTime,
+ IntRange.class, null, mNoteTime,
"from", 0);
- this.duration = _duration;
+ this.mDuration = duration;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, duration,
+ IntRange.class, null, mDuration,
"from", -1);
- this.proxy = _proxy;
+ this.mProxy = proxy;
// onConstructed(); // You can define this method to get a callback
}
@@ -2602,10 +2687,10 @@
/*
@DataClass.Generated(
- time = 1574809856220L,
+ time = 1576811792274L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
- inputSignatures = "public final @android.annotation.IntRange(from=0L) long noteTime\npublic final @android.annotation.IntRange(from=-1) long duration\npublic final @android.annotation.Nullable android.app.NoteOpEventProxyInfo proxy\nclass NoteOpEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
+ inputSignatures = "private @android.annotation.IntRange(from=0L) long mNoteTime\nprivate @android.annotation.IntRange(from=-1) long mDuration\nprivate @android.annotation.Nullable android.app.OpEventProxyInfo mProxy\npublic void reinit(long,long,android.app.OpEventProxyInfo,android.util.Pools.Pool<android.app.OpEventProxyInfo>)\npublic @java.lang.Override java.lang.Object clone()\nclass NoteOpEvent extends java.lang.Object implements [android.os.Parcelable, java.lang.Cloneable]\n@com.android.internal.util.DataClass")
@Deprecated
private void __metadata() {}
*/
@@ -2751,7 +2836,7 @@
return -1;
}
- return lastEvent.noteTime;
+ return lastEvent.getNoteTime();
}
/**
@@ -2847,7 +2932,7 @@
return -1;
}
- return lastEvent.noteTime;
+ return lastEvent.getNoteTime();
}
/**
@@ -2922,7 +3007,7 @@
return -1;
}
- return lastEvent.duration;
+ return lastEvent.getDuration();
}
/**
@@ -3000,7 +3085,7 @@
return null;
}
- return lastEvent.proxy;
+ return lastEvent.getProxy();
}
private static class LongSparseArrayParceling implements
@@ -3304,7 +3389,7 @@
toUidState, flags);
if (lastAccessEvent == null || (lastFeatureAccessEvent != null
- && lastFeatureAccessEvent.noteTime > lastAccessEvent.noteTime)) {
+ && lastFeatureAccessEvent.getNoteTime() > lastAccessEvent.getNoteTime())) {
lastAccessEvent = lastFeatureAccessEvent;
}
}
@@ -3335,7 +3420,7 @@
return -1;
}
- return lastEvent.noteTime;
+ return lastEvent.getNoteTime();
}
/**
@@ -3418,7 +3503,7 @@
toUidState, flags);
if (lastAccessEvent == null || (lastFeatureAccessEvent != null
- && lastFeatureAccessEvent.noteTime > lastAccessEvent.noteTime)) {
+ && lastFeatureAccessEvent.getNoteTime() > lastAccessEvent.getNoteTime())) {
lastAccessEvent = lastFeatureAccessEvent;
}
}
@@ -3449,7 +3534,7 @@
return -1;
}
- return lastEvent.noteTime;
+ return lastEvent.getNoteTime();
}
/**
@@ -3544,7 +3629,7 @@
return -1;
}
- return lastEvent.duration;
+ return lastEvent.getDuration();
}
/**
@@ -3674,7 +3759,7 @@
return null;
}
- return lastEvent.proxy;
+ return lastEvent.getProxy();
}
@@ -5517,8 +5602,8 @@
@RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
public void getHistoricalOps(@NonNull HistoricalOpsRequest request,
@NonNull Executor executor, @NonNull Consumer<HistoricalOps> callback) {
- Preconditions.checkNotNull(executor, "executor cannot be null");
- Preconditions.checkNotNull(callback, "callback cannot be null");
+ Objects.requireNonNull(executor, "executor cannot be null");
+ Objects.requireNonNull(callback, "callback cannot be null");
try {
mService.getHistoricalOps(request.mUid, request.mPackageName, request.mOpNames,
request.mBeginTimeMillis, request.mEndTimeMillis, request.mFlags,
@@ -5556,8 +5641,8 @@
@RequiresPermission(Manifest.permission.MANAGE_APPOPS)
public void getHistoricalOpsFromDiskRaw(@NonNull HistoricalOpsRequest request,
@Nullable Executor executor, @NonNull Consumer<HistoricalOps> callback) {
- Preconditions.checkNotNull(executor, "executor cannot be null");
- Preconditions.checkNotNull(callback, "callback cannot be null");
+ Objects.requireNonNull(executor, "executor cannot be null");
+ Objects.requireNonNull(callback, "callback cannot be null");
try {
mService.getHistoricalOpsFromDiskRaw(request.mUid, request.mPackageName,
request.mOpNames, request.mBeginTimeMillis, request.mEndTimeMillis,
@@ -6236,9 +6321,23 @@
public int noteOpNoThrow(int op, int uid, @Nullable String packageName,
@Nullable String featureId, @Nullable String message) {
try {
- int mode = mService.noteOperation(op, uid, packageName, featureId);
+ int collectionMode = getNotedOpCollectionMode(uid, packageName, op);
+ if (collectionMode == COLLECT_ASYNC) {
+ if (message == null) {
+ // Set stack trace as default message
+ message = getFormattedStackTrace();
+ }
+ }
+
+ int mode = mService.noteOperation(op, uid, packageName, featureId,
+ collectionMode == COLLECT_ASYNC, message);
+
if (mode == MODE_ALLOWED) {
- markAppOpNoted(uid, packageName, op, featureId, message);
+ if (collectionMode == COLLECT_SELF) {
+ collectNotedOpForSelf(op, featureId);
+ } else if (collectionMode == COLLECT_SYNC) {
+ collectNotedOpSync(op, featureId);
+ }
}
return mode;
@@ -6382,14 +6481,27 @@
int myUid = Process.myUid();
try {
+ int collectionMode = getNotedOpCollectionMode(proxiedUid, proxiedPackageName, op);
+ if (collectionMode == COLLECT_ASYNC) {
+ if (message == null) {
+ // Set stack trace as default message
+ message = getFormattedStackTrace();
+ }
+ }
+
int mode = mService.noteProxyOperation(op, proxiedUid, proxiedPackageName,
proxiedFeatureId, myUid, mContext.getOpPackageName(),
- mContext.getFeatureId());
- if (mode == MODE_ALLOWED
- // Only collect app-ops when the proxy is trusted
- && mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1, myUid)
- == PackageManager.PERMISSION_GRANTED) {
- markAppOpNoted(proxiedUid, proxiedPackageName, op, proxiedFeatureId, message);
+ mContext.getFeatureId(), collectionMode == COLLECT_ASYNC, message);
+
+ if (mode == MODE_ALLOWED) {
+ if (collectionMode == COLLECT_SELF) {
+ collectNotedOpForSelf(op, proxiedFeatureId);
+ } else if (collectionMode == COLLECT_SYNC
+ // Only collect app-ops when the proxy is trusted
+ && mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
+ myUid) == PackageManager.PERMISSION_GRANTED) {
+ collectNotedOpSync(op, proxiedFeatureId);
+ }
}
return mode;
@@ -6679,10 +6791,23 @@
public int startOpNoThrow(int op, int uid, @NonNull String packageName,
boolean startIfModeDefault, @Nullable String featureId, @Nullable String message) {
try {
+ int collectionMode = getNotedOpCollectionMode(uid, packageName, op);
+ if (collectionMode == COLLECT_ASYNC) {
+ if (message == null) {
+ // Set stack trace as default message
+ message = getFormattedStackTrace();
+ }
+ }
+
int mode = mService.startOperation(getClientId(), op, uid, packageName,
- featureId, startIfModeDefault);
+ featureId, startIfModeDefault, collectionMode == COLLECT_ASYNC, message);
+
if (mode == MODE_ALLOWED) {
- markAppOpNoted(uid, packageName, op, featureId, message);
+ if (collectionMode == COLLECT_SELF) {
+ collectNotedOpForSelf(op, featureId);
+ } else if (collectionMode == COLLECT_SYNC) {
+ collectNotedOpSync(op, featureId);
+ }
}
return mode;
@@ -6846,85 +6971,106 @@
}
/**
- * Mark an app-op as noted
+ * Collect a noted op for the current process.
+ *
+ * @param op The noted op
+ * @param featureId The feature the op is noted for
*/
- private void markAppOpNoted(int uid, @Nullable String packageName, int code,
- @Nullable String featureId, @Nullable String message) {
+ private void collectNotedOpForSelf(int op, @Nullable String featureId) {
+ synchronized (sLock) {
+ if (sNotedAppOpsCollector != null) {
+ sNotedAppOpsCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
+ }
+ }
+ }
+
+ /**
+ * Collect a noted op when inside of a two-way binder call.
+ *
+ * <p> Delivered to caller via {@link #prefixParcelWithAppOpsIfNeeded}
+ *
+ * @param op The noted op
+ * @param featureId The feature the op is noted for
+ */
+ private void collectNotedOpSync(int op, @Nullable String featureId) {
+ // If this is inside of a two-way binder call:
+ // We are inside of a two-way binder call. Delivered to caller via
+ // {@link #prefixParcelWithAppOpsIfNeeded}
+ ArrayMap<String, long[]> appOpsNoted = sAppOpsNotedInThisBinderTransaction.get();
+ if (appOpsNoted == null) {
+ appOpsNoted = new ArrayMap<>(1);
+ sAppOpsNotedInThisBinderTransaction.set(appOpsNoted);
+ }
+
+ long[] appOpsNotedForFeature = appOpsNoted.get(featureId);
+ if (appOpsNotedForFeature == null) {
+ appOpsNotedForFeature = new long[2];
+ appOpsNoted.put(featureId, appOpsNotedForFeature);
+ }
+
+ if (op < 64) {
+ appOpsNotedForFeature[0] |= 1L << op;
+ } else {
+ appOpsNotedForFeature[1] |= 1L << (op - 64);
+ }
+ }
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ DONT_COLLECT,
+ COLLECT_SELF,
+ COLLECT_SYNC,
+ COLLECT_ASYNC
+ })
+ private @interface NotedOpCollectionMode {}
+ private static final int DONT_COLLECT = 0;
+ private static final int COLLECT_SELF = 1;
+ private static final int COLLECT_SYNC = 2;
+ private static final int COLLECT_ASYNC = 3;
+
+ /**
+ * Mark an app-op as noted.
+ */
+ private @NotedOpCollectionMode int getNotedOpCollectionMode(int uid,
+ @Nullable String packageName, int op) {
if (packageName == null) {
packageName = "android";
}
// check it the appops needs to be collected and cache result
- if (sAppOpsToNote[code] == SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED) {
+ if (sAppOpsToNote[op] == SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED) {
boolean shouldCollectNotes;
try {
- shouldCollectNotes = mService.shouldCollectNotes(code);
+ shouldCollectNotes = mService.shouldCollectNotes(op);
} catch (RemoteException e) {
- return;
+ return DONT_COLLECT;
}
if (shouldCollectNotes) {
- sAppOpsToNote[code] = SHOULD_COLLECT_NOTE_OP;
+ sAppOpsToNote[op] = SHOULD_COLLECT_NOTE_OP;
} else {
- sAppOpsToNote[code] = SHOULD_NOT_COLLECT_NOTE_OP;
+ sAppOpsToNote[op] = SHOULD_NOT_COLLECT_NOTE_OP;
}
}
- if (sAppOpsToNote[code] != SHOULD_COLLECT_NOTE_OP) {
- return;
+ if (sAppOpsToNote[op] != SHOULD_COLLECT_NOTE_OP) {
+ return DONT_COLLECT;
+ }
+
+ synchronized (sLock) {
+ if (uid == Process.myUid()
+ && packageName.equals(ActivityThread.currentOpPackageName())) {
+ return COLLECT_SELF;
+ }
}
Integer binderUid = sBinderThreadCallingUid.get();
- synchronized (sLock) {
- if (sNotedAppOpsCollector != null && uid == Process.myUid() && packageName.equals(
- ActivityThread.currentOpPackageName())) {
- // This app is noting an app-op for itself. Deliver immediately.
- sNotedAppOpsCollector.onSelfNoted(new SyncNotedAppOp(code, featureId));
-
- return;
- }
- }
-
if (binderUid != null && binderUid == uid) {
- // If this is inside of a two-way binder call: Delivered to caller via
- // {@link #prefixParcelWithAppOpsIfNeeded}
- // We are inside of a two-way binder call. Delivered to caller via
- // {@link #prefixParcelWithAppOpsIfNeeded}
- ArrayMap<String, long[]> appOpsNoted = sAppOpsNotedInThisBinderTransaction.get();
- if (appOpsNoted == null) {
- appOpsNoted = new ArrayMap<>(1);
- sAppOpsNotedInThisBinderTransaction.set(appOpsNoted);
- }
-
- long[] appOpsNotedForFeature = appOpsNoted.get(featureId);
- if (appOpsNotedForFeature == null) {
- appOpsNotedForFeature = new long[2];
- appOpsNoted.put(featureId, appOpsNotedForFeature);
- }
-
- if (code < 64) {
- appOpsNotedForFeature[0] |= 1L << code;
- } else {
- appOpsNotedForFeature[1] |= 1L << (code - 64);
- }
+ return COLLECT_SYNC;
} else {
- // Cannot deliver the note synchronous: Hence send it to the system server to
- // notify the noted process.
- if (message == null) {
- // Default message is a stack trace
- message = getFormattedStackTrace();
- }
-
- long token = Binder.clearCallingIdentity();
- try {
- mService.noteAsyncOp(mContext.getOpPackageName(), uid, packageName, code,
- featureId, message);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ return COLLECT_ASYNC;
}
}
@@ -7062,7 +7208,7 @@
private final IAppOpsAsyncNotedCallback mAsyncCb = new IAppOpsAsyncNotedCallback.Stub() {
@Override
public void opNoted(AsyncNotedAppOp op) {
- Preconditions.checkNotNull(op);
+ Objects.requireNonNull(op);
getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
}
@@ -7331,7 +7477,8 @@
final long key = makeKey(uidState, flag);
NoteOpEvent event = events.get(key);
- if (lastEvent == null || event != null && event.noteTime > lastEvent.noteTime) {
+ if (lastEvent == null
+ || event != null && event.getNoteTime() > lastEvent.getNoteTime()) {
lastEvent = event;
}
}
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index bd7ef2a..099037c 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.util.SparseIntArray;
+import com.android.internal.util.function.HexFunction;
import com.android.internal.util.function.QuadFunction;
/**
@@ -63,12 +64,16 @@
* @param uid The UID for which to note.
* @param packageName The package for which to note. {@code null} for system package.
* @param featureId Id of the feature in the package
+ * @param shouldCollectAsyncNotedOp If an {@link AsyncNotedAppOp} should be collected
+ * @param message The message in the async noted op
* @param superImpl The super implementation.
* @return The app op note result.
*/
int noteOperation(int code, int uid, @Nullable String packageName,
- @Nullable String featureId,
- @NonNull QuadFunction<Integer, Integer, String, String, Integer> superImpl);
+ @Nullable String featureId, boolean shouldCollectAsyncNotedOp,
+ @Nullable String message,
+ @NonNull HexFunction<Integer, Integer, String, String, Boolean, String, Integer>
+ superImpl);
}
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7f26565..1c6a561 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -100,7 +100,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
-import com.android.internal.util.Preconditions;
import com.android.internal.util.UserIcons;
import dalvik.system.VMRuntime;
@@ -2149,7 +2148,7 @@
} else if (vol.isPrimaryPhysical()) {
volumeUuid = StorageManager.UUID_PRIMARY_PHYSICAL;
} else {
- volumeUuid = Preconditions.checkNotNull(vol.fsUuid);
+ volumeUuid = Objects.requireNonNull(vol.fsUuid);
}
return mPM.movePackage(packageName, volumeUuid);
@@ -2259,7 +2258,7 @@
} else if (vol.isPrimaryPhysical()) {
volumeUuid = StorageManager.UUID_PRIMARY_PHYSICAL;
} else {
- volumeUuid = Preconditions.checkNotNull(vol.fsUuid);
+ volumeUuid = Objects.requireNonNull(vol.fsUuid);
}
return mPM.movePrimaryStorage(volumeUuid);
@@ -2661,8 +2660,8 @@
/** @hide */
@Override
public KeySet getKeySetByAlias(String packageName, String alias) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(alias);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(alias);
try {
return mPM.getKeySetByAlias(packageName, alias);
} catch (RemoteException e) {
@@ -2673,7 +2672,7 @@
/** @hide */
@Override
public KeySet getSigningKeySet(String packageName) {
- Preconditions.checkNotNull(packageName);
+ Objects.requireNonNull(packageName);
try {
return mPM.getSigningKeySet(packageName);
} catch (RemoteException e) {
@@ -2684,8 +2683,8 @@
/** @hide */
@Override
public boolean isSignedBy(String packageName, KeySet ks) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(ks);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(ks);
try {
return mPM.isPackageSignedByKeySet(packageName, ks);
} catch (RemoteException e) {
@@ -2696,8 +2695,8 @@
/** @hide */
@Override
public boolean isSignedByExactly(String packageName, KeySet ks) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(ks);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(ks);
try {
return mPM.isPackageSignedByKeySetExactly(packageName, ks);
} catch (RemoteException e) {
diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index 0e1f921..c3ef3ad 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -45,12 +45,6 @@
/** Uid that noted the op */
private final @IntRange(from = 0) int mNotingUid;
- /**
- * Package that noted the op. {@code null} if the package name that noted the op could be not
- * be determined (e.g. when the op is noted from native code).
- */
- private final @Nullable String mNotingPackageName;
-
/** {@link android.content.Context#createFeatureContext Feature} in the app */
private final @Nullable String mFeatureId;
@@ -69,7 +63,7 @@
- // Code below generated by codegen v1.0.9.
+ // Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -89,9 +83,6 @@
* Op that was noted
* @param notingUid
* Uid that noted the op
- * @param notingPackageName
- * Package that noted the op. {@code null} if the package name that noted the op could be not
- * be determined (e.g. when the op is noted from native code).
* @param featureId
* {@link android.content.Context#createFeatureContext Feature} in the app
* @param message
@@ -104,7 +95,6 @@
public AsyncNotedAppOp(
@IntRange(from = 0, to = AppOpsManager._NUM_OP - 1) int opCode,
@IntRange(from = 0) int notingUid,
- @Nullable String notingPackageName,
@Nullable String featureId,
@NonNull String message,
@IntRange(from = 0) long time) {
@@ -117,7 +107,6 @@
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mNotingUid,
"from", 0);
- this.mNotingPackageName = notingPackageName;
this.mFeatureId = featureId;
this.mMessage = message;
com.android.internal.util.AnnotationValidations.validate(
@@ -139,15 +128,6 @@
}
/**
- * Package that noted the op. {@code null} if the package name that noted the op could be not
- * be determined (e.g. when the op is noted from native code).
- */
- @DataClass.Generated.Member
- public @Nullable String getNotingPackageName() {
- return mNotingPackageName;
- }
-
- /**
* {@link android.content.Context#createFeatureContext Feature} in the app
*/
@DataClass.Generated.Member
@@ -186,7 +166,6 @@
return true
&& mOpCode == that.mOpCode
&& mNotingUid == that.mNotingUid
- && java.util.Objects.equals(mNotingPackageName, that.mNotingPackageName)
&& java.util.Objects.equals(mFeatureId, that.mFeatureId)
&& java.util.Objects.equals(mMessage, that.mMessage)
&& mTime == that.mTime;
@@ -201,7 +180,6 @@
int _hash = 1;
_hash = 31 * _hash + mOpCode;
_hash = 31 * _hash + mNotingUid;
- _hash = 31 * _hash + java.util.Objects.hashCode(mNotingPackageName);
_hash = 31 * _hash + java.util.Objects.hashCode(mFeatureId);
_hash = 31 * _hash + java.util.Objects.hashCode(mMessage);
_hash = 31 * _hash + Long.hashCode(mTime);
@@ -215,12 +193,10 @@
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
- if (mNotingPackageName != null) flg |= 0x4;
- if (mFeatureId != null) flg |= 0x8;
+ if (mFeatureId != null) flg |= 0x4;
dest.writeByte(flg);
dest.writeInt(mOpCode);
dest.writeInt(mNotingUid);
- if (mNotingPackageName != null) dest.writeString(mNotingPackageName);
if (mFeatureId != null) dest.writeString(mFeatureId);
dest.writeString(mMessage);
dest.writeLong(mTime);
@@ -240,8 +216,7 @@
byte flg = in.readByte();
int opCode = in.readInt();
int notingUid = in.readInt();
- String notingPackageName = (flg & 0x4) == 0 ? null : in.readString();
- String featureId = (flg & 0x8) == 0 ? null : in.readString();
+ String featureId = (flg & 0x4) == 0 ? null : in.readString();
String message = in.readString();
long time = in.readLong();
@@ -254,7 +229,6 @@
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mNotingUid,
"from", 0);
- this.mNotingPackageName = notingPackageName;
this.mFeatureId = featureId;
this.mMessage = message;
com.android.internal.util.AnnotationValidations.validate(
@@ -282,11 +256,15 @@
};
@DataClass.Generated(
- time = 1571327470155L,
- codegenVersion = "1.0.9",
+ time = 1576864422226L,
+ codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
- inputSignatures = "private final @android.annotation.IntRange(from=0L, to=92L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mNotingPackageName\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
+ inputSignatures = "private final @android.annotation.IntRange(from=0L, to=92L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
+
+ //@formatter:on
+ // End of generated code
+
}
diff --git a/core/java/android/app/AuthenticationRequiredException.java b/core/java/android/app/AuthenticationRequiredException.java
index 0d87336..847d2c4 100644
--- a/core/java/android/app/AuthenticationRequiredException.java
+++ b/core/java/android/app/AuthenticationRequiredException.java
@@ -21,7 +21,7 @@
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
/**
* Specialization of {@link SecurityException} that is thrown when authentication is needed from the
@@ -60,7 +60,7 @@
*/
public AuthenticationRequiredException(Throwable cause, PendingIntent userAction) {
super(cause.getMessage());
- mUserAction = Preconditions.checkNotNull(userAction);
+ mUserAction = Objects.requireNonNull(userAction);
}
/**
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index bd87fcd..cd84310 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2794,7 +2794,7 @@
public ApplicationContentResolver(Context context, ActivityThread mainThread) {
super(context);
- mMainThread = Preconditions.checkNotNull(mainThread);
+ mMainThread = Objects.requireNonNull(mainThread);
}
@Override
diff --git a/core/java/android/app/DirectAction.java b/core/java/android/app/DirectAction.java
index ef3627b..0268f7c 100644
--- a/core/java/android/app/DirectAction.java
+++ b/core/java/android/app/DirectAction.java
@@ -172,7 +172,7 @@
* current application state.
*/
public Builder(@NonNull String id) {
- Preconditions.checkNotNull(id);
+ Objects.requireNonNull(id);
mId = id;
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 453c600..775b1d1 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -46,7 +46,7 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
-import android.sysprop.ProductProperties;
+import android.sysprop.VndkProperties;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
@@ -785,13 +785,12 @@
// Similar to vendor apks, we should add /product/lib for apks from product partition
// when product apps are marked as unbundled. We cannot use the same way from vendor
// to check if lib path exists because there is possibility that /product/lib would not
- // exist from legacy device while product apks are bundled. To make this clear, new
- // property ("ro.product.apps.unbundled") is defined which should be true only when
- // product apks are unbundled.
+ // exist from legacy device while product apks are bundled. To make this clear, we use
+ // "ro.product.vndk.version" property. If the property is defined, we regard all product
+ // apks as unbundled.
if (mApplicationInfo.getCodePath() != null
- && mApplicationInfo.isProduct() && ProductProperties.unbundled_apps().orElse(false)
- // TODO(b/128557860): Change target SDK version when version code R is available.
- && getTargetSdkVersion() == Build.VERSION_CODES.CUR_DEVELOPMENT) {
+ && mApplicationInfo.isProduct()
+ && VndkProperties.product_vndk_version().isPresent()) {
isBundledApp = false;
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 31c73b9..ca3d0d7 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -198,6 +198,7 @@
import com.android.internal.util.Preconditions;
import java.util.Map;
+import java.util.Objects;
/**
* Manages all of the system services that can be returned by {@link Context#getSystemService}.
@@ -1429,8 +1430,8 @@
@NonNull StaticServiceProducerWithBinder<TServiceClass> serviceProducer) {
ensureInitializing("registerStaticService");
Preconditions.checkStringNotEmpty(serviceName);
- Preconditions.checkNotNull(serviceWrapperClass);
- Preconditions.checkNotNull(serviceProducer);
+ Objects.requireNonNull(serviceWrapperClass);
+ Objects.requireNonNull(serviceProducer);
registerService(serviceName, serviceWrapperClass,
new StaticServiceFetcher<TServiceClass>() {
@@ -1453,8 +1454,8 @@
@NonNull StaticServiceProducerWithoutBinder<TServiceClass> serviceProducer) {
ensureInitializing("registerStaticService");
Preconditions.checkStringNotEmpty(serviceName);
- Preconditions.checkNotNull(serviceWrapperClass);
- Preconditions.checkNotNull(serviceProducer);
+ Objects.requireNonNull(serviceWrapperClass);
+ Objects.requireNonNull(serviceProducer);
registerService(serviceName, serviceWrapperClass,
new StaticServiceFetcher<TServiceClass>() {
@@ -1486,8 +1487,8 @@
@NonNull ContextAwareServiceProducerWithBinder<TServiceClass> serviceProducer) {
ensureInitializing("registerContextAwareService");
Preconditions.checkStringNotEmpty(serviceName);
- Preconditions.checkNotNull(serviceWrapperClass);
- Preconditions.checkNotNull(serviceProducer);
+ Objects.requireNonNull(serviceWrapperClass);
+ Objects.requireNonNull(serviceProducer);
registerService(serviceName, serviceWrapperClass,
new CachedServiceFetcher<TServiceClass>() {
@@ -1514,8 +1515,8 @@
@NonNull ContextAwareServiceProducerWithoutBinder<TServiceClass> serviceProducer) {
ensureInitializing("registerContextAwareService");
Preconditions.checkStringNotEmpty(serviceName);
- Preconditions.checkNotNull(serviceWrapperClass);
- Preconditions.checkNotNull(serviceProducer);
+ Objects.requireNonNull(serviceWrapperClass);
+ Objects.requireNonNull(serviceProducer);
registerService(serviceName, serviceWrapperClass,
new CachedServiceFetcher<TServiceClass>() {
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index b37120f..c262ec2 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -44,6 +44,7 @@
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -1129,8 +1130,8 @@
*/
public boolean registerOnDestroyedCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull Runnable callback) {
- Preconditions.checkNotNull(executor);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
if (isDestroyed()) {
Log.w(TAG, "Cannot interact with a destroyed voice interactor");
return false;
@@ -1146,7 +1147,7 @@
* @return whether the callback was unregistered.
*/
public boolean unregisterOnDestroyedCallback(@NonNull Runnable callback) {
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(callback);
if (isDestroyed()) {
Log.w(TAG, "Cannot interact with a destroyed voice interactor");
return false;
diff --git a/core/java/android/app/admin/DevicePolicyEventLogger.java b/core/java/android/app/admin/DevicePolicyEventLogger.java
index 95a7973..4c0e176 100644
--- a/core/java/android/app/admin/DevicePolicyEventLogger.java
+++ b/core/java/android/app/admin/DevicePolicyEventLogger.java
@@ -25,6 +25,7 @@
import com.android.internal.util.Preconditions;
import java.util.Arrays;
+import java.util.Objects;
/**
* A wrapper for logging managed device events using {@link StatsLog}.
@@ -136,7 +137,7 @@
* in that order.
*/
public DevicePolicyEventLogger setStrings(String value, String[] values) {
- Preconditions.checkNotNull(values, "values parameter cannot be null");
+ Objects.requireNonNull(values, "values parameter cannot be null");
mStringArrayValue = new String[values.length + 1];
mStringArrayValue[0] = value;
System.arraycopy(values, 0, mStringArrayValue, 1, values.length);
@@ -150,7 +151,7 @@
* and <code>values</code>, in that order.
*/
public DevicePolicyEventLogger setStrings(String value1, String value2, String[] values) {
- Preconditions.checkNotNull(values, "values parameter cannot be null");
+ Objects.requireNonNull(values, "values parameter cannot be null");
mStringArrayValue = new String[values.length + 2];
mStringArrayValue[0] = value1;
mStringArrayValue[1] = value2;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index acdf919..8daaaaa 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -115,6 +115,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -4263,7 +4264,7 @@
* {@link #WIPE_SILENTLY} is set.
*/
public void wipeData(int flags, @NonNull CharSequence reason) {
- Preconditions.checkNotNull(reason, "reason string is null");
+ Objects.requireNonNull(reason, "reason string is null");
Preconditions.checkStringNotEmpty(reason, "reason string is empty");
Preconditions.checkArgument((flags & WIPE_SILENTLY) == 0, "WIPE_SILENTLY cannot be set");
wipeDataInternal(flags, reason.toString());
@@ -10430,8 +10431,8 @@
@NonNull String packageName, @NonNull @CallbackExecutor Executor executor,
@NonNull OnClearApplicationUserDataListener listener) {
throwIfParentInstance("clearAppData");
- Preconditions.checkNotNull(executor);
- Preconditions.checkNotNull(listener);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(listener);
try {
mService.clearApplicationUserData(admin, packageName,
new IPackageDataObserver.Stub() {
@@ -10881,7 +10882,7 @@
@WorkerThread public @PrivateDnsModeErrorCodes int setGlobalPrivateDnsModeSpecifiedHost(
@NonNull ComponentName admin, @NonNull String privateDnsHost) {
throwIfParentInstance("setGlobalPrivateDnsModeSpecifiedHost");
- Preconditions.checkNotNull(privateDnsHost, "dns resolver is null");
+ Objects.requireNonNull(privateDnsHost, "dns resolver is null");
if (mService == null) {
return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 80c5b17..22d8c87 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -41,6 +41,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
/**
* <p>This API automatically creates assist data from the platform's
@@ -1889,7 +1890,7 @@
@Override
public void setTextIdEntry(@NonNull String entryName) {
- mNode.mTextIdEntry = Preconditions.checkNotNull(entryName);
+ mNode.mTextIdEntry = Objects.requireNonNull(entryName);
}
@Override
@@ -1899,7 +1900,7 @@
@Override
public void setHintIdEntry(@NonNull String entryName) {
- mNode.mHintIdEntry = Preconditions.checkNotNull(entryName);
+ mNode.mHintIdEntry = Objects.requireNonNull(entryName);
}
@Override
diff --git a/core/java/android/app/prediction/AppPredictionManager.java b/core/java/android/app/prediction/AppPredictionManager.java
index cb5b7e7..ca22721 100644
--- a/core/java/android/app/prediction/AppPredictionManager.java
+++ b/core/java/android/app/prediction/AppPredictionManager.java
@@ -20,7 +20,7 @@
import android.annotation.TestApi;
import android.content.Context;
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
/**
* Class that provides methods to create prediction clients.
@@ -37,7 +37,7 @@
* @hide
*/
public AppPredictionManager(Context context) {
- mContext = Preconditions.checkNotNull(context);
+ mContext = Objects.requireNonNull(context);
}
/**
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
index 6f21490..14e32b83 100644
--- a/core/java/android/app/prediction/AppTarget.java
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -25,7 +25,7 @@
import android.os.Parcelable;
import android.os.UserHandle;
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
/**
* A representation of a launchable target.
@@ -55,9 +55,9 @@
mId = id;
mShortcutInfo = null;
- mPackageName = Preconditions.checkNotNull(packageName);
+ mPackageName = Objects.requireNonNull(packageName);
mClassName = className;
- mUser = Preconditions.checkNotNull(user);
+ mUser = Objects.requireNonNull(user);
mRank = 0;
}
@@ -69,7 +69,7 @@
public AppTarget(@NonNull AppTargetId id, @NonNull ShortcutInfo shortcutInfo,
@Nullable String className) {
mId = id;
- mShortcutInfo = Preconditions.checkNotNull(shortcutInfo);
+ mShortcutInfo = Objects.requireNonNull(shortcutInfo);
mPackageName = mShortcutInfo.getPackage();
mUser = mShortcutInfo.getUserHandle();
@@ -224,9 +224,9 @@
@TestApi
public Builder(@NonNull AppTargetId id, @NonNull String packageName,
@NonNull UserHandle user) {
- mId = Preconditions.checkNotNull(id);
- mPackageName = Preconditions.checkNotNull(packageName);
- mUser = Preconditions.checkNotNull(user);
+ mId = Objects.requireNonNull(id);
+ mPackageName = Objects.requireNonNull(packageName);
+ mUser = Objects.requireNonNull(user);
}
/**
@@ -237,8 +237,8 @@
@SystemApi
@TestApi
public Builder(@NonNull AppTargetId id, @NonNull ShortcutInfo info) {
- mId = Preconditions.checkNotNull(id);
- mShortcutInfo = Preconditions.checkNotNull(info);
+ mId = Objects.requireNonNull(id);
+ mShortcutInfo = Objects.requireNonNull(info);
mPackageName = info.getPackage();
mUser = info.getUserHandle();
}
@@ -253,8 +253,8 @@
if (mPackageName != null) {
throw new IllegalArgumentException("Target is already set");
}
- mPackageName = Preconditions.checkNotNull(packageName);
- mUser = Preconditions.checkNotNull(user);
+ mPackageName = Objects.requireNonNull(packageName);
+ mUser = Objects.requireNonNull(user);
return this;
}
@@ -266,7 +266,7 @@
@Deprecated
public Builder setTarget(@NonNull ShortcutInfo info) {
setTarget(info.getPackage(), info.getUserHandle());
- mShortcutInfo = Preconditions.checkNotNull(info);
+ mShortcutInfo = Objects.requireNonNull(info);
return this;
}
@@ -275,7 +275,7 @@
*/
@NonNull
public Builder setClassName(@NonNull String className) {
- mClassName = Preconditions.checkNotNull(className);
+ mClassName = Objects.requireNonNull(className);
return this;
}
diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
index a7319f6..823fdd2 100644
--- a/core/java/android/app/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -28,7 +28,6 @@
import android.os.Parcelable;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -428,7 +427,7 @@
* @see SliceItem#getSubType()
*/
public Builder addSubSlice(@NonNull Slice slice, @Nullable @SliceSubtype String subType) {
- Preconditions.checkNotNull(slice);
+ Objects.requireNonNull(slice);
mItems.add(new SliceItem(slice, SliceItem.FORMAT_SLICE, subType,
slice.getHints().toArray(new String[slice.getHints().size()])));
return this;
@@ -441,8 +440,8 @@
*/
public Slice.Builder addAction(@NonNull PendingIntent action, @NonNull Slice s,
@Nullable @SliceSubtype String subType) {
- Preconditions.checkNotNull(action);
- Preconditions.checkNotNull(s);
+ Objects.requireNonNull(action);
+ Objects.requireNonNull(s);
List<String> hints = s.getHints();
s.mSpec = null;
mItems.add(new SliceItem(action, s, SliceItem.FORMAT_ACTION, subType, hints.toArray(
@@ -468,7 +467,7 @@
*/
public Builder addIcon(Icon icon, @Nullable @SliceSubtype String subType,
@SliceHint List<String> hints) {
- Preconditions.checkNotNull(icon);
+ Objects.requireNonNull(icon);
mItems.add(new SliceItem(icon, SliceItem.FORMAT_IMAGE, subType, hints));
return this;
}
@@ -481,7 +480,7 @@
public Slice.Builder addRemoteInput(RemoteInput remoteInput,
@Nullable @SliceSubtype String subType,
@SliceHint List<String> hints) {
- Preconditions.checkNotNull(remoteInput);
+ Objects.requireNonNull(remoteInput);
mItems.add(new SliceItem(remoteInput, SliceItem.FORMAT_REMOTE_INPUT,
subType, hints));
return this;
@@ -529,7 +528,7 @@
*/
public Slice.Builder addBundle(Bundle bundle, @Nullable @SliceSubtype String subType,
@SliceHint List<String> hints) {
- Preconditions.checkNotNull(bundle);
+ Objects.requireNonNull(bundle);
mItems.add(new SliceItem(bundle, SliceItem.FORMAT_BUNDLE, subType,
hints));
return this;
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index 90ecce2..4da1acb 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -51,6 +51,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -241,7 +242,7 @@
* @see Slice
*/
public @Nullable Slice bindSlice(@NonNull Uri uri, @NonNull Set<SliceSpec> supportedSpecs) {
- Preconditions.checkNotNull(uri, "uri");
+ Objects.requireNonNull(uri, "uri");
ContentResolver resolver = mContext.getContentResolver();
try (ContentProviderClient provider = resolver.acquireUnstableContentProviderClient(uri)) {
if (provider == null) {
@@ -336,7 +337,7 @@
}
private Uri resolveStatic(@NonNull Intent intent, ContentResolver resolver) {
- Preconditions.checkNotNull(intent, "intent");
+ Objects.requireNonNull(intent, "intent");
Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
|| intent.getData() != null,
"Slice intent must be explicit %s", intent);
@@ -371,7 +372,7 @@
*/
public @Nullable Slice bindSlice(@NonNull Intent intent,
@NonNull Set<SliceSpec> supportedSpecs) {
- Preconditions.checkNotNull(intent, "intent");
+ Objects.requireNonNull(intent, "intent");
Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
|| intent.getData() != null,
"Slice intent must be explicit %s", intent);
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 7412970..4346d97 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -16,8 +16,6 @@
package android.app.usage;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import android.annotation.Nullable;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -42,6 +40,8 @@
import com.android.internal.annotations.VisibleForTesting;
+import java.util.Objects;
+
/**
* Provides access to network usage history and statistics. Usage data is collected in
* discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details.
@@ -418,7 +418,7 @@
/** @hide */
public void registerUsageCallback(NetworkTemplate template, int networkType,
long thresholdBytes, UsageCallback callback, @Nullable Handler handler) {
- checkNotNull(callback, "UsageCallback cannot be null");
+ Objects.requireNonNull(callback, "UsageCallback cannot be null");
final Looper looper;
if (handler == null) {
diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java
index eecf092..1ef1563 100644
--- a/core/java/android/app/usage/StorageStatsManager.java
+++ b/core/java/android/app/usage/StorageStatsManager.java
@@ -63,8 +63,8 @@
/** {@hide} */
public StorageStatsManager(Context context, IStorageStatsManager service) {
- mContext = Preconditions.checkNotNull(context);
- mService = Preconditions.checkNotNull(service);
+ mContext = Objects.requireNonNull(context);
+ mService = Objects.requireNonNull(service);
}
/** {@hide} */
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index 83eaa72..38498bc 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -472,63 +472,6 @@
}
/**
- * Get the volume of the device.
- *
- * <p> The volume is between -128 dB (mute) to 0 dB.
- *
- * @return volume of the hearing aid device.
- * @hide
- */
- @RequiresPermission(Manifest.permission.BLUETOOTH)
- public int getVolume() {
- if (VDBG) {
- log("getVolume()");
- }
- final IBluetoothHearingAid service = getService();
- try {
- if (service != null && isEnabled()) {
- return service.getVolume();
- }
- if (service == null) Log.w(TAG, "Proxy not attached to service");
- return 0;
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return 0;
- }
- }
-
- /**
- * Tells remote device to adjust volume. Uses the following values:
- * <ul>
- * <li>{@link AudioManager#ADJUST_LOWER}</li>
- * <li>{@link AudioManager#ADJUST_RAISE}</li>
- * <li>{@link AudioManager#ADJUST_MUTE}</li>
- * <li>{@link AudioManager#ADJUST_UNMUTE}</li>
- * </ul>
- *
- * @param direction One of the supported adjust values.
- * @hide
- */
- @RequiresPermission(Manifest.permission.BLUETOOTH)
- public void adjustVolume(int direction) {
- if (DBG) log("adjustVolume(" + direction + ")");
-
- final IBluetoothHearingAid service = getService();
- try {
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- return;
- }
-
- if (!isEnabled()) return;
-
- service.adjustVolume(direction);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- }
- }
-
- /**
* Tells remote device to set an absolute volume.
*
* @param volume Absolute volume to be set on remote
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 47edf2e..32803ab 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -202,6 +202,7 @@
public static final String TAG_OVERLAY = "overlay";
public static final String TAG_PACKAGE = "package";
public static final String TAG_PACKAGE_VERIFIER = "package-verifier";
+ public static final String TAG_FEATURE = "feature";
public static final String TAG_PERMISSION = "permission";
public static final String TAG_PERMISSION_GROUP = "permission-group";
public static final String TAG_PERMISSION_TREE = "permission-tree";
diff --git a/core/java/android/content/pm/VersionedPackage.java b/core/java/android/content/pm/VersionedPackage.java
index 3e22eb2..21df7ec 100644
--- a/core/java/android/content/pm/VersionedPackage.java
+++ b/core/java/android/content/pm/VersionedPackage.java
@@ -96,6 +96,20 @@
}
@Override
+ public boolean equals(Object o) {
+ return o instanceof VersionedPackage
+ && ((VersionedPackage) o).mPackageName.equals(mPackageName)
+ && ((VersionedPackage) o).mVersionCode == mVersionCode;
+ }
+
+ @Override
+ public int hashCode() {
+ // Roll our own hash function without using Objects#hash which incurs the overhead
+ // of autoboxing.
+ return 31 * mPackageName.hashCode() + Long.hashCode(mVersionCode);
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java
index 0562dff..990c835 100644
--- a/core/java/android/content/pm/parsing/AndroidPackage.java
+++ b/core/java/android/content/pm/parsing/AndroidPackage.java
@@ -27,6 +27,7 @@
import android.content.pm.SharedLibraryInfo;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
@@ -245,6 +246,9 @@
List<ParsedInstrumentation> getInstrumentations();
@Nullable
+ List<ParsedFeature> getFeatures();
+
+ @Nullable
List<ParsedPermissionGroup> getPermissionGroups();
@Nullable
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
index 3f22967..a001ada 100644
--- a/core/java/android/content/pm/parsing/ApkParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkParseUtils.java
@@ -793,6 +793,10 @@
parseResult = parseKeySets(parseInput, parsingPackage, res, parser);
success = parseResult.isSuccess();
break;
+ case PackageParser.TAG_FEATURE:
+ parseResult = parseFeature(parseInput, parsingPackage, res, parser);
+ success = parseResult.isSuccess();
+ break;
case PackageParser.TAG_PERMISSION_GROUP:
parseResult = parsePermissionGroup(parseInput, parsingPackage, res,
parser);
@@ -880,6 +884,13 @@
);
}
+ if (!ComponentParseUtils.ParsedFeature.isCombinationValid(parsingPackage.getFeatures())) {
+ return parseInput.error(
+ INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Combination <feature> tags are not valid"
+ );
+ }
+
convertNewPermissions(parsingPackage);
convertSplitPermissions(parsingPackage);
@@ -1260,6 +1271,31 @@
return parseInput.success(parsingPackage);
}
+ private static ParseResult parseFeature(
+ ParseInput parseInput,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser
+ ) throws IOException, XmlPullParserException {
+ // TODO(b/135203078): Remove, replace with ParseResult
+ String[] outError = new String[1];
+
+ ComponentParseUtils.ParsedFeature parsedFeature =
+ ComponentParseUtils.parseFeature(res, parser, outError);
+
+ if (parsedFeature == null || outError[0] != null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.addFeature(parsedFeature);
+
+ return parseInput.success(parsingPackage);
+ }
+
+
private static ParseResult parsePermissionGroup(
ParseInput parseInput,
ParsingPackage parsingPackage,
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
index fc210b2..7b24d3d 100644
--- a/core/java/android/content/pm/parsing/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java
@@ -24,6 +24,9 @@
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityTaskManager;
import android.content.ComponentName;
@@ -47,6 +50,7 @@
import android.os.Parcelable;
import android.os.PatternMatcher;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
@@ -54,6 +58,7 @@
import android.view.Gravity;
import com.android.internal.R;
+import com.android.internal.util.DataClass;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -62,6 +67,7 @@
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
@@ -931,6 +937,186 @@
};
}
+ /**
+ * A {@link android.R.styleable#AndroidManifestFeature <feature>} tag parsed from the
+ * manifest.
+ */
+ // @DataClass verifier is broken, hence comment out for now
+ public static class ParsedFeature implements Parcelable {
+ /** Maximum length of featureId */
+ public static final int MAX_FEATURE_ID_LEN = 50;
+
+ /** Maximum amount of features per package */
+ private static final int MAX_NUM_FEATURES = 1000;
+
+ /** Id of the feature */
+ public final @NonNull String id;
+
+ /** User visible label fo the feature */
+ public final @StringRes int label;
+
+ /** Ids of previously declared features this feature inherits from */
+ public final @NonNull List<String> inheritFrom;
+
+ /**
+ * @return Is this set of features a valid combination for a single package?
+ */
+ public static boolean isCombinationValid(@Nullable List<ParsedFeature> features) {
+ if (features == null) {
+ return true;
+ }
+
+ ArraySet<String> featureIds = new ArraySet<>(features.size());
+ ArraySet<String> inheritFromFeatureIds = new ArraySet<>();
+
+ int numFeatures = features.size();
+ if (numFeatures > MAX_NUM_FEATURES) {
+ return false;
+ }
+
+ for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
+ boolean wasAdded = featureIds.add(features.get(featureNum).id);
+ if (!wasAdded) {
+ // feature id is not unique
+ return false;
+ }
+ }
+
+ for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
+ ParsedFeature feature = features.get(featureNum);
+
+ int numInheritFrom = feature.inheritFrom.size();
+ for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) {
+ String inheritFrom = feature.inheritFrom.get(inheritFromNum);
+
+ if (featureIds.contains(inheritFrom)) {
+ // Cannot inherit from a feature that is still defined
+ return false;
+ }
+
+ boolean wasAdded = inheritFromFeatureIds.add(inheritFrom);
+ if (!wasAdded) {
+ // inheritFrom is not unique
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+
+
+ // Code below generated by codegen v1.0.14.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/ComponentParseUtils.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new ParsedFeature.
+ *
+ * @param id
+ * Id of the feature
+ * @param label
+ * User visible label fo the feature (if defined as resource)
+ * @param inheritFrom
+ * Ids of previously declared features this feature inherits from
+ */
+ @DataClass.Generated.Member
+ public ParsedFeature(
+ @NonNull String id,
+ @StringRes int label,
+ @NonNull List<String> inheritFrom) {
+ this.id = id;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, id);
+ this.label = label;
+ com.android.internal.util.AnnotationValidations.validate(
+ StringRes.class, null, label);
+ this.inheritFrom = inheritFrom;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, inheritFrom);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeString(id);
+ dest.writeInt(label);
+ dest.writeStringList(inheritFrom);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected ParsedFeature(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ String _id = in.readString();
+ int _label = in.readInt();
+ List<String> _inheritFrom = new ArrayList<>();
+ in.readStringList(_inheritFrom);
+
+ this.id = _id;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, id);
+ this.label = _label;
+ com.android.internal.util.AnnotationValidations.validate(
+ StringRes.class, null, label);
+ this.inheritFrom = _inheritFrom;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, inheritFrom);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<ParsedFeature> CREATOR
+ = new Parcelable.Creator<ParsedFeature>() {
+ @Override
+ public ParsedFeature[] newArray(int size) {
+ return new ParsedFeature[size];
+ }
+
+ @Override
+ public ParsedFeature createFromParcel(@NonNull Parcel in) {
+ return new ParsedFeature(in);
+ }
+ };
+
+ /*@DataClass.Generated(
+ time = 1576783172965L,
+ codegenVersion = "1.0.14",
+ sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ComponentParseUtils.java",
+ inputSignatures = "public final @android.annotation.NonNull java.lang.String id\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static boolean isCombinationValid(java.util.List<android.content.pm.parsing.ParsedFeature>)\nclass ParsedFeature extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
+ */
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+ }
+
public static class ParsedPermission extends ParsedComponent<ParsedIntentInfo> {
public String backgroundPermission;
@@ -2566,6 +2752,85 @@
return result;
}
+ public static ParsedFeature parseFeature(
+ Resources res,
+ XmlResourceParser parser,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ String featureId;
+ int label;
+ List<String> inheritFrom = null;
+
+ TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeature);
+ if (sa == null) {
+ outError[0] = "<feature> could not be parsed";
+ return null;
+ }
+
+ try {
+ featureId = sa.getNonConfigurationString(R.styleable.AndroidManifestFeature_featureId,
+ 0);
+ if (featureId == null) {
+ outError[0] = "<featureId> does not specify android:featureId";
+ return null;
+ }
+ if (featureId.length() > ParsedFeature.MAX_FEATURE_ID_LEN) {
+ outError[0] = "<featureId> is too long. Max length is "
+ + ParsedFeature.MAX_FEATURE_ID_LEN;
+ return null;
+ }
+
+ label = sa.getResourceId(R.styleable.AndroidManifestFeature_label, 0);
+ if (label == Resources.ID_NULL) {
+ outError[0] = "<featureId> does not specify android:label";
+ return null;
+ }
+ } finally {
+ sa.recycle();
+ }
+
+ int type;
+ final int innerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("inherit-from")) {
+ sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeatureInheritFrom);
+ if (sa == null) {
+ outError[0] = "<inherit-from> could not be parsed";
+ return null;
+ }
+
+ try {
+ String inheritFromId = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestFeatureInheritFrom_featureId,0);
+
+ if (inheritFrom == null) {
+ inheritFrom = new ArrayList<>();
+ }
+ inheritFrom.add(inheritFromId);
+ } finally {
+ sa.recycle();
+ }
+ } else {
+ outError[0] = "Bad element under <feature>: " + tagName;
+ return null;
+ }
+ }
+
+ if (inheritFrom == null) {
+ inheritFrom = Collections.emptyList();
+ } else {
+ ((ArrayList) inheritFrom).trimToSize();
+ }
+
+ return new ParsedFeature(featureId, label, inheritFrom);
+ }
+
public static ParsedPermission parsePermission(
ParsingPackage parsingPackage,
Resources res,
diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java
index 18dee23..8677fce 100644
--- a/core/java/android/content/pm/parsing/PackageImpl.java
+++ b/core/java/android/content/pm/parsing/PackageImpl.java
@@ -36,6 +36,7 @@
import android.content.pm.SharedLibraryInfo;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
@@ -175,6 +176,9 @@
private ArrayList<ComponentParseUtils.ParsedProvider> providers;
@Nullable
+ private ArrayList<ComponentParseUtils.ParsedFeature> features;
+
+ @Nullable
private ArrayList<ComponentParseUtils.ParsedPermission> permissions;
@Nullable
@@ -580,6 +584,12 @@
return permissions;
}
+ @Nullable
+ @Override
+ public List<ParsedFeature> getFeatures() {
+ return features;
+ }
+
@Override
public String getCpuAbiOverride() {
return cpuAbiOverride;
@@ -792,6 +802,12 @@
}
@Override
+ public PackageImpl addFeature(ParsedFeature feature) {
+ this.features = ArrayUtils.add(this.features, feature);
+ return this;
+ }
+
+ @Override
public PackageImpl addPermission(ParsedPermission permission) {
this.permissions = ArrayUtils.add(this.permissions, permission);
return this;
@@ -3021,6 +3037,7 @@
dest.writeTypedList(this.receivers);
dest.writeTypedList(this.services);
dest.writeTypedList(this.providers);
+ dest.writeTypedList(this.features);
dest.writeTypedList(this.permissions);
dest.writeTypedList(this.permissionGroups);
dest.writeTypedList(this.instrumentations);
@@ -3173,6 +3190,7 @@
this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR);
this.services = in.createTypedArrayList(ParsedService.CREATOR);
this.providers = in.createTypedArrayList(ParsedProvider.CREATOR);
+ this.features = in.createTypedArrayList(ParsedFeature.CREATOR);
this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR);
this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR);
this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR);
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 47dac55..411c749 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -24,6 +24,7 @@
import android.content.pm.PackageParser;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
@@ -64,6 +65,8 @@
ParsingPackage addOverlayable(String overlayableName, String actorName);
+ ParsingPackage addFeature(ParsedFeature permission);
+
ParsingPackage addPermission(ParsedPermission permission);
ParsingPackage addPermissionGroup(ParsedPermissionGroup permissionGroup);
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index c89796d..6378db0 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -88,6 +89,11 @@
private final SparseLongArray mCeSnapshotInodes;
/**
+ * The userdata policy to execute when a rollback for this package is committed.
+ */
+ private final int mRollbackDataPolicy;
+
+ /**
* Returns the name of the package to roll back from.
*/
@NonNull
@@ -148,6 +154,11 @@
}
/** @hide */
+ public @PackageManager.RollbackDataPolicy int getRollbackDataPolicy() {
+ return mRollbackDataPolicy;
+ }
+
+ /** @hide */
public IntArray getSnapshottedUsers() {
return mSnapshottedUsers;
}
@@ -181,11 +192,23 @@
@NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores,
boolean isApex, @NonNull IntArray snapshottedUsers,
@NonNull SparseLongArray ceSnapshotInodes) {
+ this(packageRolledBackFrom, packageRolledBackTo, pendingBackups, pendingRestores, isApex,
+ snapshottedUsers, ceSnapshotInodes, PackageManager.RollbackDataPolicy.RESTORE);
+ }
+
+ /** @hide */
+ public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
+ VersionedPackage packageRolledBackTo,
+ @NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores,
+ boolean isApex, @NonNull IntArray snapshottedUsers,
+ @NonNull SparseLongArray ceSnapshotInodes,
+ @PackageManager.RollbackDataPolicy int rollbackDataPolicy) {
this.mVersionRolledBackFrom = packageRolledBackFrom;
this.mVersionRolledBackTo = packageRolledBackTo;
this.mPendingBackups = pendingBackups;
this.mPendingRestores = pendingRestores;
this.mIsApex = isApex;
+ this.mRollbackDataPolicy = rollbackDataPolicy;
this.mSnapshottedUsers = snapshottedUsers;
this.mCeSnapshotInodes = ceSnapshotInodes;
}
@@ -198,6 +221,7 @@
this.mPendingBackups = null;
this.mSnapshottedUsers = null;
this.mCeSnapshotInodes = null;
+ this.mRollbackDataPolicy = PackageManager.RollbackDataPolicy.RESTORE;
}
@Override
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 7e1506f..4c114fd 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -90,19 +90,19 @@
* @hide
*/
@SystemApi
- int EMPTY_SET = 0x0;
+ int EMPTY_SET = 0x0000;
/**
* Placeholder for the theoretical strongest biometric security tier.
* @hide
*/
- int BIOMETRIC_MAX_STRENGTH = 0x001;
+ int BIOMETRIC_MAX_STRENGTH = 0x0001;
/**
* Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the
* requirements for <strong>Strong</strong>, as defined by the Android CDD.
*/
- int BIOMETRIC_STRONG = 0x00F;
+ int BIOMETRIC_STRONG = 0x000F;
/**
* Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the
@@ -111,7 +111,7 @@
* <p>Note that this is a superset of {@link #BIOMETRIC_STRONG} and is defined such that
* <code>BIOMETRIC_STRONG | BIOMETRIC_WEAK == BIOMETRIC_WEAK</code>.
*/
- int BIOMETRIC_WEAK = 0x0FF;
+ int BIOMETRIC_WEAK = 0x00FF;
/**
* Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the
@@ -121,7 +121,7 @@
* @hide
*/
@SystemApi
- int BIOMETRIC_CONVENIENCE = 0xFFF;
+ int BIOMETRIC_CONVENIENCE = 0x0FFF;
/**
* Placeholder for the theoretical weakest biometric security tier.
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index c3ebe43..6f90db4 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -240,6 +240,11 @@
*
* <p>This value is looked up the first time, and cached subsequently.</p>
*
+ * <p>This function may be called without cacheTag() if this is not a vendor key.
+ * If this is a vendor key, cacheTag() must be called first before getTag() can
+ * be called. Otherwise, mVendorId could be default (Long.MAX_VALUE) and vendor
+ * tag lookup could fail.</p>
+ *
* @return The tag numeric value corresponding to the string
*/
@UnsupportedAppUsage
@@ -252,6 +257,27 @@
}
/**
+ * Whether this key's tag is cached.
+ *
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public final boolean hasTag() {
+ return mHasTag;
+ }
+
+ /**
+ * Cache this key's tag.
+ *
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public final void cacheTag(int tag) {
+ mHasTag = true;
+ mTag = tag;
+ }
+
+ /**
* Get the raw class backing the type {@code T} for this key.
*
* <p>The distinction is only important if {@code T} is a generic, e.g.
@@ -523,7 +549,13 @@
}
private <T> T getBase(Key<T> key) {
- int tag = nativeGetTagFromKeyLocal(key.getName());
+ int tag;
+ if (key.hasTag()) {
+ tag = key.getTag();
+ } else {
+ tag = nativeGetTagFromKeyLocal(key.getName());
+ key.cacheTag(tag);
+ }
byte[] values = readValues(tag);
if (values == null) {
// If the key returns null, use the fallback key if exists.
@@ -1451,7 +1483,13 @@
}
private <T> void setBase(Key<T> key, T value) {
- int tag = nativeGetTagFromKeyLocal(key.getName());
+ int tag;
+ if (key.hasTag()) {
+ tag = key.getTag();
+ } else {
+ tag = nativeGetTagFromKeyLocal(key.getName());
+ key.cacheTag(tag);
+ }
if (value == null) {
// Erase the entry
writeValues(tag, /*src*/null);
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index a45f703..fe4f860 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -722,15 +722,6 @@
}
/**
- * Returns whether inline suggestions are enabled on this service.
- *
- * TODO(b/137800469): check XML for value.
- */
- private boolean isInlineSuggestionsEnabled() {
- return true;
- }
-
- /**
* Sends an {@link InlineSuggestionsRequest} obtained from
* {@link #onCreateInlineSuggestionsRequest()} to the current Autofill Session through
* {@link IInlineSuggestionsRequestCallback#onInlineSuggestionsRequest}.
@@ -763,23 +754,14 @@
private void handleOnCreateInlineSuggestionsRequest(@NonNull ComponentName componentName,
@NonNull AutofillId autofillId, @NonNull IInlineSuggestionsRequestCallback callback) {
- mInlineSuggestionsRequestInfo = new InlineSuggestionsRequestInfo(componentName, autofillId,
- callback);
-
- if (!isInlineSuggestionsEnabled()) {
- try {
- callback.onInlineSuggestionsUnsupported();
- } catch (RemoteException e) {
- Log.w(TAG, "handleMakeInlineSuggestionsRequest() RemoteException:" + e);
- }
- return;
- }
-
if (!mInputStarted) {
Log.w(TAG, "onStartInput() not called yet");
return;
}
+ mInlineSuggestionsRequestInfo = new InlineSuggestionsRequestInfo(componentName, autofillId,
+ callback);
+
makeInlineSuggestionsRequest();
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 1c4ef382..3d44944 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -2590,4 +2590,12 @@
* @hide
*/
public static native long getIonMappedSizeKb();
+
+ /**
+ * Return whether virtually-mapped kernel stacks are enabled (CONFIG_VMAP_STACK).
+ * Note: caller needs config_gz read sepolicy permission
+ *
+ * @hide
+ */
+ public static native boolean isVmapStack();
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index a3215a4..2583292 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -318,8 +318,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(allOf = {Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
- Manifest.permission.PACKAGE_USAGE_STATS})
+ @RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS)
public void startOneTimePermissionSession(@NonNull String packageName, long timeoutMillis,
@ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer,
@ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) {
@@ -340,8 +339,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(allOf = {Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
- Manifest.permission.PACKAGE_USAGE_STATS})
+ @RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS)
public void stopOneTimePermissionSession(@NonNull String packageName) {
try {
mPermissionManager.stopOneTimePermissionSession(packageName,
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index b7ec281..fbc25a6 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -80,6 +80,8 @@
@Nullable
private final ArrayMap<String, Long> mCompatibilityPackages;
+ private final boolean mInlineSuggestionsEnabled;
+
public AutofillServiceInfo(Context context, ComponentName comp, int userHandle)
throws PackageManager.NameNotFoundException {
this(context, getServiceInfoOrThrow(comp, userHandle));
@@ -112,11 +114,13 @@
if (parser == null) {
mSettingsActivity = null;
mCompatibilityPackages = null;
+ mInlineSuggestionsEnabled = false;
return;
}
String settingsActivity = null;
ArrayMap<String, Long> compatibilityPackages = null;
+ boolean inlineSuggestionsEnabled = false; // false by default.
try {
final Resources resources = context.getPackageManager().getResourcesForApplication(
@@ -135,6 +139,8 @@
com.android.internal.R.styleable.AutofillService);
settingsActivity = afsAttributes.getString(
R.styleable.AutofillService_settingsActivity);
+ inlineSuggestionsEnabled = afsAttributes.getBoolean(
+ R.styleable.AutofillService_supportsInlineSuggestions, false);
} finally {
if (afsAttributes != null) {
afsAttributes.recycle();
@@ -150,6 +156,7 @@
mSettingsActivity = settingsActivity;
mCompatibilityPackages = compatibilityPackages;
+ mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
}
private ArrayMap<String, Long> parseCompatibilityPackages(XmlPullParser parser,
@@ -227,6 +234,10 @@
return mCompatibilityPackages;
}
+ public boolean isInlineSuggestionsEnabled() {
+ return mInlineSuggestionsEnabled;
+ }
+
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
@@ -235,6 +246,7 @@
builder.append(", settings:").append(mSettingsActivity);
builder.append(", hasCompatPckgs:").append(mCompatibilityPackages != null
&& !mCompatibilityPackages.isEmpty()).append("]");
+ builder.append(", inline suggestions enabled:").append(mInlineSuggestionsEnabled);
return builder.toString();
}
@@ -245,5 +257,7 @@
pw.print(prefix); pw.print("Component: "); pw.println(getServiceInfo().getComponentName());
pw.print(prefix); pw.print("Settings: "); pw.println(mSettingsActivity);
pw.print(prefix); pw.print("Compat packages: "); pw.println(mCompatibilityPackages);
+ pw.print(prefix); pw.print("Inline Suggestions Enabled: ");
+ pw.println(mInlineSuggestionsEnabled);
}
}
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 484eddc..6334d9d 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -38,6 +38,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.service.autofill.Dataset;
import android.service.autofill.augmented.PresentationParams.SystemPopupPresentationParams;
import android.util.Log;
import android.util.Pair;
@@ -47,6 +48,7 @@
import android.view.autofill.AutofillValue;
import android.view.autofill.IAugmentedAutofillManagerClient;
import android.view.autofill.IAutofillWindowPresenter;
+import android.view.inputmethod.InlineSuggestionsRequest;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -106,10 +108,11 @@
@Override
public void onFillRequest(int sessionId, IBinder client, int taskId,
ComponentName componentName, AutofillId focusedId, AutofillValue focusedValue,
- long requestTime, IFillCallback callback) {
+ long requestTime, @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
+ IFillCallback callback) {
mHandler.sendMessage(obtainMessage(AugmentedAutofillService::handleOnFillRequest,
AugmentedAutofillService.this, sessionId, client, taskId, componentName,
- focusedId, focusedValue, requestTime, callback));
+ focusedId, focusedValue, requestTime, inlineSuggestionsRequest, callback));
}
@Override
@@ -212,6 +215,7 @@
private void handleOnFillRequest(int sessionId, @NonNull IBinder client, int taskId,
@NonNull ComponentName componentName, @NonNull AutofillId focusedId,
@Nullable AutofillValue focusedValue, long requestTime,
+ @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
@NonNull IFillCallback callback) {
if (mAutofillProxies == null) {
mAutofillProxies = new SparseArray<>();
@@ -236,9 +240,8 @@
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
- // TODO(b/146453195): pass the inline suggestion request over.
- onFillRequest(new FillRequest(proxy, /* inlineSuggestionsRequest= */null),
- cancellationSignal, new FillController(proxy), new FillCallback(proxy));
+ onFillRequest(new FillRequest(proxy, inlineSuggestionsRequest), cancellationSignal,
+ new FillController(proxy), new FillCallback(proxy));
}
private void handleOnDestroyAllFillWindowsRequest() {
@@ -484,6 +487,14 @@
}
}
+ public void onInlineSuggestionsDataReady(@NonNull List<Dataset> inlineSuggestionsData) {
+ try {
+ mCallback.onSuccess(inlineSuggestionsData.toArray(new Dataset[]{}));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling back with the inline suggestions data: " + e);
+ }
+ }
+
// Used (mostly) for metrics.
public void report(@ReportEvent int event) {
if (sVerbose) Log.v(TAG, "report(): " + event);
diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java
index 0251386..b767799 100644
--- a/core/java/android/service/autofill/augmented/FillCallback.java
+++ b/core/java/android/service/autofill/augmented/FillCallback.java
@@ -21,9 +21,12 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.service.autofill.Dataset;
import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
import android.util.Log;
+import java.util.List;
+
/**
* Callback used to indicate at {@link FillRequest} has been fulfilled.
*
@@ -45,7 +48,7 @@
* Sets the response associated with the request.
*
* @param response response associated with the request, or {@code null} if the service
- * could not provide autofill for the request.
+ * could not provide autofill for the request.
*/
public void onSuccess(@Nullable FillResponse response) {
if (sDebug) Log.d(TAG, "onSuccess(): " + response);
@@ -55,6 +58,12 @@
return;
}
+ List<Dataset> inlineSuggestions = response.getInlineSuggestions();
+ if (inlineSuggestions != null && !inlineSuggestions.isEmpty()) {
+ mProxy.onInlineSuggestionsDataReady(inlineSuggestions);
+ return;
+ }
+
final FillWindow fillWindow = response.getFillWindow();
if (fillWindow != null) {
fillWindow.show();
diff --git a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
index 103fc4d..4911348 100644
--- a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
+++ b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
@@ -22,6 +22,7 @@
import android.service.autofill.augmented.IFillCallback;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
+import android.view.inputmethod.InlineSuggestionsRequest;
import java.util.List;
@@ -35,7 +36,9 @@
void onDisconnected();
void onFillRequest(int sessionId, in IBinder autofillManagerClient, int taskId,
in ComponentName activityComponent, in AutofillId focusedId,
- in AutofillValue focusedValue, long requestTime, in IFillCallback callback);
+ in AutofillValue focusedValue, long requestTime,
+ in InlineSuggestionsRequest inlineSuggestionsRequest,
+ in IFillCallback callback);
void onDestroyAllFillWindowsRequest();
}
diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java
index 2fd51a1..eca8541 100644
--- a/core/java/android/service/controls/ControlsProviderService.java
+++ b/core/java/android/service/controls/ControlsProviderService.java
@@ -20,7 +20,6 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Service;
import android.content.Intent;
-import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -88,7 +87,7 @@
* {@link Control.StatelessBuilder}).
* @param controls
*/
- public void onLoad(@NonNull List<Control> controls) {
+ public final void onLoad(@NonNull List<Control> controls) {
Preconditions.checkNotNull(controls);
List<Control> list = new ArrayList<>();
for (Control control: controls) {
@@ -114,7 +113,7 @@
* their state.
* @param statefulControls
*/
- public void onRefreshState(@NonNull List<Control> statefulControls) {
+ public final void onRefreshState(@NonNull List<Control> statefulControls) {
Preconditions.checkNotNull(statefulControls);
try {
mCallback.onRefreshState(mToken, statefulControls);
@@ -128,7 +127,7 @@
* @param controlId
* @param response
*/
- public void onControlActionResponse(
+ public final void onControlActionResponse(
@NonNull String controlId, @ControlAction.ResponseResult int response) {
Preconditions.checkNotNull(controlId);
if (!ControlAction.isValidResponse(response)) {
@@ -172,7 +171,7 @@
public void onAction(String id, ControlAction action) {
ActionMessage msg = new ActionMessage(id, action);
- mHandler.obtainMessage(RequestHandler.MSG_SUBSCRIBE, msg).sendToTarget();
+ mHandler.obtainMessage(RequestHandler.MSG_ON_ACTION, msg).sendToTarget();
}
};
}
diff --git a/core/java/android/service/controls/templates/ThermostatTemplate.aidl b/core/java/android/service/controls/templates/TemperatureControlTemplate.aidl
similarity index 94%
rename from core/java/android/service/controls/templates/ThermostatTemplate.aidl
rename to core/java/android/service/controls/templates/TemperatureControlTemplate.aidl
index 1fefda4..7994d26 100644
--- a/core/java/android/service/controls/templates/ThermostatTemplate.aidl
+++ b/core/java/android/service/controls/templates/TemperatureControlTemplate.aidl
@@ -16,4 +16,4 @@
package android.service.controls.templates;
-parcelable ThermostatTemplate;
\ No newline at end of file
+parcelable TemperatureControlTemplate;
\ No newline at end of file
diff --git a/core/java/android/telephony/SubscriptionPlan.java b/core/java/android/telephony/SubscriptionPlan.java
index 28a5c20..ff2f4ad 100644
--- a/core/java/android/telephony/SubscriptionPlan.java
+++ b/core/java/android/telephony/SubscriptionPlan.java
@@ -228,24 +228,6 @@
}
/**
- * Return the networkTypes array converted to a {@link TelephonyManager.NetworkTypeBitMask}
- * @hide
- */
- public long getNetworkTypesBitMask() {
- // calculate bitmask the first time and save for future calls
- if (networkTypesBitMask == 0) {
- if (networkTypes == null) {
- networkTypesBitMask = ~0;
- } else {
- for (int networkType : networkTypes) {
- networkTypesBitMask |= TelephonyManager.getBitMaskForNetworkType(networkType);
- }
- }
- }
- return networkTypesBitMask;
- }
-
- /**
* Return an iterator that will return all valid data usage cycles based on
* any recurrence rules. The iterator starts from the currently active cycle
* and walks backwards through time.
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 08e4eeb..5f74b2a 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -82,9 +82,6 @@
// Input event dispatching is paused.
public boolean paused;
- // Window layer.
- public int layer;
-
// Id of process and user that owns the window.
public int ownerPid;
public int ownerUid;
@@ -126,7 +123,6 @@
@Override
public String toString() {
return new StringBuilder(name != null ? name : "")
- .append(", layer=").append(layer)
.append(", frame=[").append(frameLeft).append(",").append(frameTop).append(",")
.append(frameRight).append(",").append(frameBottom).append("]")
.append(", touchableRegion=").append(touchableRegion)
diff --git a/core/java/android/view/autofill/AutofillValue.java b/core/java/android/view/autofill/AutofillValue.java
index 64c8777..cfd624ac 100644
--- a/core/java/android/view/autofill/AutofillValue.java
+++ b/core/java/android/view/autofill/AutofillValue.java
@@ -68,7 +68,7 @@
}
/**
- * Checks is this is a text value.
+ * Checks if this is a text value.
*
* <p>See {@link View#AUTOFILL_TYPE_TEXT} for more info.</p>
*/
@@ -89,7 +89,7 @@
}
/**
- * Checks is this is a toggle value.
+ * Checks if this is a toggle value.
*
* <p>See {@link View#AUTOFILL_TYPE_TOGGLE} for more info.</p>
*/
@@ -110,7 +110,7 @@
}
/**
- * Checks is this is a list value.
+ * Checks if this is a list value.
*
* <p>See {@link View#AUTOFILL_TYPE_LIST} for more info.</p>
*/
@@ -131,7 +131,7 @@
}
/**
- * Checks is this is a date value.
+ * Checks if this is a date value.
*
* <p>See {@link View#AUTOFILL_TYPE_DATE} for more info.</p>
*/
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 34005ac..2864485 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -58,6 +58,7 @@
* @attr ref android.R.styleable#InputMethod_settingsActivity
* @attr ref android.R.styleable#InputMethod_isDefault
* @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
+ * @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions
*/
public final class InputMethodInfo implements Parcelable {
static final String TAG = "InputMethodInfo";
@@ -111,6 +112,11 @@
private final boolean mSupportsSwitchingToNextInputMethod;
/**
+ * The flag whether this IME supports inline suggestions.
+ */
+ private final boolean mInlineSuggestionsEnabled;
+
+ /**
* @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
* @return a unique ID to be returned by {@link #getId()}. We have used
* {@link ComponentName#flattenToShortString()} for this purpose (and it is already
@@ -152,6 +158,7 @@
mId = computeId(service);
boolean isAuxIme = true;
boolean supportsSwitchingToNextInputMethod = false; // false as default
+ boolean inlineSuggestionsEnabled = false; // false as default
mForceDefault = false;
PackageManager pm = context.getPackageManager();
@@ -193,6 +200,8 @@
supportsSwitchingToNextInputMethod = sa.getBoolean(
com.android.internal.R.styleable.InputMethod_supportsSwitchingToNextInputMethod,
false);
+ inlineSuggestionsEnabled = sa.getBoolean(
+ com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false);
sa.recycle();
final int depth = parser.getDepth();
@@ -263,6 +272,7 @@
mIsDefaultResId = isDefaultResId;
mIsAuxIme = isAuxIme;
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
+ mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
mIsVrOnly = isVrOnly;
}
@@ -272,6 +282,7 @@
mIsDefaultResId = source.readInt();
mIsAuxIme = source.readInt() == 1;
mSupportsSwitchingToNextInputMethod = source.readInt() == 1;
+ mInlineSuggestionsEnabled = source.readInt() == 1;
mIsVrOnly = source.readBoolean();
mService = ResolveInfo.CREATOR.createFromParcel(source);
mSubtypes = new InputMethodSubtypeArray(source);
@@ -286,7 +297,7 @@
this(buildDummyResolveInfo(packageName, className, label), false /* isAuxIme */,
settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
- false /* isVrOnly */);
+ false /* inlineSuggestionsEnabled */, false /* isVrOnly */);
}
/**
@@ -297,7 +308,8 @@
String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
boolean forceDefault) {
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
- true /* supportsSwitchingToNextInputMethod */, false /* isVrOnly */);
+ true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */,
+ false /* isVrOnly */);
}
/**
@@ -307,6 +319,18 @@
public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) {
+ this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
+ supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly);
+ }
+
+ /**
+ * Temporary API for creating a built-in input method for test.
+ * @hide
+ */
+ public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
+ List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
+ boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled,
+ boolean isVrOnly) {
final ServiceInfo si = ri.serviceInfo;
mService = ri;
mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -316,6 +340,7 @@
mSubtypes = new InputMethodSubtypeArray(subtypes);
mForceDefault = forceDefault;
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
+ mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
mIsVrOnly = isVrOnly;
}
@@ -467,7 +492,8 @@
pw.println(prefix + "mId=" + mId
+ " mSettingsActivityName=" + mSettingsActivityName
+ " mIsVrOnly=" + mIsVrOnly
- + " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod);
+ + " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod
+ + " mInlineSuggestionsEnabled=" + mInlineSuggestionsEnabled);
pw.println(prefix + "mIsDefaultResId=0x"
+ Integer.toHexString(mIsDefaultResId));
pw.println(prefix + "Service:");
@@ -528,6 +554,14 @@
}
/**
+ * @return true if this input method supports inline suggestions.
+ * @hide
+ */
+ public boolean isInlineSuggestionsEnabled() {
+ return mInlineSuggestionsEnabled;
+ }
+
+ /**
* Used to package this object into a {@link Parcel}.
*
* @param dest The {@link Parcel} to be written.
@@ -540,6 +574,7 @@
dest.writeInt(mIsDefaultResId);
dest.writeInt(mIsAuxIme ? 1 : 0);
dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0);
+ dest.writeInt(mInlineSuggestionsEnabled ? 1 : 0);
dest.writeBoolean(mIsVrOnly);
mService.writeToParcel(dest, flags);
mSubtypes.writeToParcel(dest);
diff --git a/core/java/android/view/textclassifier/TextClassificationSession.java b/core/java/android/view/textclassifier/TextClassificationSession.java
index abfbc6c..4329a20 100644
--- a/core/java/android/view/textclassifier/TextClassificationSession.java
+++ b/core/java/android/view/textclassifier/TextClassificationSession.java
@@ -20,6 +20,7 @@
import android.view.textclassifier.SelectionEvent.InvocationMethod;
import com.android.internal.util.Preconditions;
+
import java.util.Objects;
/**
@@ -183,6 +184,7 @@
mSmartEvent = event;
break;
case SelectionEvent.ACTION_ABANDON:
+ case SelectionEvent.ACTION_OVERTYPE:
if (mPrevEvent != null) {
event.setEntityType(mPrevEvent.getEntityType());
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 3b6a009..f6aaa6f 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -139,6 +139,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* Helper class used by TextView to handle editable text views.
@@ -7062,11 +7063,11 @@
private final List<ResolveInfo> mSupportedActivities = new ArrayList<>();
private ProcessTextIntentActionsHandler(Editor editor) {
- mEditor = Preconditions.checkNotNull(editor);
- mTextView = Preconditions.checkNotNull(mEditor.mTextView);
- mContext = Preconditions.checkNotNull(mTextView.getContext());
- mPackageManager = Preconditions.checkNotNull(mContext.getPackageManager());
- mPackageName = Preconditions.checkNotNull(mContext.getPackageName());
+ mEditor = Objects.requireNonNull(editor);
+ mTextView = Objects.requireNonNull(mEditor.mTextView);
+ mContext = Objects.requireNonNull(mTextView.getContext());
+ mPackageManager = Objects.requireNonNull(mContext.getPackageManager());
+ mPackageName = Objects.requireNonNull(mContext.getPackageName());
}
/**
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index f58b6d1..2924dd9 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -62,6 +62,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* Android magnifier widget. Can be used by any view which is attached to a window.
@@ -1154,7 +1155,7 @@
* @param view the view this magnifier is attached to
*/
public Builder(@NonNull View view) {
- mView = Preconditions.checkNotNull(view);
+ mView = Objects.requireNonNull(view);
applyDefaults();
}
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index d0f8093..4ef3f61 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -87,7 +87,7 @@
private final SmartSelectSprite mSmartSelectSprite;
SelectionActionModeHelper(@NonNull Editor editor) {
- mEditor = Preconditions.checkNotNull(editor);
+ mEditor = Objects.requireNonNull(editor);
mTextView = mEditor.getTextView();
mTextClassificationHelper = new TextClassificationHelper(
mTextView.getContext(),
@@ -500,7 +500,7 @@
private final LogAbandonRunnable mDelayedLogAbandon = new LogAbandonRunnable();
SelectionTracker(TextView textView) {
- mTextView = Preconditions.checkNotNull(textView);
+ mTextView = Objects.requireNonNull(textView);
mLogger = new SelectionMetricsLogger(textView);
}
@@ -703,7 +703,7 @@
private String mText;
SelectionMetricsLogger(TextView textView) {
- Preconditions.checkNotNull(textView);
+ Objects.requireNonNull(textView);
mEditTextLogger = textView.isTextEditable();
mTokenIterator = SelectionSessionLogger.getTokenIterator(textView.getTextLocale());
}
@@ -714,7 +714,7 @@
CharSequence text, int index,
@InvocationMethod int invocationMethod) {
try {
- Preconditions.checkNotNull(text);
+ Objects.requireNonNull(text);
Preconditions.checkArgumentInRange(index, 0, text.length(), "index");
if (mText == null || !mText.contentEquals(text)) {
mText = text.toString();
@@ -972,11 +972,11 @@
@NonNull Consumer<SelectionResult> selectionResultCallback,
@NonNull Supplier<SelectionResult> timeOutResultSupplier) {
super(textView != null ? textView.getHandler() : null);
- mTextView = Preconditions.checkNotNull(textView);
+ mTextView = Objects.requireNonNull(textView);
mTimeOutDuration = timeOut;
- mSelectionResultSupplier = Preconditions.checkNotNull(selectionResultSupplier);
- mSelectionResultCallback = Preconditions.checkNotNull(selectionResultCallback);
- mTimeOutResultSupplier = Preconditions.checkNotNull(timeOutResultSupplier);
+ mSelectionResultSupplier = Objects.requireNonNull(selectionResultSupplier);
+ mSelectionResultCallback = Objects.requireNonNull(selectionResultCallback);
+ mTimeOutResultSupplier = Objects.requireNonNull(timeOutResultSupplier);
// Make a copy of the original text.
mOriginalText = getText(mTextView).toString();
}
@@ -1051,14 +1051,14 @@
TextClassificationHelper(Context context, Supplier<TextClassifier> textClassifier,
CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
init(textClassifier, text, selectionStart, selectionEnd, locales);
- mContext = Preconditions.checkNotNull(context);
+ mContext = Objects.requireNonNull(context);
}
@UiThread
public void init(Supplier<TextClassifier> textClassifier, CharSequence text,
int selectionStart, int selectionEnd, LocaleList locales) {
- mTextClassifier = Preconditions.checkNotNull(textClassifier);
- mText = Preconditions.checkNotNull(text).toString();
+ mTextClassifier = Objects.requireNonNull(textClassifier);
+ mText = Objects.requireNonNull(text).toString();
mLastClassificationText = null; // invalidate.
Preconditions.checkArgument(selectionEnd > selectionStart);
mSelectionStart = selectionStart;
diff --git a/core/java/android/widget/SmartSelectSprite.java b/core/java/android/widget/SmartSelectSprite.java
index 9a84f69..dc472e1 100644
--- a/core/java/android/widget/SmartSelectSprite.java
+++ b/core/java/android/widget/SmartSelectSprite.java
@@ -38,13 +38,12 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
-import com.android.internal.util.Preconditions;
-
import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Objects;
/**
* A utility class for creating and animating the Smart Select animation.
@@ -75,7 +74,7 @@
private final int mTextSelectionLayout;
RectangleWithTextSelectionLayout(RectF rectangle, int textSelectionLayout) {
- mRectangle = Preconditions.checkNotNull(rectangle);
+ mRectangle = Objects.requireNonNull(rectangle);
mTextSelectionLayout = textSelectionLayout;
}
@@ -342,7 +341,7 @@
context,
android.R.interpolator.fast_out_linear_in);
mFillColor = highlightColor;
- mInvalidator = Preconditions.checkNotNull(invalidator);
+ mInvalidator = Objects.requireNonNull(invalidator);
}
/**
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index a86b566..06e96d5 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -98,10 +98,10 @@
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
-import android.view.WindowInsets;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
+import android.widget.Space;
import android.widget.TextView;
import android.widget.Toast;
@@ -1546,6 +1546,21 @@
return -1;
}
+ @Override
+ protected boolean shouldAddFooterView() {
+ // To accommodate for window insets
+ return true;
+ }
+
+ @Override
+ protected void applyFooterView(int height) {
+ int count = mChooserMultiProfilePagerAdapter.getItemCount();
+
+ for (int i = 0; i < count; i++) {
+ mChooserMultiProfilePagerAdapter.getAdapterForIndex(i).setFooterHeight(height);
+ }
+ }
+
void queryTargetServices(ChooserListAdapter adapter) {
mQueriedTargetServicesTimeMs = System.currentTimeMillis();
@@ -2413,12 +2428,17 @@
}
/**
- * Intentionally override the {@link ResolverActivity} implementation as we only need that
- * implementation for the intent resolver case.
+ * Add a footer to the list, to support scrolling behavior below the navbar.
*/
- @Override
- protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
- return insets.consumeSystemWindowInsets();
+ final class FooterViewHolder extends RecyclerView.ViewHolder {
+ FooterViewHolder(View itemView) {
+ super(itemView);
+ }
+
+ public void setHeight(int height) {
+ itemView.setLayoutParams(
+ new RecyclerView.LayoutParams(LayoutParams.MATCH_PARENT, height));
+ }
}
/**
@@ -2451,11 +2471,14 @@
private boolean mLayoutRequested = false;
+ private FooterViewHolder mFooterViewHolder;
+
private static final int VIEW_TYPE_DIRECT_SHARE = 0;
private static final int VIEW_TYPE_NORMAL = 1;
private static final int VIEW_TYPE_PROFILE = 2;
private static final int VIEW_TYPE_AZ_LABEL = 3;
private static final int VIEW_TYPE_CALLER_AND_RANK = 4;
+ private static final int VIEW_TYPE_FOOTER = 5;
private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4;
private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8;
@@ -2467,6 +2490,9 @@
mChooserListAdapter = wrappedAdapter;
mLayoutInflater = LayoutInflater.from(ChooserActivity.this);
+ mFooterViewHolder = new FooterViewHolder(
+ new Space(ChooserActivity.this.getApplicationContext()));
+
mShowAzLabelIfPoss = getNumSheetExpansions() < NUM_EXPANSIONS_TO_HIDE_AZ_LABEL;
wrappedAdapter.registerDataSetObserver(new DataSetObserver() {
@@ -2484,6 +2510,10 @@
});
}
+ public void setFooterHeight(int height) {
+ mFooterViewHolder.setHeight(height);
+ }
+
/**
* Calculate the chooser target width to maximize space per item
*
@@ -2534,6 +2564,10 @@
return mChooserListAdapter.getOtherProfile() == null ? 0 : 1;
}
+ public int getFooterRowCount() {
+ return 1;
+ }
+
public int getCallerAndRankedTargetRowCount() {
return (int) Math.ceil(
((float) mChooserListAdapter.getCallerTargetCount()
@@ -2563,6 +2597,7 @@
+ getCallerAndRankedTargetRowCount()
+ getAzLabelRowCount()
+ mChooserListAdapter.getAlphaTargetCount()
+ + getFooterRowCount()
);
}
@@ -2578,6 +2613,8 @@
case VIEW_TYPE_DIRECT_SHARE:
case VIEW_TYPE_CALLER_AND_RANK:
return createItemGroupViewHolder(viewType, parent);
+ case VIEW_TYPE_FOOTER:
+ return mFooterViewHolder;
default:
// Since we catch all possible viewTypes above, no chance this is being called.
return null;
@@ -2615,6 +2652,8 @@
countSum += (count = getAzLabelRowCount());
if (count > 0 && position < countSum) return VIEW_TYPE_AZ_LABEL;
+ if (position == getItemCount() - 1) return VIEW_TYPE_FOOTER;
+
return VIEW_TYPE_NORMAL;
}
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 46025aa..4e764fc 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -31,9 +31,11 @@
// be kept in sync with frameworks/native/libs/binder/include/binder/IAppOpsService.h
// and not be reordered
int checkOperation(int code, int uid, String packageName);
- int noteOperation(int code, int uid, String packageName, @nullable String featureId);
+ int noteOperation(int code, int uid, String packageName, @nullable String featureId,
+ boolean shouldCollectAsyncNotedOp, String message);
int startOperation(IBinder clientId, int code, int uid, String packageName,
- @nullable String featureId, boolean startIfModeDefault);
+ @nullable String featureId, boolean startIfModeDefault,
+ boolean shouldCollectAsyncNotedOp, String message);
@UnsupportedAppUsage
void finishOperation(IBinder clientId, int code, int uid, String packageName,
@nullable String featureId);
@@ -41,8 +43,6 @@
void stopWatchingMode(IAppOpsCallback callback);
int permissionToOpCode(String permission);
int checkAudioOperation(int code, int usage, int uid, String packageName);
- void noteAsyncOp(@nullable String callingPackageName, int uid, @nullable String packageName,
- int opCode, @nullable String featureId, String message);
boolean shouldCollectNotes(int opCode);
void setCameraAudioRestriction(int mode);
// End of methods also called by native code.
@@ -50,7 +50,7 @@
int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
String proxiedFeatureId, int proxyUid, String proxyPackageName,
- String proxyFeatureId);
+ String proxyFeatureId, boolean shouldCollectAsyncNotedOp, String message);
// Remaining methods are only used in Java.
int checkPackage(int uid, String packageName);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 8dc3a07..8d3c572 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -353,7 +353,11 @@
finish();
}
});
- if (isVoiceInteraction()) {
+
+ boolean hasTouchScreen = getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
+
+ if (isVoiceInteraction() || !hasTouchScreen) {
rdl.setCollapsed(false);
}
@@ -472,34 +476,52 @@
finish();
}
+ /**
+ * Numerous layouts are supported, each with optional ViewGroups.
+ * Make sure the inset gets added to the correct View, using
+ * a footer for Lists so it can properly scroll under the navbar.
+ */
+ protected boolean shouldAddFooterView() {
+ if (useLayoutWithDefault()) return true;
+
+ View buttonBar = findViewById(R.id.button_bar);
+ if (buttonBar == null || buttonBar.getVisibility() == View.GONE) return true;
+
+ return false;
+ }
+
+ protected void applyFooterView(int height) {
+ if (mFooterSpacer == null) {
+ mFooterSpacer = new Space(getApplicationContext());
+ } else {
+ ((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter)
+ .getCurrentAdapterView().removeFooterView(mFooterSpacer);
+ }
+ mFooterSpacer.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,
+ mSystemWindowInsets.bottom));
+ ((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter)
+ .getCurrentAdapterView().addFooterView(mFooterSpacer);
+ }
+
protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
mSystemWindowInsets = insets.getSystemWindowInsets();
mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top,
mSystemWindowInsets.right, 0);
+ resetButtonBar();
+
// Need extra padding so the list can fully scroll up
- if (useLayoutWithDefault()) {
- if (mFooterSpacer == null) {
- mFooterSpacer = new Space(getApplicationContext());
- } else {
- ((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter)
- .getCurrentAdapterView().removeFooterView(mFooterSpacer);
- }
- mFooterSpacer.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,
- mSystemWindowInsets.bottom));
- ((ResolverMultiProfilePagerAdapter) mMultiProfilePagerAdapter)
- .getCurrentAdapterView().addFooterView(mFooterSpacer);
- } else {
- View emptyView = findViewById(R.id.empty);
- if (emptyView != null) {
- emptyView.setPadding(0, 0, 0, mSystemWindowInsets.bottom
- + getResources().getDimensionPixelSize(
- R.dimen.chooser_edge_margin_normal) * 2);
- }
+ if (shouldAddFooterView()) {
+ applyFooterView(mSystemWindowInsets.bottom);
}
- resetButtonBar();
+ View emptyView = findViewById(R.id.empty);
+ if (emptyView != null) {
+ emptyView.setPadding(0, 0, 0, mSystemWindowInsets.bottom
+ + getResources().getDimensionPixelSize(
+ R.dimen.chooser_edge_margin_normal) * 2);
+ }
return insets.consumeSystemWindowInsets();
}
@@ -1283,10 +1305,11 @@
// In case this method is called again (due to activity recreation), avoid adding a new
// header if one is already present.
- if (useHeader && listView != null && listView.getHeaderViewsCount() == 0) {
+ if (useHeader && listView.getHeaderViewsCount() == 0) {
listView.setHeaderDividersEnabled(true);
listView.addHeaderView(LayoutInflater.from(this).inflate(
- R.layout.resolver_different_item_header, listView, false));
+ R.layout.resolver_different_item_header, listView, false),
+ null, false);
}
}
@@ -1349,6 +1372,8 @@
if (useLayoutWithDefault() && filteredPosition != ListView.INVALID_POSITION) {
setAlwaysButtonEnabled(true, filteredPosition, false);
mOnceButton.setEnabled(true);
+ // Focus the button if we already have the default option
+ mOnceButton.requestFocus();
return;
}
@@ -1481,6 +1506,7 @@
mOnceButton.setEnabled(hasValidSelection);
if (hasValidSelection) {
currentAdapterView.smoothScrollToPosition(checkedPos);
+ mOnceButton.requestFocus();
}
mLastSelected = checkedPos;
} else {
diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java
index 857377a..e9d7d05 100644
--- a/core/java/com/android/internal/infra/ServiceConnector.java
+++ b/core/java/com/android/internal/infra/ServiceConnector.java
@@ -223,7 +223,7 @@
private final @NonNull ServiceConnection mServiceConnection = this;
private final @NonNull Runnable mTimeoutDisconnect = this;
- private final @NonNull Context mContext;
+ protected final @NonNull Context mContext;
private final @NonNull Intent mIntent;
private final int mBindingFlags;
private final int mUserId;
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index 4a21d37..8d281b7 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -184,9 +184,8 @@
Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
}
- fetchUsapPoolPolicyProps();
-
mUsapPoolSupported = true;
+ fetchUsapPoolPolicyProps();
}
void setForkChild() {
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index 362bc92..580c2fa 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -107,9 +107,12 @@
* Amount of RAM that is in use by the kernel for actual allocations.
*/
public long getKernelUsedSizeKb() {
- return mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB_UNRECLAIMABLE]
- + mInfos[Debug.MEMINFO_VM_ALLOC_USED] + mInfos[Debug.MEMINFO_PAGE_TABLES]
- + mInfos[Debug.MEMINFO_KERNEL_STACK];
+ long size = mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB_UNRECLAIMABLE]
+ + mInfos[Debug.MEMINFO_VM_ALLOC_USED] + mInfos[Debug.MEMINFO_PAGE_TABLES];
+ if (!Debug.isVmapStack()) {
+ size += mInfos[Debug.MEMINFO_KERNEL_STACK];
+ }
+ return size;
}
public long getSwapTotalSizeKb() {
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 1bb2ba2..e0c3823 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -187,7 +187,7 @@
public void setCollapsed(boolean collapsed) {
if (!isLaidOut()) {
- mOpenOnLayout = collapsed;
+ mOpenOnLayout = !collapsed;
} else {
smoothScrollTo(collapsed ? mCollapsibleHeight : 0, 0);
}
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index 2265268..79f62cb 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -59,7 +59,6 @@
jfieldID hasFocus;
jfieldID hasWallpaper;
jfieldID paused;
- jfieldID layer;
jfieldID ownerPid;
jfieldID ownerUid;
jfieldID inputFeatures;
@@ -152,8 +151,6 @@
gInputWindowHandleClassInfo.hasWallpaper);
mInfo.paused = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.paused);
- mInfo.layer = env->GetIntField(obj,
- gInputWindowHandleClassInfo.layer);
mInfo.ownerPid = env->GetIntField(obj,
gInputWindowHandleClassInfo.ownerPid);
mInfo.ownerUid = env->GetIntField(obj,
@@ -332,9 +329,6 @@
GET_FIELD_ID(gInputWindowHandleClassInfo.paused, clazz,
"paused", "Z");
- GET_FIELD_ID(gInputWindowHandleClassInfo.layer, clazz,
- "layer", "I");
-
GET_FIELD_ID(gInputWindowHandleClassInfo.ownerPid, clazz,
"ownerPid", "I");
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 6e0d5d8..4314eb6 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -50,6 +50,7 @@
#include <memunreachable/memunreachable.h>
#include <android-base/strings.h>
#include "android_os_Debug.h"
+#include <vintf/VintfObject.h>
namespace android
{
@@ -835,6 +836,23 @@
return ionPss;
}
+static jboolean android_os_Debug_isVmapStack(JNIEnv *env, jobject clazz)
+{
+ static enum {
+ CONFIG_UNKNOWN,
+ CONFIG_SET,
+ CONFIG_UNSET,
+ } cfg_state = CONFIG_UNKNOWN;
+
+ if (cfg_state == CONFIG_UNKNOWN) {
+ const std::map<std::string, std::string> configs =
+ vintf::VintfObject::GetInstance()->getRuntimeInfo()->kernelConfigs();
+ std::map<std::string, std::string>::const_iterator it = configs.find("CONFIG_VMAP_STACK");
+ cfg_state = (it != configs.end() && it->second == "y") ? CONFIG_SET : CONFIG_UNSET;
+ }
+ return cfg_state == CONFIG_SET;
+}
+
/*
* JNI registration.
*/
@@ -884,6 +902,8 @@
(void*)android_os_Debug_getIonPoolsSizeKb },
{ "getIonMappedSizeKb", "()J",
(void*)android_os_Debug_getIonMappedSizeKb },
+ { "isVmapStack", "()Z",
+ (void*)android_os_Debug_isVmapStack },
};
int register_android_os_Debug(JNIEnv *env)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7719165..5410cf5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3591,6 +3591,11 @@
<permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to start and stop one time permission sessions
+ @hide -->
+ <permission android:name="android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS"
+ android:protectionLevel="signature|installer" />
+
<!-- @SystemApi Allows an application to manage the holders of a role.
@hide
STOPSHIP b/145526313: Remove wellbeing protection flag from MANAGE_ROLE_HOLDERS. -->
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index eb1f553..00c0d30 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1283,7 +1283,7 @@
<string name="heavy_weight_switcher_text" msgid="6814316627367160126">"للحصول على أداء أفضل، يمكن فتح لعبة واحدة فقط من هذه الألعاب في كل مرة."</string>
<string name="old_app_action" msgid="725331621042848590">"الرجوع إلى <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
<string name="new_app_action" msgid="547772182913269801">"فتح <xliff:g id="NEW_APP">%1$s</xliff:g>"</string>
- <string name="new_app_description" msgid="1958903080400806644">"سيتم إغلاق <xliff:g id="OLD_APP">%1$s</xliff:g> من دون حفظ"</string>
+ <string name="new_app_description" msgid="1958903080400806644">"سيتم إغلاق <xliff:g id="OLD_APP">%1$s</xliff:g> بدون حفظ"</string>
<string name="dump_heap_notification" msgid="5316644945404825032">"لقد تجاوزت <xliff:g id="PROC">%1$s</xliff:g> حد الذاكرة."</string>
<string name="dump_heap_ready_notification" msgid="2302452262927390268">"نَسْخ الذاكرة <xliff:g id="PROC">%1$s</xliff:g> جاهز"</string>
<string name="dump_heap_notification_detail" msgid="8431586843001054050">"تم جمع مقدار كبير من بيانات الذاكرة. انقر للمشاركة."</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index aa28bf2..3e23679 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -665,7 +665,7 @@
<string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Sletter denne brukerens data på dette nettbrettet uten advarsel."</string>
<string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"Tøm dataene til denne brukeren på denne Android TV-enheten uten advarsel."</string>
<string name="policydesc_wipeData_secondaryUser" product="default" msgid="2788325512167208654">"Sletter denne brukerens data på denne telefonen uten advarsel."</string>
- <string name="policylab_setGlobalProxy" msgid="215332221188670221">"Angi enhetens globale mellomtjener"</string>
+ <string name="policylab_setGlobalProxy" msgid="215332221188670221">"Angi enhetens globale proxy-tjener"</string>
<string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"Angir den globale proxy-tjeneren på enheten som skal brukes når regelen er aktivert. Bare eieren av enheten kan angi den globale proxy-tjeneren."</string>
<string name="policylab_expirePassword" msgid="6015404400532459169">"Angi utløpstid for skjermlås"</string>
<string name="policydesc_expirePassword" msgid="9136524319325960675">"Endrer hvor ofte PIN-koden, passordet eller mønsteret til skjermlåsen skal byttes."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index be173dd..7aa91f7 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -497,10 +497,8 @@
<string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Aplikaciji omogoča ogled konfiguracije Bluetootha tabličnega računalnika ter vzpostavljanje in sprejemanje povezave s seznanjenimi napravami."</string>
<string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Aplikaciji dovoljuje ogled konfiguracije vmesnika Bluetooth v napravi Android TV ter ustvarjanje in sprejemanje povezav s seznanjenimi napravami."</string>
<string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Aplikaciji omogoča ogled konfiguracije Bluetootha telefona ter ustvarjanje in sprejemanje povezave s seznanjenimi napravami."</string>
- <!-- no translation found for permlab_preferredPaymentInfo (5274423844767445054) -->
- <skip />
- <!-- no translation found for permdesc_preferredPaymentInfo (8583552469807294967) -->
- <skip />
+ <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Podatki o prednostni storitvi za plačevanje prek povezave NFC"</string>
+ <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Aplikaciji omogoča pridobivanje podatkov o prednostni storitvi za plačevanje prek povezave NFC, kot so registrirani pripomočki in cilj preusmeritve."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"nadzor nad komunikacijo s tehnologijo bližnjega polja"</string>
<string name="permdesc_nfc" msgid="8352737680695296741">"Podpira komunikacijo med računalnikom in oznakami, karticami in bralniki komunikacije s tehnologijo bližnjega polja."</string>
<string name="permlab_disableKeyguard" msgid="3605253559020928505">"onemogočanje zaklepanja zaslona"</string>
@@ -1663,12 +1661,6 @@
<string name="accessibility_shortcut_enabling_service" msgid="6141620395915529473">"Bližnjica funkcij za ljudi s posebnimi potrebami je vklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="1287340429965172651">"Bližnjica funkcij za ljudi s posebnimi potrebami je izklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Za uporabo storitve <xliff:g id="SERVICE_NAME">%1$s</xliff:g> pritisnite obe tipki za glasnost in ju pridržite tri sekunde"</string>
- <string name="accessibility_button_prompt_text" msgid="1634298854002673171">"Izberite storitev, ki jo želite uporabljati, ko se dotaknete gumba za funkcije za ljudi s posebnimi potrebami:"</string>
- <string name="accessibility_gesture_prompt_text" msgid="3271927619707898924">"Izberite storitev, ki jo želite zagnati s potezo za ljudi s posebnimi potrebami (vlečenje z dvema prstoma z dna zaslona navzgor):"</string>
- <string name="accessibility_gesture_3finger_prompt_text" msgid="218295923313037542">"Izberite storitev, ki jo želite zagnati s potezo za ljudi s posebnimi potrebami (vlečenje s tremi prsti z dna zaslona navzgor):"</string>
- <string name="accessibility_button_instructional_text" msgid="8523635009916665153">"Če želite preklopiti med storitvami, pridržite gumb za funkcije za ljudi s posebnimi potrebami."</string>
- <string name="accessibility_gesture_instructional_text" msgid="927882482331885974">"Če želite preklopiti med storitvami, z dvema prstoma povlecite navzgor in pridržite."</string>
- <string name="accessibility_gesture_3finger_instructional_text" msgid="7527523742771203377">"Če želite preklopiti med storitvami, s tremi prsti povlecite navzgor in pridržite."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Povečava"</string>
<string name="user_switched" msgid="7249833311585228097">"Trenutni uporabnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="1912993630661332336">"Preklop na uporabnika <xliff:g id="NAME">%1$s</xliff:g> …"</string>
@@ -1927,11 +1919,9 @@
<string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Vzpostavljena povezava z napravo <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Dotaknite se, če si želite ogledati datoteke"</string>
<string name="pin_target" msgid="8036028973110156895">"Pripenjanje"</string>
- <!-- no translation found for pin_specific_target (7824671240625957415) -->
- <skip />
+ <string name="pin_specific_target" msgid="7824671240625957415">"Pripni aplikacijo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="unpin_target" msgid="3963318576590204447">"Odpenjanje"</string>
- <!-- no translation found for unpin_specific_target (3859828252160908146) -->
- <skip />
+ <string name="unpin_specific_target" msgid="3859828252160908146">"Odpni aplikacijo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="app_info" msgid="6113278084877079851">"Podatki o aplikacijah"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Začenjanje predstavitve …"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index d01e8e7..2cc42d7 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -491,8 +491,8 @@
<string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"允許應用程式查看平板電腦的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
<string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"允許應用程式查看 Android TV 裝置的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
<string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"允許應用程式查看手機的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
- <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"首選 NFC 付款服務資訊"</string>
- <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"允許應用程式取得首選 NFC 付款服務的資訊 (如已註冊的付款輔助和最終付款對象)。"</string>
+ <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"由用戶允許授權的 NFC 付款服務資訊"</string>
+ <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"允許應用程式取得由用戶允許授權的 NFC 付款服務資訊 (如已註冊的付款輔助功能和最終付款對象)。"</string>
<string name="permlab_nfc" msgid="1904455246837674977">"控制近距離無線通訊"</string>
<string name="permdesc_nfc" msgid="8352737680695296741">"允許應用程式使用近距離無線通訊 (NFC) 標記、卡片及讀取程式進行通訊。"</string>
<string name="permlab_disableKeyguard" msgid="3605253559020928505">"停用螢幕上鎖"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 38d3e9c..9c08728 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3469,6 +3469,8 @@
device -->
<attr name="isVrOnly" format="boolean"/>
<attr name="__removed2" format="boolean" />
+ <!-- Specifies whether the IME supports showing inline suggestions. -->
+ <attr name="supportsInlineSuggestions" format="boolean" />
</declare-styleable>
<!-- This is the subtype of InputMethod. Subtype can describe locales (for example, en_US and
@@ -8177,6 +8179,9 @@
<!-- Fully qualified class name of an activity that allows the user to modify
the settings for this service. -->
<attr name="settingsActivity" />
+
+ <!-- Specifies whether the AutofillService supports inline suggestions-->
+ <attr name="supportsInlineSuggestions" format="boolean" />
</declare-styleable>
<!-- Use <code>compatibility-package</code> as a child tag of <code>autofill-service</code>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 85f7d61..6435cdd 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1533,7 +1533,8 @@
<code>com.google.app.<em>appname</em></code>
<p>Inside of the manifest tag, may appear the following tags
- in any order: {@link #AndroidManifestPermission permission},
+ in any order: {@link #AndroidManifestFeature feature},
+ {@link #AndroidManifestPermission permission},
{@link #AndroidManifestPermissionGroup permission-group},
{@link #AndroidManifestPermissionTree permission-tree},
{@link #AndroidManifestUsesSdk uses-sdk},
@@ -1763,6 +1764,29 @@
The default value is {@code false}. -->
<attr name="crossProfile" format="boolean" />
</declare-styleable>
+
+ <!-- The <code>feature</code> tag declares a feature. A feature is a part of an app. E.g.
+ photo sharing app might include a direct messaging component.
+
+ <p>This appears as a child tag of the root {@link #AndroidManifest manifest} tag.
+
+ <p>In case this feature inherits from another feature, this tag can contain one or multiple
+ {@link #AndroidManifestFeatureInheritFrom inherit-from} tags. -->
+ <declare-styleable name="AndroidManifestFeature" parent="AndroidManifest">
+ <!-- Required identifier for a feature. Can be passed to
+ {@link android.content.Context#createFeatureContext} to create a context for this feature
+ -->
+ <attr name="featureId" format="string" />
+ <!-- Required user visible label for a feature. -->
+ <attr name="label" format="string" />
+ </declare-styleable>
+
+ <!-- Declares previously declared features this feature inherits from. -->
+ <declare-styleable name="AndroidManifestFeatureInheritFrom" parent="AndroidManifestFeature">
+ <!-- Identifier of the feature this feature inherits from -->
+ <attr name="featureId" format="string" />
+ </declare-styleable>
+
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
features in your package (or other packages). See the
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0b63518..d12d069 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3004,6 +3004,9 @@
<public name="resourcesMap" />
<public name="animatedImageDrawable"/>
<public name="htmlDescription"/>
+ <public name="preferMinimalPostProcessing"/>
+ <public name="featureId" />
+ <public name="supportsInlineSuggestions" />
</public-group>
<public-group type="drawable" first-id="0x010800b5">
@@ -3049,10 +3052,6 @@
<public name="accessibilitySystemActionLockScreen" />
<public name="accessibilitySystemActionTakeScreenshot" />
</public-group>
-
- <public-group type="attr" first-id="0x0101060c">
- <public name="preferMinimalPostProcessing"/>
- </public-group>
<!-- ===============================================================
DO NOT ADD UN-GROUPED ITEMS HERE
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e874ac7..a00296c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3209,11 +3209,6 @@
<java-symbol type="id" name="accessibility_button_target_label" />
<java-symbol type="string" name="accessibility_magnification_chooser_text" />
- <java-symbol type="string" name="accessibility_gesture_prompt_text" />
- <java-symbol type="string" name="accessibility_gesture_3finger_prompt_text" />
- <java-symbol type="string" name="accessibility_gesture_instructional_text" />
- <java-symbol type="string" name="accessibility_gesture_3finger_instructional_text" />
-
<java-symbol type="drawable" name="ic_accessibility_magnification" />
<!-- com.android.internal.widget.RecyclerView -->
diff --git a/core/tests/coretests/res/xml/ime_meta_inline_suggestions.xml b/core/tests/coretests/res/xml/ime_meta_inline_suggestions.xml
new file mode 100644
index 0000000..e67bf63
--- /dev/null
+++ b/core/tests/coretests/res/xml/ime_meta_inline_suggestions.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<input-method
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:settingsActivity="com.android.inputmethod.latin.settings.SettingsActivity"
+ android:supportsInlineSuggestions="true"
+>
+ <subtype
+ android:label="subtype1"
+ android:imeSubtypeLocale="en_US"
+ android:imeSubtypeMode="keyboard" />
+</input-method>
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
index f24e232..8718b95 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -54,10 +54,12 @@
final InputMethodInfo imi = buildInputMethodForTest(R.xml.ime_meta);
assertThat(imi.supportsSwitchingToNextInputMethod(), is(false));
+ assertThat(imi.isInlineSuggestionsEnabled(), is(false));
final InputMethodInfo clone = cloneViaParcel(imi);
assertThat(clone.supportsSwitchingToNextInputMethod(), is(false));
+ assertThat(imi.isInlineSuggestionsEnabled(), is(false));
}
@Test
@@ -72,6 +74,17 @@
}
@Test
+ public void testInlineSuggestionsEnabled() throws Exception {
+ final InputMethodInfo imi = buildInputMethodForTest(R.xml.ime_meta_inline_suggestions);
+
+ assertThat(imi.isInlineSuggestionsEnabled(), is(true));
+
+ final InputMethodInfo clone = cloneViaParcel(imi);
+
+ assertThat(clone.isInlineSuggestionsEnabled(), is(true));
+ }
+
+ @Test
public void testIsVrOnly() throws Exception {
final InputMethodInfo imi = buildInputMethodForTest(R.xml.ime_meta_vr_only);
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index c3ef1c8..fbe4c1a 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -1022,23 +1022,11 @@
@Test
public void testSelectionMetricsLogger_abandonEventIncludesEntityType() throws Throwable {
- final List<SelectionEvent> selectionEvents = new ArrayList<>();
- final TextClassifier classifier = new TextClassifier() {
- @Override
- public void onSelectionEvent(SelectionEvent event) {
- selectionEvents.add(event);
- }
-
- @Override
- public TextSelection suggestSelection(TextSelection.Request request) {
- return new TextSelection.Builder(request.getStartIndex(), request.getEndIndex())
- .setEntityType(TextClassifier.TYPE_PHONE, 1)
- .build();
- }
- };
+ final TestableTextClassifier classifier = new TestableTextClassifier();
final TextView textView = mActivity.findViewById(R.id.textview);
mActivityRule.runOnUiThread(() -> textView.setTextClassifier(classifier));
mInstrumentation.waitForIdleSync();
+
final String text = "My number is 987654321";
onView(withId(R.id.textview)).perform(replaceText(text));
@@ -1053,6 +1041,7 @@
long waitTime = 0;
SelectionEvent lastEvent;
do {
+ final List<SelectionEvent> selectionEvents = classifier.getSelectionEvents();
lastEvent = selectionEvents.get(selectionEvents.size() - 1);
if (lastEvent.getEventType() == SelectionEvent.ACTION_ABANDON) {
break;
@@ -1061,6 +1050,29 @@
waitTime += pollInterval;
} while (waitTime < abandonDelay * 10);
assertEquals(SelectionEvent.ACTION_ABANDON, lastEvent.getEventType());
+ }
+
+ @Test
+ public void testSelectionMetricsLogger_overtypeEventIncludesEntityType() throws Throwable {
+ final TestableTextClassifier classifier = new TestableTextClassifier();
+ final TextView textView = mActivity.findViewById(R.id.textview);
+ mActivityRule.runOnUiThread(() -> textView.setTextClassifier(classifier));
+ mInstrumentation.waitForIdleSync();
+
+ final String text = "My number is 987654321";
+
+ // Long press to trigger selection
+ onView(withId(R.id.textview)).perform(replaceText(text));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('9')));
+ sleepForFloatingToolbarPopup();
+
+ // Type over the selection
+ onView(withId(R.id.textview)).perform(pressKey(KeyEvent.KEYCODE_A));
+ mInstrumentation.waitForIdleSync();
+
+ final List<SelectionEvent> selectionEvents = classifier.getSelectionEvents();
+ final SelectionEvent lastEvent = selectionEvents.get(selectionEvents.size() - 1);
+ assertEquals(SelectionEvent.ACTION_OVERTYPE, lastEvent.getEventType());
assertEquals(TextClassifier.TYPE_PHONE, lastEvent.getEntityType());
}
@@ -1115,4 +1127,24 @@
private enum TextStyle {
PLAIN, STYLED
}
+
+ private final class TestableTextClassifier implements TextClassifier {
+ final List<SelectionEvent> mSelectionEvents = new ArrayList<>();
+
+ @Override
+ public void onSelectionEvent(SelectionEvent event) {
+ mSelectionEvents.add(event);
+ }
+
+ @Override
+ public TextSelection suggestSelection(TextSelection.Request request) {
+ return new TextSelection.Builder(request.getStartIndex(), request.getEndIndex())
+ .setEntityType(TextClassifier.TYPE_PHONE, 1)
+ .build();
+ }
+
+ List<SelectionEvent> getSelectionEvents() {
+ return mSelectionEvents;
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 8622b7e..c086421 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -54,6 +54,7 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager.ShareShortcutInfo;
+import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -977,6 +978,7 @@
serviceTargets,
TARGET_TYPE_CHOOSER_TARGET)
);
+
// Thread.sleep shouldn't be a thing in an integration test but it's
// necessary here because of the way the code is structured
// TODO: restructure the tests b/129870719
@@ -1075,7 +1077,29 @@
// This test is too long and too slow and should not be taken as an example for future tests.
@Test
- public void testDirectTargetLoggingWithAppTargetNotRanked() throws InterruptedException {
+ public void testDirectTargetLoggingWithAppTargetNotRankedPortrait()
+ throws InterruptedException {
+ testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_PORTRAIT, 4);
+ }
+
+ @Test
+ public void testDirectTargetLoggingWithAppTargetNotRankedLandscape()
+ throws InterruptedException {
+ testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_LANDSCAPE, 8);
+ }
+
+ private void testDirectTargetLoggingWithAppTargetNotRanked(
+ int orientation, int appTargetsExpected
+ ) throws InterruptedException {
+ Configuration configuration =
+ new Configuration(InstrumentationRegistry.getInstrumentation().getContext()
+ .getResources().getConfiguration());
+ configuration.orientation = orientation;
+
+ sOverrides.resources = Mockito.spy(
+ InstrumentationRegistry.getInstrumentation().getContext().getResources());
+ when(sOverrides.resources.getConfiguration()).thenReturn(configuration);
+
Intent sendIntent = createSendTextIntent();
// We need app targets for direct targets to get displayed
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(15);
@@ -1111,8 +1135,10 @@
// TODO: restructure the tests b/129870719
Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
- assertThat("Chooser should have 20 targets (4 apps, 1 direct, 15 A-Z)",
- activity.getAdapter().getCount(), is(20));
+ assertThat(
+ String.format("Chooser should have %d targets (%d apps, 1 direct, 15 A-Z)",
+ appTargetsExpected + 16, appTargetsExpected),
+ activity.getAdapter().getCount(), is(appTargetsExpected + 16));
assertThat("Chooser should have exactly one selectable direct target",
activity.getAdapter().getSelectableServiceTargetCount(), is(1));
assertThat("The resolver info must match the resolver info used to create the target",
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index f1941fc..38a9f46 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -130,7 +130,6 @@
<permission name="android.permission.APPROVE_INCIDENT_REPORTS"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
- <permission name="android.permission.PACKAGE_USAGE_STATS" />
</privapp-permissions>
<privapp-permissions package="com.android.phone">
diff --git a/media/Android.bp b/media/Android.bp
index a1365179..499d0da 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -1,110 +1,3 @@
-java_library {
- name: "updatable-media",
-
- srcs: [
- ":updatable-media-srcs",
- ],
-
- aidl: {
- export_include_dirs: [
- "apex/java",
- ],
-
- // It would be great if we don't need to add include_dirs for public
- // parcelable classes. Find a better way.
- include_dirs: [
- // To refer:
- // android.os.Bundle
- // android.os.ResultReceiver
- "frameworks/base/core/java",
- ],
- },
-
- permitted_packages: [
- "android.media",
- ],
-
- installable: true,
-
- // TODO: build against stable API surface. Use core_platform for now to avoid
- // link-check failure with exoplayer building against "current".
- sdk_version: "core_platform",
- libs: [
- // The order matters. android_system_* library should come later.
- "framework_media_annotation",
- "android_system_stubs_current",
- ],
-
- static_libs: [
- "exoplayer2-core"
- ],
- jarjar_rules: "jarjar_rules.txt",
-
- plugins: ["java_api_finder"],
-}
-
-filegroup {
- name: "updatable-media-srcs",
- srcs: [
- ":mediaparser-srcs",
- ":mediasession2-srcs",
- ],
-}
-
-filegroup {
- name: "mediasession2-srcs",
- srcs: [
- "apex/java/android/media/Controller2Link.java",
- "apex/java/android/media/IMediaController2.aidl",
- "apex/java/android/media/IMediaSession2.aidl",
- "apex/java/android/media/IMediaSession2Service.aidl",
- "apex/java/android/media/MediaConstants.java",
- "apex/java/android/media/MediaController2.java",
- "apex/java/android/media/MediaSession2.java",
- "apex/java/android/media/MediaSession2Service.java",
- "apex/java/android/media/Session2Command.java",
- "apex/java/android/media/Session2CommandGroup.java",
- "apex/java/android/media/Session2Link.java",
- "apex/java/android/media/Session2Token.java",
- ],
- path: "apex/java",
-}
-
-filegroup {
- name: "mediaparser-srcs",
- srcs: [
- "apex/java/android/media/MediaParser.java"
- ],
- path: "apex/java"
-}
-
-droidstubs {
- name: "updatable-media-stubs",
- srcs: [
- ":updatable-media-srcs",
- ":framework-media-annotation-srcs",
- ],
- defaults: [ "framework-module-stubs-defaults-systemapi" ],
- aidl: {
- // TODO(b/135922046) remove this
- include_dirs: ["frameworks/base/core/java"],
- },
- sdk_version: "system_current",
-}
-
-java_library {
- name: "updatable_media_stubs",
- srcs: [":updatable-media-stubs"],
- sdk_version: "system_current",
-}
-
-java_library {
- name: "framework_media_annotation",
- srcs: [":framework-media-annotation-srcs"],
- installable: false,
- sdk_version: "core_current",
-}
-
aidl_interface {
name: "audio_common-aidl",
local_include_dir: "java",
diff --git a/media/apex/java/android/media/CloseGuard.java b/media/apex/java/android/media/CloseGuard.java
deleted file mode 100644
index 2014673..0000000
--- a/media/apex/java/android/media/CloseGuard.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (C) 2010 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;
-
-import android.util.Log;
-
-/**
- * Note: This file is copied from dalvik.system package with the following modifications:
- * - Remove @CorePlatformApi, @IntraCoreApi and @UnsupportedAppUsage annotations.
- * - Replace System.logW() with android.util.Log.w().
- * This file should be used only within media mainline module.
- * TODO: Remove this file and use dalvik.system.CloseGuard once
- * @CorePlatformApi becomes stable or we have a replacement in SDK API.
- * b/120419300
- *
- * CloseGuard is a mechanism for flagging implicit finalizer cleanup of
- * resources that should have been cleaned up by explicit close
- * methods (aka "explicit termination methods" in Effective Java).
- * <p>
- * A simple example: <pre> {@code
- * class Foo {
- *
- * {@literal @}ReachabilitySensitive
- * private final CloseGuard guard = CloseGuard.get();
- *
- * ...
- *
- * public Foo() {
- * ...;
- * guard.open("cleanup");
- * }
- *
- * public void cleanup() {
- * guard.close();
- * ...;
- * }
- *
- * protected void finalize() throws Throwable {
- * try {
- * // Note that guard could be null if the constructor threw.
- * if (guard != null) {
- * guard.warnIfOpen();
- * }
- * cleanup();
- * } finally {
- * super.finalize();
- * }
- * }
- * }
- * }</pre>
- *
- * In usage where the resource to be explicitly cleaned up is
- * allocated after object construction, CloseGuard protection can
- * be deferred. For example: <pre> {@code
- * class Bar {
- *
- * {@literal @}ReachabilitySensitive
- * private final CloseGuard guard = CloseGuard.get();
- *
- * ...
- *
- * public Bar() {
- * ...;
- * }
- *
- * public void connect() {
- * ...;
- * guard.open("cleanup");
- * }
- *
- * public void cleanup() {
- * guard.close();
- * ...;
- * }
- *
- * protected void finalize() throws Throwable {
- * try {
- * // Note that guard could be null if the constructor threw.
- * if (guard != null) {
- * guard.warnIfOpen();
- * }
- * cleanup();
- * } finally {
- * super.finalize();
- * }
- * }
- * }
- * }</pre>
- *
- * When used in a constructor, calls to {@code open} should occur at
- * the end of the constructor since an exception that would cause
- * abrupt termination of the constructor will mean that the user will
- * not have a reference to the object to cleanup explicitly. When used
- * in a method, the call to {@code open} should occur just after
- * resource acquisition.
- *
- * The @ReachabilitySensitive annotation ensures that finalize() cannot be
- * called during the explicit call to cleanup(), prior to the guard.close call.
- * There is an extremely small chance that, for code that neglects to call
- * cleanup(), finalize() and thus cleanup() will be called while a method on
- * the object is still active, but the "this" reference is no longer required.
- * If missing cleanup() calls are expected, additional @ReachabilitySensitive
- * annotations or reachabilityFence() calls may be required.
- *
- * @hide
- */
-final class CloseGuard {
-
- /**
- * True if collection of call-site information (the expensive operation
- * here) and tracking via a Tracker (see below) are enabled.
- * Enabled by default so we can diagnose issues early in VM startup.
- * Note, however, that Android disables this early in its startup,
- * but enables it with DropBoxing for system apps on debug builds.
- */
- private static volatile boolean stackAndTrackingEnabled = true;
-
- /**
- * Hook for customizing how CloseGuard issues are reported.
- * Bypassed if stackAndTrackingEnabled was false when open was called.
- */
- private static volatile Reporter reporter = new DefaultReporter();
-
- /**
- * Hook for customizing how CloseGuard issues are tracked.
- */
- private static volatile Tracker currentTracker = null; // Disabled by default.
-
- /**
- * Returns a CloseGuard instance. {@code #open(String)} can be used to set
- * up the instance to warn on failure to close.
- */
- public static CloseGuard get() {
- return new CloseGuard();
- }
-
- /**
- * Enables/disables stack capture and tracking. A call stack is captured
- * during open(), and open/close events are reported to the Tracker, only
- * if enabled is true. If a stack trace was captured, the {@link
- * #getReporter() reporter} is informed of unclosed resources; otherwise a
- * one-line warning is logged.
- */
- public static void setEnabled(boolean enabled) {
- CloseGuard.stackAndTrackingEnabled = enabled;
- }
-
- /**
- * True if CloseGuard stack capture and tracking are enabled.
- */
- public static boolean isEnabled() {
- return stackAndTrackingEnabled;
- }
-
- /**
- * Used to replace default Reporter used to warn of CloseGuard
- * violations when stack tracking is enabled. Must be non-null.
- */
- public static void setReporter(Reporter rep) {
- if (rep == null) {
- throw new NullPointerException("reporter == null");
- }
- CloseGuard.reporter = rep;
- }
-
- /**
- * Returns non-null CloseGuard.Reporter.
- */
- public static Reporter getReporter() {
- return reporter;
- }
-
- /**
- * Sets the {@link Tracker} that is notified when resources are allocated and released.
- * The Tracker is invoked only if CloseGuard {@link #isEnabled()} held when {@link #open()}
- * was called. A null argument disables tracking.
- *
- * <p>This is only intended for use by {@code dalvik.system.CloseGuardSupport} class and so
- * MUST NOT be used for any other purposes.
- */
- public static void setTracker(Tracker tracker) {
- currentTracker = tracker;
- }
-
- /**
- * Returns {@link #setTracker(Tracker) last Tracker that was set}, or null to indicate
- * there is none.
- *
- * <p>This is only intended for use by {@code dalvik.system.CloseGuardSupport} class and so
- * MUST NOT be used for any other purposes.
- */
- public static Tracker getTracker() {
- return currentTracker;
- }
-
- private CloseGuard() {}
-
- /**
- * {@code open} initializes the instance with a warning that the caller
- * should have explicitly called the {@code closer} method instead of
- * relying on finalization.
- *
- * @param closer non-null name of explicit termination method. Printed by warnIfOpen.
- * @throws NullPointerException if closer is null.
- */
- public void open(String closer) {
- // always perform the check for valid API usage...
- if (closer == null) {
- throw new NullPointerException("closer == null");
- }
- // ...but avoid allocating an allocation stack if "disabled"
- if (!stackAndTrackingEnabled) {
- closerNameOrAllocationInfo = closer;
- return;
- }
- String message = "Explicit termination method '" + closer + "' not called";
- Throwable stack = new Throwable(message);
- closerNameOrAllocationInfo = stack;
- Tracker tracker = currentTracker;
- if (tracker != null) {
- tracker.open(stack);
- }
- }
-
- // We keep either an allocation stack containing the closer String or, when
- // in disabled state, just the closer String.
- // We keep them in a single field only to minimize overhead.
- private Object /* String or Throwable */ closerNameOrAllocationInfo;
-
- /**
- * Marks this CloseGuard instance as closed to avoid warnings on
- * finalization.
- */
- public void close() {
- Tracker tracker = currentTracker;
- if (tracker != null && closerNameOrAllocationInfo instanceof Throwable) {
- // Invoke tracker on close only if we invoked it on open. Tracker may have changed.
- tracker.close((Throwable) closerNameOrAllocationInfo);
- }
- closerNameOrAllocationInfo = null;
- }
-
- /**
- * Logs a warning if the caller did not properly cleanup by calling an
- * explicit close method before finalization. If CloseGuard was enabled
- * when the CloseGuard was created, passes the stacktrace associated with
- * the allocation to the current reporter. If it was not enabled, it just
- * directly logs a brief message.
- */
- public void warnIfOpen() {
- if (closerNameOrAllocationInfo != null) {
- if (closerNameOrAllocationInfo instanceof String) {
- Log.w("CloseGuard", "A resource failed to call "
- + (String) closerNameOrAllocationInfo + ". ");
- } else {
- String message =
- "A resource was acquired at attached stack trace but never released. ";
- message += "See java.io.Closeable for information on avoiding resource leaks.";
- Throwable stack = (Throwable) closerNameOrAllocationInfo;
- reporter.report(message, stack);
- }
- }
- }
-
- /**
- * Interface to allow customization of tracking behaviour.
- *
- * <p>This is only intended for use by {@code dalvik.system.CloseGuardSupport} class and so
- * MUST NOT be used for any other purposes.
- */
- public interface Tracker {
- void open(Throwable allocationSite);
- void close(Throwable allocationSite);
- }
-
- /**
- * Interface to allow customization of reporting behavior.
- * @hide
- */
- public interface Reporter {
- void report(String message, Throwable allocationSite);
- }
-
- /**
- * Default Reporter which reports CloseGuard violations to the log.
- */
- private static final class DefaultReporter implements Reporter {
- private DefaultReporter() {}
-
- @Override public void report (String message, Throwable allocationSite) {
- Log.w("CloseGuard", message, allocationSite);
- }
- }
-}
diff --git a/media/java/android/media/AudioRecordingConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java
index 5f32c0f..f3613d3 100644
--- a/media/java/android/media/AudioRecordingConfiguration.java
+++ b/media/java/android/media/AudioRecordingConfiguration.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.media.audiofx.AudioEffect;
@@ -224,15 +225,16 @@
public String getClientPackageName() { return mClientPackageName; }
/**
- * @pending for SystemApi
* Returns the user id of the application performing the recording.
* <p>This information is only available if the caller has the
* {@link android.Manifest.permission.MODIFY_AUDIO_ROUTING}
* permission.
* <br>The result is -1 without the permission.
* @return the user id
+ *
+ * @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
public int getClientUid() { return mClientUid; }
/**
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 176bb37..f780d40 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -362,7 +362,8 @@
</tr>
<tr>
<td>FLAC</td>
- <td>mandatory metadata block (called the STREAMINFO block),<br>
+ <td>"fLaC", the FLAC stream marker in ASCII,<br>
+ followed by the STREAMINFO block (the mandatory metadata block),<br>
optionally followed by any number of other metadata blocks</td>
<td class=NA>Not Used</td>
<td class=NA>Not Used</td>
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 0be49d8..9100032 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -547,8 +547,6 @@
* {@link SessionCallback#onSessionCreationFailed}.
* <p>
* Pass {@code null} to sessionInfo for the failure case.
- *
- * TODO: What should router do when the session is created by manager?
*/
void createControllerOnHandler(@Nullable RouteSessionInfo sessionInfo, int requestId) {
SessionCreationRequest matchingRequest = null;
@@ -559,40 +557,44 @@
}
}
- if (matchingRequest == null) {
- Log.w(TAG, "Ignoring session creation result for unknown request."
- + " requestId=" + requestId + ", sessionInfo=" + sessionInfo);
- return;
+ if (matchingRequest != null) {
+ mSessionCreationRequests.remove(matchingRequest);
+
+ MediaRoute2Info requestedRoute = matchingRequest.mRoute;
+ String requestedControlCategory = matchingRequest.mControlCategory;
+
+ if (sessionInfo == null) {
+ // TODO: We may need to distinguish between failure and rejection.
+ // One way can be introducing 'reason'.
+ notifySessionCreationFailed(requestedRoute, requestedControlCategory);
+ return;
+ } else if (!TextUtils.equals(requestedControlCategory,
+ sessionInfo.getControlCategory())) {
+ Log.w(TAG, "The session has different control category from what we requested. "
+ + "(requested=" + requestedControlCategory
+ + ", actual=" + sessionInfo.getControlCategory()
+ + ")");
+ notifySessionCreationFailed(requestedRoute, requestedControlCategory);
+ return;
+ } else if (!sessionInfo.getSelectedRoutes().contains(requestedRoute.getId())) {
+ Log.w(TAG, "The session does not contain the requested route. "
+ + "(requestedRouteId=" + requestedRoute.getId()
+ + ", actualRoutes=" + sessionInfo.getSelectedRoutes()
+ + ")");
+ notifySessionCreationFailed(requestedRoute, requestedControlCategory);
+ return;
+ } else if (!TextUtils.equals(requestedRoute.getProviderId(),
+ sessionInfo.getProviderId())) {
+ Log.w(TAG, "The session's provider ID does not match the requested route's. "
+ + "(requested route's providerId=" + requestedRoute.getProviderId()
+ + ", actual providerId=" + sessionInfo.getProviderId()
+ + ")");
+ notifySessionCreationFailed(requestedRoute, requestedControlCategory);
+ return;
+ }
}
- mSessionCreationRequests.remove(matchingRequest);
-
- MediaRoute2Info requestedRoute = matchingRequest.mRoute;
- String requestedControlCategory = matchingRequest.mControlCategory;
-
- if (sessionInfo == null) {
- // TODO: We may need to distinguish between failure and rejection.
- // One way can be introducing 'reason'.
- notifySessionCreationFailed(requestedRoute, requestedControlCategory);
- } else if (!TextUtils.equals(requestedControlCategory, sessionInfo.getControlCategory())) {
- Log.w(TAG, "The session has different control category from what we requested. "
- + "(requested=" + requestedControlCategory
- + ", actual=" + sessionInfo.getControlCategory()
- + ")");
- notifySessionCreationFailed(requestedRoute, requestedControlCategory);
- } else if (!sessionInfo.getSelectedRoutes().contains(requestedRoute.getId())) {
- Log.w(TAG, "The session does not contain the requested route. "
- + "(requestedRouteId=" + requestedRoute.getId()
- + ", actualRoutes=" + sessionInfo.getSelectedRoutes()
- + ")");
- notifySessionCreationFailed(requestedRoute, requestedControlCategory);
- } else if (!TextUtils.equals(requestedRoute.getProviderId(), sessionInfo.getProviderId())) {
- Log.w(TAG, "The session's provider ID does not match the requested route's. "
- + "(requested route's providerId=" + requestedRoute.getProviderId()
- + ", actual providerId=" + sessionInfo.getProviderId()
- + ")");
- notifySessionCreationFailed(requestedRoute, requestedControlCategory);
- } else {
+ if (sessionInfo != null) {
RouteSessionController controller = new RouteSessionController(sessionInfo);
mSessionControllers.put(controller.getUniqueSessionId(), controller);
notifySessionCreated(controller);
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index ef806e4..da52696 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -966,7 +966,7 @@
{ "nativeStopFilter", "()I", (void *)android_media_tv_Tuner_stop_filter },
{ "nativeFlushFilter", "()I", (void *)android_media_tv_Tuner_flush_filter },
{ "nativeRead", "([BII)I", (void *)android_media_tv_Tuner_read_filter_fmq },
- { "nativeCloseFilter", "()I", (void *)android_media_tv_Tuner_close_filter },
+ { "nativeClose", "()I", (void *)android_media_tv_Tuner_close_filter },
};
static const JNINativeMethod gDescramblerMethods[] = {
@@ -975,7 +975,7 @@
{ "nativeRemovePid", "(IILandroid/media/tv/tuner/Tuner$Filter;)I",
(void *)android_media_tv_Tuner_remove_pid },
{ "nativeSetKeyToken", "([B)I", (void *)android_media_tv_Tuner_set_key_token },
- { "nativeClose", "()V", (void *)android_media_tv_Tuner_close_descrambler },
+ { "nativeClose", "()I", (void *)android_media_tv_Tuner_close_descrambler },
};
static const JNINativeMethod gDvrMethods[] = {
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index 1d51c96..83c7c17 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -29,6 +29,7 @@
import android.media.MediaRoute2Info;
import android.media.MediaRouter2;
import android.media.MediaRouter2.RouteCallback;
+import android.media.MediaRouter2.SessionCallback;
import android.media.MediaRouter2Manager;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
@@ -101,8 +102,8 @@
private String mPackageName;
private final List<MediaRouter2Manager.Callback> mManagerCallbacks = new ArrayList<>();
- private final List<RouteCallback> mRouteCallbacks =
- new ArrayList<>();
+ private final List<RouteCallback> mRouteCallbacks = new ArrayList<>();
+ private final List<SessionCallback> mSessionCallbacks = new ArrayList<>();
public static final List<String> CATEGORIES_ALL = new ArrayList();
public static final List<String> CATEGORIES_SPECIAL = new ArrayList();
@@ -205,27 +206,26 @@
}
/**
- * Tests if MR2.Callback.onRouteSelected is called when a route is selected from MR2Manager.
- *
- * TODO: Change this test so that this test check whether the route is added in a session.
- * Until then, temporailiy marking @Ignore
+ * Tests if MR2.SessionCallback.onSessionCreated is called
+ * when a route is selected from MR2Manager.
*/
@Test
- @Ignore
- public void testRouterOnRouteSelected() throws Exception {
+ public void testRouterOnSessionCreated() throws Exception {
Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
CountDownLatch latch = new CountDownLatch(1);
addManagerCallback(new MediaRouter2Manager.Callback());
-// addRouterCallback(new RouteDiscoveryCallback() {
-// @Override
-// public void onRouteSelected(MediaRoute2Info route, int reason, Bundle controlHints) {
-// if (route != null && TextUtils.equals(route.getId(), ROUTE_ID1)) {
-// latch.countDown();
-// }
-// }
-// });
+ //TODO: remove this when it's not necessary.
+ addRouterCallback(new MediaRouter2.RouteCallback());
+ addSessionCallback(new SessionCallback() {
+ @Override
+ public void onSessionCreated(MediaRouter2.RouteSessionController controller) {
+ if (createRouteMap(controller.getSelectedRoutes()).containsKey(ROUTE_ID1)) {
+ latch.countDown();
+ }
+ }
+ });
MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
assertNotNull(routeToSelect);
@@ -446,6 +446,11 @@
mRouter2.registerRouteCallback(mExecutor, routeCallback);
}
+ private void addSessionCallback(SessionCallback sessionCallback) {
+ mSessionCallbacks.add(sessionCallback);
+ mRouter2.registerSessionCallback(mExecutor, sessionCallback);
+ }
+
private void clearCallbacks() {
for (MediaRouter2Manager.Callback callback : mManagerCallbacks) {
mManager.unregisterCallback(callback);
@@ -456,5 +461,10 @@
mRouter2.unregisterRouteCallback(routeCallback);
}
mRouteCallbacks.clear();
+
+ for (SessionCallback sessionCallback : mSessionCallbacks) {
+ mRouter2.unregisterSessionCallback(sessionCallback);
+ }
+ mSessionCallbacks.clear();
}
}
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
index 7fc65a3..b4f5253 100644
--- a/packages/SettingsLib/res/values-ar/arrays.xml
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -170,7 +170,7 @@
<string-array name="select_logpersist_titles">
<item msgid="704720725704372366">"إيقاف"</item>
<item msgid="6014837961827347618">"الكل"</item>
- <item msgid="7387060437894578132">"الكل دون اللاسلكي"</item>
+ <item msgid="7387060437894578132">"الكل بدون اللاسلكي"</item>
<item msgid="7300881231043255746">"kernel فقط"</item>
</string-array>
<string-array name="select_logpersist_summaries">
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index d4e1b63..43d2ece 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -68,14 +68,14 @@
<string name="bluetooth_connecting" msgid="5871702668260192755">"جارٍ الاتصال…"</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"الجهاز متصل<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_pairing" msgid="4269046942588193600">"جارٍ الاقتران..."</string>
- <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"الجهاز متصل (من دون هاتف)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"الجهاز متصل (من دون وسائط)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"الجهاز متصل (من دون وصول إلى الرسائل)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2893204819854215433">"الجهاز متصل (من دون هاتف أو وسائط)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"الجهاز متصل (بدون هاتف)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"الجهاز متصل (بدون وسائط)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"الجهاز متصل (بدون وصول إلى الرسائل)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2893204819854215433">"الجهاز متصل (بدون هاتف أو وسائط)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"الجهاز متصل، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"الجهاز متصل (من دون هاتف)، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"الجهاز متصل (من دون وسائط)، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"الجهاز متّصل (من دون هاتف أو وسائط)، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"الجهاز متصل (بدون هاتف)، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"الجهاز متصل (بدون وسائط)، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"الجهاز متّصل (بدون هاتف أو وسائط)، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level" msgid="3450745316700494425">"نشط، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"مفعّلة، مستوى البطارية: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، المعدّل: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_battery_level" msgid="2893696778200201555">"مستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 07d5ccb..3f99d10 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -227,8 +227,7 @@
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Konexioa partekatzeko hardwarearen azelerazioa"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Erakutsi Bluetooth gailuak izenik gabe"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desgaitu bolumen absolutua"</string>
- <!-- no translation found for bluetooth_enable_gabeldorsche (9131730396242883416) -->
- <skip />
+ <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gaitu Gabeldorsche"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP bertsioa"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Hautatu Bluetooth AVRCP bertsioa"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"Bluetooth bidezko audioaren kodeka"</string>
@@ -277,8 +276,7 @@
<string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Egiaztatu ADB/ADT bidez instalatutako aplikazioak portaera kaltegarriak atzemateko"</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Bluetooth gailuak izenik gabe (MAC helbideak soilik) erakutsiko dira"</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Bluetooth bidezko bolumen absolutuaren eginbidea desgaitu egiten du urruneko gailuetan arazoak hautematen badira; esaterako, bolumena ozenegia bada edo ezin bada kontrolatu"</string>
- <!-- no translation found for bluetooth_enable_gabeldorsche_summary (8472344901097607030) -->
- <skip />
+ <string name="bluetooth_enable_gabeldorsche_summary" msgid="8472344901097607030">"Bluetooth Gabeldorsche eginbide sorta gaitzen du."</string>
<string name="enable_terminal_title" msgid="3834790541986303654">"Tokiko terminala"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Gaitu tokiko shell-sarbidea duen terminal-aplikazioa"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP egiaztapena"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 154f386..f9ac3a5 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -227,8 +227,7 @@
<string name="tethering_hardware_offload" msgid="4116053719006939161">"हार्डवेयर से तेज़ी लाने के लिए टेदर करें"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"बिना नाम वाले ब्लूटूथ डिवाइस दिखाएं"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ब्लूटूथ से आवाज़ के नियंत्रण की सुविधा रोकें"</string>
- <!-- no translation found for bluetooth_enable_gabeldorsche (9131730396242883416) -->
- <skip />
+ <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche चालू करें"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ब्लूटूथ एवीआरसीपी वर्शन"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ब्लूटूथ AVRCP वर्शन चुनें"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"ब्लूटूथ ऑडियो कोडेक"</string>
@@ -277,8 +276,7 @@
<string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"नुकसानदेह व्यवहार के लिए ADB/ADT से इंस्टॉल किए गए ऐप्लिकेशन जाँचें."</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"बिना नाम वाले ब्लूटूथ डिवाइस (केवल MAC पते वाले) दिखाए जाएंगे"</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"दूर के डिवाइस पर आवाज़ बहुत बढ़ जाने या उससे नियंत्रण हटने जैसी समस्याएं होने पर, यह ब्लूटूथ के ज़रिए आवाज़ के नियंत्रण की सुविधा रोक देता है."</string>
- <!-- no translation found for bluetooth_enable_gabeldorsche_summary (8472344901097607030) -->
- <skip />
+ <string name="bluetooth_enable_gabeldorsche_summary" msgid="8472344901097607030">"Bluetooth Gabeldorsche सुविधा का स्टैक चालू करें."</string>
<string name="enable_terminal_title" msgid="3834790541986303654">"स्थानीय टर्मिनल"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"लोकल शेल तक पहुंचने की सुविधा देने वाले टर्मिनल ऐप को चालू करें"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"एचडीसीपी जाँच"</string>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
index 4c22bda..d946316 100644
--- a/packages/SettingsLib/res/values-sl/arrays.xml
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -82,8 +82,6 @@
<item msgid="1049450003868150455">"Zvok <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
<item msgid="2908219194098827570">"Zvok <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
<item msgid="3825367753087348007">"LDAC"</item>
- <item msgid="5832677994279829983">"Omogoči izbirne kodeke"</item>
- <item msgid="9205039209798344398">"Onemogoči izbirne kodeke"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_summaries">
<item msgid="8868109554557331312">"Uporabi sistemsko izbiro (privzeto)"</item>
@@ -92,8 +90,6 @@
<item msgid="8627333814413492563">"Zvok <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
<item msgid="3517061573669307965">"Zvok <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
<item msgid="2553206901068987657">"LDAC"</item>
- <item msgid="221347164942544028">"Omogoči izbirne kodeke"</item>
- <item msgid="7416462860415701287">"Onemogoči izbirne kodeke"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="926809261293414607">"Uporabi sistemsko izbiro (privzeto)"</item>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 90d7829..efd7c08 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -227,6 +227,7 @@
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Strojno pospeševanje za internetno povezavo prek mobilnega telefona"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži naprave Bluetooth brez imen"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogočanje absolutne glasnosti"</string>
+ <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogoči Gabeldorsche"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Različica profila AVRCP za Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Izberite različico profila AVRCP za Bluetooth"</string>
<string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"Zvočni kodek za Bluetooth"</string>
@@ -275,6 +276,7 @@
<string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Preveri, ali so aplikacije, nameščene prek ADB/ADT, škodljive."</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Prikazane bodo naprave Bluetooth brez imen (samo z naslovi MAC)"</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Onemogoči funkcijo absolutne glasnosti za Bluetooth, če pride do težav z glasnostjo z oddaljenimi napravami, kot je nesprejemljivo visoka glasnost ali pomanjkanje nadzora."</string>
+ <string name="bluetooth_enable_gabeldorsche_summary" msgid="8472344901097607030">"Omogoči sklad funkcij Bluetooth Gabeldorche."</string>
<string name="enable_terminal_title" msgid="3834790541986303654">"Lokalni terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Omogočanje terminalske aplikacije za dostop do lokalne lupine"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"Preverjanje HDCP"</string>
@@ -379,7 +381,7 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (rdeča – zelena)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (modra – rumena)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Popravljanje barv"</string>
- <string name="accessibility_display_daltonizer_preference_subtitle" msgid="5190814747212060815">"To je preskusna funkcija in lahko vpliva na učinkovitost delovanja."</string>
+ <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Popravljanje barv osebam z barvno slepoto pomaga, da vidijo bolj prave barve"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Preglasila nastavitev: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Še približno <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index 58655a2..b4b55f3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -203,13 +203,6 @@
}
}
- public int getVolume() {
- if (mService == null) {
- return 0;
- }
- return mService.getVolume();
- }
-
public void setVolume(int volume) {
if (mService == null) {
return;
@@ -224,20 +217,6 @@
return mService.getHiSyncId(device);
}
- public int getDeviceSide(BluetoothDevice device) {
- if (mService == null) {
- return BluetoothHearingAid.SIDE_LEFT;
- }
- return mService.getDeviceSide(device);
- }
-
- public int getDeviceMode(BluetoothDevice device) {
- if (mService == null) {
- return BluetoothHearingAid.MODE_MONAURAL;
- }
- return mService.getDeviceMode(device);
- }
-
public String toString() {
return NAME;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index b960de5..35a65aa 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -26,8 +26,6 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -37,7 +35,6 @@
import android.view.WindowManager;
import android.widget.ImageView;
-import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.PhoneConstants;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -258,12 +255,22 @@
@Override
public void run() {
- try {
- if (DEBUG) {
- Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")");
- }
- final int[] result = ITelephony.Stub.asInterface(ServiceManager
- .checkService("phone")).supplyPinReportResultForSubscriber(mSubId, mPin);
+ if (DEBUG) {
+ Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")");
+ }
+ TelephonyManager telephonyManager =
+ ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
+ .createForSubscriptionId(mSubId);
+ final int[] result = telephonyManager.supplyPinReportResult(mPin);
+ if (result == null || result.length == 0) {
+ Log.e(TAG, "Error result for supplyPinReportResult.");
+ post(new Runnable() {
+ @Override
+ public void run() {
+ onSimCheckResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
+ }
+ });
+ } else {
if (DEBUG) {
Log.v(TAG, "supplyPinReportResult returned: " + result[0] + " " + result[1]);
}
@@ -273,14 +280,6 @@
onSimCheckResponse(result[0], result[1]);
}
});
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException for supplyPinReportResult:", e);
- post(new Runnable() {
- @Override
- public void run() {
- onSimCheckResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
- }
- });
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 7e08ab3..dc68115 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -25,8 +25,6 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -36,7 +34,6 @@
import android.view.WindowManager;
import android.widget.ImageView;
-import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.PhoneConstants;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -318,10 +315,20 @@
@Override
public void run() {
- try {
- if (DEBUG) Log.v(TAG, "call supplyPukReportResult()");
- final int[] result = ITelephony.Stub.asInterface(ServiceManager
- .checkService("phone")).supplyPukReportResultForSubscriber(mSubId, mPuk, mPin);
+ if (DEBUG) Log.v(TAG, "call supplyPukReportResult()");
+ TelephonyManager telephonyManager =
+ ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
+ .createForSubscriptionId(mSubId);
+ final int[] result = telephonyManager.supplyPukReportResult(mPuk, mPin);
+ if (result == null || result.length == 0) {
+ Log.e(TAG, "Error result for supplyPukReportResult.");
+ post(new Runnable() {
+ @Override
+ public void run() {
+ onSimLockChangedResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
+ }
+ });
+ } else {
if (DEBUG) {
Log.v(TAG, "supplyPukReportResult returned: " + result[0] + " " + result[1]);
}
@@ -331,14 +338,6 @@
onSimLockChangedResponse(result[0], result[1]);
}
});
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException for supplyPukReportResult:", e);
- post(new Runnable() {
- @Override
- public void run() {
- onSimLockChangedResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
- }
- });
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index 995b35f..fdeaf1f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -134,7 +134,8 @@
if (isStack) {
mViewPositionOnTouchDown.set(mStack.getStackPosition());
mStack.onDragStart();
- if (!mStack.isShowingBubbleMenu() && !mStack.isExpanded()) {
+ if (!mStack.isShowingBubbleMenu() && !mStack.isExpanded()
+ && BubbleExperimentConfig.allowBubbleScreenshotMenu(mContext)) {
mShowBubbleMenuRunnable = mStack::showBubbleMenu;
mStack.postDelayed(mShowBubbleMenuRunnable,
ViewConfiguration.getLongPressTimeout());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 9261412..bbff117 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -42,6 +42,7 @@
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Manages the lifecycle of a TileService.
@@ -84,7 +85,8 @@
private int mBindTryCount;
private int mBindRetryDelay = DEFAULT_BIND_RETRY_DELAY;
private boolean mBound;
- boolean mReceiverRegistered;
+ private AtomicBoolean mPackageReceiverRegistered = new AtomicBoolean(false);
+ private AtomicBoolean mUserReceiverRegistered = new AtomicBoolean(false);
private boolean mUnbindImmediate;
private TileChangeListener mChangeListener;
// Return value from bindServiceAsUser, determines whether safe to call unbind.
@@ -274,7 +276,7 @@
public void handleDestroy() {
if (DEBUG) Log.d(TAG, "handleDestroy");
- if (mReceiverRegistered) {
+ if (mPackageReceiverRegistered.get() || mUserReceiverRegistered.get()) {
stopPackageListening();
}
}
@@ -310,17 +312,31 @@
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
- mContext.registerReceiverAsUser(this, mUser, filter, null, mHandler);
+ try {
+ mPackageReceiverRegistered.set(true);
+ mContext.registerReceiverAsUser(this, mUser, filter, null, mHandler);
+ } catch (Exception ex) {
+ mPackageReceiverRegistered.set(false);
+ Log.e(TAG, "Could not register package receiver", ex);
+ }
filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
- mBroadcastDispatcher.registerReceiver(this, filter, mHandler, mUser);
- mReceiverRegistered = true;
+ try {
+ mUserReceiverRegistered.set(true);
+ mBroadcastDispatcher.registerReceiver(this, filter, mHandler, mUser);
+ } catch (Exception ex) {
+ mUserReceiverRegistered.set(false);
+ Log.e(TAG, "Could not register unlock receiver", ex);
+ }
}
private void stopPackageListening() {
if (DEBUG) Log.d(TAG, "stopPackageListening");
- mContext.unregisterReceiver(this);
- mBroadcastDispatcher.unregisterReceiver(this);
- mReceiverRegistered = false;
+ if (mUserReceiverRegistered.compareAndSet(true, false)) {
+ mBroadcastDispatcher.unregisterReceiver(this);
+ }
+ if (mPackageReceiverRegistered.compareAndSet(true, false)) {
+ mContext.unregisterReceiver(this);
+ }
}
public void setTileChangeListener(TileChangeListener changeListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 9a33c8c..f06c849 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -38,7 +38,6 @@
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.FlashlightTile;
import com.android.systemui.qs.tiles.HotspotTile;
-import com.android.systemui.qs.tiles.IntentTile;
import com.android.systemui.qs.tiles.LocationTile;
import com.android.systemui.qs.tiles.NfcTile;
import com.android.systemui.qs.tiles.NightDisplayTile;
@@ -182,8 +181,7 @@
return mUiModeNightTileProvider.get();
}
- // Intent tiles.
- if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(mHost, tileSpec);
+ // Custom tiles
if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(mHost, tileSpec);
// Debug tiles.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
deleted file mode 100644
index a639a95..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2014 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.qs.tiles;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.qs.QSTile.State;
-import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.tileimpl.QSTileImpl;
-
-import java.util.Arrays;
-import java.util.Objects;
-
-public class IntentTile extends QSTileImpl<State> {
- public static final String PREFIX = "intent(";
-
- private PendingIntent mOnClick;
- private String mOnClickUri;
- private PendingIntent mOnLongClick;
- private String mOnLongClickUri;
- private int mCurrentUserId;
- private String mIntentPackage;
-
- private Intent mLastIntent;
-
- private IntentTile(QSHost host, String action) {
- super(host);
- mContext.registerReceiver(mReceiver, new IntentFilter(action));
- }
-
- @Override
- protected void handleDestroy() {
- super.handleDestroy();
- mContext.unregisterReceiver(mReceiver);
- }
-
- public static IntentTile create(QSHost host, String spec) {
- if (spec == null || !spec.startsWith(PREFIX) || !spec.endsWith(")")) {
- throw new IllegalArgumentException("Bad intent tile spec: " + spec);
- }
- final String action = spec.substring(PREFIX.length(), spec.length() - 1);
- if (action.isEmpty()) {
- throw new IllegalArgumentException("Empty intent tile spec action");
- }
- return new IntentTile(host, action);
- }
-
- @Override
- public void handleSetListening(boolean listening) {
- }
-
- @Override
- public State newTileState() {
- return new State();
- }
-
- @Override
- protected void handleUserSwitch(int newUserId) {
- super.handleUserSwitch(newUserId);
- mCurrentUserId = newUserId;
- }
-
- @Override
- protected void handleClick() {
- sendIntent("click", mOnClick, mOnClickUri);
- }
-
- @Override
- public Intent getLongClickIntent() {
- return null;
- }
-
- @Override
- protected void handleLongClick() {
- sendIntent("long-click", mOnLongClick, mOnLongClickUri);
- }
-
- private void sendIntent(String type, PendingIntent pi, String uri) {
- try {
- if (pi != null) {
- if (pi.isActivity()) {
- Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(pi);
- } else {
- pi.send();
- }
- } else if (uri != null) {
- final Intent intent = Intent.parseUri(uri, Intent.URI_INTENT_SCHEME);
- mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
- }
- } catch (Throwable t) {
- Log.w(TAG, "Error sending " + type + " intent", t);
- }
- }
-
- @Override
- public CharSequence getTileLabel() {
- return getState().label;
- }
-
- @Override
- protected void handleUpdateState(State state, Object arg) {
- Intent intent = (Intent) arg;
- if (intent == null) {
- if (mLastIntent == null) {
- return;
- }
- // No intent but need to refresh state, just use the last one.
- intent = mLastIntent;
- }
- // Save the last one in case we need it later.
- mLastIntent = intent;
- state.contentDescription = intent.getStringExtra("contentDescription");
- state.label = intent.getStringExtra("label");
- state.icon = null;
- final byte[] iconBitmap = intent.getByteArrayExtra("iconBitmap");
- if (iconBitmap != null) {
- try {
- state.icon = new BytesIcon(iconBitmap);
- } catch (Throwable t) {
- Log.w(TAG, "Error loading icon bitmap, length " + iconBitmap.length, t);
- }
- } else {
- final int iconId = intent.getIntExtra("iconId", 0);
- if (iconId != 0) {
- final String iconPackage = intent.getStringExtra("iconPackage");
- if (!TextUtils.isEmpty(iconPackage)) {
- state.icon = new PackageDrawableIcon(iconPackage, iconId);
- } else {
- state.icon = ResourceIcon.get(iconId);
- }
- }
- }
- mOnClick = intent.getParcelableExtra("onClick");
- mOnClickUri = intent.getStringExtra("onClickUri");
- mOnLongClick = intent.getParcelableExtra("onLongClick");
- mOnLongClickUri = intent.getStringExtra("onLongClickUri");
- mIntentPackage = intent.getStringExtra("package");
- mIntentPackage = mIntentPackage == null ? "" : mIntentPackage;
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.QS_INTENT;
- }
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- refreshState(intent);
- }
- };
-
- private static class BytesIcon extends Icon {
- private final byte[] mBytes;
-
- public BytesIcon(byte[] bytes) {
- mBytes = bytes;
- }
-
- @Override
- public Drawable getDrawable(Context context) {
- final Bitmap b = BitmapFactory.decodeByteArray(mBytes, 0, mBytes.length);
- return new BitmapDrawable(context.getResources(), b);
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof BytesIcon && Arrays.equals(((BytesIcon) o).mBytes, mBytes);
- }
-
- @Override
- public String toString() {
- return String.format("BytesIcon[len=%s]", mBytes.length);
- }
- }
-
- private class PackageDrawableIcon extends Icon {
- private final String mPackage;
- private final int mResId;
-
- public PackageDrawableIcon(String pkg, int resId) {
- mPackage = pkg;
- mResId = resId;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof PackageDrawableIcon)) return false;
- final PackageDrawableIcon other = (PackageDrawableIcon) o;
- return Objects.equals(other.mPackage, mPackage) && other.mResId == mResId;
- }
-
- @Override
- public Drawable getDrawable(Context context) {
- try {
- return context.createPackageContext(mPackage, 0).getDrawable(mResId);
- } catch (Throwable t) {
- Log.w(TAG, "Error loading package drawable pkg=" + mPackage + " id=" + mResId, t);
- return null;
- }
- }
-
- @Override
- public String toString() {
- return String.format("PackageDrawableIcon[pkg=%s,id=0x%08x]", mPackage, mResId);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index d3ccbeb..77c3ad9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -27,7 +27,6 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
-import android.graphics.Point;
import android.graphics.drawable.Icon;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
@@ -42,6 +41,7 @@
import android.util.Log;
import android.util.Size;
import android.view.Surface;
+import android.view.WindowManager;
import android.widget.Toast;
import com.android.systemui.R;
@@ -76,7 +76,7 @@
private static final String ACTION_DELETE = "com.android.systemui.screenrecord.DELETE";
private static final int TOTAL_NUM_TRACKS = 1;
- private static final int VIDEO_BIT_RATE = 6000000;
+ private static final int VIDEO_BIT_RATE = 10000000;
private static final int VIDEO_FRAME_RATE = 30;
private static final int AUDIO_BIT_RATE = 16;
private static final int AUDIO_SAMPLE_RATE = 44100;
@@ -238,7 +238,9 @@
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// Set up video
- DisplayMetrics metrics = getResources().getDisplayMetrics();
+ DisplayMetrics metrics = new DisplayMetrics();
+ WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
+ wm.getDefaultDisplay().getRealMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index 8dd801b..8cc45f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -51,7 +51,7 @@
private final Context mContext;
private final NotificationManager mNotificationManager;
private final Handler mMainHandler;
- private final List<NotifServiceListener> mNotificationListeners = new ArrayList<>();
+ private final List<NotificationHandler> mNotificationHandlers = new ArrayList<>();
private final ArrayList<NotificationSettingsListener> mSettingsListeners = new ArrayList<>();
@Inject
@@ -65,11 +65,11 @@
}
/** Registers a listener that's notified when notifications are added/removed/etc. */
- public void addNotificationListener(NotifServiceListener listener) {
- if (mNotificationListeners.contains(listener)) {
+ public void addNotificationHandler(NotificationHandler handler) {
+ if (mNotificationHandlers.contains(handler)) {
throw new IllegalArgumentException("Listener is already added");
}
- mNotificationListeners.add(listener);
+ mNotificationHandlers.add(handler);
}
/** Registers a listener that's notified when any notification-related settings change. */
@@ -100,7 +100,7 @@
final RankingMap completeMap = new RankingMap(newRankings.toArray(new Ranking[0]));
for (StatusBarNotification sbn : notifications) {
- for (NotifServiceListener listener : mNotificationListeners) {
+ for (NotificationHandler listener : mNotificationHandlers) {
listener.onNotificationPosted(sbn, completeMap);
}
}
@@ -117,8 +117,8 @@
mMainHandler.post(() -> {
processForRemoteInput(sbn.getNotification(), mContext);
- for (NotifServiceListener listener : mNotificationListeners) {
- listener.onNotificationPosted(sbn, rankingMap);
+ for (NotificationHandler handler : mNotificationHandlers) {
+ handler.onNotificationPosted(sbn, rankingMap);
}
});
}
@@ -130,8 +130,8 @@
if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn + " reason: " + reason);
if (sbn != null && !onPluginNotificationRemoved(sbn, rankingMap)) {
mMainHandler.post(() -> {
- for (NotifServiceListener listener : mNotificationListeners) {
- listener.onNotificationRemoved(sbn, rankingMap, reason);
+ for (NotificationHandler handler : mNotificationHandlers) {
+ handler.onNotificationRemoved(sbn, rankingMap, reason);
}
});
}
@@ -148,8 +148,8 @@
if (rankingMap != null) {
RankingMap r = onPluginRankingUpdate(rankingMap);
mMainHandler.post(() -> {
- for (NotifServiceListener listener : mNotificationListeners) {
- listener.onNotificationRankingUpdate(r);
+ for (NotificationHandler handler : mNotificationHandlers) {
+ handler.onNotificationRankingUpdate(r);
}
});
}
@@ -207,7 +207,7 @@
}
/** Interface for listening to add/remove events that we receive from NotificationManager. */
- public interface NotifServiceListener {
+ public interface NotificationHandler {
void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap);
void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap);
void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap, int reason);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index 778443c..fdb793e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -33,6 +33,7 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Keeps track of the currently active {@link RemoteInputView}s.
@@ -108,8 +109,8 @@
* @param token a token identifying the view that is managing the remote input
*/
public void addRemoteInput(NotificationEntry entry, Object token) {
- Preconditions.checkNotNull(entry);
- Preconditions.checkNotNull(token);
+ Objects.requireNonNull(entry);
+ Objects.requireNonNull(token);
boolean found = pruneWeakThenRemoveAndContains(
entry /* contains */, null /* remove */, token /* removeToken */);
@@ -129,7 +130,7 @@
* entry. If null, the entry is removed regardless.
*/
public void removeRemoteInput(NotificationEntry entry, Object token) {
- Preconditions.checkNotNull(entry);
+ Objects.requireNonNull(entry);
pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */, token);
@@ -143,8 +144,8 @@
* @param token the token of the view managing the remote input.
*/
public void addSpinning(String key, Object token) {
- Preconditions.checkNotNull(key);
- Preconditions.checkNotNull(token);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(token);
mSpinning.put(key, token);
}
@@ -158,7 +159,7 @@
* entry. If null, the entry is removed regardless.
*/
public void removeSpinning(String key, Object token) {
- Preconditions.checkNotNull(key);
+ Objects.requireNonNull(key);
if (token == null || mSpinning.get(key) == token) {
mSpinning.remove(key);
@@ -237,7 +238,7 @@
public void addCallback(Callback callback) {
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(callback);
mCallbacks.add(callback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index b8afb78..33d97a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -36,7 +36,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationListener.NotifServiceListener;
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
@@ -179,7 +179,7 @@
/** Once called, the NEM will start processing notification events from system server. */
public void attach(NotificationListener notificationListener) {
- notificationListener.addNotificationListener(mNotifListener);
+ notificationListener.addNotificationHandler(mNotifListener);
}
/** Adds a {@link NotificationEntryListener}. */
@@ -326,7 +326,7 @@
}
}
- private final NotifServiceListener mNotifListener = new NotifServiceListener() {
+ private final NotificationHandler mNotifListener = new NotificationHandler() {
@Override
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
final boolean isUpdate = mActiveNotifications.containsKey(sbn.getKey());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
index 7b1dc07..f2765db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
@@ -16,14 +16,14 @@
package com.android.systemui.statusbar.notification;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+import java.util.Objects;
+
/**
* Root controller for the list of notifications in the shade.
*
@@ -39,9 +39,9 @@
NotificationEntryManager entryManager,
NotificationListContainer listContainer,
DeviceProvisionedController deviceProvisionedController) {
- mEntryManager = checkNotNull(entryManager);
- mListContainer = checkNotNull(listContainer);
- mDeviceProvisionedController = checkNotNull(deviceProvisionedController);
+ mEntryManager = Objects.requireNonNull(entryManager);
+ mListContainer = Objects.requireNonNull(listContainer);
+ mDeviceProvisionedController = Objects.requireNonNull(deviceProvisionedController);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java
index cefb506..87aaea0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java
@@ -24,18 +24,6 @@
*/
public interface CollectionReadyForBuildListener {
/**
- * Called after the NotifCollection has received an update from NotificationManager but before
- * it dispatches any change events to its listeners. This is to inform the list builder that
- * the first stage of the pipeline has been triggered. After events have been dispatched,
- * onBuildList() will be called.
- *
- * While onBuildList() is always called after this method is called, the converse is not always
- * true: sometimes the NotifCollection applies an update that does not need to dispatch events,
- * in which case this method will be skipped and onBuildList will be called directly.
- */
- void onBeginDispatchToListeners();
-
- /**
* Called by the NotifCollection to indicate that something in the collection has changed and
* that the list builder should regenerate the list.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 7f85c88..873cdbc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -35,8 +35,6 @@
import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
@@ -49,8 +47,9 @@
import android.util.Log;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationListener.NotifServiceListener;
+import com.android.systemui.statusbar.notification.collection.notifcollection.CoalescedEvent;
+import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
+import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer.BatchableNotificationHandler;
import com.android.systemui.util.Assert;
import java.lang.annotation.Retention;
@@ -60,6 +59,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -109,14 +109,14 @@
}
/** Initializes the NotifCollection and registers it to receive notification events. */
- public void attach(NotificationListener listenerService) {
+ public void attach(GroupCoalescer groupCoalescer) {
Assert.isMainThread();
if (mAttached) {
throw new RuntimeException("attach() called twice");
}
mAttached = true;
- listenerService.addNotificationListener(mNotifServiceListener);
+ groupCoalescer.setNotificationHandler(mNotifHandler);
}
/**
@@ -170,7 +170,7 @@
@CancellationReason int reason,
@NonNull DismissedByUserStats stats) {
Assert.isMainThread();
- checkNotNull(stats);
+ Objects.requireNonNull(stats);
checkForReentrantCall();
removeNotification(entry.getKey(), null, reason, stats);
@@ -179,15 +179,52 @@
private void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
Assert.isMainThread();
+ postNotification(sbn, requireRanking(rankingMap, sbn.getKey()), rankingMap);
+ rebuildList();
+ }
+
+ private void onNotificationGroupPosted(List<CoalescedEvent> batch) {
+ Assert.isMainThread();
+
+ Log.d(TAG, "POSTED GROUP " + batch.get(0).getSbn().getGroupKey()
+ + " (" + batch.size() + " events)");
+ for (CoalescedEvent event : batch) {
+ postNotification(event.getSbn(), event.getRanking(), null);
+ }
+ rebuildList();
+ }
+
+ private void onNotificationRemoved(
+ StatusBarNotification sbn,
+ RankingMap rankingMap,
+ int reason) {
+ Assert.isMainThread();
+
+ Log.d(TAG, "REMOVED " + sbn.getKey() + " reason=" + reason);
+ removeNotification(sbn.getKey(), rankingMap, reason, null);
+ }
+
+ private void onNotificationRankingUpdate(RankingMap rankingMap) {
+ Assert.isMainThread();
+ applyRanking(rankingMap);
+ rebuildList();
+ }
+
+ private void postNotification(
+ StatusBarNotification sbn,
+ Ranking ranking,
+ @Nullable RankingMap rankingMap) {
NotificationEntry entry = mNotificationSet.get(sbn.getKey());
if (entry == null) {
// A new notification!
Log.d(TAG, "POSTED " + sbn.getKey());
- entry = new NotificationEntry(sbn, requireRanking(rankingMap, sbn.getKey()));
+ entry = new NotificationEntry(sbn, ranking);
mNotificationSet.put(sbn.getKey(), entry);
- applyRanking(rankingMap);
+ if (rankingMap != null) {
+ applyRanking(rankingMap);
+ }
dispatchOnEntryAdded(entry);
@@ -200,34 +237,19 @@
cancelLifetimeExtension(entry);
entry.setSbn(sbn);
- applyRanking(rankingMap);
+ if (rankingMap != null) {
+ applyRanking(rankingMap);
+ }
dispatchOnEntryUpdated(entry);
}
-
- rebuildList();
- }
-
- private void onNotificationRemoved(
- StatusBarNotification sbn,
- @Nullable RankingMap rankingMap,
- int reason) {
- Assert.isMainThread();
- Log.d(TAG, "REMOVED " + sbn.getKey() + " reason=" + reason);
- removeNotification(sbn.getKey(), rankingMap, reason, null);
- }
-
- private void onNotificationRankingUpdate(RankingMap rankingMap) {
- Assert.isMainThread();
- applyRanking(rankingMap);
- rebuildList();
}
private void removeNotification(
String key,
@Nullable RankingMap rankingMap,
@CancellationReason int reason,
- DismissedByUserStats dismissedByUserStats) {
+ @Nullable DismissedByUserStats dismissedByUserStats) {
NotificationEntry entry = mNotificationSet.get(key);
if (entry == null) {
@@ -272,7 +294,7 @@
rebuildList();
}
- private void applyRanking(RankingMap rankingMap) {
+ private void applyRanking(@NonNull RankingMap rankingMap) {
for (NotificationEntry entry : mNotificationSet.values()) {
if (!isLifetimeExtended(entry)) {
Ranking ranking = requireRanking(rankingMap, entry.getKey());
@@ -339,9 +361,6 @@
private void dispatchOnEntryAdded(NotificationEntry entry) {
mAmDispatchingToOtherCode = true;
- if (mBuildListener != null) {
- mBuildListener.onBeginDispatchToListeners();
- }
for (NotifCollectionListener listener : mNotifCollectionListeners) {
listener.onEntryAdded(entry);
}
@@ -350,9 +369,6 @@
private void dispatchOnEntryUpdated(NotificationEntry entry) {
mAmDispatchingToOtherCode = true;
- if (mBuildListener != null) {
- mBuildListener.onBeginDispatchToListeners();
- }
for (NotifCollectionListener listener : mNotifCollectionListeners) {
listener.onEntryUpdated(entry);
}
@@ -364,22 +380,24 @@
@CancellationReason int reason,
boolean removedByUser) {
mAmDispatchingToOtherCode = true;
- if (mBuildListener != null) {
- mBuildListener.onBeginDispatchToListeners();
- }
for (NotifCollectionListener listener : mNotifCollectionListeners) {
listener.onEntryRemoved(entry, reason, removedByUser);
}
mAmDispatchingToOtherCode = false;
}
- private final NotifServiceListener mNotifServiceListener = new NotifServiceListener() {
+ private final BatchableNotificationHandler mNotifHandler = new BatchableNotificationHandler() {
@Override
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
NotifCollection.this.onNotificationPosted(sbn, rankingMap);
}
@Override
+ public void onNotificationBatchPosted(List<CoalescedEvent> events) {
+ NotifCollection.this.onNotificationGroupPosted(events);
+ }
+
+ @Override
public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
NotifCollection.this.onNotificationRemoved(sbn, rankingMap, REASON_UNKNOWN);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
index f0a003f..19d90f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
@@ -18,7 +18,6 @@
import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY;
import static com.android.systemui.statusbar.notification.collection.ListDumper.dumpList;
-import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_BUILD_PENDING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_BUILD_STARTED;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_FINALIZING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_GROUPING;
@@ -198,12 +197,6 @@
private final CollectionReadyForBuildListener mReadyForBuildListener =
new CollectionReadyForBuildListener() {
@Override
- public void onBeginDispatchToListeners() {
- Assert.isMainThread();
- mPipelineState.incrementTo(STATE_BUILD_PENDING);
- }
-
- @Override
public void onBuildList(Collection<NotificationEntry> entries) {
Assert.isMainThread();
mPipelineState.requireIsBefore(STATE_BUILD_STARTED);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index dd3a3e0..4f4fb24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -29,7 +29,6 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
-import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
import android.annotation.NonNull;
@@ -162,9 +161,9 @@
public NotificationEntry(
@NonNull StatusBarNotification sbn,
@NonNull Ranking ranking) {
- super(checkNotNull(checkNotNull(sbn).getKey()));
+ super(Objects.requireNonNull(Objects.requireNonNull(sbn).getKey()));
- checkNotNull(ranking);
+ Objects.requireNonNull(ranking);
mKey = sbn.getKey();
setSbn(sbn);
@@ -194,8 +193,8 @@
* TODO: Make this package-private
*/
public void setSbn(@NonNull StatusBarNotification sbn) {
- checkNotNull(sbn);
- checkNotNull(sbn.getKey());
+ Objects.requireNonNull(sbn);
+ Objects.requireNonNull(sbn.getKey());
if (!sbn.getKey().equals(mKey)) {
throw new IllegalArgumentException("New key " + sbn.getKey()
@@ -223,8 +222,8 @@
* TODO: Make this package-private
*/
public void setRanking(@NonNull Ranking ranking) {
- checkNotNull(ranking);
- checkNotNull(ranking.getKey());
+ Objects.requireNonNull(ranking);
+ Objects.requireNonNull(ranking.getKey());
if (!ranking.getKey().equals(mKey)) {
throw new IllegalArgumentException("New key " + ranking.getKey()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
index 8afbc27..6c93618 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.collection;
-import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
@@ -51,6 +50,8 @@
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import java.util.Objects;
+
/** Handles inflating and updating views for notifications. */
public class NotificationRowBinderImpl implements NotificationRowBinder {
@@ -265,7 +266,7 @@
row.inflateViews();
// bind the click event to the content area
- checkNotNull(mNotificationClicker).register(row, sbn);
+ Objects.requireNonNull(mNotificationClicker).register(row, sbn);
}
private void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
index 5fc55da..5e0bd4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
@@ -24,6 +24,7 @@
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators;
+import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -36,6 +37,7 @@
*/
@Singleton
public class NewNotifPipeline implements Dumpable {
+ private final GroupCoalescer mGroupCoalescer;
private final NotifCollection mNotifCollection;
private final NotifListBuilderImpl mNotifPipeline;
private final NotifCoordinators mNotifPluggableCoordinators;
@@ -45,10 +47,12 @@
@Inject
public NewNotifPipeline(
+ GroupCoalescer groupCoalescer,
NotifCollection notifCollection,
NotifListBuilderImpl notifPipeline,
NotifCoordinators notifCoordinators,
DumpController dumpController) {
+ mGroupCoalescer = groupCoalescer;
mNotifCollection = notifCollection;
mNotifPipeline = notifPipeline;
mNotifPluggableCoordinators = notifCoordinators;
@@ -58,20 +62,26 @@
/** Hooks the new pipeline up to NotificationManager */
public void initialize(
NotificationListener notificationService) {
- mFakePipelineConsumer.attach(mNotifPipeline);
- mNotifPipeline.attach(mNotifCollection);
- mNotifCollection.attach(notificationService);
- mNotifPluggableCoordinators.attach(mNotifCollection, mNotifPipeline);
-
- Log.d(TAG, "Notif pipeline initialized");
mDumpController.registerDumpable("NotifPipeline", this);
+
+ // Wire up coordinators
+ mFakePipelineConsumer.attach(mNotifPipeline);
+ mNotifPluggableCoordinators.attach(mNotifCollection, mNotifPipeline);
+
+ // Wire up pipeline
+ mNotifPipeline.attach(mNotifCollection);
+ mNotifCollection.attach(mGroupCoalescer);
+ mGroupCoalescer.attach(notificationService);
+
+ Log.d(TAG, "Notif pipeline initialized");
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mFakePipelineConsumer.dump(fd, pw, args);
mNotifPluggableCoordinators.dump(fd, pw, args);
+ mGroupCoalescer.dump(fd, pw, args);
}
private static final String TAG = "NewNotifPipeline";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
index 85f828d..084d038 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
@@ -76,19 +76,17 @@
}
public static final int STATE_IDLE = 0;
- public static final int STATE_BUILD_PENDING = 1;
- public static final int STATE_BUILD_STARTED = 2;
- public static final int STATE_RESETTING = 3;
- public static final int STATE_PRE_GROUP_FILTERING = 4;
- public static final int STATE_GROUPING = 5;
- public static final int STATE_TRANSFORMING = 6;
- public static final int STATE_SORTING = 7;
- public static final int STATE_PRE_RENDER_FILTERING = 8;
- public static final int STATE_FINALIZING = 9;
+ public static final int STATE_BUILD_STARTED = 1;
+ public static final int STATE_RESETTING = 2;
+ public static final int STATE_PRE_GROUP_FILTERING = 3;
+ public static final int STATE_GROUPING = 4;
+ public static final int STATE_TRANSFORMING = 5;
+ public static final int STATE_SORTING = 6;
+ public static final int STATE_PRE_RENDER_FILTERING = 7;
+ public static final int STATE_FINALIZING = 8;
@IntDef(prefix = { "STATE_" }, value = {
STATE_IDLE,
- STATE_BUILD_PENDING,
STATE_BUILD_STARTED,
STATE_RESETTING,
STATE_PRE_GROUP_FILTERING,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CoalescedEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CoalescedEvent.kt
new file mode 100644
index 0000000..b6218b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CoalescedEvent.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.statusbar.notification.collection.notifcollection
+
+import android.service.notification.NotificationListenerService.Ranking
+import android.service.notification.StatusBarNotification
+
+data class CoalescedEvent(
+ val key: String,
+ var position: Int,
+ var sbn: StatusBarNotification,
+ var ranking: Ranking,
+ var batch: EventBatch?
+) {
+ override fun toString(): String {
+ return "CoalescedEvent(key=$key)"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/EventBatch.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/EventBatch.java
new file mode 100644
index 0000000..ac51178
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/EventBatch.java
@@ -0,0 +1,42 @@
+/*
+ * 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.statusbar.notification.collection.notifcollection;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a set of notification post events for a particular notification group.
+ */
+public class EventBatch {
+ /** SystemClock.uptimeMillis() */
+ final long mCreatedTimestamp;
+
+ /** SBN.getGroupKey -- same for all members */
+ final String mGroupKey;
+
+ /**
+ * All members of the batch. Must share the same group key. Includes both children and
+ * summaries.
+ */
+ final List<CoalescedEvent> mMembers = new ArrayList<>();
+
+ EventBatch(long createdTimestamp, String groupKey) {
+ mCreatedTimestamp = createdTimestamp;
+ this.mGroupKey = groupKey;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java
new file mode 100644
index 0000000..069c15f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java
@@ -0,0 +1,303 @@
+/*
+ * 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.statusbar.notification.collection.notifcollection;
+
+import static com.android.systemui.statusbar.notification.logging.NotifEvent.COALESCED_EVENT;
+import static com.android.systemui.statusbar.notification.logging.NotifEvent.EARLY_BATCH_EMIT;
+import static com.android.systemui.statusbar.notification.logging.NotifEvent.EMIT_EVENT_BATCH;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.MainThread;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
+import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.time.SystemClock;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+
+/**
+ * An attempt to make posting notification groups an atomic process
+ *
+ * Due to the nature of the groups API, individual members of a group are posted to system server
+ * one at a time. This means that whenever a group member is posted, we don't know if there are any
+ * more members soon to be posted.
+ *
+ * The Coalescer sits between the NotificationListenerService and the NotifCollection. It clusters
+ * new notifications that are members of groups and delays their posting until any of the following
+ * criteria are met:
+ *
+ * - A few milliseconds pass (see groupLingerDuration on the constructor)
+ * - Any notification in the delayed group is updated
+ * - Any notification in the delayed group is retracted
+ *
+ * Once we cross this threshold, all members of the group in question are posted atomically to the
+ * NotifCollection. If this process was triggered by an update or removal, then that event is then
+ * passed along to the NotifCollection.
+ */
+@MainThread
+public class GroupCoalescer implements Dumpable {
+ private final DelayableExecutor mMainExecutor;
+ private final SystemClock mClock;
+ private final NotifLog mLog;
+ private final long mGroupLingerDuration;
+
+ private BatchableNotificationHandler mHandler;
+
+ private final Map<String, CoalescedEvent> mCoalescedEvents = new ArrayMap<>();
+ private final Map<String, EventBatch> mBatches = new ArrayMap<>();
+
+ @Inject
+ public GroupCoalescer(
+ @Main DelayableExecutor mainExecutor,
+ SystemClock clock, NotifLog log) {
+ this(mainExecutor, clock, log, GROUP_LINGER_DURATION);
+ }
+
+ /**
+ * @param groupLingerDuration How long, in ms, that notifications that are members of a group
+ * are delayed within the GroupCoalescer before being posted
+ */
+ GroupCoalescer(
+ @Main DelayableExecutor mainExecutor,
+ SystemClock clock,
+ NotifLog log,
+ long groupLingerDuration) {
+ mMainExecutor = mainExecutor;
+ mClock = clock;
+ mLog = log;
+ mGroupLingerDuration = groupLingerDuration;
+ }
+
+ /**
+ * Attaches the coalescer to the pipeline, making it ready to receive events. Should only be
+ * called once.
+ */
+ public void attach(NotificationListener listenerService) {
+ listenerService.addNotificationHandler(mListener);
+ }
+
+ public void setNotificationHandler(BatchableNotificationHandler handler) {
+ mHandler = handler;
+ }
+
+ private final NotificationHandler mListener = new NotificationHandler() {
+ @Override
+ public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
+ maybeEmitBatch(sbn.getKey());
+ applyRanking(rankingMap);
+
+ final boolean shouldCoalesce = handleNotificationPosted(sbn, rankingMap);
+
+ if (shouldCoalesce) {
+ mLog.log(COALESCED_EVENT, String.format("Coalesced notification %s", sbn.getKey()));
+ mHandler.onNotificationRankingUpdate(rankingMap);
+ } else {
+ mHandler.onNotificationPosted(sbn, rankingMap);
+ }
+ }
+
+ @Override
+ public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
+ maybeEmitBatch(sbn.getKey());
+ applyRanking(rankingMap);
+ mHandler.onNotificationRemoved(sbn, rankingMap);
+ }
+
+ @Override
+ public void onNotificationRemoved(
+ StatusBarNotification sbn,
+ RankingMap rankingMap,
+ int reason) {
+ maybeEmitBatch(sbn.getKey());
+ applyRanking(rankingMap);
+ mHandler.onNotificationRemoved(sbn, rankingMap, reason);
+ }
+
+ @Override
+ public void onNotificationRankingUpdate(RankingMap rankingMap) {
+ applyRanking(rankingMap);
+ mHandler.onNotificationRankingUpdate(rankingMap);
+ }
+ };
+
+ private void maybeEmitBatch(String memberKey) {
+ CoalescedEvent event = mCoalescedEvents.get(memberKey);
+ if (event != null) {
+ mLog.log(EARLY_BATCH_EMIT,
+ String.format("Modification of %s triggered early emit of batched group %s",
+ memberKey, requireNonNull(event.getBatch()).mGroupKey));
+ emitBatch(requireNonNull(event.getBatch()));
+ }
+ }
+
+ /**
+ * @return True if the notification was coalesced and false otherwise.
+ */
+ private boolean handleNotificationPosted(
+ StatusBarNotification sbn,
+ RankingMap rankingMap) {
+
+ if (mCoalescedEvents.containsKey(sbn.getKey())) {
+ throw new IllegalStateException(
+ "Notification has already been coalesced: " + sbn.getKey());
+ }
+
+ if (sbn.isGroup()) {
+ EventBatch batch = startBatchingGroup(sbn.getGroupKey());
+ CoalescedEvent event =
+ new CoalescedEvent(
+ sbn.getKey(),
+ batch.mMembers.size(),
+ sbn,
+ requireRanking(rankingMap, sbn.getKey()),
+ batch);
+
+ batch.mMembers.add(event);
+
+ mCoalescedEvents.put(event.getKey(), event);
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private EventBatch startBatchingGroup(final String groupKey) {
+ EventBatch batch = mBatches.get(groupKey);
+ if (batch == null) {
+ final EventBatch newBatch = new EventBatch(mClock.uptimeMillis(), groupKey);
+ mBatches.put(groupKey, newBatch);
+ mMainExecutor.executeDelayed(() -> emitBatch(newBatch), mGroupLingerDuration);
+
+ batch = newBatch;
+ }
+ return batch;
+ }
+
+ private void emitBatch(EventBatch batch) {
+ if (batch != mBatches.get(batch.mGroupKey)) {
+ // If we emit a batch early, we don't want to emit it a second time when its timeout
+ // expires.
+ return;
+ }
+ if (batch.mMembers.isEmpty()) {
+ throw new IllegalStateException("Batch " + batch.mGroupKey + " cannot be empty");
+ }
+
+ mBatches.remove(batch.mGroupKey);
+
+ final List<CoalescedEvent> events = new ArrayList<>(batch.mMembers);
+ for (CoalescedEvent event : events) {
+ mCoalescedEvents.remove(event.getKey());
+ event.setBatch(null);
+ }
+ events.sort(mEventComparator);
+
+ mLog.log(EMIT_EVENT_BATCH, "Emitting event batch for group " + batch.mGroupKey);
+
+ mHandler.onNotificationBatchPosted(events);
+ }
+
+ private Ranking requireRanking(RankingMap rankingMap, String key) {
+ Ranking ranking = new Ranking();
+ if (!rankingMap.getRanking(key, ranking)) {
+ throw new IllegalArgumentException("Ranking map does not contain key " + key);
+ }
+ return ranking;
+ }
+
+ private void applyRanking(RankingMap rankingMap) {
+ for (CoalescedEvent event : mCoalescedEvents.values()) {
+ Ranking ranking = new Ranking();
+ if (!rankingMap.getRanking(event.getKey(), ranking)) {
+ throw new IllegalStateException(
+ "Ranking map doesn't contain key: " + event.getKey());
+ }
+ event.setRanking(ranking);
+ }
+ }
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ long now = mClock.uptimeMillis();
+
+ int eventCount = 0;
+
+ pw.println();
+ pw.println("Coalesced notifications:");
+ for (EventBatch batch : mBatches.values()) {
+ pw.println(" Batch " + batch.mGroupKey + ":");
+ pw.println(" Created" + (now - batch.mCreatedTimestamp) + "ms ago");
+ for (CoalescedEvent event : batch.mMembers) {
+ pw.println(" " + event.getKey());
+ eventCount++;
+ }
+ }
+
+ if (eventCount != mCoalescedEvents.size()) {
+ pw.println(" ERROR: batches contain " + mCoalescedEvents.size() + " events but"
+ + " am tracking " + mCoalescedEvents.size() + " total events");
+ pw.println(" All tracked events:");
+ for (CoalescedEvent event : mCoalescedEvents.values()) {
+ pw.println(" " + event.getKey());
+ }
+ }
+ }
+
+ private final Comparator<CoalescedEvent> mEventComparator = (o1, o2) -> {
+ int cmp = Boolean.compare(
+ o2.getSbn().getNotification().isGroupSummary(),
+ o1.getSbn().getNotification().isGroupSummary());
+ if (cmp == 0) {
+ cmp = o1.getPosition() - o2.getPosition();
+ }
+ return cmp;
+ };
+
+ /**
+ * Extension of {@link NotificationListener.NotificationHandler} to include notification
+ * groups.
+ */
+ public interface BatchableNotificationHandler extends NotificationHandler {
+ /**
+ * Fired whenever the coalescer needs to emit a batch of multiple post events. This is
+ * usually the addition of a new group, but can contain just a single event, or just an
+ * update to a subset of an existing group.
+ */
+ void onNotificationBatchPosted(List<CoalescedEvent> events);
+ }
+
+ private static final int GROUP_LINGER_DURATION = 40;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
index c18af80..e4a57d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
@@ -23,6 +23,7 @@
import com.android.systemui.log.RichEvent;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -58,7 +59,10 @@
*/
@Override
public String[] getEventLabels() {
- assert (TOTAL_EVENT_LABELS == (TOTAL_NEM_EVENT_TYPES + TOTAL_LIST_BUILDER_EVENT_TYPES));
+ assert (TOTAL_EVENT_LABELS
+ == (TOTAL_NEM_EVENT_TYPES
+ + TOTAL_LIST_BUILDER_EVENT_TYPES
+ + TOTAL_COALESCER_EVENT_TYPES));
return EVENT_LABELS;
}
@@ -141,7 +145,10 @@
"LifetimeExtended",
"RemoveIntercepted",
"InflationAborted",
- "Inflated"
+ "Inflated",
+
+ "CoalescedEvent",
+ "EarlyBatchEmit"
};
private static final int TOTAL_EVENT_LABELS = EVENT_LABELS.length;
@@ -167,7 +174,7 @@
/**
* Events related to {@link NotificationEntryManager}
*/
- public static final int NOTIF_ADDED = TOTAL_LIST_BUILDER_EVENT_TYPES + 0;
+ public static final int NOTIF_ADDED = TOTAL_LIST_BUILDER_EVENT_TYPES;
public static final int NOTIF_REMOVED = TOTAL_LIST_BUILDER_EVENT_TYPES + 1;
public static final int NOTIF_UPDATED = TOTAL_LIST_BUILDER_EVENT_TYPES + 2;
public static final int FILTER = TOTAL_LIST_BUILDER_EVENT_TYPES + 3;
@@ -180,4 +187,12 @@
public static final int INFLATION_ABORTED = TOTAL_LIST_BUILDER_EVENT_TYPES + 9;
public static final int INFLATED = TOTAL_LIST_BUILDER_EVENT_TYPES + 10;
private static final int TOTAL_NEM_EVENT_TYPES = 11;
+
+ /**
+ * Events related to {@link GroupCoalescer}
+ */
+ public static final int COALESCED_EVENT = TOTAL_NEM_EVENT_TYPES;
+ public static final int EARLY_BATCH_EMIT = TOTAL_NEM_EVENT_TYPES + 1;
+ public static final int EMIT_EVENT_BATCH = TOTAL_NEM_EVENT_TYPES + 2;
+ private static final int TOTAL_COALESCER_EVENT_TYPES = 2;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
index b444fa5..add982d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.notification.stack;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.RectF;
@@ -32,6 +30,8 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
+import java.util.Objects;
+
/**
* Similar in size and appearance to the NotificationShelf, appears at the beginning of some
* notification sections. Currently only used for gentle notifications.
@@ -51,13 +51,13 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mContents = checkNotNull(findViewById(R.id.content));
+ mContents = Objects.requireNonNull(findViewById(R.id.content));
bindContents();
}
private void bindContents() {
- mLabelView = checkNotNull(findViewById(R.id.header_label));
- mClearAllButton = checkNotNull(findViewById(R.id.btn_clear_all));
+ mLabelView = Objects.requireNonNull(findViewById(R.id.header_label));
+ mClearAllButton = Objects.requireNonNull(findViewById(R.id.btn_clear_all));
if (mOnClearClickListener != null) {
mClearAllButton.setOnClickListener(mOnClearClickListener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index b198678..88edf8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -23,11 +23,11 @@
import android.view.View;
import android.widget.FrameLayout;
-import com.android.internal.util.Preconditions;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
+import java.util.Objects;
import java.util.function.Consumer;
/**
@@ -117,7 +117,7 @@
@Override
public void addCallback(BrightnessMirrorListener listener) {
- Preconditions.checkNotNull(listener);
+ Objects.requireNonNull(listener);
mBrightnessMirrorListeners.add(listener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 1cb2bd4..0ab08a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -27,7 +27,6 @@
import androidx.annotation.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -36,6 +35,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -98,7 +98,7 @@
@Override
public void addCallback(@NonNull Callback callback) {
- Preconditions.checkNotNull(callback, "Callback must not be null. b/128895449");
+ Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
if (!mCallbacks.contains(callback)) {
mCallbacks.add(callback);
}
@@ -106,7 +106,7 @@
@Override
public void removeCallback(@NonNull Callback callback) {
- Preconditions.checkNotNull(callback, "Callback must not be null. b/128895449");
+ Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
mCallbacks.remove(callback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java
index a797287..37da236 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java
@@ -16,7 +16,7 @@
package com.android.systemui.util.wakelock;
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
public class SettableWakeLock {
@@ -26,7 +26,7 @@
private boolean mAcquired;
public SettableWakeLock(WakeLock inner, String why) {
- Preconditions.checkNotNull(inner, "inner wakelock required");
+ Objects.requireNonNull(inner, "inner wakelock required");
mInner = inner;
mWhy = why;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index d580234..afbe668 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -36,7 +36,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationListener.NotifServiceListener;
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
import org.junit.Before;
import org.junit.Test;
@@ -51,7 +51,7 @@
private static final String TEST_PACKAGE_NAME = "test";
private static final int TEST_UID = 0;
- @Mock private NotifServiceListener mServiceListener;
+ @Mock private NotificationHandler mNotificationHandler;
@Mock private NotificationManager mNotificationManager;
private NotificationListener mListener;
@@ -69,21 +69,21 @@
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
new Notification(), UserHandle.CURRENT, null, 0);
- mListener.addNotificationListener(mServiceListener);
+ mListener.addNotificationHandler(mNotificationHandler);
}
@Test
public void testNotificationAddCallsAddNotification() {
mListener.onNotificationPosted(mSbn, mRanking);
TestableLooper.get(this).processAllMessages();
- verify(mServiceListener).onNotificationPosted(mSbn, mRanking);
+ verify(mNotificationHandler).onNotificationPosted(mSbn, mRanking);
}
@Test
public void testNotificationRemovalCallsRemoveNotification() {
mListener.onNotificationRemoved(mSbn, mRanking);
TestableLooper.get(this).processAllMessages();
- verify(mServiceListener).onNotificationRemoved(eq(mSbn), eq(mRanking), anyInt());
+ verify(mNotificationHandler).onNotificationRemoved(eq(mSbn), eq(mRanking), anyInt());
}
@Test
@@ -91,7 +91,7 @@
mListener.onNotificationRankingUpdate(mRanking);
TestableLooper.get(this).processAllMessages();
// RankingMap may be modified by plugins.
- verify(mServiceListener).onNotificationRankingUpdate(any());
+ verify(mNotificationHandler).onNotificationRankingUpdate(any());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
index 94b3ac4..2605402 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
@@ -116,6 +116,27 @@
public SbnBuilder setNotification(Notification notification) {
mNotification = notification;
+ mNotificationBuilder = null;
+ return this;
+ }
+
+ public SbnBuilder setContentTitle(Context context, String contentTitle) {
+ modifyNotification(context).setContentTitle(contentTitle);
+ return this;
+ }
+
+ public SbnBuilder setContentText(Context context, String contentText) {
+ modifyNotification(context).setContentText(contentText);
+ return this;
+ }
+
+ public SbnBuilder setGroup(Context context, String groupKey) {
+ modifyNotification(context).setGroup(groupKey);
+ return this;
+ }
+
+ public SbnBuilder setGroupSummary(Context context, boolean isGroupSummary) {
+ modifyNotification(context).setGroupSummary(isGroupSummary);
return this;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
new file mode 100644
index 0000000..c113df0b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
@@ -0,0 +1,99 @@
+/*
+ * 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.statusbar.notification.collection;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
+import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Simulates a NotificationManager
+ *
+ * You can post and retract notifications, each with an accompanying Ranking. The simulator will
+ * keep its RankingMap up to date and call appropriate event listeners.
+ */
+public class NoManSimulator {
+ private final List<NotificationHandler> mListeners = new ArrayList<>();
+ private final Map<String, Ranking> mRankings = new ArrayMap<>();
+
+ public NoManSimulator() {
+ }
+
+ public void addListener(NotificationHandler listener) {
+ mListeners.add(listener);
+ }
+
+ public NotifEvent postNotif(NotificationEntryBuilder builder) {
+ final NotificationEntry entry = builder.build();
+ mRankings.put(entry.getKey(), entry.getRanking());
+ final RankingMap rankingMap = buildRankingMap();
+ for (NotificationHandler listener : mListeners) {
+ listener.onNotificationPosted(entry.getSbn(), rankingMap);
+ }
+ return new NotifEvent(entry.getSbn(), entry.getRanking(), rankingMap);
+ }
+
+ public NotifEvent retractNotif(StatusBarNotification sbn, int reason) {
+ assertNotNull(mRankings.remove(sbn.getKey()));
+ final RankingMap rankingMap = buildRankingMap();
+ for (NotificationHandler listener : mListeners) {
+ listener.onNotificationRemoved(sbn, rankingMap, reason);
+ }
+ return new NotifEvent(sbn, null, rankingMap);
+ }
+
+ public void issueRankingUpdate() {
+ final RankingMap rankingMap = buildRankingMap();
+ for (NotificationHandler listener : mListeners) {
+ listener.onNotificationRankingUpdate(rankingMap);
+ }
+ }
+
+ public void setRanking(String key, Ranking ranking) {
+ mRankings.put(key, ranking);
+ }
+
+ private RankingMap buildRankingMap() {
+ return new RankingMap(mRankings.values().toArray(new Ranking[0]));
+ }
+
+ public static class NotifEvent {
+ public final String key;
+ public final StatusBarNotification sbn;
+ public final Ranking ranking;
+ public final RankingMap rankingMap;
+
+ private NotifEvent(
+ StatusBarNotification sbn,
+ Ranking ranking,
+ RankingMap rankingMap) {
+ this.key = sbn.getKey();
+ this.sbn = sbn;
+ this.ranking = ranking;
+ this.rankingMap = rankingMap;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 0dcd253..0837a42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -19,39 +19,41 @@
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CLICK;
-import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_UNKNOWN;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.Nullable;
import android.os.RemoteException;
import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.NotificationStats;
-import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
+import android.util.ArraySet;
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationListener.NotifServiceListener;
import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
+import com.android.systemui.statusbar.notification.collection.notifcollection.CoalescedEvent;
+import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
+import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer.BatchableNotificationHandler;
import com.android.systemui.util.Assert;
import org.junit.Before;
@@ -64,6 +66,8 @@
import org.mockito.Spy;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
import java.util.Map;
@SmallTest
@@ -72,18 +76,20 @@
public class NotifCollectionTest extends SysuiTestCase {
@Mock private IStatusBarService mStatusBarService;
- @Mock private NotificationListener mListenerService;
+ @Mock private GroupCoalescer mGroupCoalescer;
@Spy private RecordingCollectionListener mCollectionListener;
+ @Mock private CollectionReadyForBuildListener mBuildListener;
@Spy private RecordingLifetimeExtender mExtender1 = new RecordingLifetimeExtender("Extender1");
@Spy private RecordingLifetimeExtender mExtender2 = new RecordingLifetimeExtender("Extender2");
@Spy private RecordingLifetimeExtender mExtender3 = new RecordingLifetimeExtender("Extender3");
- @Captor private ArgumentCaptor<NotifServiceListener> mListenerCaptor;
+ @Captor private ArgumentCaptor<BatchableNotificationHandler> mListenerCaptor;
@Captor private ArgumentCaptor<NotificationEntry> mEntryCaptor;
+ @Captor private ArgumentCaptor<Collection<NotificationEntry>> mBuildListCaptor;
private NotifCollection mCollection;
- private NotifServiceListener mServiceListener;
+ private BatchableNotificationHandler mNotifHandler;
private NoManSimulator mNoMan;
@@ -93,21 +99,23 @@
Assert.sMainLooper = TestableLooper.get(this).getLooper();
mCollection = new NotifCollection(mStatusBarService);
- mCollection.attach(mListenerService);
+ mCollection.attach(mGroupCoalescer);
mCollection.addCollectionListener(mCollectionListener);
+ mCollection.setBuildListener(mBuildListener);
// Capture the listener object that the collection registers with the listener service so
// we can simulate listener service events in tests below
- verify(mListenerService).addNotificationListener(mListenerCaptor.capture());
- mServiceListener = checkNotNull(mListenerCaptor.getValue());
+ verify(mGroupCoalescer).setNotificationHandler(mListenerCaptor.capture());
+ mNotifHandler = requireNonNull(mListenerCaptor.getValue());
- mNoMan = new NoManSimulator(mServiceListener);
+ mNoMan = new NoManSimulator();
+ mNoMan.addListener(mNotifHandler);
}
@Test
public void testEventDispatchedWhenNotifPosted() {
// WHEN a notification is posted
- PostedNotif notif1 = mNoMan.postNotif(
+ NotifEvent notif1 = mNoMan.postNotif(
buildNotif(TEST_PACKAGE, 3)
.setRank(4747));
@@ -121,13 +129,68 @@
}
@Test
+ public void testEventDispatchedWhenNotifBatchPosted() {
+ // GIVEN a NotifCollection with one notif already posted
+ mNoMan.postNotif(buildNotif(TEST_PACKAGE, 2)
+ .setGroup(mContext, "group_1")
+ .setContentTitle(mContext, "Old version"));
+
+ clearInvocations(mCollectionListener);
+ clearInvocations(mBuildListener);
+
+ // WHEN three notifications from the same group are posted (one of them an update, two of
+ // them new)
+ NotificationEntry entry1 = buildNotif(TEST_PACKAGE, 1)
+ .setGroup(mContext, "group_1")
+ .build();
+ NotificationEntry entry2 = buildNotif(TEST_PACKAGE, 2)
+ .setGroup(mContext, "group_1")
+ .setContentTitle(mContext, "New version")
+ .build();
+ NotificationEntry entry3 = buildNotif(TEST_PACKAGE, 3)
+ .setGroup(mContext, "group_1")
+ .build();
+
+ mNotifHandler.onNotificationBatchPosted(Arrays.asList(
+ new CoalescedEvent(entry1.getKey(), 0, entry1.getSbn(), entry1.getRanking(), null),
+ new CoalescedEvent(entry2.getKey(), 1, entry2.getSbn(), entry2.getRanking(), null),
+ new CoalescedEvent(entry3.getKey(), 2, entry3.getSbn(), entry3.getRanking(), null)
+ ));
+
+ // THEN onEntryAdded is called on the new ones
+ verify(mCollectionListener, times(2)).onEntryAdded(mEntryCaptor.capture());
+
+ List<NotificationEntry> capturedAdds = mEntryCaptor.getAllValues();
+
+ assertEquals(entry1.getSbn(), capturedAdds.get(0).getSbn());
+ assertEquals(entry1.getRanking(), capturedAdds.get(0).getRanking());
+
+ assertEquals(entry3.getSbn(), capturedAdds.get(1).getSbn());
+ assertEquals(entry3.getRanking(), capturedAdds.get(1).getRanking());
+
+ // THEN onEntryUpdated is called on the middle one
+ verify(mCollectionListener).onEntryUpdated(mEntryCaptor.capture());
+ NotificationEntry capturedUpdate = mEntryCaptor.getValue();
+ assertEquals(entry2.getSbn(), capturedUpdate.getSbn());
+ assertEquals(entry2.getRanking(), capturedUpdate.getRanking());
+
+ // THEN onBuildList is called only once
+ verify(mBuildListener).onBuildList(mBuildListCaptor.capture());
+ assertEquals(new ArraySet<>(Arrays.asList(
+ capturedAdds.get(0),
+ capturedAdds.get(1),
+ capturedUpdate
+ )), new ArraySet<>(mBuildListCaptor.getValue()));
+ }
+
+ @Test
public void testEventDispatchedWhenNotifUpdated() {
// GIVEN a collection with one notif
mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
.setRank(4747));
// WHEN the notif is reposted
- PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
+ NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
.setRank(89));
// THEN the listener is notified
@@ -145,7 +208,7 @@
mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3));
clearInvocations(mCollectionListener);
- PostedNotif notif = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+ NotifEvent notif = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
NotificationEntry entry = mCollectionListener.getEntry(notif.key);
clearInvocations(mCollectionListener);
@@ -161,7 +224,7 @@
@Test
public void testRankingsAreUpdatedForOtherNotifs() {
// GIVEN a collection with one notif
- PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
.setRank(47));
NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
@@ -178,11 +241,11 @@
@Test
public void testRankingUpdateIsProperlyIssuedToEveryone() {
// GIVEN a collection with a couple notifs
- PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
.setRank(3));
- PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 8)
+ NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 8)
.setRank(2));
- PostedNotif notif3 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 77)
+ NotifEvent notif3 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 77)
.setRank(1));
NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
@@ -217,7 +280,7 @@
@Test
public void testNotifEntriesAreNotPersistedAcrossRemovalAndReposting() {
// GIVEN a notification that has been posted
- PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3));
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3));
NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
// WHEN the notification is retracted and then reposted
@@ -234,8 +297,8 @@
// GIVEN a collection with a couple notifications and a lifetime extender
mCollection.addNotificationLifetimeExtender(mExtender1);
- PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
- PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag"));
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag"));
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
// WHEN a notification is manually dismissed
@@ -267,9 +330,9 @@
@Test(expected = IllegalStateException.class)
public void testDismissingNonExistentNotificationThrows() {
// GIVEN a collection that originally had three notifs, but where one was dismissed
- PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
- PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
- PostedNotif notif3 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 99));
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+ NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+ NotifEvent notif3 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 99));
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN);
@@ -292,8 +355,8 @@
mCollection.addNotificationLifetimeExtender(mExtender2);
mCollection.addNotificationLifetimeExtender(mExtender3);
- PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
- PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+ NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
// WHEN a notification is removed
@@ -320,8 +383,8 @@
mCollection.addNotificationLifetimeExtender(mExtender2);
mCollection.addNotificationLifetimeExtender(mExtender3);
- PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
- PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+ NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
// GIVEN a notification gets lifetime-extended by one of them
@@ -357,8 +420,8 @@
mCollection.addNotificationLifetimeExtender(mExtender2);
mCollection.addNotificationLifetimeExtender(mExtender3);
- PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
- PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+ NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
// GIVEN a notification gets lifetime-extended by a couple of them
@@ -392,8 +455,8 @@
mCollection.addNotificationLifetimeExtender(mExtender2);
mCollection.addNotificationLifetimeExtender(mExtender3);
- PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
- PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+ NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
// GIVEN a notification gets lifetime-extended by a couple of them
@@ -422,8 +485,8 @@
mExtender1.shouldExtendLifetime = true;
mExtender2.shouldExtendLifetime = true;
- PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
- PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+ NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
// GIVEN a notification gets lifetime-extended by a couple of them
@@ -452,8 +515,8 @@
mExtender1.shouldExtendLifetime = true;
mExtender2.shouldExtendLifetime = true;
- PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
- PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+ NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
// GIVEN a notification gets lifetime-extended by a couple of them
@@ -481,8 +544,8 @@
mExtender1.shouldExtendLifetime = true;
mExtender2.shouldExtendLifetime = true;
- PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
- PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+ NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
// GIVEN a notification gets lifetime-extended by a couple of them
@@ -491,7 +554,7 @@
clearInvocations(mExtender1, mExtender2, mExtender3);
// WHEN the notification is reposted
- PostedNotif notif2a = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88)
+ NotifEvent notif2a = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88)
.setRank(4747)
.setExplanation("Some new explanation"));
@@ -512,53 +575,6 @@
.setId(id);
}
- private static class NoManSimulator {
- private final NotifServiceListener mListener;
- private final Map<String, Ranking> mRankings = new ArrayMap<>();
-
- private NoManSimulator(
- NotifServiceListener listener) {
- mListener = listener;
- }
-
- PostedNotif postNotif(NotificationEntryBuilder builder) {
- NotificationEntry entry = builder.build();
- mRankings.put(entry.getKey(), entry.getRanking());
- mListener.onNotificationPosted(entry.getSbn(), buildRankingMap());
- return new PostedNotif(entry.getSbn(), entry.getRanking());
- }
-
- void retractNotif(StatusBarNotification sbn, int reason) {
- assertNotNull(mRankings.remove(sbn.getKey()));
- mListener.onNotificationRemoved(sbn, buildRankingMap(), reason);
- }
-
- void issueRankingUpdate() {
- mListener.onNotificationRankingUpdate(buildRankingMap());
- }
-
- void setRanking(String key, Ranking ranking) {
- mRankings.put(key, ranking);
- }
-
- private RankingMap buildRankingMap() {
- return new RankingMap(mRankings.values().toArray(new Ranking[0]));
- }
- }
-
- private static class PostedNotif {
- public final String key;
- public final StatusBarNotification sbn;
- public final Ranking ranking;
-
- private PostedNotif(StatusBarNotification sbn,
- Ranking ranking) {
- this.key = sbn.getKey();
- this.sbn = sbn;
- this.ranking = ranking;
- }
- }
-
private static class RecordingCollectionListener implements NotifCollectionListener {
private final Map<String, NotificationEntry> mLastSeenEntries = new ArrayMap<>();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
index 6e9c2c8..3e4068b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.collection;
-import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.systemui.statusbar.notification.collection.ListDumper.dumpList;
import static org.junit.Assert.assertEquals;
@@ -67,6 +66,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.stream.Collectors;
@SmallTest
@@ -105,7 +105,7 @@
mListBuilder.attach(mNotifCollection);
Mockito.verify(mNotifCollection).setBuildListener(mBuildListenerCaptor.capture());
- mReadyForBuildListener = checkNotNull(mBuildListenerCaptor.getValue());
+ mReadyForBuildListener = Objects.requireNonNull(mBuildListenerCaptor.getValue());
}
@Test
@@ -1021,7 +1021,6 @@
mPendingSet.clear();
}
- mReadyForBuildListener.onBeginDispatchToListeners();
mReadyForBuildListener.onBuildList(mEntrySet);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index e6a61d6..300ec18 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -140,6 +140,28 @@
return this;
}
+ /* Delegated to Notification.Builder (via SbnBuilder) */
+
+ public NotificationEntryBuilder setContentTitle(Context context, String contentTitle) {
+ mSbnBuilder.setContentTitle(context, contentTitle);
+ return this;
+ }
+
+ public NotificationEntryBuilder setContentText(Context context, String contentText) {
+ mSbnBuilder.setContentText(context, contentText);
+ return this;
+ }
+
+ public NotificationEntryBuilder setGroup(Context context, String groupKey) {
+ mSbnBuilder.setGroup(context, groupKey);
+ return this;
+ }
+
+ public NotificationEntryBuilder setGroupSummary(Context context, boolean isGroupSummary) {
+ mSbnBuilder.setGroupSummary(context, isGroupSummary);
+ return this;
+ }
+
/* Delegated to RankingBuilder */
public NotificationEntryBuilder setRank(int rank) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescerTest.java
new file mode 100644
index 0000000..7ff3240
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescerTest.java
@@ -0,0 +1,323 @@
+/*
+ * 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.statusbar.notification.collection.notifcollection;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
+import android.service.notification.StatusBarNotification;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.NoManSimulator;
+import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class GroupCoalescerTest extends SysuiTestCase {
+
+ private GroupCoalescer mCoalescer;
+
+ @Mock private NotificationListener mListenerService;
+ @Mock private GroupCoalescer.BatchableNotificationHandler mListener;
+ @Mock private NotifLog mLog;
+
+ @Captor private ArgumentCaptor<NotificationHandler> mListenerCaptor;
+
+ private final NoManSimulator mNoMan = new NoManSimulator();
+ private final FakeSystemClock mClock = new FakeSystemClock();
+ private final FakeExecutor mExecutor = new FakeExecutor(mClock);
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mCoalescer =
+ new GroupCoalescer(
+ mExecutor,
+ mClock,
+ mLog,
+ LINGER_DURATION);
+ mCoalescer.setNotificationHandler(mListener);
+ mCoalescer.attach(mListenerService);
+
+ verify(mListenerService).addNotificationHandler(mListenerCaptor.capture());
+ NotificationHandler serviceListener = checkNotNull(mListenerCaptor.getValue());
+ mNoMan.addListener(serviceListener);
+ }
+
+ @Test
+ public void testUngroupedNotificationsAreNotCoalesced() {
+ // WHEN a notification that doesn't have a group key is posted
+ NotifEvent notif1 = mNoMan.postNotif(
+ new NotificationEntryBuilder()
+ .setId(0)
+ .setPkg(TEST_PACKAGE_A));
+ mClock.advanceTime(LINGER_DURATION);
+
+ // THEN the event is passed through to the handler
+ verify(mListener).onNotificationPosted(notif1.sbn, notif1.rankingMap);
+
+ // Then the event isn't emitted in a batch
+ verify(mListener, never()).onNotificationBatchPosted(anyList());
+ }
+
+ @Test
+ public void testGroupedNotificationsAreCoalesced() {
+ // WHEN a notification that has a group key is posted
+ NotifEvent notif1 = mNoMan.postNotif(
+ new NotificationEntryBuilder()
+ .setId(0)
+ .setPkg(TEST_PACKAGE_A)
+ .setGroup(mContext, GROUP_1));
+
+ // THEN the event is not passed on to the handler
+ verify(mListener, never()).onNotificationPosted(
+ any(StatusBarNotification.class),
+ any(RankingMap.class));
+
+ // Then the event isn't (yet) emitted in a batch
+ verify(mListener, never()).onNotificationBatchPosted(anyList());
+ }
+
+ @Test
+ public void testCoalescedNotificationsStillPassThroughRankingUpdate() {
+ // WHEN a notification that has a group key is posted
+ NotifEvent notif1 = mNoMan.postNotif(
+ new NotificationEntryBuilder()
+ .setId(0)
+ .setPkg(TEST_PACKAGE_A)
+ .setGroup(mContext, GROUP_1));
+
+ // THEN the listener receives a ranking update instead of an add
+ verify(mListener).onNotificationRankingUpdate(notif1.rankingMap);
+ }
+
+ @Test
+ public void testCoalescedNotificationsArePosted() {
+ // GIVEN three notifs are posted that are part of the same group
+ NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(1)
+ .setGroup(mContext, GROUP_1));
+
+ NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(2)
+ .setGroup(mContext, GROUP_1)
+ .setGroupSummary(mContext, true));
+
+ NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(3)
+ .setGroup(mContext, GROUP_1));
+
+ verify(mListener, never()).onNotificationPosted(
+ any(StatusBarNotification.class),
+ any(RankingMap.class));
+ verify(mListener, never()).onNotificationBatchPosted(anyList());
+
+ // WHEN enough time passes
+ mClock.advanceTime(LINGER_DURATION);
+
+ // THEN the coalesced notifs are applied. The summary is sorted to the front.
+ verify(mListener).onNotificationBatchPosted(Arrays.asList(
+ new CoalescedEvent(notif2.key, 1, notif2.sbn, notif2.ranking, null),
+ new CoalescedEvent(notif1.key, 0, notif1.sbn, notif1.ranking, null),
+ new CoalescedEvent(notif3.key, 2, notif3.sbn, notif3.ranking, null)
+ ));
+ }
+
+ @Test
+ public void testCoalescedEventsThatAreLaterUngroupedAreEmittedImmediatelyAndNotLater() {
+ // GIVEN a few newly posted notifications in the same group
+ NotifEvent notif1a = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(1)
+ .setContentTitle(mContext, "Grouped message")
+ .setGroup(mContext, GROUP_1));
+ NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(2)
+ .setGroup(mContext, GROUP_1));
+ NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(3)
+ .setGroup(mContext, GROUP_1));
+
+ verify(mListener, never()).onNotificationPosted(
+ any(StatusBarNotification.class),
+ any(RankingMap.class));
+ verify(mListener, never()).onNotificationBatchPosted(anyList());
+
+ // WHEN one of them is updated to no longer be in the group
+ NotifEvent notif1b = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(1)
+ .setContentTitle(mContext, "Oops no longer grouped"));
+
+ // THEN the pre-existing batch is first emitted
+ InOrder inOrder = inOrder(mListener);
+ inOrder.verify(mListener).onNotificationBatchPosted(Arrays.asList(
+ new CoalescedEvent(notif1a.key, 0, notif1a.sbn, notif1a.ranking, null),
+ new CoalescedEvent(notif2.key, 1, notif2.sbn, notif2.ranking, null),
+ new CoalescedEvent(notif3.key, 2, notif3.sbn, notif3.ranking, null)
+ ));
+
+ // THEN the updated notif is emitted
+ inOrder.verify(mListener).onNotificationPosted(notif1b.sbn, notif1b.rankingMap);
+
+ // WHEN the time runs out on the remainder of the group
+ clearInvocations(mListener);
+ mClock.advanceTime(LINGER_DURATION);
+
+ // THEN no lingering batch is applied
+ verify(mListener, never()).onNotificationBatchPosted(anyList());
+ }
+
+ @Test
+ public void testUpdatingCoalescedNotifTriggersBatchEmit() {
+ // GIVEN two grouped, coalesced notifications
+ NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(1)
+ .setGroup(mContext, GROUP_1));
+ NotifEvent notif2a = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(2)
+ .setContentTitle(mContext, "Version 1")
+ .setGroup(mContext, GROUP_1));
+
+ // WHEN one of them gets updated
+ NotifEvent notif2b = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(2)
+ .setContentTitle(mContext, "Version 2")
+ .setGroup(mContext, GROUP_1));
+
+ // THEN first, the coalesced group is emitted
+ verify(mListener).onNotificationBatchPosted(Arrays.asList(
+ new CoalescedEvent(notif1.key, 0, notif1.sbn, notif1.ranking, null),
+ new CoalescedEvent(notif2a.key, 1, notif2a.sbn, notif2a.ranking, null)
+ ));
+ verify(mListener, never()).onNotificationPosted(
+ any(StatusBarNotification.class),
+ any(RankingMap.class));
+
+ // THEN second, the update is emitted
+ mClock.advanceTime(LINGER_DURATION);
+ verify(mListener).onNotificationBatchPosted(Collections.singletonList(
+ new CoalescedEvent(notif2b.key, 0, notif2b.sbn, notif2b.ranking, null)
+ ));
+ }
+
+ @Test
+ public void testRemovingCoalescedNotifTriggersBatchEmit() {
+ // GIVEN two grouped, coalesced notifications
+ NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(1)
+ .setGroup(mContext, GROUP_1));
+ NotifEvent notif2a = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(2)
+ .setGroup(mContext, GROUP_1));
+
+ // WHEN one of them gets retracted
+ NotifEvent notif2b = mNoMan.retractNotif(notif2a.sbn, 0);
+
+ // THEN first, the coalesced group is emitted
+ InOrder inOrder = inOrder(mListener);
+ inOrder.verify(mListener).onNotificationBatchPosted(Arrays.asList(
+ new CoalescedEvent(notif1.key, 0, notif1.sbn, notif1.ranking, null),
+ new CoalescedEvent(notif2a.key, 1, notif2a.sbn, notif2a.ranking, null)
+ ));
+
+ // THEN second, the removal is emitted
+ inOrder.verify(mListener).onNotificationRemoved(notif2b.sbn, notif2b.rankingMap, 0);
+ }
+
+ @Test
+ public void testRankingsAreUpdated() {
+ // GIVEN a couple coalesced notifications
+ NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(1)
+ .setGroup(mContext, GROUP_1));
+ NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(2)
+ .setGroup(mContext, GROUP_1));
+
+ // WHEN an update to an unrelated notification comes in that updates their rankings
+ Ranking ranking1b = new RankingBuilder()
+ .setKey(notif1.key)
+ .setLastAudiblyAlertedMs(4747)
+ .build();
+ Ranking ranking2b = new RankingBuilder()
+ .setKey(notif2.key)
+ .setLastAudiblyAlertedMs(3333)
+ .build();
+ mNoMan.setRanking(notif1.key, ranking1b);
+ mNoMan.setRanking(notif2.key, ranking2b);
+ mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_B)
+ .setId(17));
+
+ // THEN they have the new rankings when they are eventually emitted
+ mClock.advanceTime(LINGER_DURATION);
+ verify(mListener).onNotificationBatchPosted(Arrays.asList(
+ new CoalescedEvent(notif1.key, 0, notif1.sbn, ranking1b, null),
+ new CoalescedEvent(notif2.key, 1, notif2.sbn, ranking2b, null)
+ ));
+ }
+
+ private static final long LINGER_DURATION = 4700;
+
+ private static final String TEST_PACKAGE_A = "com.test.package_a";
+ private static final String TEST_PACKAGE_B = "com.test.package_b";
+ private static final String GROUP_1 = "group_1";
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
index a024454..3d59d61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
@@ -18,8 +18,6 @@
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -50,6 +48,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Objects;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -85,11 +85,11 @@
// Capture the entry listener object so we can simulate events in tests below
verify(mEntryManager).addNotificationEntryListener(mListenerCaptor.capture());
- mEntryListener = checkNotNull(mListenerCaptor.getValue());
+ mEntryListener = Objects.requireNonNull(mListenerCaptor.getValue());
// Capture the callback object so we can simulate callback events in tests below
verify(mCommandQueue).addCallback(mCallbacksCaptor.capture());
- mCallbacks = checkNotNull(mCallbacksCaptor.getValue());
+ mCallbacks = Objects.requireNonNull(mCallbacksCaptor.getValue());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java
index e15ca1d..27b225e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java
@@ -30,14 +30,13 @@
import android.os.SystemClock;
import android.util.ArraySet;
-import com.android.internal.util.Preconditions;
-
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@@ -113,7 +112,7 @@
@Override
protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
- Preconditions.checkNotNull(listener);
+ Objects.requireNonNull(listener);
for (FakeGenericSensor s : mSensors) {
if (sensor == null || s.mSensor == sensor) {
s.mListeners.remove(listener);
@@ -125,8 +124,8 @@
protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
int delayUs,
Handler handler, int maxReportLatencyUs, int reservedFlags) {
- Preconditions.checkNotNull(sensor);
- Preconditions.checkNotNull(listener);
+ Objects.requireNonNull(sensor);
+ Objects.requireNonNull(listener);
for (FakeGenericSensor s : mSensors) {
if (s.mSensor == sensor) {
s.mListeners.add(listener);
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiTapAndHold.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTapAndHold.java
index 6a1f1a5..a0428a5 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiTapAndHold.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTapAndHold.java
@@ -38,6 +38,12 @@
}
@Override
+ protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ super.onUp(event, rawEvent, policyFlags);
+ cancelAfterDoubleTapTimeout(event, rawEvent, policyFlags);
+ }
+
+ @Override
public String getGestureName() {
switch (mTargetTaps) {
case 2:
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index f6eb31b..ba890c5 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -286,10 +286,6 @@
@Override
public void onDoubleTapAndHold() {
- // Pointers should not be zero when running this command.
- if (mState.getLastReceivedEvent().getPointerCount() == 0) {
- return;
- }
// Try to use the standard accessibility API to long click
if (!mAms.performActionOnAccessibilityFocusedItem(
AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK)) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index c689ed1..03d9626 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -288,7 +288,14 @@
boolean isTemporary) {
mAugmentedAutofillState.setServiceInfo(userId, serviceName, isTemporary);
synchronized (mLock) {
- getServiceForUserLocked(userId).updateRemoteAugmentedAutofillService();
+ final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ if (service == null) {
+ // If we cannot get the service from the services cache, it will call
+ // updateRemoteAugmentedAutofillService() finally. Skip call this update again.
+ getServiceForUserLocked(userId);
+ } else {
+ service.updateRemoteAugmentedAutofillService();
+ }
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 202f900..bf801fc 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -970,6 +970,8 @@
} else {
pw.println(compatPkgs);
}
+ pw.print(prefix); pw.print("Inline Suggestions Enabled: ");
+ pw.println(isInlineSuggestionsEnabled());
pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
pw.print(prefix); pw.print("Disabled apps: ");
@@ -1120,6 +1122,14 @@
}
@GuardedBy("mLock")
+ boolean isInlineSuggestionsEnabled() {
+ if (mInfo != null) {
+ return mInfo.isInlineSuggestionsEnabled();
+ }
+ return false;
+ }
+
+ @GuardedBy("mLock")
@Nullable RemoteAugmentedAutofillService getRemoteAugmentedAutofillServiceLocked() {
if (mRemoteAugmentedAutofillService == null) {
final String serviceName = mMaster.mAugmentedAutofillResolver.getServiceName(mUserId);
diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java
new file mode 100644
index 0000000..3af15c7
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import static com.android.server.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.service.autofill.Dataset;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.autofill.AutofillId;
+import android.view.autofill.IAutoFillManagerClient;
+import android.view.inline.InlinePresentationSpec;
+import android.view.inputmethod.InlineSuggestion;
+import android.view.inputmethod.InlineSuggestionInfo;
+import android.view.inputmethod.InlineSuggestionsRequest;
+import android.view.inputmethod.InlineSuggestionsResponse;
+
+import com.android.internal.view.inline.IInlineContentCallback;
+import com.android.internal.view.inline.IInlineContentProvider;
+import com.android.server.autofill.ui.InlineSuggestionUi;
+
+import java.util.ArrayList;
+
+
+/**
+ * @hide
+ */
+public final class InlineSuggestionFactory {
+ private static final String TAG = "InlineSuggestionFactory";
+
+ /**
+ * Creates an {@link InlineSuggestionsResponse} with the {@code datasets} provided by
+ * augmented autofill service.
+ */
+ public static InlineSuggestionsResponse createAugmentedInlineSuggestionsResponse(
+ int sessionId,
+ @NonNull Dataset[] datasets,
+ @NonNull AutofillId autofillId,
+ @NonNull InlineSuggestionsRequest request,
+ @NonNull Handler uiHandler,
+ @NonNull Context context,
+ @NonNull IAutoFillManagerClient client) {
+ if (sDebug) Slog.d(TAG, "createInlineSuggestionsResponse called");
+
+ final ArrayList<InlineSuggestion> inlineSuggestions = new ArrayList<>();
+ final InlineSuggestionUi inlineSuggestionUi = new InlineSuggestionUi(context);
+ for (Dataset dataset : datasets) {
+ // TODO(b/146453195): use the spec in the dataset.
+ InlinePresentationSpec spec = request.getPresentationSpecs().get(0);
+ if (spec == null) {
+ Slog.w(TAG, "InlinePresentationSpec is not provided in the response data set");
+ continue;
+ }
+ InlineSuggestion inlineSuggestion = createAugmentedInlineSuggestion(sessionId, dataset,
+ autofillId, spec, uiHandler, inlineSuggestionUi, client);
+ inlineSuggestions.add(inlineSuggestion);
+ }
+ return new InlineSuggestionsResponse(inlineSuggestions);
+ }
+
+ private static InlineSuggestion createAugmentedInlineSuggestion(int sessionId,
+ @NonNull Dataset dataset,
+ @NonNull AutofillId autofillId,
+ @NonNull InlinePresentationSpec spec,
+ @NonNull Handler uiHandler,
+ @NonNull InlineSuggestionUi inlineSuggestionUi,
+ @NonNull IAutoFillManagerClient client) {
+ // TODO(b/146453195): fill in the autofill hint properly.
+ final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
+ spec, InlineSuggestionInfo.SOURCE_PLATFORM, new String[]{""});
+ final View.OnClickListener onClickListener = createOnClickListener(sessionId, dataset,
+ client);
+ final InlineSuggestion inlineSuggestion = new InlineSuggestion(inlineSuggestionInfo,
+ createInlineContentProvider(autofillId, dataset, uiHandler, inlineSuggestionUi,
+ onClickListener));
+ return inlineSuggestion;
+ }
+
+ private static IInlineContentProvider.Stub createInlineContentProvider(
+ @NonNull AutofillId autofillId, @NonNull Dataset dataset, @NonNull Handler uiHandler,
+ @NonNull InlineSuggestionUi inlineSuggestionUi,
+ @Nullable View.OnClickListener onClickListener) {
+ return new IInlineContentProvider.Stub() {
+ @Override
+ public void provideContent(int width, int height,
+ IInlineContentCallback callback) {
+ uiHandler.post(() -> {
+ SurfaceControl sc = inlineSuggestionUi.inflate(dataset, autofillId,
+ width, height, onClickListener);
+ try {
+ callback.onContent(sc);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Encounter exception calling back with inline content.");
+ }
+ });
+ }
+ };
+ }
+
+ private static View.OnClickListener createOnClickListener(int sessionId,
+ @NonNull Dataset dataset,
+ @NonNull IAutoFillManagerClient client) {
+ return v -> {
+ if (sDebug) Slog.d(TAG, "Inline suggestion clicked");
+ try {
+ client.autofill(sessionId, dataset.getFieldIds(), dataset.getFieldValues());
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Encounter exception autofilling the values");
+ }
+ };
+ }
+
+ private InlineSuggestionFactory() {
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index c5011b3..2a7357b 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -46,12 +46,15 @@
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
+import android.view.inputmethod.InlineSuggestionsRequest;
import com.android.internal.infra.AbstractRemoteService;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ServiceConnector;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.view.IInlineSuggestionsResponseCallback;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
@@ -137,7 +140,9 @@
*/
public void onRequestAutofillLocked(int sessionId, @NonNull IAutoFillManagerClient client,
int taskId, @NonNull ComponentName activityComponent, @NonNull AutofillId focusedId,
- @Nullable AutofillValue focusedValue) {
+ @Nullable AutofillValue focusedValue,
+ @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
+ @Nullable IInlineSuggestionsResponseCallback inlineSuggestionsCallback) {
long requestTime = SystemClock.elapsedRealtime();
AtomicReference<ICancellationSignal> cancellationRef = new AtomicReference<>();
@@ -151,10 +156,13 @@
final IBinder realClient = resultData
.getBinder(AutofillManager.EXTRA_AUGMENTED_AUTOFILL_CLIENT);
service.onFillRequest(sessionId, realClient, taskId, activityComponent,
- focusedId, focusedValue, requestTime, new IFillCallback.Stub() {
+ focusedId, focusedValue, requestTime, inlineSuggestionsRequest,
+ new IFillCallback.Stub() {
@Override
public void onSuccess(@Nullable Dataset[] inlineSuggestionsData) {
- // TODO(b/146453195): handle non-null inline suggestions data.
+ maybeHandleInlineSuggestions(sessionId, inlineSuggestionsData,
+ focusedId, inlineSuggestionsRequest,
+ inlineSuggestionsCallback, client);
requestAutofill.complete(null);
}
@@ -216,6 +224,26 @@
});
}
+ private void maybeHandleInlineSuggestions(int sessionId,
+ @Nullable Dataset[] inlineSuggestionsData, @NonNull AutofillId focusedId,
+ @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
+ @Nullable IInlineSuggestionsResponseCallback inlineSuggestionsCallback,
+ @NonNull IAutoFillManagerClient client) {
+ if (inlineSuggestionsRequest == null
+ || ArrayUtils.isEmpty(inlineSuggestionsData)
+ || inlineSuggestionsCallback == null) {
+ return;
+ }
+ try {
+ inlineSuggestionsCallback.onInlineSuggestionsResponse(
+ InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
+ sessionId, inlineSuggestionsData, focusedId, inlineSuggestionsRequest,
+ getJobHandler(), mContext, client));
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Exception sending inline suggestions response back to IME.");
+ }
+ }
+
@Override
public String toString() {
return "RemoteAugmentedAutofillService["
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 5af4399..2c8bc22 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -323,7 +323,7 @@
mInlineSuggestionsResponseCallbackFuture;
@Nullable
- private InlineSuggestionsRequestCallback mInlineSuggestionsRequestCallback;
+ private InlineSuggestionsRequestCallbackImpl mInlineSuggestionsRequestCallback;
private static final int INLINE_REQUEST_TIMEOUT_MS = 1000;
@@ -424,19 +424,7 @@
final ArrayList<FillContext> contexts =
mergePreviousSessionLocked(/* forSave= */ false);
- InlineSuggestionsRequest suggestionsRequest = null;
- if (mSuggestionsRequestFuture != null) {
- try {
- suggestionsRequest = mSuggestionsRequestFuture.get(
- INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- Log.w(TAG, "Exception getting inline suggestions request in time: " + e);
- } catch (CancellationException e) {
- Log.w(TAG, "Inline suggestions request cancelled");
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
+ final InlineSuggestionsRequest suggestionsRequest = getInlineSuggestionsRequest();
request = new FillRequest(requestId, contexts, mClientState, flags,
suggestionsRequest);
@@ -624,9 +612,8 @@
/**
* Returns whether inline suggestions are enabled for Autofill.
*/
- // TODO(b/137800469): Implement this
private boolean isInlineSuggestionsEnabled() {
- return true;
+ return mService.isInlineSuggestionsEnabled();
}
/**
@@ -639,7 +626,7 @@
mInlineSuggestionsResponseCallbackFuture = new CompletableFuture<>();
if (mInlineSuggestionsRequestCallback == null) {
- mInlineSuggestionsRequestCallback = new InlineSuggestionsRequestCallback(this);
+ mInlineSuggestionsRequestCallback = new InlineSuggestionsRequestCallbackImpl(this);
}
mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(
@@ -649,11 +636,11 @@
requestNewFillResponseLocked(viewState, newState, flags);
}
- private static final class InlineSuggestionsRequestCallback
+ private static final class InlineSuggestionsRequestCallbackImpl
extends IInlineSuggestionsRequestCallback.Stub {
private final WeakReference<Session> mSession;
- private InlineSuggestionsRequestCallback(Session session) {
+ private InlineSuggestionsRequestCallbackImpl(Session session) {
mSession = new WeakReference<>(session);
}
@@ -2692,21 +2679,8 @@
*/
private boolean requestShowInlineSuggestions(List<Slice> inlineSuggestionSlices,
FillResponse response) {
- IInlineSuggestionsResponseCallback inlineContentCallback = null;
- synchronized (mLock) {
- if (mInlineSuggestionsResponseCallbackFuture != null) {
- try {
- inlineContentCallback = mInlineSuggestionsResponseCallbackFuture.get(
- INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- Log.w(TAG, "Exception getting inline suggestions callback in time: " + e);
- } catch (CancellationException e) {
- Log.w(TAG, "Inline suggestions callback cancelled");
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
- }
+ final IInlineSuggestionsResponseCallback inlineContentCallback =
+ getInlineSuggestionsResponseCallback();
if (inlineContentCallback == null) {
Log.w(TAG, "Session input method callback is not set yet");
@@ -3063,9 +3037,12 @@
final AutofillId focusedId = AutofillId.withoutSession(mCurrentViewId);
- // TODO(b/137800469): implement inlined suggestions for augmented autofill
+ final InlineSuggestionsRequest inlineSuggestionsRequest = getInlineSuggestionsRequest();
+ final IInlineSuggestionsResponseCallback inlineSuggestionsResponseCallback =
+ getInlineSuggestionsResponseCallback();
+
remoteService.onRequestAutofillLocked(id, mClient, taskId, mComponentName, focusedId,
- currentValue);
+ currentValue, inlineSuggestionsRequest, inlineSuggestionsResponseCallback);
if (mAugmentedAutofillDestroyer == null) {
mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest();
@@ -3073,6 +3050,40 @@
return mAugmentedAutofillDestroyer;
}
+ @Nullable
+ private InlineSuggestionsRequest getInlineSuggestionsRequest() {
+ if (mSuggestionsRequestFuture != null) {
+ try {
+ return mSuggestionsRequestFuture.get(
+ INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ Log.w(TAG, "Exception getting inline suggestions request in time: " + e);
+ } catch (CancellationException e) {
+ Log.w(TAG, "Inline suggestions request cancelled");
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private IInlineSuggestionsResponseCallback getInlineSuggestionsResponseCallback() {
+ if (mInlineSuggestionsResponseCallbackFuture != null) {
+ try {
+ return mInlineSuggestionsResponseCallbackFuture.get(
+ INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ Log.w(TAG, "Exception getting inline suggestions callback in time: " + e);
+ } catch (CancellationException e) {
+ Log.w(TAG, "Inline suggestions callback cancelled");
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return null;
+ }
+
@GuardedBy("mLock")
private void cancelAugmentedAutofillLocked() {
final RemoteAugmentedAutofillService remoteService = mService
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index e57b7b3..0511bf2 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -24,8 +24,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.metrics.LogMaker;
import android.os.Bundle;
@@ -40,13 +38,9 @@
import android.util.Slog;
import android.view.KeyEvent;
import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.WindowManager;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
-import android.view.autofill.AutofillValue;
import android.view.autofill.IAutofillWindowPresenter;
-import android.widget.TextView;
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
@@ -189,8 +183,16 @@
Slog.w(TAG, "getSuggestionSurfaceForShowing() called with null dataset");
}
mHandler.post(() -> {
- final SurfaceControl suggestionSurface = inflateInlineSuggestion(dataset, response,
- autofillId, width, height);
+ final InlineSuggestionUi inlineSuggestionUi = new InlineSuggestionUi(mContext);
+ final SurfaceControl suggestionSurface = inlineSuggestionUi.inflate(dataset,
+ autofillId, width, height, v -> {
+ Slog.d(TAG, "Inline suggestion clicked");
+ hideFillUiUiThread(mCallback, true);
+ if (mCallback != null) {
+ final int datasetIndex = response.getDatasets().indexOf(dataset);
+ mCallback.fill(response.getRequestId(), datasetIndex, dataset);
+ }
+ });
try {
cb.onContent(suggestionSurface);
@@ -201,51 +203,6 @@
}
/**
- * TODO(b/137800469): Fill in javadoc, generate custom templated view for inline suggestions.
- * TODO: Move to ExtServices.
- *
- * @return a {@link SurfaceControl} with the inflated content embedded in it.
- */
- private SurfaceControl inflateInlineSuggestion(@NonNull Dataset dataset,
- @NonNull FillResponse response, AutofillId autofillId, int width, int height) {
- Slog.i(TAG, "inflate() called");
- final Context context = mContext;
- final int index = dataset.getFieldIds().indexOf(autofillId);
- if (index < 0) {
- Slog.w(TAG, "inflateInlineSuggestion(): AutofillId=" + autofillId
- + " not found in dataset");
- }
-
- final AutofillValue datasetValue = dataset.getFieldValues().get(index);
- //TODO(b/137800469): Pass in inputToken from IME.
- final SurfaceControlViewHost wvr = new SurfaceControlViewHost(context, context.getDisplay(),
- (IBinder) null);
- // TODO(b/134365580): Use the package instead of the SurfaceControl itself
- // for accessibility support.
- final SurfaceControl sc = wvr.getSurfacePackage().getSurfaceControl();
-
- TextView textView = new TextView(context);
- textView.setText(datasetValue.getTextValue());
- textView.setBackgroundColor(Color.WHITE);
- textView.setTextColor(Color.BLACK);
- textView.setOnClickListener(v -> {
- Slog.d(TAG, "Inline suggestion clicked");
- hideFillUiUiThread(mCallback, true);
- if (mCallback != null) {
- final int datasetIndex = response.getDatasets().indexOf(dataset);
- mCallback.fill(response.getRequestId(), datasetIndex, dataset);
- }
- });
-
- WindowManager.LayoutParams lp =
- new WindowManager.LayoutParams(width, height,
- WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.OPAQUE);
- wvr.addView(textView, lp);
-
- return sc;
- }
-
- /**
* Shows the fill UI, removing the previous fill UI if the has changed.
*
* @param focusedId the currently focused field
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.java
new file mode 100644
index 0000000..17cb739
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.java
@@ -0,0 +1,89 @@
+/*
+ * 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.autofill.ui;
+
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.service.autofill.Dataset;
+import android.util.Log;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.widget.TextView;
+
+/**
+ * This is a temporary inline suggestion UI inflater which will be replaced by the ExtServices
+ * implementation.
+ *
+ * TODO(b/146453086): remove this class once autofill ext service is implemented.
+ *
+ * @hide
+ */
+public class InlineSuggestionUi {
+
+ private static final String TAG = "InlineSuggestionUi";
+
+ private final Context mContext;
+
+ public InlineSuggestionUi(Context context) {
+ this.mContext = context;
+ }
+
+ /**
+ * Returns a {@link SurfaceControl} with the inflated content embedded in it.
+ */
+ @MainThread
+ @Nullable
+ public SurfaceControl inflate(@NonNull Dataset dataset, @NonNull AutofillId autofillId,
+ int width, int height, @Nullable View.OnClickListener onClickListener) {
+ Log.d(TAG, "Inflating the inline suggestion UI");
+ final int index = dataset.getFieldIds().indexOf(autofillId);
+ if (index < 0) {
+ Slog.w(TAG, "inflateInlineSuggestion(): AutofillId=" + autofillId
+ + " not found in dataset");
+ return null;
+ }
+ final AutofillValue datasetValue = dataset.getFieldValues().get(index);
+ //TODO(b/137800469): Pass in inputToken from IME.
+ final SurfaceControlViewHost wvr = new SurfaceControlViewHost(mContext,
+ mContext.getDisplay(), (IBinder) null);
+ final SurfaceControl sc = wvr.getSurfacePackage().getSurfaceControl();
+
+ TextView textView = new TextView(mContext);
+ textView.setText(datasetValue.getTextValue());
+ textView.setBackgroundColor(Color.WHITE);
+ textView.setTextColor(Color.BLACK);
+ if (onClickListener != null) {
+ textView.setOnClickListener(onClickListener);
+ }
+
+ WindowManager.LayoutParams lp =
+ new WindowManager.LayoutParams(width, height,
+ WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
+ wvr.addView(textView, lp);
+ return sc;
+ }
+}
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index 7d5b176..72e170f 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -63,6 +63,7 @@
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
/**
* Class to keep track of the information related to "force app standby", which includes:
@@ -416,12 +417,12 @@
}
mStarted = true;
- mIActivityManager = Preconditions.checkNotNull(injectIActivityManager());
- mActivityManagerInternal = Preconditions.checkNotNull(injectActivityManagerInternal());
- mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
- mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
- mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
- mAppStandbyInternal = Preconditions.checkNotNull(injectAppStandbyInternal());
+ mIActivityManager = Objects.requireNonNull(injectIActivityManager());
+ mActivityManagerInternal = Objects.requireNonNull(injectActivityManagerInternal());
+ mAppOpsManager = Objects.requireNonNull(injectAppOpsManager());
+ mAppOpsService = Objects.requireNonNull(injectIAppOpsService());
+ mPowerManagerInternal = Objects.requireNonNull(injectPowerManagerInternal());
+ mAppStandbyInternal = Objects.requireNonNull(injectAppStandbyInternal());
mFlagsObserver = new FeatureFlagsObserver();
mFlagsObserver.register();
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bb78ace..deac1e3 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -47,8 +47,6 @@
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IPPROTO_UDP;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.BroadcastOptions;
@@ -904,7 +902,7 @@
* @see IpConnectivityMetrics.Logger
*/
public IpConnectivityMetrics.Logger getMetricsLogger() {
- return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
+ return Objects.requireNonNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
"no IpConnectivityMetrics service");
}
@@ -933,7 +931,7 @@
IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd, Dependencies deps) {
if (DBG) log("ConnectivityService starting up");
- mDeps = checkNotNull(deps, "missing Dependencies");
+ mDeps = Objects.requireNonNull(deps, "missing Dependencies");
mSystemProperties = mDeps.getSystemProperties();
mNetIdManager = mDeps.makeNetIdManager();
@@ -962,14 +960,14 @@
mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
- mContext = checkNotNull(context, "missing Context");
- mNMS = checkNotNull(netManager, "missing INetworkManagementService");
- mStatsService = checkNotNull(statsService, "missing INetworkStatsService");
- mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
- mPolicyManagerInternal = checkNotNull(
+ mContext = Objects.requireNonNull(context, "missing Context");
+ mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
+ mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService");
+ mPolicyManager = Objects.requireNonNull(policyManager, "missing INetworkPolicyManager");
+ mPolicyManagerInternal = Objects.requireNonNull(
LocalServices.getService(NetworkPolicyManagerInternal.class),
"missing NetworkPolicyManagerInternal");
- mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver");
+ mDnsResolver = Objects.requireNonNull(dnsresolver, "missing IDnsResolver");
mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
mNetd = netd;
@@ -5195,7 +5193,7 @@
@Override
public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities,
PendingIntent operation) {
- checkNotNull(operation, "PendingIntent cannot be null.");
+ Objects.requireNonNull(operation, "PendingIntent cannot be null.");
networkCapabilities = new NetworkCapabilities(networkCapabilities);
enforceNetworkRequestPermissions(networkCapabilities);
enforceMeteredApnPolicy(networkCapabilities);
@@ -5222,7 +5220,7 @@
@Override
public void releasePendingNetworkRequest(PendingIntent operation) {
- checkNotNull(operation, "PendingIntent cannot be null.");
+ Objects.requireNonNull(operation, "PendingIntent cannot be null.");
mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
getCallingUid(), 0, operation));
}
@@ -5280,7 +5278,7 @@
@Override
public void pendingListenForNetwork(NetworkCapabilities networkCapabilities,
PendingIntent operation) {
- checkNotNull(operation, "PendingIntent cannot be null.");
+ Objects.requireNonNull(operation, "PendingIntent cannot be null.");
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
}
diff --git a/services/core/java/com/android/server/ExplicitHealthCheckController.java b/services/core/java/com/android/server/ExplicitHealthCheckController.java
index f7c4aac..77059d9 100644
--- a/services/core/java/com/android/server/ExplicitHealthCheckController.java
+++ b/services/core/java/com/android/server/ExplicitHealthCheckController.java
@@ -47,6 +47,7 @@
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
@@ -113,9 +114,9 @@
Slog.wtf(TAG, "Resetting health check controller callbacks");
}
- mPassedConsumer = Preconditions.checkNotNull(passedConsumer);
- mSupportedConsumer = Preconditions.checkNotNull(supportedConsumer);
- mNotifySyncRunnable = Preconditions.checkNotNull(notifySyncRunnable);
+ mPassedConsumer = Objects.requireNonNull(passedConsumer);
+ mSupportedConsumer = Objects.requireNonNull(supportedConsumer);
+ mNotifySyncRunnable = Objects.requireNonNull(notifySyncRunnable);
}
}
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index a629b3f..c987620 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -25,8 +25,6 @@
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.SOCK_DGRAM;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.Context;
@@ -76,6 +74,7 @@
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* A service to manage multiple clients that want to access the IpSec API. The service is
@@ -566,7 +565,7 @@
}
void put(int key, RefcountedResource<T> obj) {
- checkNotNull(obj, "Null resources cannot be added");
+ Objects.requireNonNull(obj, "Null resources cannot be added");
mArray.put(key, obj);
}
@@ -1101,7 +1100,7 @@
if (requestedSpi > 0 && requestedSpi < 256) {
throw new IllegalArgumentException("ESP SPI must not be in the range of 0-255.");
}
- checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex");
+ Objects.requireNonNull(binder, "Null Binder passed to allocateSecurityParameterIndex");
int callingUid = Binder.getCallingUid();
UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
@@ -1218,7 +1217,7 @@
throw new IllegalArgumentException(
"Specified port number must be a valid non-reserved UDP port");
}
- checkNotNull(binder, "Null Binder passed to openUdpEncapsulationSocket");
+ Objects.requireNonNull(binder, "Null Binder passed to openUdpEncapsulationSocket");
int callingUid = Binder.getCallingUid();
UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
@@ -1278,8 +1277,8 @@
String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder,
String callingPackage) {
enforceTunnelFeatureAndPermissions(callingPackage);
- checkNotNull(binder, "Null Binder passed to createTunnelInterface");
- checkNotNull(underlyingNetwork, "No underlying network was specified");
+ Objects.requireNonNull(binder, "Null Binder passed to createTunnelInterface");
+ Objects.requireNonNull(underlyingNetwork, "No underlying network was specified");
checkInetAddress(localAddr);
checkInetAddress(remoteAddr);
@@ -1556,7 +1555,7 @@
"IPsec Tunnel Mode requires PackageManager.FEATURE_IPSEC_TUNNELS");
}
- checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels");
+ Objects.requireNonNull(callingPackage, "Null calling package cannot create IpSec tunnels");
switch (getAppOpsManager().noteOp(TUNNEL_OP, Binder.getCallingUid(), callingPackage)) {
case AppOpsManager.MODE_DEFAULT:
mContext.enforceCallingOrSelfPermission(
@@ -1625,12 +1624,12 @@
@Override
public synchronized IpSecTransformResponse createTransform(
IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException {
- checkNotNull(c);
+ Objects.requireNonNull(c);
if (c.getMode() == IpSecTransform.MODE_TUNNEL) {
enforceTunnelFeatureAndPermissions(callingPackage);
}
checkIpSecConfig(c);
- checkNotNull(binder, "Null Binder passed to createTransform");
+ Objects.requireNonNull(binder, "Null Binder passed to createTransform");
final int resourceId = mNextResourceId++;
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index cad917b..c5f1923 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -23,7 +23,6 @@
import static android.location.LocationManager.PASSIVE_PROVIDER;
import static android.os.PowerManager.locationPowerSaveModeToString;
-import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkState;
import android.Manifest;
@@ -121,6 +120,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
@@ -821,7 +821,7 @@
@GuardedBy("mLock")
public void attachLocked(AbstractLocationProvider provider) {
- checkNotNull(provider);
+ Objects.requireNonNull(provider);
checkState(mProvider == null);
if (D) {
@@ -1430,7 +1430,7 @@
@Override
public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName,
String featureId, String listenerIdentifier) {
- Preconditions.checkNotNull(listenerIdentifier);
+ Objects.requireNonNull(listenerIdentifier);
return mGnssManagerService == null ? false : mGnssManagerService.addGnssBatchingCallback(
callback, packageName, featureId, listenerIdentifier);
@@ -2119,7 +2119,7 @@
public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
PendingIntent intent, String packageName, String featureId,
String listenerIdentifier) {
- Preconditions.checkNotNull(listenerIdentifier);
+ Objects.requireNonNull(listenerIdentifier);
synchronized (mLock) {
if (request == null) request = DEFAULT_LOCATION_REQUEST;
@@ -2470,7 +2470,7 @@
@Override
public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
String packageName, String featureId, String listenerIdentifier) {
- Preconditions.checkNotNull(listenerIdentifier);
+ Objects.requireNonNull(listenerIdentifier);
if (request == null) request = DEFAULT_LOCATION_REQUEST;
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
@@ -2567,7 +2567,7 @@
@Override
public boolean addGnssMeasurementsListener(IGnssMeasurementsListener listener,
String packageName, String featureId, String listenerIdentifier) {
- Preconditions.checkNotNull(listenerIdentifier);
+ Objects.requireNonNull(listenerIdentifier);
return mGnssManagerService == null ? false
: mGnssManagerService.addGnssMeasurementsListener(listener, packageName, featureId,
@@ -2600,7 +2600,7 @@
@Override
public boolean addGnssNavigationMessageListener(IGnssNavigationMessageListener listener,
String packageName, String featureId, String listenerIdentifier) {
- Preconditions.checkNotNull(listenerIdentifier);
+ Objects.requireNonNull(listenerIdentifier);
return mGnssManagerService == null ? false
: mGnssManagerService.addGnssNavigationMessageListener(listener, packageName,
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index ad02aad..eac767f 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -46,6 +46,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.LinkedList;
+import java.util.Objects;
/**
* Generic connector class for interfacing with a native daemon which uses the
@@ -126,7 +127,7 @@
*/
public void setWarnIfHeld(Object warnIfHeld) {
Preconditions.checkState(mWarnIfHeld == null);
- mWarnIfHeld = Preconditions.checkNotNull(warnIfHeld);
+ mWarnIfHeld = Objects.requireNonNull(warnIfHeld);
}
@Override
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 0d496b6..1f73650 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -109,6 +109,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* @hide
@@ -456,7 +457,7 @@
@Override
public void registerTetheringStatsProvider(ITetheringStatsProvider provider, String name) {
NetworkStack.checkNetworkStackPermission(mContext);
- Preconditions.checkNotNull(provider);
+ Objects.requireNonNull(provider);
synchronized(mTetheringStatsProviders) {
mTetheringStatsProviders.put(provider, name);
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 22fa8ff4..c474f47 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2102,7 +2102,7 @@
public void setVolumeNickname(String fsUuid, String nickname) {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
- Preconditions.checkNotNull(fsUuid);
+ Objects.requireNonNull(fsUuid);
synchronized (mLock) {
final VolumeRecord rec = mRecords.get(fsUuid);
rec.nickname = nickname;
@@ -2115,7 +2115,7 @@
public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
- Preconditions.checkNotNull(fsUuid);
+ Objects.requireNonNull(fsUuid);
synchronized (mLock) {
final VolumeRecord rec = mRecords.get(fsUuid);
rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
@@ -2128,7 +2128,7 @@
public void forgetVolume(String fsUuid) {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
- Preconditions.checkNotNull(fsUuid);
+ Objects.requireNonNull(fsUuid);
synchronized (mLock) {
final VolumeRecord rec = mRecords.remove(fsUuid);
@@ -2534,7 +2534,7 @@
@Override
public String getMountedObbPath(String rawPath) {
- Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
+ Objects.requireNonNull(rawPath, "rawPath cannot be null");
warnOnNotMounted();
@@ -2552,7 +2552,7 @@
@Override
public boolean isObbMounted(String rawPath) {
- Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
+ Objects.requireNonNull(rawPath, "rawPath cannot be null");
synchronized (mObbMounts) {
return mObbPathToStateMap.containsKey(rawPath);
}
@@ -2561,10 +2561,10 @@
@Override
public void mountObb(String rawPath, String canonicalPath, String key,
IObbActionListener token, int nonce, ObbInfo obbInfo) {
- Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
- Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
- Preconditions.checkNotNull(token, "token cannot be null");
- Preconditions.checkNotNull(obbInfo, "obbIfno cannot be null");
+ Objects.requireNonNull(rawPath, "rawPath cannot be null");
+ Objects.requireNonNull(canonicalPath, "canonicalPath cannot be null");
+ Objects.requireNonNull(token, "token cannot be null");
+ Objects.requireNonNull(obbInfo, "obbIfno cannot be null");
final int callingUid = Binder.getCallingUid();
final ObbState obbState = new ObbState(rawPath, canonicalPath,
@@ -2578,7 +2578,7 @@
@Override
public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
- Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
+ Objects.requireNonNull(rawPath, "rawPath cannot be null");
final ObbState existingState;
synchronized (mObbMounts) {
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index 5ed94e3..179780d 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -28,6 +28,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@@ -73,7 +74,7 @@
*/
public static @NonNull Future<?> submit(@NonNull Runnable runnable,
@NonNull String description) {
- Preconditions.checkNotNull(description, "description cannot be null");
+ Objects.requireNonNull(description, "description cannot be null");
SystemServerInitThreadPool instance;
synchronized (LOCK) {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index c741fce..783715c 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -785,9 +785,11 @@
if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
r.callback.onServiceStateChanged(rawSs);
} else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
- r.callback.onServiceStateChanged(rawSs.sanitizeLocationInfo(false));
+ r.callback.onServiceStateChanged(
+ rawSs.createLocationInfoSanitizedCopy(false));
} else {
- r.callback.onServiceStateChanged(rawSs.sanitizeLocationInfo(true));
+ r.callback.onServiceStateChanged(
+ rawSs.createLocationInfoSanitizedCopy(true));
}
} catch (RemoteException ex) {
remove(r.binder);
@@ -1142,9 +1144,9 @@
if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
stateToSend = new ServiceState(state);
} else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
- stateToSend = state.sanitizeLocationInfo(false);
+ stateToSend = state.createLocationInfoSanitizedCopy(false);
} else {
- stateToSend = state.sanitizeLocationInfo(true);
+ stateToSend = state.createLocationInfoSanitizedCopy(true);
}
if (DBG) {
log("notifyServiceStateForSubscriber: callback.onSSC r=" + r
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index d19d2dd..c27b0da 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -16,8 +16,6 @@
package com.android.server;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -55,6 +53,7 @@
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
/** @hide */
@@ -82,9 +81,9 @@
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
- mContext = checkNotNull(context, "missing Context");
- mNMS = checkNotNull(netManager, "missing INetworkManagementService");
- mNetd = checkNotNull(NetdService.getInstance(), "could not get netd instance");
+ mContext = Objects.requireNonNull(context, "missing Context");
+ mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
+ mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance");
}
/**
@@ -96,7 +95,7 @@
private TestNetworkInterface createInterface(boolean isTun, LinkAddress[] linkAddrs) {
enforceTestNetworkPermissions(mContext);
- checkNotNull(linkAddrs, "missing linkAddrs");
+ Objects.requireNonNull(linkAddrs, "missing linkAddrs");
String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX;
String iface = ifacePrefix + sTestTunIndex.getAndIncrement();
@@ -233,8 +232,8 @@
int callingUid,
@NonNull IBinder binder)
throws RemoteException, SocketException {
- checkNotNull(looper, "missing Looper");
- checkNotNull(context, "missing Context");
+ Objects.requireNonNull(looper, "missing Looper");
+ Objects.requireNonNull(context, "missing Context");
// iface and binder validity checked by caller
// Build network info with special testing type
@@ -267,7 +266,7 @@
// Find the currently assigned addresses, and add them to LinkProperties
boolean allowIPv4 = false, allowIPv6 = false;
NetworkInterface netIntf = NetworkInterface.getByName(iface);
- checkNotNull(netIntf, "No such network interface found: " + netIntf);
+ Objects.requireNonNull(netIntf, "No such network interface found: " + netIntf);
for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) {
lp.addLinkAddress(
@@ -305,8 +304,8 @@
@NonNull IBinder binder) {
enforceTestNetworkPermissions(mContext);
- checkNotNull(iface, "missing Iface");
- checkNotNull(binder, "missing IBinder");
+ Objects.requireNonNull(iface, "missing Iface");
+ Objects.requireNonNull(binder, "missing IBinder");
if (!(iface.startsWith(INetd.IPSEC_INTERFACE_PREFIX)
|| iface.startsWith(TEST_TUN_PREFIX))) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 5996b7d..a372fca0 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -463,7 +463,7 @@
Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
- Preconditions.checkNotNull(account, "account cannot be null");
+ Objects.requireNonNull(account, "account cannot be null");
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
callingUid, account.type);
@@ -544,7 +544,7 @@
@Override
public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
- Preconditions.checkNotNull(account, "account cannot be null");
+ Objects.requireNonNull(account, "account cannot be null");
int callingUid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
if (!isAccountManagedByCaller(account.type, callingUid, userId)
@@ -590,8 +590,8 @@
@Override
public int getAccountVisibility(Account account, String packageName) {
- Preconditions.checkNotNull(account, "account cannot be null");
- Preconditions.checkNotNull(packageName, "packageName cannot be null");
+ Objects.requireNonNull(account, "account cannot be null");
+ Objects.requireNonNull(packageName, "packageName cannot be null");
int callingUid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
if (!isAccountManagedByCaller(account.type, callingUid, userId)
@@ -659,7 +659,7 @@
*/
private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
UserAccounts accounts) {
- Preconditions.checkNotNull(packageName, "packageName cannot be null");
+ Objects.requireNonNull(packageName, "packageName cannot be null");
int uid = -1;
try {
long identityToken = clearCallingIdentity();
@@ -755,8 +755,8 @@
@Override
public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
- Preconditions.checkNotNull(account, "account cannot be null");
- Preconditions.checkNotNull(packageName, "packageName cannot be null");
+ Objects.requireNonNull(account, "account cannot be null");
+ Objects.requireNonNull(packageName, "packageName cannot be null");
int callingUid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
if (!isAccountManagedByCaller(account.type, callingUid, userId)
@@ -1525,7 +1525,7 @@
+ ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
- Preconditions.checkNotNull(account, "account cannot be null");
+ Objects.requireNonNull(account, "account cannot be null");
int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
@@ -1563,8 +1563,8 @@
account, key, callingUid, Binder.getCallingPid());
Log.v(TAG, msg);
}
- Preconditions.checkNotNull(account, "account cannot be null");
- Preconditions.checkNotNull(key, "key cannot be null");
+ Objects.requireNonNull(account, "account cannot be null");
+ Objects.requireNonNull(key, "key cannot be null");
int userId = UserHandle.getCallingUserId();
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
String msg = String.format(
@@ -1715,7 +1715,7 @@
callingUid);
Log.v(TAG, msg);
}
- Preconditions.checkNotNull(account, "account cannot be null");
+ Objects.requireNonNull(account, "account cannot be null");
int userId = UserHandle.getCallingUserId();
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
String msg = String.format(
@@ -2401,8 +2401,8 @@
@Override
public void invalidateAuthToken(String accountType, String authToken) {
int callerUid = Binder.getCallingUid();
- Preconditions.checkNotNull(accountType, "accountType cannot be null");
- Preconditions.checkNotNull(authToken, "authToken cannot be null");
+ Objects.requireNonNull(accountType, "accountType cannot be null");
+ Objects.requireNonNull(authToken, "authToken cannot be null");
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "invalidateAuthToken: accountType " + accountType
+ ", caller's uid " + callerUid
@@ -2518,8 +2518,8 @@
+ ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
- Preconditions.checkNotNull(account, "account cannot be null");
- Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
+ Objects.requireNonNull(account, "account cannot be null");
+ Objects.requireNonNull(authTokenType, "authTokenType cannot be null");
int userId = UserHandle.getCallingUserId();
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
String msg = String.format(
@@ -2551,8 +2551,8 @@
+ ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
- Preconditions.checkNotNull(account, "account cannot be null");
- Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
+ Objects.requireNonNull(account, "account cannot be null");
+ Objects.requireNonNull(authTokenType, "authTokenType cannot be null");
int userId = UserHandle.getCallingUserId();
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
String msg = String.format(
@@ -2578,7 +2578,7 @@
+ ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
- Preconditions.checkNotNull(account, "account cannot be null");
+ Objects.requireNonNull(account, "account cannot be null");
int userId = UserHandle.getCallingUserId();
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
String msg = String.format(
@@ -2644,7 +2644,7 @@
+ ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
- Preconditions.checkNotNull(account, "account cannot be null");
+ Objects.requireNonNull(account, "account cannot be null");
int userId = UserHandle.getCallingUserId();
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
String msg = String.format(
@@ -3946,9 +3946,9 @@
if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
throw new SecurityException("Can be called only by system UID");
}
- Preconditions.checkNotNull(account, "account cannot be null");
- Preconditions.checkNotNull(packageName, "packageName cannot be null");
- Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
+ Objects.requireNonNull(account, "account cannot be null");
+ Objects.requireNonNull(packageName, "packageName cannot be null");
+ Objects.requireNonNull(userHandle, "userHandle cannot be null");
final int userId = userHandle.getIdentifier();
@@ -4022,9 +4022,9 @@
throw new SecurityException("Can be called only by system UID");
}
- Preconditions.checkNotNull(account, "account cannot be null");
- Preconditions.checkNotNull(packageName, "packageName cannot be null");
- Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
+ Objects.requireNonNull(account, "account cannot be null");
+ Objects.requireNonNull(packageName, "packageName cannot be null");
+ Objects.requireNonNull(userHandle, "userHandle cannot be null");
final int userId = userHandle.getIdentifier();
diff --git a/services/core/java/com/android/server/accounts/CryptoHelper.java b/services/core/java/com/android/server/accounts/CryptoHelper.java
index 2ade673..863d6b9 100644
--- a/services/core/java/com/android/server/accounts/CryptoHelper.java
+++ b/services/core/java/com/android/server/accounts/CryptoHelper.java
@@ -10,6 +10,7 @@
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
+import java.util.Objects;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
@@ -54,7 +55,7 @@
@NonNull
/* default */ Bundle encryptBundle(@NonNull Bundle bundle) throws GeneralSecurityException {
- Preconditions.checkNotNull(bundle, "Cannot encrypt null bundle.");
+ Objects.requireNonNull(bundle, "Cannot encrypt null bundle.");
Parcel parcel = Parcel.obtain();
bundle.writeToParcel(parcel, 0);
byte[] clearBytes = parcel.marshall();
@@ -76,7 +77,7 @@
@Nullable
/* default */ Bundle decryptBundle(@NonNull Bundle bundle) throws GeneralSecurityException {
- Preconditions.checkNotNull(bundle, "Cannot decrypt null bundle.");
+ Objects.requireNonNull(bundle, "Cannot decrypt null bundle.");
byte[] iv = bundle.getByteArray(KEY_IV);
byte[] encryptedBytes = bundle.getByteArray(KEY_CIPHER);
byte[] mac = bundle.getByteArray(KEY_MAC);
diff --git a/services/core/java/com/android/server/accounts/TokenCache.java b/services/core/java/com/android/server/accounts/TokenCache.java
index 2af2f38..e38cf5f 100644
--- a/services/core/java/com/android/server/accounts/TokenCache.java
+++ b/services/core/java/com/android/server/accounts/TokenCache.java
@@ -193,7 +193,7 @@
String packageName,
byte[] sigDigest,
long expiryMillis) {
- Preconditions.checkNotNull(account);
+ Objects.requireNonNull(account);
if (token == null || System.currentTimeMillis() > expiryMillis) {
return;
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 154d16f..a58bd9b 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -570,7 +570,7 @@
}
mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null,
- true);
+ true, false, null);
}
final ServiceMap smap = getServiceMapLocked(r.userId);
@@ -1395,7 +1395,7 @@
mAm.mAppOpsService.startOperation(
AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName,
- null, true);
+ null, true, false, "");
StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
r.appInfo.uid, r.shortInstanceName,
StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d7a46fe..dd1f370 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -324,6 +324,7 @@
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.MemInfoReader;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.HexFunction;
import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.TriFunction;
import com.android.server.AlarmManagerInternal;
@@ -3120,7 +3121,7 @@
private boolean hasUsageStatsPermission(String callingPackage) {
final int mode = mAppOpsService.noteOperation(AppOpsManager.OP_GET_USAGE_STATS,
- Binder.getCallingUid(), callingPackage, null);
+ Binder.getCallingUid(), callingPackage, null, false, "");
if (mode == AppOpsManager.MODE_DEFAULT) {
return checkCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS)
== PackageManager.PERMISSION_GRANTED;
@@ -5816,7 +5817,8 @@
public int noteOp(String op, int uid, String packageName) {
// TODO moltmann: Allow to specify featureId
return mActivityManagerService.mAppOpsService
- .noteOperation(AppOpsManager.strOpToOp(op), uid, packageName, null);
+ .noteOperation(AppOpsManager.strOpToOp(op), uid, packageName, null,
+ false, "");
}
@Override
@@ -5968,7 +5970,7 @@
}
// ...and legacy apps get an AppOp check
int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
- uid, packageName, null);
+ uid, packageName, null, false, "");
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
}
@@ -19253,18 +19255,22 @@
@Override
public int noteOperation(int code, int uid, @Nullable String packageName,
- @Nullable String featureId,
- @NonNull QuadFunction<Integer, Integer, String, String, Integer> superImpl) {
+ @Nullable String featureId, boolean shouldCollectAsyncNotedOp,
+ @Nullable String message,
+ @NonNull HexFunction<Integer, Integer, String, String, Boolean, String, Integer>
+ superImpl) {
if (uid == mTargetUid && isTargetOp(code)) {
final long identity = Binder.clearCallingIdentity();
try {
return mAppOpsService.noteProxyOperation(code, Process.SHELL_UID,
- "com.android.shell", null, uid, packageName, featureId);
+ "com.android.shell", null, uid, packageName, featureId,
+ shouldCollectAsyncNotedOp, message);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- return superImpl.apply(code, uid, packageName, featureId);
+ return superImpl.apply(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
+ message);
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 79fe610..a4c44fa 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -111,6 +111,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -1785,7 +1786,7 @@
}
int runGetCurrentUser(PrintWriter pw) throws RemoteException {
- UserInfo currentUser = Preconditions.checkNotNull(mInterface.getCurrentUser(),
+ UserInfo currentUser = Objects.requireNonNull(mInterface.getCurrentUser(),
"Current user not set");
pw.println(currentUser.id);
return 0;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 10492a7..6fca3f6 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -650,7 +650,7 @@
// TODO moltmann: Set featureId from caller
if (opCode != AppOpsManager.OP_NONE
&& mService.mAppOpsService.noteOperation(opCode, r.callingUid,
- r.callerPackage, null) != AppOpsManager.MODE_ALLOWED) {
+ r.callerPackage, null, false, "") != AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
@@ -680,10 +680,10 @@
break;
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
- // TODO moltmann: Set componentId from caller
+ // TODO moltmann: Set featureId from caller
if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
&& mService.mAppOpsService.noteOperation(appOp,
- filter.receiverList.uid, filter.packageName, null)
+ filter.receiverList.uid, filter.packageName, null, false, "")
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent.toString()
@@ -713,10 +713,10 @@
skip = true;
}
}
- // TODO moltmann: Set componentId from caller
+ // TODO moltmann: Set featureId from caller
if (!skip && r.appOp != AppOpsManager.OP_NONE
&& mService.mAppOpsService.noteOperation(r.appOp,
- filter.receiverList.uid, filter.packageName, null)
+ filter.receiverList.uid, filter.packageName, null, false, "")
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent.toString()
@@ -1370,10 +1370,10 @@
skip = true;
} else if (!skip && info.activityInfo.permission != null) {
final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);
- // TODO moltmann: Set componentId from caller
+ // TODO moltmann: Set featureId from caller
if (opCode != AppOpsManager.OP_NONE
- && mService.mAppOpsService.noteOperation(opCode, r.callingUid,
- r.callerPackage, null) != AppOpsManager.MODE_ALLOWED) {
+ && mService.mAppOpsService.noteOperation(opCode, r.callingUid, r.callerPackage,
+ null, false, "") != AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
@@ -1409,10 +1409,11 @@
break;
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
- // TODO moltmann: Set componentId from caller
+ // TODO moltmann: Set featureId from caller
if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
&& mService.mAppOpsService.noteOperation(appOp,
- info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, null)
+ info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, null,
+ false, "")
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent + " to "
@@ -1426,10 +1427,11 @@
}
}
}
- // TODO moltmann: Set componentId from caller
+ // TODO moltmann: Set featureId from caller
if (!skip && r.appOp != AppOpsManager.OP_NONE
&& mService.mAppOpsService.noteOperation(r.appOp,
- info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, null)
+ info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, null, false,
+ "")
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent + " to "
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index f9730a9..eb1ab38 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1723,7 +1723,7 @@
}
void registerUserSwitchObserver(IUserSwitchObserver observer, String name) {
- Preconditions.checkNotNull(name, "Observer name cannot be null");
+ Objects.requireNonNull(name, "Observer name cannot be null");
checkCallingPermission(INTERACT_ACROSS_USERS_FULL, "registerUserSwitchObserver");
mUserSwitchObservers.register(observer, name);
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 9f23cdaf..5bbb517 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -18,7 +18,6 @@
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.AppOpsManager.NoteOpEvent;
-import static android.app.AppOpsManager.OpEventProxyInfo;
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_COARSE_LOCATION;
import static android.app.AppOpsManager.OP_FLAGS_ALL;
@@ -26,6 +25,7 @@
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.OpEventProxyInfo;
import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
import static android.app.AppOpsManager.UID_STATE_CACHED;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
@@ -40,9 +40,12 @@
import static android.app.AppOpsManager.modeToName;
import static android.app.AppOpsManager.opToName;
import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
+import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.EXTRA_REPLACING;
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
import android.Manifest;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -69,6 +72,8 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.PermissionInfo;
import android.content.pm.UserInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
import android.database.ContentObserver;
import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION;
import android.net.Uri;
@@ -98,6 +103,7 @@
import android.util.KeyValueListParser;
import android.util.LongSparseArray;
import android.util.Pair;
+import android.util.Pools.SimplePool;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -122,6 +128,7 @@
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
+import com.android.server.SystemServerInitThreadPool;
import libcore.util.EmptyArray;
@@ -195,16 +202,26 @@
};
private static final int MAX_UNFORWARED_OPS = 10;
+ private static final int MAX_UNUSED_POOLED_OBJECTS = 3;
Context mContext;
final AtomicFile mFile;
final Handler mHandler;
+ /** Pool for {@link OpEventProxyInfoPool} to avoid to constantly reallocate new objects */
+ @GuardedBy("this")
+ private final OpEventProxyInfoPool mOpEventProxyInfoPool = new OpEventProxyInfoPool();
+
+ /** Pool for {@link InProgressStartOpEventPool} to avoid to constantly reallocate new objects */
+ @GuardedBy("this")
+ private final InProgressStartOpEventPool mInProgressStartOpEventPool =
+ new InProgressStartOpEventPool();
+
private final AppOpsManagerInternalImpl mAppOpsManagerInternal
= new AppOpsManagerInternalImpl();
/**
- * Registered callbacks, called from {@link #noteAsyncOp}.
+ * Registered callbacks, called from {@link #collectAsyncNotedOp}.
*
* <p>(package name, uid) -> callbacks
*
@@ -215,7 +232,7 @@
mAsyncOpWatchers = new ArrayMap<>();
/**
- * Async note-ops collected from {@link #noteAsyncOp} that have not been delivered to a
+ * Async note-ops collected from {@link #collectAsyncNotedOp} that have not been delivered to a
* callback yet.
*
* <p>(package name, uid) -> list<ops>
@@ -266,6 +283,46 @@
private SparseArray<List<Integer>> mSwitchOpToOps;
/**
+ * An unsynchronized pool of {@link OpEventProxyInfo} objects.
+ */
+ private class OpEventProxyInfoPool extends SimplePool<OpEventProxyInfo> {
+ OpEventProxyInfoPool() {
+ super(MAX_UNUSED_POOLED_OBJECTS);
+ }
+
+ OpEventProxyInfo acquire(@IntRange(from = 0) int uid, @Nullable String packageName,
+ @Nullable String featureId) {
+ OpEventProxyInfo recycled = acquire();
+ if (recycled != null) {
+ recycled.reinit(uid, packageName, featureId);
+ return recycled;
+ }
+
+ return new OpEventProxyInfo(uid, packageName, featureId);
+ }
+ }
+
+ /**
+ * An unsynchronized pool of {@link InProgressStartOpEvent} objects.
+ */
+ private class InProgressStartOpEventPool extends SimplePool<InProgressStartOpEvent> {
+ InProgressStartOpEventPool() {
+ super(MAX_UNUSED_POOLED_OBJECTS);
+ }
+
+ InProgressStartOpEvent acquire(long startTime, long elapsedTime, @NonNull IBinder clientId,
+ @NonNull Runnable onDeath, int uidState) throws RemoteException {
+ InProgressStartOpEvent recycled = acquire();
+ if (recycled != null) {
+ recycled.reinit(startTime, elapsedTime, clientId, onDeath, uidState);
+ return recycled;
+ }
+
+ return new InProgressStartOpEvent(startTime, elapsedTime, clientId, onDeath, uidState);
+ }
+ }
+
+ /**
* All times are in milliseconds. These constants are kept synchronized with the system
* global Settings. Any access to this class or its fields should be done while
* holding the AppOpsService lock.
@@ -468,6 +525,9 @@
final UidState uidState;
final boolean isPrivileged;
+ /** Lazily populated cache of featureIds of this package */
+ final @NonNull ArraySet<String> knownFeatureIds = new ArraySet<>();
+
Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
packageName = _packageName;
uidState = _uidState;
@@ -477,39 +537,97 @@
/** A in progress startOp->finishOp event */
private static final class InProgressStartOpEvent implements IBinder.DeathRecipient {
- /** Time of startOp event */
- final long startTime;
+ /** Wall clock time of startOp event (not monotonic) */
+ private long mStartTime;
+
+ /** Elapsed time since boot of startOp event */
+ private long mStartElapsedTime;
/** Id of the client that started the event */
- final @NonNull IBinder clientId;
+ private @NonNull IBinder mClientId;
/** To call when client dies */
- final @NonNull Runnable onDeath;
+ private @NonNull Runnable mOnDeath;
/** uidstate used when calling startOp */
- final @AppOpsManager.UidState int uidState;
+ private @AppOpsManager.UidState int mUidState;
/** How many times the op was started but not finished yet */
int numUnfinishedStarts;
- private InProgressStartOpEvent(long startTime, @NonNull IBinder clientId,
- @NonNull Runnable onDeath, int uidState) throws RemoteException {
- this.startTime = startTime;
- this.clientId = clientId;
- this.onDeath = onDeath;
- this.uidState = uidState;
+ /**
+ * Create a new {@link InProgressStartOpEvent}.
+ *
+ * @param startTime The time {@link #startOperation} was called
+ * @param startElapsedTime The elapsed time when {@link #startOperation} was called
+ * @param clientId The client id of the caller of {@link #startOperation}
+ * @param onDeath The code to execute on client death
+ * @param uidState The uidstate of the app {@link #startOperation} was called for
+ *
+ * @throws RemoteException If the client is dying
+ */
+ private InProgressStartOpEvent(long startTime, long startElapsedTime,
+ @NonNull IBinder clientId, @NonNull Runnable onDeath, int uidState)
+ throws RemoteException {
+ mStartTime = startTime;
+ mStartElapsedTime = startElapsedTime;
+ mClientId = clientId;
+ mOnDeath = onDeath;
+ mUidState = uidState;
clientId.linkToDeath(this, 0);
}
/** Clean up event */
public void finish() {
- clientId.unlinkToDeath(this, 0);
+ mClientId.unlinkToDeath(this, 0);
}
@Override
public void binderDied() {
- onDeath.run();
+ mOnDeath.run();
+ }
+
+ /**
+ * Reinit existing object with new state.
+ *
+ * @param startTime The time {@link #startOperation} was called
+ * @param startElapsedTime The elapsed time when {@link #startOperation} was called
+ * @param clientId The client id of the caller of {@link #startOperation}
+ * @param onDeath The code to execute on client death
+ * @param uidState The uidstate of the app {@link #startOperation} was called for
+ *
+ * @throws RemoteException If the client is dying
+ */
+ public void reinit(long startTime, long startElapsedTime, @NonNull IBinder clientId,
+ @NonNull Runnable onDeath, int uidState) throws RemoteException {
+ mStartTime = startTime;
+ mStartElapsedTime = startElapsedTime;
+ mClientId = clientId;
+ mOnDeath = onDeath;
+ mUidState = uidState;
+
+ clientId.linkToDeath(this, 0);
+ }
+
+ /** @return Wall clock time of startOp event */
+ public long getStartTime() {
+ return mStartTime;
+ }
+
+ /** @return Elapsed time since boot of startOp event */
+ public long getStartElapsedTime() {
+ return mStartElapsedTime;
+ }
+
+ /** @return Id of the client that started the event */
+ public @NonNull IBinder getClientId() {
+ return mClientId;
+ }
+
+ /** @return uidstate used when calling startOp */
+ public int getUidState() {
+ return mUidState;
}
}
@@ -522,7 +640,7 @@
* <p>Key is {@link AppOpsManager#makeKey}
*/
@GuardedBy("AppOpsService.this")
- private @Nullable LongSparseArray<AppOpsManager.NoteOpEvent> mAccessEvents;
+ private @Nullable LongSparseArray<NoteOpEvent> mAccessEvents;
/**
* Last rejected accesses for each uidState/opFlag combination
@@ -530,7 +648,7 @@
* <p>Key is {@link AppOpsManager#makeKey}
*/
@GuardedBy("AppOpsService.this")
- private @Nullable LongSparseArray<AppOpsManager.NoteOpEvent> mRejectEvents;
+ private @Nullable LongSparseArray<NoteOpEvent> mRejectEvents;
/**
* Currently in progress startOp events
@@ -582,9 +700,16 @@
OpEventProxyInfo proxyInfo = null;
if (proxyUid != Process.INVALID_UID) {
- proxyInfo = new OpEventProxyInfo(proxyUid, proxyPackageName, proxyFeatureId);
+ proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
+ proxyFeatureId);
}
- mAccessEvents.put(key, new NoteOpEvent(noteTime, duration, proxyInfo));
+
+ NoteOpEvent existingEvent = mAccessEvents.get(key);
+ if (existingEvent != null) {
+ existingEvent.reinit(noteTime, duration, proxyInfo, mOpEventProxyInfoPool);
+ } else {
+ mAccessEvents.put(key, new NoteOpEvent(noteTime, duration, proxyInfo));
+ }
}
/**
@@ -613,7 +738,12 @@
}
// We do not collect proxy information for rejections yet
- mRejectEvents.put(key, new NoteOpEvent(noteTime, -1, null));
+ NoteOpEvent existingEvent = mRejectEvents.get(key);
+ if (existingEvent != null) {
+ existingEvent.reinit(noteTime, -1, null, mOpEventProxyInfoPool);
+ } else {
+ mRejectEvents.put(key, new NoteOpEvent(noteTime, -1, null));
+ }
}
/**
@@ -633,27 +763,15 @@
mInProgressEvents = new ArrayMap<>(1);
}
-
InProgressStartOpEvent event = mInProgressEvents.get(clientId);
if (event == null) {
- event = new InProgressStartOpEvent(System.currentTimeMillis(), clientId, () -> {
- // In the case the client dies without calling finish first
- synchronized (AppOpsService.this) {
- if (mInProgressEvents == null) {
- return;
- }
-
- InProgressStartOpEvent deadEvent = mInProgressEvents.get(clientId);
- if (deadEvent != null) {
- deadEvent.numUnfinishedStarts = 1;
- }
-
- finished(clientId);
- }
- }, uidState);
+ event = mInProgressStartOpEventPool.acquire(System.currentTimeMillis(),
+ SystemClock.elapsedRealtime(), clientId,
+ PooledLambda.obtainRunnable(AppOpsService::onClientDeath, this, clientId),
+ uidState);
mInProgressEvents.put(clientId, event);
} else {
- if (uidState != event.uidState) {
+ if (uidState != event.mUidState) {
onUidStateChanged(uidState);
}
}
@@ -697,13 +815,15 @@
}
// startOp events don't support proxy, hence use flags==SELF
- NoteOpEvent finishedEvent = new NoteOpEvent(event.startTime,
- System.currentTimeMillis() - event.startTime, null);
- mAccessEvents.put(makeKey(event.uidState, OP_FLAG_SELF), finishedEvent);
+ NoteOpEvent finishedEvent = new NoteOpEvent(event.getStartTime(),
+ SystemClock.elapsedRealtime() - event.getStartElapsedTime(), null);
+ mAccessEvents.put(makeKey(event.getUidState(), OP_FLAG_SELF), finishedEvent);
mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
- parent.packageName, event.uidState, AppOpsManager.OP_FLAG_SELF,
- finishedEvent.duration);
+ parent.packageName, event.getUidState(), AppOpsManager.OP_FLAG_SELF,
+ finishedEvent.getDuration());
+
+ mInProgressStartOpEventPool.release(event);
if (mInProgressEvents.isEmpty()) {
mInProgressEvents = null;
@@ -718,6 +838,26 @@
}
/**
+ * Called in the case the client dies without calling finish first
+ *
+ * @param clientId The client that died
+ */
+ void onClientDeath(@NonNull IBinder clientId) {
+ synchronized (AppOpsService.this) {
+ if (mInProgressEvents == null) {
+ return;
+ }
+
+ InProgressStartOpEvent deadEvent = mInProgressEvents.get(clientId);
+ if (deadEvent != null) {
+ deadEvent.numUnfinishedStarts = 1;
+ }
+
+ finished(clientId);
+ }
+ }
+
+ /**
* Notify that the state of the uid changed
*
* @param newState The new state
@@ -731,10 +871,10 @@
for (int i = 0; i < numInProgressEvents; i++) {
InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
- if (event.uidState != newState) {
+ if (event.getUidState() != newState) {
try {
- finished(event.clientId, false);
- started(event.clientId, newState);
+ finished(event.getClientId(), false);
+ started(event.getClientId(), newState);
} catch (RemoteException e) {
if (DEBUG) Slog.e(TAG, "Cannot switch to new uidState " + newState);
}
@@ -742,6 +882,59 @@
}
}
+ /**
+ * Combine {@code a} and {@code b} and return the result. The result might be {@code a}
+ * or {@code b}. If there is an event for the same key in both the later event is retained.
+ */
+ private @Nullable LongSparseArray<NoteOpEvent> add(@Nullable LongSparseArray<NoteOpEvent> a,
+ @Nullable LongSparseArray<NoteOpEvent> b) {
+ if (a == null) {
+ return b;
+ }
+
+ if (b == null) {
+ return a;
+ }
+
+ int numEventsToAdd = b.size();
+ for (int i = 0; i < numEventsToAdd; i++) {
+ long keyOfEventToAdd = b.keyAt(i);
+ NoteOpEvent bEvent = b.valueAt(i);
+ NoteOpEvent aEvent = a.get(keyOfEventToAdd);
+
+ if (aEvent == null || bEvent.getNoteTime() > aEvent.getNoteTime()) {
+ a.put(keyOfEventToAdd, bEvent);
+ }
+ }
+
+ return a;
+ }
+
+ /**
+ * Add all data from the {@code featureToAdd} to this op.
+ *
+ * <p>If there is an event for the same key in both the later event is retained.
+ * <p>{@code opToAdd} should not be used after this method is called.
+ *
+ * @param opToAdd The op to add
+ */
+ public void add(@NonNull FeatureOp opToAdd) {
+ if (opToAdd.mInProgressEvents != null) {
+ Slog.w(TAG, "Ignoring " + opToAdd.mInProgressEvents.size() + " running app-ops");
+
+ int numInProgressEvents = opToAdd.mInProgressEvents.size();
+ for (int i = 0; i < numInProgressEvents; i++) {
+ InProgressStartOpEvent event = opToAdd.mInProgressEvents.valueAt(i);
+
+ event.finish();
+ mInProgressStartOpEventPool.release(event);
+ }
+ }
+
+ mAccessEvents = add(mAccessEvents, opToAdd.mAccessEvents);
+ mRejectEvents = add(mRejectEvents, opToAdd.mRejectEvents);
+ }
+
public boolean isRunning() {
return mInProgressEvents != null;
}
@@ -751,15 +944,30 @@
|| (mRejectEvents != null && mRejectEvents.size() > 0);
}
- @NonNull OpFeatureEntry createFeatureEntryLocked() {
- LongSparseArray<NoteOpEvent> accessEvents = null;
- if (mAccessEvents != null) {
- accessEvents = mAccessEvents.clone();
+ /**
+ * Clone a {@link LongSparseArray} and clone all values.
+ */
+ private @Nullable LongSparseArray<NoteOpEvent> deepClone(
+ @Nullable LongSparseArray<NoteOpEvent> original) {
+ if (original == null) {
+ return original;
}
+ int size = original.size();
+ LongSparseArray<NoteOpEvent> clone = new LongSparseArray<>(size);
+ for (int i = 0; i < size; i++) {
+ clone.put(original.keyAt(i), new NoteOpEvent(original.valueAt(i)));
+ }
+
+ return clone;
+ }
+
+ @NonNull OpFeatureEntry createFeatureEntryLocked() {
+ LongSparseArray<NoteOpEvent> accessEvents = deepClone(mAccessEvents);
+
// Add in progress events as access events
if (mInProgressEvents != null) {
- long now = System.currentTimeMillis();
+ long now = SystemClock.elapsedRealtime();
int numInProgressEvents = mInProgressEvents.size();
if (accessEvents == null) {
@@ -770,15 +978,13 @@
InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
// startOp events don't support proxy
- accessEvents.append(makeKey(event.uidState, OP_FLAG_SELF),
- new NoteOpEvent(event.startTime, now - event.startTime, null));
+ accessEvents.append(makeKey(event.getUidState(), OP_FLAG_SELF),
+ new NoteOpEvent(event.getStartTime(), now - event.getStartElapsedTime(),
+ null));
}
}
- LongSparseArray<NoteOpEvent> rejectEvents = null;
- if (mRejectEvents != null) {
- rejectEvents = mRejectEvents.clone();
- }
+ LongSparseArray<NoteOpEvent> rejectEvents = deepClone(mRejectEvents);
return new OpFeatureEntry(parent.op, isRunning(), accessEvents, rejectEvents);
}
@@ -1018,6 +1224,13 @@
}
}
+ /**
+ * Call {@link FeatureOp#onClientDeath featureOp.onClientDeath(clientId)}.
+ */
+ private static void onClientDeath(@NonNull FeatureOp featureOp, @NonNull IBinder clientId) {
+ featureOp.onClientDeath(clientId);
+ }
+
public AppOpsService(File storagePath, Handler handler) {
LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
mFile = new AtomicFile(storagePath, "appops");
@@ -1032,20 +1245,110 @@
LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
}
+ /** Handler for work when packages are removed or updated */
+ private BroadcastReceiver mOnPackageUpdatedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ String pkgName = intent.getData().getEncodedSchemeSpecificPart();
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
+
+ if (action.equals(ACTION_PACKAGE_REMOVED) && !intent.hasExtra(EXTRA_REPLACING)) {
+ synchronized (AppOpsService.this) {
+ UidState uidState = mUidStates.get(uid);
+ if (uidState == null || uidState.pkgOps == null) {
+ return;
+ }
+
+ Ops removedOps = uidState.pkgOps.remove(pkgName);
+ if (removedOps != null) {
+ scheduleFastWriteLocked();
+ }
+ }
+ } else if (action.equals(Intent.ACTION_PACKAGE_REPLACED)) {
+ AndroidPackage pkg = LocalServices.getService(
+ PackageManagerInternal.class).getPackage(pkgName);
+ if (pkg == null) {
+ return;
+ }
+
+ ArrayMap<String, String> dstFeatureIds = new ArrayMap<>();
+ ArraySet<String> featureIds = new ArraySet<>();
+ if (pkg.getFeatures() != null) {
+ int numFeatures = pkg.getFeatures().size();
+ for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
+ ParsedFeature feature = pkg.getFeatures().get(featureNum);
+ featureIds.add(feature.id);
+
+ int numInheritFrom = feature.inheritFrom.size();
+ for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
+ inheritFromNum++) {
+ dstFeatureIds.put(feature.inheritFrom.get(inheritFromNum),
+ feature.id);
+ }
+ }
+ }
+
+ synchronized (AppOpsService.this) {
+ UidState uidState = mUidStates.get(uid);
+ if (uidState == null || uidState.pkgOps == null) {
+ return;
+ }
+
+ Ops ops = uidState.pkgOps.get(pkgName);
+ if (ops == null) {
+ return;
+ }
+
+ ops.knownFeatureIds.clear();
+ int numOps = ops.size();
+ for (int opNum = 0; opNum < numOps; opNum++) {
+ Op op = ops.valueAt(opNum);
+
+ int numFeatures = op.mFeatures.size();
+ for (int featureNum = numFeatures - 1; featureNum >= 0; featureNum--) {
+ String featureId = op.mFeatures.keyAt(featureNum);
+
+ if (featureIds.contains(featureId)) {
+ // feature still exist after upgrade
+ continue;
+ }
+
+ String newFeatureId = dstFeatureIds.get(featureId);
+
+ FeatureOp newFeatureOp = op.getOrCreateFeature(op, newFeatureId);
+ newFeatureOp.add(op.mFeatures.valueAt(featureNum));
+ op.mFeatures.removeAt(featureNum);
+
+ scheduleFastWriteLocked();
+ }
+ }
+ }
+ }
+ }
+ };
+
public void systemReady() {
mConstants.startMonitoring(mContext.getContentResolver());
mHistoricalRegistry.systemReady(mContext.getContentResolver());
- synchronized (this) {
- boolean changed = false;
- for (int i = mUidStates.size() - 1; i >= 0; i--) {
- UidState uidState = mUidStates.valueAt(i);
+ IntentFilter packageUpdateFilter = new IntentFilter();
+ packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ packageUpdateFilter.addDataScheme("package");
- String[] packageNames = getPackagesForUid(uidState.uid);
- if (ArrayUtils.isEmpty(packageNames)) {
+ mContext.registerReceiver(mOnPackageUpdatedReceiver, packageUpdateFilter);
+
+ synchronized (this) {
+ for (int uidNum = mUidStates.size() - 1; uidNum >= 0; uidNum--) {
+ int uid = mUidStates.keyAt(uidNum);
+ UidState uidState = mUidStates.valueAt(uidNum);
+
+ String[] pkgsInUid = getPackagesForUid(uidState.uid);
+ if (ArrayUtils.isEmpty(pkgsInUid)) {
uidState.clear();
- mUidStates.removeAt(i);
- changed = true;
+ mUidStates.removeAt(uidNum);
+ scheduleFastWriteLocked();
continue;
}
@@ -1054,31 +1357,24 @@
continue;
}
- Iterator<Ops> it = pkgs.values().iterator();
- while (it.hasNext()) {
- Ops ops = it.next();
- int curUid = -1;
- try {
- curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
- PackageManager.MATCH_UNINSTALLED_PACKAGES,
- UserHandle.getUserId(ops.uidState.uid));
- } catch (RemoteException ignored) {
- }
- if (curUid != ops.uidState.uid) {
- Slog.i(TAG, "Pruning old package " + ops.packageName
- + "/" + ops.uidState + ": new uid=" + curUid);
- it.remove();
- changed = true;
- }
- }
+ int numPkgs = pkgs.size();
+ for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
+ String pkg = pkgs.keyAt(pkgNum);
- if (uidState.isDefault()) {
- mUidStates.removeAt(i);
+ String action;
+ if (!ArrayUtils.contains(pkgsInUid, pkg)) {
+ action = Intent.ACTION_PACKAGE_REMOVED;
+ } else {
+ action = Intent.ACTION_PACKAGE_REPLACED;
+ }
+
+ SystemServerInitThreadPool.submit(
+ () -> mOnPackageUpdatedReceiver.onReceive(mContext, new Intent(action)
+ .setData(Uri.fromParts("package", pkg, null))
+ .putExtra(Intent.EXTRA_UID, uid)),
+ "Update app-ops uidState in case package " + pkg + " changed");
}
}
- if (changed) {
- scheduleFastWriteLocked();
- }
}
final IntentFilter packageSuspendFilter = new IntentFilter();
@@ -1140,11 +1436,13 @@
return Zygote.MOUNT_EXTERNAL_NONE;
}
if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
- packageName, null) != AppOpsManager.MODE_ALLOWED) {
+ packageName, null, true, "External storage policy")
+ != AppOpsManager.MODE_ALLOWED) {
return Zygote.MOUNT_EXTERNAL_NONE;
}
if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
- packageName, null) != AppOpsManager.MODE_ALLOWED) {
+ packageName, null, true, "External storage policy")
+ != AppOpsManager.MODE_ALLOWED) {
return Zygote.MOUNT_EXTERNAL_READ;
}
return Zygote.MOUNT_EXTERNAL_WRITE;
@@ -1192,7 +1490,7 @@
FeatureOp featureOp = op.mFeatures.valueAt(featureNum);
while (featureOp.mInProgressEvents != null) {
- featureOp.mInProgressEvents.valueAt(0).onDeath.run();
+ featureOp.finished(featureOp.mInProgressEvents.keyAt(0));
}
}
}
@@ -1382,7 +1680,7 @@
return Collections.emptyList();
}
synchronized (this) {
- Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* isPrivileged */,
+ Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, null, false /* isPrivileged */,
false /* edit */);
if (pkgOps == null) {
return null;
@@ -1411,7 +1709,7 @@
.setOpNames(opNames)
.setFlags(flags)
.build();
- Preconditions.checkNotNull(callback, "callback cannot be null");
+ Objects.requireNonNull(callback, "callback cannot be null");
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
@@ -1436,7 +1734,7 @@
.setOpNames(opNames)
.setFlags(flags)
.build();
- Preconditions.checkNotNull(callback, "callback cannot be null");
+ Objects.requireNonNull(callback, "callback cannot be null");
mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
@@ -1482,7 +1780,7 @@
op.removeFeaturesWithNoTime();
if (op.mFeatures.size() == 0) {
- Ops ops = getOpsRawLocked(uid, packageName, false /* isPrivileged */,
+ Ops ops = getOpsRawLocked(uid, packageName, null, false /* isPrivileged */,
false /* edit */);
if (ops != null) {
ops.remove(op.op);
@@ -1746,7 +2044,7 @@
boolean isPrivileged;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+ isPrivileged = verifyAndGetIsPrivileged(uid, packageName, null);
} catch (SecurityException e) {
Slog.e(TAG, "Cannot setMode", e);
return;
@@ -1761,7 +2059,7 @@
synchronized (this) {
UidState uidState = getUidStateLocked(uid, false);
- Op op = getOpLocked(code, uid, packageName, isPrivileged, true);
+ Op op = getOpLocked(code, uid, packageName, null, isPrivileged, true);
if (op != null) {
if (op.mode != mode) {
op.mode = mode;
@@ -2131,7 +2429,7 @@
boolean isPrivileged;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+ isPrivileged = verifyAndGetIsPrivileged(uid, packageName, null);
} catch (SecurityException e) {
Slog.e(TAG, "checkOperation", e);
return AppOpsManager.opToDefaultMode(code);
@@ -2141,7 +2439,7 @@
return AppOpsManager.MODE_IGNORED;
}
synchronized (this) {
- if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
+ if (isOpRestrictedLocked(uid, code, packageName, null, isPrivileged)) {
return AppOpsManager.MODE_IGNORED;
}
code = AppOpsManager.opToSwitch(code);
@@ -2151,7 +2449,7 @@
final int rawMode = uidState.opModes.get(code);
return raw ? rawMode : uidState.evalMode(code, rawMode);
}
- Op op = getOpLocked(code, uid, packageName, false, false);
+ Op op = getOpLocked(code, uid, packageName, null, false, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
@@ -2212,9 +2510,9 @@
@Override
public int checkPackage(int uid, String packageName) {
- Preconditions.checkNotNull(packageName);
+ Objects.requireNonNull(packageName);
try {
- verifyAndGetIsPrivileged(uid, packageName);
+ verifyAndGetIsPrivileged(uid, packageName, null);
return AppOpsManager.MODE_ALLOWED;
} catch (SecurityException ignored) {
@@ -2225,7 +2523,7 @@
@Override
public int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
String proxiedFeatureId, int proxyUid, String proxyPackageName,
- String proxyFeatureId) {
+ String proxyFeatureId, boolean shouldCollectAsyncNotedOp, String message) {
verifyIncomingUid(proxyUid);
verifyIncomingOp(code);
@@ -2241,7 +2539,8 @@
final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
: AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
final int proxyMode = noteOperationUnchecked(code, proxyUid, resolveProxyPackageName,
- proxyFeatureId, Process.INVALID_UID, null, null, proxyFlags);
+ proxyFeatureId, Process.INVALID_UID, null, null, proxyFlags,
+ !isProxyTrusted, "proxy " + message);
if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
return proxyMode;
}
@@ -2254,23 +2553,27 @@
: AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
proxiedFeatureId, proxyUid, resolveProxyPackageName, proxyFeatureId,
- proxiedFlags);
+ proxiedFlags, shouldCollectAsyncNotedOp, message);
}
@Override
- public int noteOperation(int code, int uid, String packageName, String featureId) {
+ public int noteOperation(int code, int uid, String packageName, String featureId,
+ boolean shouldCollectAsyncNotedOp, String message) {
final CheckOpsDelegate delegate;
synchronized (this) {
delegate = mCheckOpsDelegate;
}
if (delegate == null) {
- return noteOperationImpl(code, uid, packageName, featureId);
+ return noteOperationImpl(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
+ message);
}
- return delegate.noteOperation(code, uid, packageName, featureId,
- AppOpsService.this::noteOperationImpl);
+ return delegate.noteOperation(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
+ message, AppOpsService.this::noteOperationImpl);
}
- private int noteOperationImpl(int code, int uid, String packageName, String featureId) {
+ private int noteOperationImpl(int code, int uid, @Nullable String packageName,
+ @Nullable String featureId, boolean shouldCollectAsyncNotedOp,
+ @Nullable String message) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
String resolvedPackageName = resolvePackageName(uid, packageName);
@@ -2278,24 +2581,25 @@
return AppOpsManager.MODE_IGNORED;
}
return noteOperationUnchecked(code, uid, resolvedPackageName, featureId,
- Process.INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF);
+ Process.INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF,
+ shouldCollectAsyncNotedOp, message);
}
- private int noteOperationUnchecked(int code, int uid, String packageName, String featureId,
- int proxyUid, String proxyPackageName, @Nullable String proxyFeatureId,
- @OpFlags int flags) {
- // TODO moltmann: Verify that feature is declared in package
-
+ private int noteOperationUnchecked(int code, int uid, @NonNull String packageName,
+ @Nullable String featureId, int proxyUid, String proxyPackageName,
+ @Nullable String proxyFeatureId, @OpFlags int flags, boolean shouldCollectAsyncNotedOp,
+ @Nullable String message) {
boolean isPrivileged;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+ isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
} catch (SecurityException e) {
Slog.e(TAG, "noteOperation", e);
return AppOpsManager.MODE_ERRORED;
}
synchronized (this) {
- final Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, true /* edit */);
+ final Ops ops = getOpsRawLocked(uid, packageName, featureId, isPrivileged,
+ true /* edit */);
if (ops == null) {
scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_IGNORED);
@@ -2303,9 +2607,9 @@
+ " package " + packageName);
return AppOpsManager.MODE_ERRORED;
}
- final Op op = getOpLocked(ops, code, true);
+ final Op op = getOpLocked(ops, code, uid, true);
final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
- if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
+ if (isOpRestrictedLocked(uid, code, packageName, featureId, isPrivileged)) {
scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_IGNORED);
return AppOpsManager.MODE_IGNORED;
@@ -2314,7 +2618,7 @@
if (featureOp.isRunning()) {
Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code "
+ code + " startTime of in progress event="
- + featureOp.mInProgressEvents.valueAt(0).startTime);
+ + featureOp.mInProgressEvents.valueAt(0).getStartTime());
}
final int switchCode = AppOpsManager.opToSwitch(code);
@@ -2333,7 +2637,8 @@
return uidMode;
}
} else {
- final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
+ final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
+ : op;
final int mode = switchOp.evalMode();
if (mode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
@@ -2354,6 +2659,11 @@
uidState.state, flags);
scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_ALLOWED);
+
+ if (shouldCollectAsyncNotedOp) {
+ collectAsyncNotedOp(uid, packageName, code, featureId, message);
+ }
+
return AppOpsManager.MODE_ALLOWED;
}
}
@@ -2419,7 +2729,7 @@
Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
"Invalid op code in: " + Arrays.toString(ops));
- Preconditions.checkNotNull(callback, "Callback cannot be null");
+ Objects.requireNonNull(callback, "Callback cannot be null");
synchronized (this) {
SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
if (callbacks == null) {
@@ -2436,7 +2746,7 @@
@Override
public void stopWatchingNoted(IAppOpsNotedCallback callback) {
- Preconditions.checkNotNull(callback, "Callback cannot be null");
+ Objects.requireNonNull(callback, "Callback cannot be null");
synchronized (this) {
final SparseArray<NotedCallback> notedCallbacks =
mNotedWatchers.remove(callback.asBinder());
@@ -2450,21 +2760,20 @@
}
}
- @Override
- public void noteAsyncOp(String callingPackageName, int uid, String packageName, int opCode,
- String featureId, String message) {
- Preconditions.checkNotNull(message);
- verifyAndGetIsPrivileged(uid, packageName);
-
- verifyIncomingUid(uid);
- verifyIncomingOp(opCode);
+ /**
+ * Collect an {@link AsyncNotedAppOp}.
+ *
+ * @param uid The uid the op was noted for
+ * @param packageName The package the op was noted for
+ * @param opCode The code of the op noted
+ * @param featureId The id of the feature to op was noted for
+ * @param message The message for the op noting
+ */
+ private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode,
+ @Nullable String featureId, @NonNull String message) {
+ Objects.requireNonNull(message);
int callingUid = Binder.getCallingUid();
- long now = System.currentTimeMillis();
-
- if (callingPackageName != null) {
- verifyAndGetIsPrivileged(callingUid, callingPackageName);
- }
long token = Binder.clearCallingIdentity();
try {
@@ -2473,7 +2782,7 @@
RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
- callingPackageName, featureId, message, now);
+ featureId, message, System.currentTimeMillis());
final boolean[] wasNoteForwarded = {false};
if (callbacks != null) {
@@ -2522,13 +2831,13 @@
@Override
public void startWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(callback);
int uid = Binder.getCallingUid();
Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
- verifyAndGetIsPrivileged(uid, packageName);
+ verifyAndGetIsPrivileged(uid, packageName, null);
synchronized (this) {
RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
@@ -2552,13 +2861,13 @@
@Override
public void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
- Preconditions.checkNotNull(packageName);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(callback);
int uid = Binder.getCallingUid();
Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
- verifyAndGetIsPrivileged(uid, packageName);
+ verifyAndGetIsPrivileged(uid, packageName, null);
synchronized (this) {
RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
@@ -2573,11 +2882,11 @@
@Override
public List<AsyncNotedAppOp> extractAsyncOps(String packageName) {
- Preconditions.checkNotNull(packageName);
+ Objects.requireNonNull(packageName);
int uid = Binder.getCallingUid();
- verifyAndGetIsPrivileged(uid, packageName);
+ verifyAndGetIsPrivileged(uid, packageName, null);
synchronized (this) {
return mUnforwardedAsyncNotedOps.remove(getAsyncNotedOpsKey(packageName, uid));
@@ -2586,7 +2895,8 @@
@Override
public int startOperation(IBinder clientId, int code, int uid, String packageName,
- String featureId, boolean startIfModeDefault) {
+ String featureId, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
+ String message) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
String resolvedPackageName = resolvePackageName(uid, packageName);
@@ -2596,22 +2906,22 @@
boolean isPrivileged;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+ isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
} catch (SecurityException e) {
Slog.e(TAG, "startOperation", e);
return AppOpsManager.MODE_ERRORED;
}
synchronized (this) {
- final Ops ops = getOpsRawLocked(uid, resolvedPackageName, isPrivileged,
+ final Ops ops = getOpsRawLocked(uid, resolvedPackageName, featureId, isPrivileged,
true /* edit */);
if (ops == null) {
if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
+ " package " + resolvedPackageName);
return AppOpsManager.MODE_ERRORED;
}
- final Op op = getOpLocked(ops, code, true);
- if (isOpRestrictedLocked(uid, code, resolvedPackageName, isPrivileged)) {
+ final Op op = getOpLocked(ops, code, uid, true);
+ if (isOpRestrictedLocked(uid, code, resolvedPackageName, featureId, isPrivileged)) {
return AppOpsManager.MODE_IGNORED;
}
final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
@@ -2633,7 +2943,8 @@
return uidMode;
}
} else {
- final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
+ final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
+ : op;
final int mode = switchOp.evalMode();
if (mode != AppOpsManager.MODE_ALLOWED
&& (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
@@ -2656,6 +2967,10 @@
}
}
+ if (shouldCollectAsyncNotedOp) {
+ collectAsyncNotedOp(uid, packageName, code, featureId, message);
+ }
+
return AppOpsManager.MODE_ALLOWED;
}
@@ -2671,14 +2986,14 @@
boolean isPrivileged;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+ isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
} catch (SecurityException e) {
Slog.e(TAG, "Cannot finishOperation", e);
return;
}
synchronized (this) {
- Op op = getOpLocked(code, uid, resolvedPackageName, isPrivileged, true);
+ Op op = getOpLocked(code, uid, resolvedPackageName, featureId, isPrivileged, true);
if (op == null) {
return;
}
@@ -2909,22 +3224,24 @@
*
* @param uid The uid the package belongs to
* @param packageName The package the might belong to the uid
+ * @param featureId The feature in the package or {@code null} if no need to verify
*
* @return {@code true} iff the package is privileged
*/
- private boolean verifyAndGetIsPrivileged(int uid, String packageName) {
+ private boolean verifyAndGetIsPrivileged(int uid, String packageName,
+ @Nullable String featureId) {
if (uid == Process.ROOT_UID) {
// For backwards compatibility, don't check package name for root UID.
return false;
}
- // Do not check if uid/packageName is already known
+ // Do not check if uid/packageName/featureId is already known
synchronized (this) {
UidState uidState = mUidStates.get(uid);
if (uidState != null && uidState.pkgOps != null) {
Ops ops = uidState.pkgOps.get(packageName);
- if (ops != null) {
+ if (ops != null && (featureId == null || ops.knownFeatureIds.contains(featureId))) {
return ops.isPrivileged;
}
}
@@ -2934,19 +3251,31 @@
final long ident = Binder.clearCallingIdentity();
try {
int pkgUid;
+ AndroidPackage pkg = LocalServices.getService(PackageManagerInternal.class).getPackage(
+ packageName);
+ boolean isFeatureIdValid = false;
- ApplicationInfo appInfo = LocalServices.getService(PackageManagerInternal.class)
- .getApplicationInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
- | PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_INSTANT,
- Process.SYSTEM_UID, UserHandle.getUserId(uid));
- if (appInfo != null) {
- pkgUid = appInfo.uid;
- isPrivileged = (appInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+ if (pkg != null) {
+ if (featureId == null) {
+ isFeatureIdValid = true;
+ } else {
+ if (pkg.getFeatures() != null) {
+ int numFeatures = pkg.getFeatures().size();
+ for (int i = 0; i < numFeatures; i++) {
+ if (pkg.getFeatures().get(i).id.equals(featureId)) {
+ isFeatureIdValid = true;
+ }
+ }
+ }
+ }
+
+ pkgUid = UserHandle.getUid(
+ UserHandle.getUserId(uid), UserHandle.getAppId(pkg.getUid()));
+ isPrivileged = pkg.isPrivileged();
} else {
+ // Allow any feature id for resolvable uids
+ isFeatureIdValid = true;
+
pkgUid = resolveUid(packageName);
if (pkgUid >= 0) {
isPrivileged = false;
@@ -2956,6 +3285,12 @@
throw new SecurityException("Specified package " + packageName + " under uid " + uid
+ " but it is really " + pkgUid);
}
+
+ if (!isFeatureIdValid) {
+ // TODO moltmann: Switch from logging to enforcement
+ Slog.e(TAG, "featureId " + featureId + " not declared in manifest of "
+ + packageName);
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2968,12 +3303,14 @@
*
* @param uid The uid the package belongs to
* @param packageName The name of the package
+ * @param featureId The feature in the package
* @param isPrivileged If the package is privilidged (ignored if {@code edit} is false)
* @param edit If an ops does not exist, create the ops?
* @return
*/
- private Ops getOpsRawLocked(int uid, String packageName, boolean isPrivileged, boolean edit) {
+ private Ops getOpsRawLocked(int uid, String packageName, @Nullable String featureId,
+ boolean isPrivileged, boolean edit) {
UidState uidState = getUidStateLocked(uid, edit);
if (uidState == null) {
return null;
@@ -2994,6 +3331,9 @@
ops = new Ops(packageName, uidState, isPrivileged);
uidState.pkgOps.put(packageName, ops);
}
+ if (edit && featureId != null) {
+ ops.knownFeatureIds.add(featureId);
+ }
return ops;
}
@@ -3004,13 +3344,14 @@
*
* @param uid The uid the of the package
* @param packageName The package name for which to get the state for
+ * @param featureId The feature in the package
* @param edit Iff {@code true} create the {@link Ops} object if not yet created
* @param isPrivileged Whether the package is privileged or not
*
* @return The {@link Ops state} of all ops for the package
*/
private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
- boolean edit, boolean isPrivileged) {
+ @Nullable String featureId, boolean edit, boolean isPrivileged) {
UidState uidState = getUidStateLocked(uid, edit);
if (uidState == null) {
return null;
@@ -3031,6 +3372,11 @@
ops = new Ops(packageName, uidState, isPrivileged);
uidState.pkgOps.put(packageName, ops);
}
+
+ if (edit && featureId != null) {
+ ops.knownFeatureIds.add(featureId);
+ }
+
return ops;
}
@@ -3056,6 +3402,7 @@
* @param code The code of the op
* @param uid The uid the of the package
* @param packageName The package name for which to get the state for
+ * @param featureId The feature in the package
* @param isPrivileged Whether the package is privileged or not (only used if {@code edit
* == true})
* @param edit Iff {@code true} create the {@link Op} object if not yet created
@@ -3063,21 +3410,21 @@
* @return The {@link Op state} of the op
*/
private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
- boolean isPrivileged, boolean edit) {
- Ops ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
+ @Nullable String featureId, boolean isPrivileged, boolean edit) {
+ Ops ops = getOpsRawNoVerifyLocked(uid, packageName, featureId, edit, isPrivileged);
if (ops == null) {
return null;
}
- return getOpLocked(ops, code, edit);
+ return getOpLocked(ops, code, uid, edit);
}
- private Op getOpLocked(Ops ops, int code, boolean edit) {
+ private Op getOpLocked(Ops ops, int code, int uid, boolean edit) {
Op op = ops.get(code);
if (op == null) {
if (!edit) {
return null;
}
- op = new Op(ops.uidState, ops.packageName, code, ops.uidState.uid);
+ op = new Op(ops.uidState, ops.packageName, code, uid);
ops.put(code, op);
}
if (edit) {
@@ -3095,7 +3442,7 @@
}
private boolean isOpRestrictedLocked(int uid, int code, String packageName,
- boolean isPrivileged) {
+ @Nullable String featureId, boolean isPrivileged) {
int userHandle = UserHandle.getUserId(uid);
final int restrictionSetCount = mOpUserRestrictions.size();
@@ -3107,7 +3454,7 @@
if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
// If we are the system, bypass user restrictions for certain codes
synchronized (this) {
- Ops ops = getOpsRawLocked(uid, packageName, isPrivileged,
+ Ops ops = getOpsRawLocked(uid, packageName, featureId, isPrivileged,
true /* edit */);
if ((ops != null) && ops.isPrivileged) {
return false;
@@ -3484,7 +3831,7 @@
out.startTag(null, "uid");
out.attribute(null, "n", Integer.toString(pkg.getUid()));
synchronized (this) {
- Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
+ Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), null,
false /* isPrivileged */, false /* edit */);
// Should always be present as the list of PackageOps is generated
// from Ops.
@@ -4050,7 +4397,8 @@
if (shell.packageName != null) {
shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid,
- shell.packageName, shell.featureId, true);
+ shell.packageName, shell.featureId, true, true,
+ "appops start shell command");
} else {
return -1;
}
@@ -4188,18 +4536,18 @@
final FeatureOp featureOp = op.mFeatures.get(featureId);
if (featureOp.isRunning()) {
- long earliestStartTime = Long.MAX_VALUE;
+ long earliestElapsedTime = Long.MAX_VALUE;
long maxNumStarts = 0;
int numInProgressEvents = featureOp.mInProgressEvents.size();
for (int i = 0; i < numInProgressEvents; i++) {
InProgressStartOpEvent event = featureOp.mInProgressEvents.valueAt(i);
- earliestStartTime = Math.min(earliestStartTime, event.startTime);
+ earliestElapsedTime = Math.min(earliestElapsedTime, event.getStartElapsedTime());
maxNumStarts = Math.max(maxNumStarts, event.numUnfinishedStarts);
}
pw.print(prefix + "Running start at: ");
- TimeUtils.formatDuration(nowElapsed - earliestStartTime, pw);
+ TimeUtils.formatDuration(nowElapsed - earliestElapsedTime, pw);
pw.println();
if (maxNumStarts > 1) {
@@ -4471,7 +4819,7 @@
if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
boolean hasOp = dumpOp < 0 || (uidState.opModes != null
&& uidState.opModes.indexOfKey(dumpOp) >= 0);
- boolean hasPackage = dumpPackage == null;
+ boolean hasPackage = dumpPackage == null || dumpUid == mUidStates.keyAt(i);
boolean hasMode = dumpMode < 0;
if (!hasMode && opModes != null) {
for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
@@ -4702,8 +5050,8 @@
@Override
public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
checkSystemUid("setUserRestrictions");
- Preconditions.checkNotNull(restrictions);
- Preconditions.checkNotNull(token);
+ Objects.requireNonNull(restrictions);
+ Objects.requireNonNull(token);
for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
String restriction = AppOpsManager.opToRestriction(i);
if (restriction != null) {
@@ -4730,7 +5078,7 @@
}
}
verifyIncomingOp(code);
- Preconditions.checkNotNull(token);
+ Objects.requireNonNull(token);
setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
}
@@ -4801,7 +5149,7 @@
}
// TODO moltmann: Allow to check for feature op activeness
synchronized (AppOpsService.this) {
- Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false, false);
+ Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, null, false, false);
if (pkgOps == null) {
return false;
}
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index fc67e24..5ac5b29 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -67,6 +67,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Objects;
/**
* An attention service implementation that runs in System Server process.
@@ -120,7 +121,7 @@
AttentionManagerService(Context context, PowerManager powerManager, Object lock,
AttentionHandler handler) {
super(context);
- mContext = Preconditions.checkNotNull(context);
+ mContext = Objects.requireNonNull(context);
mPowerManager = powerManager;
mLock = lock;
mAttentionHandler = handler;
@@ -200,7 +201,7 @@
*/
@VisibleForTesting
boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) {
- Preconditions.checkNotNull(callbackInternal);
+ Objects.requireNonNull(callbackInternal);
if (!isAttentionServiceSupported()) {
Slog.w(LOG_TAG, "Trying to call checkAttention() on an unsupported device.");
@@ -543,9 +544,9 @@
UserState(int userId, Context context, Object lock, Handler handler,
ComponentName componentName) {
mUserId = userId;
- mContext = Preconditions.checkNotNull(context);
- mLock = Preconditions.checkNotNull(lock);
- mComponentName = Preconditions.checkNotNull(componentName);
+ mContext = Objects.requireNonNull(context);
+ mLock = Objects.requireNonNull(lock);
+ mComponentName = Objects.requireNonNull(componentName);
mAttentionHandler = handler;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 114aac9..bc4dc8f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2196,7 +2196,7 @@
public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags,
String callingPackage) {
enforceModifyAudioRoutingPermission();
- Preconditions.checkNotNull(attr, "attr must not be null");
+ Objects.requireNonNull(attr, "attr must not be null");
// @todo not hold the caller context, post message
int stream = AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(attr);
final int device = getDeviceForStream(stream);
@@ -2231,7 +2231,7 @@
/** @see AudioManager#getVolumeIndexForAttributes(attr) */
public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
enforceModifyAudioRoutingPermission();
- Preconditions.checkNotNull(attr, "attr must not be null");
+ Objects.requireNonNull(attr, "attr must not be null");
int stream = AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(attr);
final int device = getDeviceForStream(stream);
@@ -2241,14 +2241,14 @@
/** @see AudioManager#getMaxVolumeIndexForAttributes(attr) */
public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
enforceModifyAudioRoutingPermission();
- Preconditions.checkNotNull(attr, "attr must not be null");
+ Objects.requireNonNull(attr, "attr must not be null");
return AudioSystem.getMaxVolumeIndexForAttributes(attr);
}
/** @see AudioManager#getMinVolumeIndexForAttributes(attr) */
public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
enforceModifyAudioRoutingPermission();
- Preconditions.checkNotNull(attr, "attr must not be null");
+ Objects.requireNonNull(attr, "attr must not be null");
return AudioSystem.getMinVolumeIndexForAttributes(attr);
}
@@ -2510,7 +2510,7 @@
private int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) {
- Preconditions.checkNotNull(attributes, "attributes must not be null");
+ Objects.requireNonNull(attributes, "attributes must not be null");
int volumeGroupId = getVolumeGroupIdForAttributesInt(attributes);
if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
return volumeGroupId;
@@ -2521,7 +2521,7 @@
}
private int getVolumeGroupIdForAttributesInt(@NonNull AudioAttributes attributes) {
- Preconditions.checkNotNull(attributes, "attributes must not be null");
+ Objects.requireNonNull(attributes, "attributes must not be null");
for (final AudioProductStrategy productStrategy :
AudioProductStrategy.getAudioProductStrategies()) {
int volumeGroupId = productStrategy.getVolumeGroupIdForAudioAttributes(attributes);
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index ff0b015..28f67fe 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -34,6 +34,7 @@
import java.io.PrintWriter;
import java.util.Arrays;
+import java.util.Objects;
/**
* A utility to map from an ambient brightness to a display's "backlight" brightness based on the
@@ -702,7 +703,7 @@
"Nits and backlight arrays must not be empty!");
Preconditions.checkArgument(nits.length == backlight.length,
"Nits and backlight arrays must be the same length!");
- Preconditions.checkNotNull(config);
+ Objects.requireNonNull(config);
Preconditions.checkArrayElementsInRange(nits, 0, Float.MAX_VALUE, "nits");
Preconditions.checkArrayElementsInRange(backlight,
PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON, "backlight");
diff --git a/services/core/java/com/android/server/display/whitebalance/AmbientSensor.java b/services/core/java/com/android/server/display/whitebalance/AmbientSensor.java
index 1707a62..75d00ff 100644
--- a/services/core/java/com/android/server/display/whitebalance/AmbientSensor.java
+++ b/services/core/java/com/android/server/display/whitebalance/AmbientSensor.java
@@ -29,6 +29,7 @@
import com.android.server.display.utils.History;
import java.io.PrintWriter;
+import java.util.Objects;
/**
* The DisplayWhiteBalanceController uses the AmbientSensor to detect changes in the ambient
@@ -139,8 +140,8 @@
private static void validateArguments(Handler handler, SensorManager sensorManager, int rate) {
- Preconditions.checkNotNull(handler, "handler cannot be null");
- Preconditions.checkNotNull(sensorManager, "sensorManager cannot be null");
+ Objects.requireNonNull(handler, "handler cannot be null");
+ Objects.requireNonNull(sensorManager, "sensorManager cannot be null");
if (rate <= 0) {
throw new IllegalArgumentException("rate must be positive");
}
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
index 88a7077..d64fcbc 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
@@ -28,6 +28,7 @@
import com.android.server.display.utils.History;
import java.io.PrintWriter;
+import java.util.Objects;
/**
* The DisplayWhiteBalanceController drives display white-balance (automatically correcting the
@@ -475,13 +476,13 @@
AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor,
AmbientFilter colorTemperatureFilter,
DisplayWhiteBalanceThrottler throttler) {
- Preconditions.checkNotNull(brightnessSensor, "brightnessSensor must not be null");
- Preconditions.checkNotNull(brightnessFilter, "brightnessFilter must not be null");
- Preconditions.checkNotNull(colorTemperatureSensor,
+ Objects.requireNonNull(brightnessSensor, "brightnessSensor must not be null");
+ Objects.requireNonNull(brightnessFilter, "brightnessFilter must not be null");
+ Objects.requireNonNull(colorTemperatureSensor,
"colorTemperatureSensor must not be null");
- Preconditions.checkNotNull(colorTemperatureFilter,
+ Objects.requireNonNull(colorTemperatureFilter,
"colorTemperatureFilter must not be null");
- Preconditions.checkNotNull(throttler, "throttler cannot be null");
+ Objects.requireNonNull(throttler, "throttler cannot be null");
}
private boolean enable() {
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceSettings.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceSettings.java
index 6e78894..0efb749 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceSettings.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceSettings.java
@@ -30,6 +30,7 @@
import com.android.server.display.whitebalance.DisplayWhiteBalanceController.Callbacks;
import java.io.PrintWriter;
+import java.util.Objects;
/**
* The DisplayWhiteBalanceSettings holds the state of all the settings related to
@@ -144,8 +145,8 @@
}
private void validateArguments(Context context, Handler handler) {
- Preconditions.checkNotNull(context, "context must not be null");
- Preconditions.checkNotNull(handler, "handler must not be null");
+ Objects.requireNonNull(context, "context must not be null");
+ Objects.requireNonNull(handler, "handler must not be null");
}
private void setEnabled(boolean enabled) {
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index 080e6ce..a9e8719 100755
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -26,6 +26,7 @@
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Feature action that handles device discovery sequences.
@@ -106,7 +107,7 @@
*/
DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback, int delay) {
super(source);
- mCallback = Preconditions.checkNotNull(callback);
+ mCallback = Objects.requireNonNull(callback);
mDelayPeriod = delay;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 5865dc4..8b6b614 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1792,10 +1792,18 @@
@GuardedBy("mMethodMap")
private void onCreateInlineSuggestionsRequestLocked(ComponentName componentName,
AutofillId autofillId, IInlineSuggestionsRequestCallback callback) {
- if (mCurMethod != null) {
- executeOrSendMessage(mCurMethod,
- mCaller.obtainMessageOOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod,
- componentName, autofillId, callback));
+
+ final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
+ try {
+ if (imi != null && imi.isInlineSuggestionsEnabled() && mCurMethod != null) {
+ executeOrSendMessage(mCurMethod,
+ mCaller.obtainMessageOOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod,
+ componentName, autofillId, callback));
+ } else {
+ callback.onInlineSuggestionsUnsupported();
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
}
}
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index f3d60f5..b1639a9 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -196,6 +196,15 @@
private void handleIntegrityVerification(Intent intent) {
int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1);
+
+ // Fail early if we don't have any rules at all.
+ if (!mIntegrityFileManager.initialized()) {
+ Slog.i(TAG, "Rules not initialized. Skipping integrity check.");
+ mPackageManagerInternal.setIntegrityVerificationResult(
+ verificationId, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
+ return;
+ }
+
try {
Slog.i(TAG, "Received integrity verification intent " + intent.toString());
Slog.i(TAG, "Extras " + intent.getExtras());
@@ -376,6 +385,9 @@
String packageName = getPackageNameNormalized(packageAndCert[0]);
String cert = packageAndCert[1];
packageCertMap.put(packageName, cert);
+ } else if (packageAndCert.length == 1
+ && packageAndCert[0].equals(ADB_INSTALLER)) {
+ packageCertMap.put(ADB_INSTALLER, INSTALLER_CERT_NOT_APPLICABLE);
}
}
}
diff --git a/services/core/java/com/android/server/integrity/IntegrityFileManager.java b/services/core/java/com/android/server/integrity/IntegrityFileManager.java
index e224724..30cafaa 100644
--- a/services/core/java/com/android/server/integrity/IntegrityFileManager.java
+++ b/services/core/java/com/android/server/integrity/IntegrityFileManager.java
@@ -24,14 +24,14 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.integrity.model.RuleMetadata;
+import com.android.server.integrity.parser.RuleBinaryParser;
import com.android.server.integrity.parser.RuleMetadataParser;
import com.android.server.integrity.parser.RuleParseException;
import com.android.server.integrity.parser.RuleParser;
-import com.android.server.integrity.parser.RuleXmlParser;
+import com.android.server.integrity.serializer.RuleBinarySerializer;
import com.android.server.integrity.serializer.RuleMetadataSerializer;
import com.android.server.integrity.serializer.RuleSerializeException;
import com.android.server.integrity.serializer.RuleSerializer;
-import com.android.server.integrity.serializer.RuleXmlSerializer;
import java.io.File;
import java.io.FileInputStream;
@@ -57,6 +57,7 @@
private final RuleParser mRuleParser;
private final RuleSerializer mRuleSerializer;
+ private final File mDataDir;
// mRulesDir contains data of the actual rules currently stored.
private final File mRulesDir;
// mStagingDir is used to store the temporary rules / metadata during updating, since we want to
@@ -75,8 +76,8 @@
private IntegrityFileManager() {
this(
- new RuleXmlParser(),
- new RuleXmlSerializer(),
+ new RuleBinaryParser(),
+ new RuleBinarySerializer(),
Environment.getDataSystemDirectory());
}
@@ -84,11 +85,12 @@
IntegrityFileManager(RuleParser ruleParser, RuleSerializer ruleSerializer, File dataDir) {
mRuleParser = ruleParser;
mRuleSerializer = ruleSerializer;
+ mDataDir = dataDir;
mRulesDir = new File(dataDir, "integrity_rules");
mStagingDir = new File(dataDir, "integrity_staging");
- if (!mStagingDir.mkdirs() && mRulesDir.mkdirs()) {
+ if (!mStagingDir.mkdirs() || !mRulesDir.mkdirs()) {
Slog.e(TAG, "Error creating staging and rules directory");
// TODO: maybe throw an exception?
}
@@ -103,6 +105,16 @@
}
}
+ /**
+ * Returns if the rules have been initialized.
+ *
+ * <p>Used to fail early if there are no rules (so we don't need to parse the apk at all).
+ */
+ public boolean initialized() {
+ return new File(mRulesDir, RULES_FILE).exists()
+ && new File(mRulesDir, METADATA_FILE).exists();
+ }
+
/** Write rules to persistent storage. */
public void writeRules(String version, String ruleProvider, List<Rule> rules)
throws IOException, RuleSerializeException {
@@ -146,7 +158,7 @@
private void switchStagingRulesDir() throws IOException {
synchronized (RULES_LOCK) {
- File tmpDir = new File(Environment.getDataSystemDirectory(), "temp");
+ File tmpDir = new File(mDataDir, "temp");
if (!(mRulesDir.renameTo(tmpDir)
&& mStagingDir.renameTo(mRulesDir)
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 25defb0..22af085 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
@@ -36,6 +36,7 @@
import android.content.integrity.Formula;
import android.content.integrity.Rule;
+import com.android.internal.util.Preconditions;
import com.android.server.integrity.IntegrityUtils;
import com.android.server.integrity.model.BitOutputStream;
@@ -46,10 +47,17 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.TreeMap;
/** A helper class to serialize rules from the {@link Rule} model to Binary representation. */
public class RuleBinarySerializer implements RuleSerializer {
+ // The parsing time seems acceptable for 100 rules based on the tests in go/ic-rule-file-format.
+ private static final int INDEXING_BLOCK_SIZE = 100;
+
+ private static final String START_INDEXING_KEY = "START_KEY";
+ private static final String END_INDEXING_KEY = "END_KEY";
+
// Get the byte representation for a list of rules.
@Override
public byte[] serialize(List<Rule> rules, Optional<Integer> formatVersion)
@@ -66,25 +74,34 @@
// Get the byte representation for a list of rules, and write them to an output stream.
@Override
public void serialize(
- List<Rule> rules, Optional<Integer> formatVersion, OutputStream outputStream)
+ List<Rule> rules, Optional<Integer> formatVersion, OutputStream originalOutputStream)
throws RuleSerializeException {
try {
// Determine the indexing groups and the order of the rules within each indexed group.
- Map<Integer, List<Rule>> indexedRules =
+ Map<Integer, TreeMap<String, List<Rule>>> indexedRules =
RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules);
+ ByteTrackedOutputStream outputStream =
+ new ByteTrackedOutputStream(originalOutputStream);
+
serializeRuleFileMetadata(formatVersion, outputStream);
- serializeIndexedRules(indexedRules.get(PACKAGE_NAME_INDEXED), outputStream);
- serializeIndexedRules(indexedRules.get(APP_CERTIFICATE_INDEXED), outputStream);
- serializeIndexedRules(indexedRules.get(NOT_INDEXED), outputStream);
+ Map<String, Long> packageNameIndexes =
+ serializeRuleList(indexedRules.get(PACKAGE_NAME_INDEXED), outputStream);
+ Map<String, Long> appCertificateIndexes =
+ serializeRuleList(indexedRules.get(APP_CERTIFICATE_INDEXED), outputStream);
+ Map<String, Long> unindexedRulesIndex =
+ serializeRuleList(indexedRules.get(NOT_INDEXED), outputStream);
+
+ // TODO(b/145493956): Write these indexes into a index file provided by integrity file
+ // manager.
} catch (Exception e) {
throw new RuleSerializeException(e.getMessage(), e);
}
}
- private void serializeRuleFileMetadata(
- Optional<Integer> formatVersion, OutputStream outputStream) throws IOException {
+ private void serializeRuleFileMetadata(Optional<Integer> formatVersion,
+ ByteTrackedOutputStream outputStream) throws IOException {
int formatVersionValue = formatVersion.orElse(DEFAULT_FORMAT_VERSION);
BitOutputStream bitOutputStream = new BitOutputStream();
@@ -92,17 +109,33 @@
outputStream.write(bitOutputStream.toByteArray());
}
- private void serializeIndexedRules(List<Rule> rules, OutputStream outputStream)
+ private Map<String, Long> serializeRuleList(TreeMap<String, List<Rule>> rulesMap,
+ ByteTrackedOutputStream outputStream)
throws IOException {
- if (rules == null) {
- return;
- }
+ Preconditions.checkArgument(rulesMap != null,
+ "serializeRuleList should never be called with null rule list.");
+
BitOutputStream bitOutputStream = new BitOutputStream();
- for (Rule rule : rules) {
- bitOutputStream.clear();
- serializeRule(rule, bitOutputStream);
- outputStream.write(bitOutputStream.toByteArray());
+ Map<String, Long> indexMapping = new TreeMap();
+ long indexTracker = 0;
+
+ indexMapping.put(START_INDEXING_KEY, outputStream.getWrittenBytesCount());
+ for (Map.Entry<String, List<Rule>> entry : rulesMap.entrySet()) {
+ if (indexTracker >= INDEXING_BLOCK_SIZE) {
+ indexMapping.put(entry.getKey(), outputStream.getWrittenBytesCount());
+ indexTracker = 0;
+ }
+
+ for (Rule rule : entry.getValue()) {
+ bitOutputStream.clear();
+ serializeRule(rule, bitOutputStream);
+ outputStream.write(bitOutputStream.toByteArray());
+ indexTracker++;
+ }
}
+ indexMapping.put(END_INDEXING_KEY, outputStream.getWrittenBytesCount());
+
+ return indexMapping;
}
private void serializeRule(Rule rule, BitOutputStream bitOutputStream) {
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java
index f9c7912..cbc365e 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java
@@ -38,23 +38,19 @@
private static final String DEFAULT_RULE_KEY = "N/A";
/**
- * Splits a given rule list into three indexing categories and returns a sorted list of rules
- * per each index.
- *
- * The sorting guarantees an order based on the key but the rules that have the same key
- * can be in arbitrary order. For example, given the rules of [package_name_a_rule_1,
- * package_name_a_rule_2, package_name_b_rule_3, package_name_b_rule_4], the method will
- * guarantee that package_name_b rules (i.e., 3 and 4) will never come before package_name_a
- * rules (i.e., 1 and 2). However, we do not care about the ordering between rule 1 and 2.
- * We also do not care about the ordering between rule 3 and 4.
+ * Splits a given rule list into three indexing categories. Each rule category is returned as a
+ * TreeMap that is sorted by their indexing keys -- where keys correspond to package name for
+ * PACKAGE_NAME_INDEXED rules, app certificate for APP_CERTIFICATE_INDEXED rules and N/A for
+ * NOT_INDEXED rules.
*/
- public static Map<Integer, List<Rule>> splitRulesIntoIndexBuckets(List<Rule> rules) {
+ public static Map<Integer, TreeMap<String, List<Rule>>> splitRulesIntoIndexBuckets(
+ List<Rule> rules) {
if (rules == null) {
throw new IllegalArgumentException(
"Index buckets cannot be created for null rule list.");
}
- Map<Integer, Map<String, List<Rule>>> typeOrganizedRuleMap = new HashMap();
+ Map<Integer, TreeMap<String, List<Rule>>> typeOrganizedRuleMap = new HashMap();
typeOrganizedRuleMap.put(NOT_INDEXED, new TreeMap());
typeOrganizedRuleMap.put(PACKAGE_NAME_INDEXED, new TreeMap());
typeOrganizedRuleMap.put(APP_CERTIFICATE_INDEXED, new TreeMap());
@@ -87,19 +83,7 @@
.add(rule);
}
- // Per indexing type, create the sorted rule set based on their key.
- Map<Integer, List<Rule>> orderedListPerIndexingType = new HashMap<>();
-
- for (Integer indexingKey : typeOrganizedRuleMap.keySet()) {
- List<Rule> sortedRules = new ArrayList();
- for (Map.Entry<String, List<Rule>> entry :
- typeOrganizedRuleMap.get(indexingKey).entrySet()) {
- sortedRules.addAll(entry.getValue());
- }
- orderedListPerIndexingType.put(indexingKey, sortedRules);
- }
-
- return orderedListPerIndexingType;
+ return typeOrganizedRuleMap;
}
private static RuleIndexingDetails getIndexingDetails(Formula formula) {
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 ebf6a2e..4c04dbc 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
@@ -35,6 +35,7 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.TreeMap;
/** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
public class RuleXmlSerializer implements RuleSerializer {
@@ -84,7 +85,7 @@
throws RuleSerializeException {
try {
// Determine the indexing groups and the order of the rules within each indexed group.
- Map<Integer, List<Rule>> indexedRules =
+ Map<Integer, TreeMap<String, List<Rule>>> indexedRules =
RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules);
// Write the XML formatted rules in order.
@@ -101,10 +102,13 @@
}
}
- private void serializeRuleList(List<Rule> rules, XmlSerializer xmlSerializer)
+ private void serializeRuleList(TreeMap<String, List<Rule>> rulesMap,
+ XmlSerializer xmlSerializer)
throws IOException {
- for (Rule rule : rules) {
- serializeRule(rule, xmlSerializer);
+ for (Map.Entry<String, List<Rule>> entry : rulesMap.entrySet()) {
+ for (Rule rule : entry.getValue()) {
+ serializeRule(rule, xmlSerializer);
+ }
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index bcc4c1f..6c65c36 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -151,6 +151,7 @@
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -1594,8 +1595,8 @@
*/
private boolean setLockCredentialInternal(LockscreenCredential credential,
LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) {
- Preconditions.checkNotNull(credential);
- Preconditions.checkNotNull(savedCredential);
+ Objects.requireNonNull(credential);
+ Objects.requireNonNull(savedCredential);
synchronized (mSpManager) {
if (isSyntheticPasswordBasedCredentialLocked(userId)) {
return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId,
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index c53647d..0fe16be 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -57,6 +57,7 @@
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Set;
@@ -228,8 +229,8 @@
* by {@link #setEscrowData} before calling this.
*/
public void recreateFromEscrow(byte[] escrowSplit0) {
- Preconditions.checkNotNull(mEscrowSplit1);
- Preconditions.checkNotNull(mEncryptedEscrowSplit0);
+ Objects.requireNonNull(mEscrowSplit1);
+ Objects.requireNonNull(mEncryptedEscrowSplit0);
recreate(escrowSplit0, mEscrowSplit1);
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 1b14ce2..383d5cf 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -75,6 +75,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -302,8 +303,8 @@
checkRecoverKeyStorePermission();
rootCertificateAlias =
mTestCertHelper.getDefaultCertificateAliasIfEmpty(rootCertificateAlias);
- Preconditions.checkNotNull(recoveryServiceCertFile, "recoveryServiceCertFile is null");
- Preconditions.checkNotNull(recoveryServiceSigFile, "recoveryServiceSigFile is null");
+ Objects.requireNonNull(recoveryServiceCertFile, "recoveryServiceCertFile is null");
+ Objects.requireNonNull(recoveryServiceSigFile, "recoveryServiceSigFile is null");
SigXml sigXml;
try {
@@ -393,7 +394,7 @@
*/
public void setRecoveryStatus(@NonNull String alias, int status) throws RemoteException {
checkRecoverKeyStorePermission();
- Preconditions.checkNotNull(alias, "alias is null");
+ Objects.requireNonNull(alias, "alias is null");
long updatedRows = mDatabase.setRecoveryStatus(Binder.getCallingUid(), alias, status);
if (updatedRows < 0) {
throw new ServiceSpecificException(
@@ -424,7 +425,7 @@
@NonNull @KeyChainProtectionParams.UserSecretType int[] secretTypes)
throws RemoteException {
checkRecoverKeyStorePermission();
- Preconditions.checkNotNull(secretTypes, "secretTypes is null");
+ Objects.requireNonNull(secretTypes, "secretTypes is null");
int userId = UserHandle.getCallingUserId();
int uid = Binder.getCallingUid();
@@ -556,11 +557,11 @@
checkRecoverKeyStorePermission();
rootCertificateAlias =
mTestCertHelper.getDefaultCertificateAliasIfEmpty(rootCertificateAlias);
- Preconditions.checkNotNull(sessionId, "invalid session");
- Preconditions.checkNotNull(verifierCertPath, "verifierCertPath is null");
- Preconditions.checkNotNull(vaultParams, "vaultParams is null");
- Preconditions.checkNotNull(vaultChallenge, "vaultChallenge is null");
- Preconditions.checkNotNull(secrets, "secrets is null");
+ Objects.requireNonNull(sessionId, "invalid session");
+ Objects.requireNonNull(verifierCertPath, "verifierCertPath is null");
+ Objects.requireNonNull(vaultParams, "vaultParams is null");
+ Objects.requireNonNull(vaultChallenge, "vaultChallenge is null");
+ Objects.requireNonNull(secrets, "secrets is null");
CertPath certPath;
try {
certPath = verifierCertPath.getCertPath();
@@ -666,13 +667,13 @@
*/
public void closeSession(@NonNull String sessionId) throws RemoteException {
checkRecoverKeyStorePermission();
- Preconditions.checkNotNull(sessionId, "invalid session");
+ Objects.requireNonNull(sessionId, "invalid session");
mRecoverySessionStorage.remove(Binder.getCallingUid(), sessionId);
}
public void removeKey(@NonNull String alias) throws RemoteException {
checkRecoverKeyStorePermission();
- Preconditions.checkNotNull(alias, "alias is null");
+ Objects.requireNonNull(alias, "alias is null");
int uid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
@@ -711,7 +712,7 @@
public String generateKeyWithMetadata(@NonNull String alias, @Nullable byte[] metadata)
throws RemoteException {
checkRecoverKeyStorePermission();
- Preconditions.checkNotNull(alias, "alias is null");
+ Objects.requireNonNull(alias, "alias is null");
int uid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
@@ -771,8 +772,8 @@
public @Nullable String importKeyWithMetadata(@NonNull String alias, @NonNull byte[] keyBytes,
@Nullable byte[] metadata) throws RemoteException {
checkRecoverKeyStorePermission();
- Preconditions.checkNotNull(alias, "alias is null");
- Preconditions.checkNotNull(keyBytes, "keyBytes is null");
+ Objects.requireNonNull(alias, "alias is null");
+ Objects.requireNonNull(keyBytes, "keyBytes is null");
if (keyBytes.length != RecoverableKeyGenerator.KEY_SIZE_BITS / Byte.SIZE) {
Log.e(TAG, "The given key for import doesn't have the required length "
+ RecoverableKeyGenerator.KEY_SIZE_BITS);
@@ -816,7 +817,7 @@
*/
public @Nullable String getKey(@NonNull String alias) throws RemoteException {
checkRecoverKeyStorePermission();
- Preconditions.checkNotNull(alias, "alias is null");
+ Objects.requireNonNull(alias, "alias is null");
int uid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
return getAlias(userId, uid, alias);
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index 423001f..f8d8f9f 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -286,6 +286,11 @@
if (mActiveConnection != connection) {
return;
}
+ if (sessionInfo != null) {
+ sessionInfo = new RouteSessionInfo.Builder(sessionInfo)
+ .setProviderId(getUniqueId())
+ .build();
+ }
mCallback.onSessionCreated(this, sessionInfo, requestId);
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 0bdcc97..82d2250 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -1071,12 +1071,6 @@
return;
}
- //TODO: remove this when we are sure that request id is properly implemented.
- if (matchingRequest.mClientRecord.mClientId != toClientId(requestId)) {
- Slog.w(TAG, "Client id is changed. This shouldn't happen.");
- return;
- }
-
mSessionCreationRequests.remove(matchingRequest);
if (sessionInfo == null) {
@@ -1086,21 +1080,17 @@
return;
}
- RouteSessionInfo sessionInfoWithProviderId = new RouteSessionInfo.Builder(sessionInfo)
- .setProviderId(provider.getUniqueId())
- .build();
-
String originalRouteId = matchingRequest.mRoute.getId();
String originalCategory = matchingRequest.mControlCategory;
Client2Record client2Record = matchingRequest.mClientRecord;
- if (!sessionInfoWithProviderId.getSelectedRoutes().contains(originalRouteId)
+ if (!sessionInfo.getSelectedRoutes().contains(originalRouteId)
|| !TextUtils.equals(originalCategory,
- sessionInfoWithProviderId.getControlCategory())) {
+ sessionInfo.getControlCategory())) {
Slog.w(TAG, "Created session doesn't match the original request."
+ " originalRouteId=" + originalRouteId
+ ", originalCategory=" + originalCategory + ", requestId=" + requestId
- + ", sessionInfo=" + sessionInfoWithProviderId);
+ + ", sessionInfo=" + sessionInfo);
notifySessionCreationFailed(matchingRequest.mClientRecord,
toClientRequestId(requestId));
return;
@@ -1108,8 +1098,8 @@
// Succeeded
notifySessionCreated(matchingRequest.mClientRecord,
- sessionInfoWithProviderId, toClientRequestId(requestId));
- mSessionToClientMap.put(sessionInfoWithProviderId.getUniqueSessionId(), client2Record);
+ sessionInfo, toClientRequestId(requestId));
+ mSessionToClientMap.put(sessionInfo.getUniqueSessionId(), client2Record);
// TODO: Tell managers for the session creation
}
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 4cb41da..ef8f647 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -45,12 +45,12 @@
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.util.Preconditions;
import com.android.server.ConnectivityService;
import com.android.server.EventLogTags;
import com.android.server.connectivity.Vpn;
import java.util.List;
+import java.util.Objects;
/**
* State tracker for lockdown mode. Watches for normal {@link NetworkInfo} to be
@@ -90,11 +90,11 @@
@NonNull Handler handler,
@NonNull Vpn vpn,
@NonNull VpnProfile profile) {
- mContext = Preconditions.checkNotNull(context);
- mConnService = Preconditions.checkNotNull(connService);
- mHandler = Preconditions.checkNotNull(handler);
- mVpn = Preconditions.checkNotNull(vpn);
- mProfile = Preconditions.checkNotNull(profile);
+ mContext = Objects.requireNonNull(context);
+ mConnService = Objects.requireNonNull(connService);
+ mHandler = Objects.requireNonNull(handler);
+ mVpn = Objects.requireNonNull(vpn);
+ mProfile = Objects.requireNonNull(profile);
final Intent configIntent = new Intent(ACTION_VPN_SETTINGS);
mConfigIntent = PendingIntent.getActivity(mContext, 0, configIntent, 0);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 99562eb..2390da5e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -91,7 +91,6 @@
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static com.android.internal.util.ArrayUtils.appendInt;
-import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -614,12 +613,12 @@
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
INetworkManagementService networkManagement, IPackageManager pm, Clock clock,
File systemDir, boolean suppressDefaultPolicy) {
- mContext = checkNotNull(context, "missing context");
- mActivityManager = checkNotNull(activityManager, "missing activityManager");
- mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
+ mContext = Objects.requireNonNull(context, "missing context");
+ mActivityManager = Objects.requireNonNull(activityManager, "missing activityManager");
+ mNetworkManager = Objects.requireNonNull(networkManagement, "missing networkManagement");
mDeviceIdleController = IDeviceIdleController.Stub.asInterface(ServiceManager.getService(
Context.DEVICE_IDLE_CONTROLLER));
- mClock = checkNotNull(clock, "missing Clock");
+ mClock = Objects.requireNonNull(clock, "missing Clock");
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
mIPm = pm;
@@ -646,7 +645,7 @@
}
public void bindConnectivityManager(IConnectivityManager connManager) {
- mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
+ mConnManager = Objects.requireNonNull(connManager, "missing IConnectivityManager");
}
@GuardedBy("mUidRulesFirstLock")
@@ -3106,17 +3105,16 @@
return;
}
- long applicableNetworkTypes = 0;
+ final ArraySet<Integer> applicableNetworkTypes = new ArraySet<Integer>();
boolean allNetworks = false;
for (SubscriptionPlan plan : plans) {
if (plan.getNetworkTypes() == null) {
allNetworks = true;
} else {
- if ((applicableNetworkTypes & plan.getNetworkTypesBitMask()) != 0) {
+ final int[] networkTypes = plan.getNetworkTypes();
+ if (!addAll(applicableNetworkTypes, networkTypes)) {
throw new IllegalArgumentException(
"Multiple subscription plans defined for a single network type.");
- } else {
- applicableNetworkTypes |= plan.getNetworkTypesBitMask();
}
}
}
@@ -3128,6 +3126,19 @@
}
}
+ /**
+ * Adds all of the {@code elements} to the {@code set}.
+ *
+ * @return {@code false} if any element is not added because the set already have the value.
+ */
+ private static boolean addAll(@NonNull Set<Integer> set, @NonNull int... elements) {
+ boolean result = true;
+ for (int element : elements) {
+ result &= set.add(element);
+ }
+ return result;
+ }
+
@Override
public SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage) {
enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
@@ -3295,7 +3306,7 @@
enforceSubscriptionPlanValidity(plans);
for (SubscriptionPlan plan : plans) {
- Preconditions.checkNotNull(plan);
+ Objects.requireNonNull(plan);
}
final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 6af962b..9eff5d1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -21,8 +21,6 @@
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.text.format.DateUtils.YEAR_IN_MILLIS;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import android.net.NetworkStats;
import android.net.NetworkStats.NonMonotonicObserver;
import android.net.NetworkStatsHistory;
@@ -54,6 +52,7 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
+import java.util.Objects;
/**
* Logic to record deltas between periodic {@link NetworkStats} snapshots into
@@ -116,9 +115,9 @@
*/
public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
- mRotator = checkNotNull(rotator, "missing FileRotator");
- mObserver = checkNotNull(observer, "missing NonMonotonicObserver");
- mDropBox = checkNotNull(dropBox, "missing DropBoxManager");
+ mRotator = Objects.requireNonNull(rotator, "missing FileRotator");
+ mObserver = Objects.requireNonNull(observer, "missing NonMonotonicObserver");
+ mDropBox = Objects.requireNonNull(dropBox, "missing DropBoxManager");
mCookie = cookie;
mBucketDuration = bucketDuration;
@@ -165,7 +164,7 @@
* as reference is valid.
*/
public NetworkStatsCollection getOrLoadCompleteLocked() {
- checkNotNull(mRotator, "missing FileRotator");
+ Objects.requireNonNull(mRotator, "missing FileRotator");
NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
if (res == null) {
res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
@@ -175,7 +174,7 @@
}
public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
- checkNotNull(mRotator, "missing FileRotator");
+ Objects.requireNonNull(mRotator, "missing FileRotator");
NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
if (res == null) {
res = loadLocked(start, end);
@@ -280,7 +279,7 @@
* {@link #mPersistThresholdBytes}.
*/
public void maybePersistLocked(long currentTimeMillis) {
- checkNotNull(mRotator, "missing FileRotator");
+ Objects.requireNonNull(mRotator, "missing FileRotator");
final long pendingBytes = mPending.getTotalBytes();
if (pendingBytes >= mPersistThresholdBytes) {
forcePersistLocked(currentTimeMillis);
@@ -293,7 +292,7 @@
* Force persisting any pending deltas.
*/
public void forcePersistLocked(long currentTimeMillis) {
- checkNotNull(mRotator, "missing FileRotator");
+ Objects.requireNonNull(mRotator, "missing FileRotator");
if (mPending.isDirty()) {
if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
try {
@@ -356,7 +355,7 @@
private final NetworkStatsCollection mCollection;
public CombiningRewriter(NetworkStatsCollection collection) {
- mCollection = checkNotNull(collection, "missing NetworkStatsCollection");
+ mCollection = Objects.requireNonNull(collection, "missing NetworkStatsCollection");
}
@Override
@@ -418,7 +417,7 @@
}
public void importLegacyNetworkLocked(File file) throws IOException {
- checkNotNull(mRotator, "missing FileRotator");
+ Objects.requireNonNull(mRotator, "missing FileRotator");
// legacy file still exists; start empty to avoid double importing
mRotator.deleteAll();
@@ -438,7 +437,7 @@
}
public void importLegacyUidLocked(File file) throws IOException {
- checkNotNull(mRotator, "missing FileRotator");
+ Objects.requireNonNull(mRotator, "missing FileRotator");
// legacy file still exists; start empty to avoid double importing
mRotator.deleteAll();
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 0288f0c..ec8a8e7 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -65,7 +65,6 @@
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
@@ -148,6 +147,7 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
/**
* Collect and persist detailed network statistics, and provide this data to
@@ -357,17 +357,18 @@
TelephonyManager teleManager, NetworkStatsSettings settings,
NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir,
File baseDir) {
- mContext = checkNotNull(context, "missing Context");
- mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
- mAlarmManager = checkNotNull(alarmManager, "missing AlarmManager");
- mClock = checkNotNull(clock, "missing Clock");
- mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
- mTeleManager = checkNotNull(teleManager, "missing TelephonyManager");
- mWakeLock = checkNotNull(wakeLock, "missing WakeLock");
- mStatsFactory = checkNotNull(factory, "missing factory");
- mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers");
- mSystemDir = checkNotNull(systemDir, "missing systemDir");
- mBaseDir = checkNotNull(baseDir, "missing baseDir");
+ mContext = Objects.requireNonNull(context, "missing Context");
+ mNetworkManager = Objects.requireNonNull(networkManager,
+ "missing INetworkManagementService");
+ mAlarmManager = Objects.requireNonNull(alarmManager, "missing AlarmManager");
+ mClock = Objects.requireNonNull(clock, "missing Clock");
+ mSettings = Objects.requireNonNull(settings, "missing NetworkStatsSettings");
+ mTeleManager = Objects.requireNonNull(teleManager, "missing TelephonyManager");
+ mWakeLock = Objects.requireNonNull(wakeLock, "missing WakeLock");
+ mStatsFactory = Objects.requireNonNull(factory, "missing factory");
+ mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers");
+ mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir");
+ mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir");
mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists();
}
@@ -896,11 +897,11 @@
@Override
public DataUsageRequest registerUsageCallback(String callingPackage,
DataUsageRequest request, Messenger messenger, IBinder binder) {
- checkNotNull(callingPackage, "calling package is null");
- checkNotNull(request, "DataUsageRequest is null");
- checkNotNull(request.template, "NetworkTemplate is null");
- checkNotNull(messenger, "messenger is null");
- checkNotNull(binder, "binder is null");
+ Objects.requireNonNull(callingPackage, "calling package is null");
+ Objects.requireNonNull(request, "DataUsageRequest is null");
+ Objects.requireNonNull(request.template, "NetworkTemplate is null");
+ Objects.requireNonNull(messenger, "messenger is null");
+ Objects.requireNonNull(binder, "binder is null");
int callingUid = Binder.getCallingUid();
@NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage);
@@ -921,7 +922,7 @@
@Override
public void unregisterUsageRequest(DataUsageRequest request) {
- checkNotNull(request, "DataUsageRequest is null");
+ Objects.requireNonNull(request, "DataUsageRequest is null");
int callingUid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
@@ -1795,7 +1796,7 @@
private final ContentResolver mResolver;
public DefaultNetworkStatsSettings(Context context) {
- mResolver = checkNotNull(context.getContentResolver());
+ mResolver = Objects.requireNonNull(context.getContentResolver());
// TODO: adjust these timings for production builds
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 12afef2..f42f4f7 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2261,8 +2261,8 @@
private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
boolean fromApp, boolean fromListener) {
- Preconditions.checkNotNull(group);
- Preconditions.checkNotNull(pkg);
+ Objects.requireNonNull(group);
+ Objects.requireNonNull(pkg);
final NotificationChannelGroup preUpdate =
mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
@@ -3005,7 +3005,7 @@
boolean needsPolicyFileChange = false;
for (int i = 0; i < channelsSize; i++) {
final NotificationChannel channel = channels.get(i);
- Preconditions.checkNotNull(channel, "channel in list is null");
+ Objects.requireNonNull(channel, "channel in list is null");
needsPolicyFileChange = mPreferencesHelper.createNotificationChannel(pkg, uid,
channel, true /* fromTargetApp */,
mConditionProviders.isPackageOrComponentAllowed(
@@ -3126,7 +3126,7 @@
public void updateNotificationChannelForPackage(String pkg, int uid,
NotificationChannel channel) {
enforceSystemOrSystemUI("Caller not system or systemui");
- Preconditions.checkNotNull(channel);
+ Objects.requireNonNull(channel);
updateNotificationChannelInt(pkg, uid, channel, false);
}
@@ -3877,21 +3877,21 @@
@Override
public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
- Preconditions.checkNotNull(id, "Id is null");
+ Objects.requireNonNull(id, "Id is null");
enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
return mZenModeHelper.getAutomaticZenRule(id);
}
@Override
public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
- Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
- Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
+ Objects.requireNonNull(automaticZenRule, "automaticZenRule is null");
+ Objects.requireNonNull(automaticZenRule.getName(), "Name is null");
if (automaticZenRule.getOwner() == null
&& automaticZenRule.getConfigurationActivity() == null) {
throw new NullPointerException(
"Rule must have a conditionproviderservice and/or configuration activity");
}
- Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
+ Objects.requireNonNull(automaticZenRule.getConditionId(), "ConditionId is null");
if (automaticZenRule.getZenPolicy() != null
&& automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) {
throw new IllegalArgumentException("ZenPolicy is only applicable to "
@@ -3906,14 +3906,14 @@
@Override
public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
throws RemoteException {
- Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
- Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
+ Objects.requireNonNull(automaticZenRule, "automaticZenRule is null");
+ Objects.requireNonNull(automaticZenRule.getName(), "Name is null");
if (automaticZenRule.getOwner() == null
&& automaticZenRule.getConfigurationActivity() == null) {
throw new NullPointerException(
"Rule must have a conditionproviderservice and/or configuration activity");
}
- Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
+ Objects.requireNonNull(automaticZenRule.getConditionId(), "ConditionId is null");
enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
@@ -3922,7 +3922,7 @@
@Override
public boolean removeAutomaticZenRule(String id) throws RemoteException {
- Preconditions.checkNotNull(id, "Id is null");
+ Objects.requireNonNull(id, "Id is null");
// Verify that they can modify zen rules.
enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
@@ -3931,7 +3931,7 @@
@Override
public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
- Preconditions.checkNotNull(packageName, "Package name is null");
+ Objects.requireNonNull(packageName, "Package name is null");
enforceSystemOrSystemUI("removeAutomaticZenRules");
return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
@@ -3939,7 +3939,7 @@
@Override
public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
- Preconditions.checkNotNull(owner, "Owner is null");
+ Objects.requireNonNull(owner, "Owner is null");
enforceSystemOrSystemUI("getRuleInstanceCount");
return mZenModeHelper.getCurrentInstanceCount(owner);
@@ -3947,8 +3947,8 @@
@Override
public void setAutomaticZenRuleState(String id, Condition condition) {
- Preconditions.checkNotNull(id, "id is null");
- Preconditions.checkNotNull(condition, "Condition is null");
+ Objects.requireNonNull(id, "id is null");
+ Objects.requireNonNull(condition, "Condition is null");
enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
@@ -4292,7 +4292,7 @@
@Override
public boolean isNotificationListenerAccessGranted(ComponentName listener) {
- Preconditions.checkNotNull(listener);
+ Objects.requireNonNull(listener);
checkCallerIsSystemOrSameApp(listener.getPackageName());
return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
getCallingUserHandle().getIdentifier());
@@ -4301,7 +4301,7 @@
@Override
public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
int userId) {
- Preconditions.checkNotNull(listener);
+ Objects.requireNonNull(listener);
checkCallerIsSystem();
return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
userId);
@@ -4309,7 +4309,7 @@
@Override
public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
- Preconditions.checkNotNull(assistant);
+ Objects.requireNonNull(assistant);
checkCallerIsSystemOrSameApp(assistant.getPackageName());
return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
getCallingUserHandle().getIdentifier());
@@ -4332,7 +4332,7 @@
@Override
public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
boolean granted) {
- Preconditions.checkNotNull(listener);
+ Objects.requireNonNull(listener);
checkCallerIsSystemOrShell();
final long identity = Binder.clearCallingIdentity();
try {
@@ -4450,7 +4450,7 @@
public void updateNotificationChannelGroupFromPrivilegedListener(
INotificationListener token, String pkg, UserHandle user,
NotificationChannelGroup group) throws RemoteException {
- Preconditions.checkNotNull(user);
+ Objects.requireNonNull(user);
verifyPrivilegedListener(token, user, false);
createNotificationChannelGroup(
pkg, getUidForPackageAndUser(pkg, user), group, false, true);
@@ -4460,9 +4460,9 @@
@Override
public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
- Preconditions.checkNotNull(channel);
- Preconditions.checkNotNull(pkg);
- Preconditions.checkNotNull(user);
+ Objects.requireNonNull(channel);
+ Objects.requireNonNull(pkg);
+ Objects.requireNonNull(user);
verifyPrivilegedListener(token, user, false);
updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
@@ -4471,8 +4471,8 @@
@Override
public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
INotificationListener token, String pkg, UserHandle user) throws RemoteException {
- Preconditions.checkNotNull(pkg);
- Preconditions.checkNotNull(user);
+ Objects.requireNonNull(pkg);
+ Objects.requireNonNull(user);
verifyPrivilegedListener(token, user, true);
return mPreferencesHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
@@ -4483,8 +4483,8 @@
public ParceledListSlice<NotificationChannelGroup>
getNotificationChannelGroupsFromPrivilegedListener(
INotificationListener token, String pkg, UserHandle user) throws RemoteException {
- Preconditions.checkNotNull(pkg);
- Preconditions.checkNotNull(user);
+ Objects.requireNonNull(pkg);
+ Objects.requireNonNull(user);
verifyPrivilegedListener(token, user, true);
List<NotificationChannelGroup> groups = new ArrayList<>();
@@ -4520,7 +4520,7 @@
@Override
public boolean isPackagePaused(String pkg) {
- Preconditions.checkNotNull(pkg);
+ Objects.requireNonNull(pkg);
checkCallerIsSameApp(pkg);
return isPackagePausedOrSuspended(pkg, Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index b1ffa8c..cdb0a17 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -621,10 +621,10 @@
@Override
public void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
boolean fromTargetApp) {
- Preconditions.checkNotNull(pkg);
- Preconditions.checkNotNull(group);
- Preconditions.checkNotNull(group.getId());
- Preconditions.checkNotNull(!TextUtils.isEmpty(group.getName()));
+ Objects.requireNonNull(pkg);
+ Objects.requireNonNull(group);
+ Objects.requireNonNull(group.getId());
+ Objects.requireNonNull(!TextUtils.isEmpty(group.getName()));
synchronized (mPackagePreferences) {
PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
if (r == null) {
@@ -658,9 +658,9 @@
@Override
public boolean createNotificationChannel(String pkg, int uid, NotificationChannel channel,
boolean fromTargetApp, boolean hasDndAccess) {
- Preconditions.checkNotNull(pkg);
- Preconditions.checkNotNull(channel);
- Preconditions.checkNotNull(channel.getId());
+ Objects.requireNonNull(pkg);
+ Objects.requireNonNull(channel);
+ Objects.requireNonNull(channel.getId());
Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName()));
boolean needsPolicyFileChange = false;
synchronized (mPackagePreferences) {
@@ -788,8 +788,8 @@
@Override
public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel,
boolean fromUser) {
- Preconditions.checkNotNull(updatedChannel);
- Preconditions.checkNotNull(updatedChannel.getId());
+ Objects.requireNonNull(updatedChannel);
+ Objects.requireNonNull(updatedChannel.getId());
synchronized (mPackagePreferences) {
PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
if (r == null) {
@@ -850,7 +850,7 @@
@Override
public NotificationChannel getNotificationChannel(String pkg, int uid, String channelId,
boolean includeDeleted) {
- Preconditions.checkNotNull(pkg);
+ Objects.requireNonNull(pkg);
synchronized (mPackagePreferences) {
PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
if (r == null) {
@@ -891,8 +891,8 @@
@Override
@VisibleForTesting
public void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId) {
- Preconditions.checkNotNull(pkg);
- Preconditions.checkNotNull(channelId);
+ Objects.requireNonNull(pkg);
+ Objects.requireNonNull(channelId);
synchronized (mPackagePreferences) {
PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
if (r == null) {
@@ -904,7 +904,7 @@
@Override
public void permanentlyDeleteNotificationChannels(String pkg, int uid) {
- Preconditions.checkNotNull(pkg);
+ Objects.requireNonNull(pkg);
synchronized (mPackagePreferences) {
PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
if (r == null) {
@@ -993,7 +993,7 @@
public NotificationChannelGroup getNotificationChannelGroupWithChannels(String pkg,
int uid, String groupId, boolean includeDeleted) {
- Preconditions.checkNotNull(pkg);
+ Objects.requireNonNull(pkg);
synchronized (mPackagePreferences) {
PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
if (r == null || groupId == null || !r.groups.containsKey(groupId)) {
@@ -1016,7 +1016,7 @@
public NotificationChannelGroup getNotificationChannelGroup(String groupId, String pkg,
int uid) {
- Preconditions.checkNotNull(pkg);
+ Objects.requireNonNull(pkg);
synchronized (mPackagePreferences) {
PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
if (r == null) {
@@ -1029,7 +1029,7 @@
@Override
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty) {
- Preconditions.checkNotNull(pkg);
+ Objects.requireNonNull(pkg);
Map<String, NotificationChannelGroup> groups = new ArrayMap<>();
synchronized (mPackagePreferences) {
PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
@@ -1111,7 +1111,7 @@
@Override
public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
boolean includeDeleted) {
- Preconditions.checkNotNull(pkg);
+ Objects.requireNonNull(pkg);
List<NotificationChannel> channels = new ArrayList<>();
synchronized (mPackagePreferences) {
PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
@@ -1168,7 +1168,7 @@
}
public int getDeletedChannelCount(String pkg, int uid) {
- Preconditions.checkNotNull(pkg);
+ Objects.requireNonNull(pkg);
int deletedCount = 0;
synchronized (mPackagePreferences) {
PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
@@ -1187,7 +1187,7 @@
}
public int getBlockedChannelCount(String pkg, int uid) {
- Preconditions.checkNotNull(pkg);
+ Objects.requireNonNull(pkg);
int blockedCount = 0;
synchronized (mPackagePreferences) {
PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 9a1b30d..1e2d52d 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -38,6 +38,7 @@
import com.android.server.SystemConfig;
import java.io.FileDescriptor;
+import java.util.Objects;
/**
* Implementation of the service that provides a privileged API to capture and consume bugreports.
@@ -67,9 +68,9 @@
FileDescriptor bugreportFd, FileDescriptor screenshotFd,
int bugreportMode, IDumpstateListener listener) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport");
- Preconditions.checkNotNull(callingPackage);
- Preconditions.checkNotNull(bugreportFd);
- Preconditions.checkNotNull(listener);
+ Objects.requireNonNull(callingPackage);
+ Objects.requireNonNull(bugreportFd);
+ Objects.requireNonNull(listener);
validateBugreportMode(bugreportMode);
final long identity = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 785ca7d..04e7372 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11319,6 +11319,12 @@
"Static shared libs cannot declare permission groups");
}
+ // Static shared libs cannot declare features
+ if (pkg.getFeatures() != null && !pkg.getFeatures().isEmpty()) {
+ throw new PackageManagerException(
+ "Static shared libs cannot declare features");
+ }
+
// Static shared libs cannot declare permissions
if (pkg.getPermissions() != null && !pkg.getPermissions().isEmpty()) {
throw new PackageManagerException(
@@ -12872,7 +12878,7 @@
@Override
public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) {
- Preconditions.checkNotNull("packageNames cannot be null", packageNames);
+ Preconditions.checkNotNull(packageNames, "packageNames cannot be null");
mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
"getUnsuspendablePackagesForUser");
final int callingUid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 605f869..9cd6f16 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3025,10 +3025,9 @@
@Override
public void startOneTimePermissionSession(String packageName, @UserIdInt int userId,
long timeoutMillis, int importanceToResetTimer, int importanceToKeepSessionAlive) {
- mContext.enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
- "Must be able to revoke runtime permissions to register permissions as one time.");
- mContext.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS,
- "Must be able to access usage stats to register permissions as one time.");
+ mContext.enforceCallingPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
+ "Must hold " + Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS
+ + " to register permissions as one time.");
packageName = Preconditions.checkNotNull(packageName);
long token = Binder.clearCallingIdentity();
@@ -3042,10 +3041,9 @@
@Override
public void stopOneTimePermissionSession(String packageName, @UserIdInt int userId) {
- mContext.enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
- "Must be able to revoke runtime permissions to remove permissions as one time.");
- mContext.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS,
- "Must be able to access usage stats to remove permissions as one time.");
+ mContext.enforceCallingPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
+ "Must hold " + Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS
+ + " to remove permissions as one time.");
Preconditions.checkNotNull(packageName);
long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index f0e4625..4142e6f 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -49,6 +49,7 @@
import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState;
import java.util.ArrayList;
+import java.util.Objects;
/**
* Responsible for battery saver mode transition logic.
@@ -237,7 +238,7 @@
private PowerManager getPowerManager() {
if (mPowerManager == null) {
mPowerManager =
- Preconditions.checkNotNull(mContext.getSystemService(PowerManager.class));
+ Objects.requireNonNull(mContext.getSystemService(PowerManager.class));
}
return mPowerManager;
}
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index c4522e0..392792d 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -511,7 +511,7 @@
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- Preconditions.checkNotNull(callback, "callback cannot be null");
+ Objects.requireNonNull(callback, "callback cannot be null");
getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags,
callback);
@@ -531,7 +531,7 @@
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- Preconditions.checkNotNull(callback, "callback cannot be null");
+ Objects.requireNonNull(callback, "callback cannot be null");
getOrCreateController(userId).onRemoveRoleHolder(roleName, packageName, flags,
callback);
@@ -550,7 +550,7 @@
"clearRoleHoldersAsUser");
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkNotNull(callback, "callback cannot be null");
+ Objects.requireNonNull(callback, "callback cannot be null");
getOrCreateController(userId).onClearRoleHolders(roleName, flags, callback);
}
@@ -566,7 +566,7 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
"addOnRoleHoldersChangedListenerAsUser");
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getOrCreateListeners(
userId);
@@ -584,7 +584,7 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
"removeOnRoleHoldersChangedListenerAsUser");
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getListeners(userId);
if (listener == null) {
@@ -599,7 +599,7 @@
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
"setRoleNamesFromController");
- Preconditions.checkNotNull(roleNames, "roleNames cannot be null");
+ Objects.requireNonNull(roleNames, "roleNames cannot be null");
int userId = UserHandle.getCallingUserId();
getOrCreateUserState(userId).setRoleNames(roleNames);
diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
index 1123f70..e6e6e23 100644
--- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
+++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
@@ -16,6 +16,7 @@
package com.android.server.rollback;
+import android.content.pm.PackageManager;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.PackageRollbackInfo.RestoreInfo;
import android.os.storage.StorageManager;
@@ -119,11 +120,22 @@
}
try {
- mInstaller.restoreAppDataSnapshot(packageRollbackInfo.getPackageName(), appId, seInfo,
- userId, rollbackId, storageFlags);
+ switch (packageRollbackInfo.getRollbackDataPolicy()) {
+ case PackageManager.RollbackDataPolicy.WIPE:
+ mInstaller.clearAppData(null, packageRollbackInfo.getPackageName(),
+ userId, storageFlags, 0);
+ break;
+ case PackageManager.RollbackDataPolicy.RESTORE:
+ mInstaller.restoreAppDataSnapshot(packageRollbackInfo.getPackageName(), appId,
+ seInfo, userId, rollbackId, storageFlags);
+ break;
+ default:
+ break;
+ }
} catch (InstallerException ie) {
- Slog.e(TAG, "Unable to restore app data snapshot: "
- + packageRollbackInfo.getPackageName(), ie);
+ Slog.e(TAG, "Unable to restore/wipe app data: "
+ + packageRollbackInfo.getPackageName() + " policy="
+ + packageRollbackInfo.getRollbackDataPolicy(), ie);
}
return changedRollback;
@@ -207,13 +219,24 @@
if (hasPendingRestore) {
try {
- mInstaller.restoreAppDataSnapshot(info.getPackageName(), ri.appId,
- ri.seInfo, userId, rollback.info.getRollbackId(),
- Installer.FLAG_STORAGE_CE);
+ switch (info.getRollbackDataPolicy()) {
+ case PackageManager.RollbackDataPolicy.WIPE:
+ mInstaller.clearAppData(null, info.getPackageName(), userId,
+ Installer.FLAG_STORAGE_CE, 0);
+ break;
+ case PackageManager.RollbackDataPolicy.RESTORE:
+ mInstaller.restoreAppDataSnapshot(info.getPackageName(), ri.appId,
+ ri.seInfo, userId, rollback.info.getRollbackId(),
+ Installer.FLAG_STORAGE_CE);
+ break;
+ default:
+ break;
+ }
info.removeRestoreInfo(ri);
} catch (InstallerException ie) {
- Slog.e(TAG, "Unable to restore app data snapshot for: "
- + info.getPackageName(), ie);
+ Slog.e(TAG, "Unable to restore/wipe app data for: "
+ + info.getPackageName() + " policy="
+ + info.getRollbackDataPolicy(), ie);
}
}
}
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 6898e1c..88c1564 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -306,7 +306,7 @@
* @return boolean True if the rollback was enabled successfully for the specified package.
*/
boolean enableForPackage(String packageName, long newVersion, long installedVersion,
- boolean isApex, String sourceDir, String[] splitSourceDirs) {
+ boolean isApex, String sourceDir, String[] splitSourceDirs, int rollbackDataPolicy) {
try {
RollbackStore.backupPackageCodePath(this, packageName, sourceDir);
if (!ArrayUtils.isEmpty(splitSourceDirs)) {
@@ -323,7 +323,8 @@
new VersionedPackage(packageName, newVersion),
new VersionedPackage(packageName, installedVersion),
new IntArray() /* pendingBackups */, new ArrayList<>() /* pendingRestores */,
- isApex, new IntArray(), new SparseLongArray() /* ceSnapshotInodes */);
+ isApex, new IntArray(), new SparseLongArray() /* ceSnapshotInodes */,
+ rollbackDataPolicy);
synchronized (mLock) {
info.getPackages().add(packageRollbackInfo);
@@ -344,10 +345,12 @@
for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
if (pkgRollbackInfo.getPackageName().equals(packageName)) {
- dataHelper.snapshotAppData(info.getRollbackId(), pkgRollbackInfo, userIds);
-
- RollbackStore.saveRollback(this);
- pkgRollbackInfo.getSnapshottedUsers().addAll(IntArray.wrap(userIds));
+ if (pkgRollbackInfo.getRollbackDataPolicy()
+ == PackageManager.RollbackDataPolicy.RESTORE) {
+ dataHelper.snapshotAppData(info.getRollbackId(), pkgRollbackInfo, userIds);
+ pkgRollbackInfo.getSnapshottedUsers().addAll(IntArray.wrap(userIds));
+ RollbackStore.saveRollback(this);
+ }
break;
}
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 6cdfcff..9a65ae6 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -841,7 +841,7 @@
ApplicationInfo appInfo = pkgInfo.applicationInfo;
return rollback.enableForPackage(packageName, newPackage.versionCode,
pkgInfo.getLongVersionCode(), isApex, appInfo.sourceDir,
- appInfo.splitSourceDirs);
+ appInfo.splitSourceDirs, session.rollbackDataPolicy);
}
@Override
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index bb09584..162a695 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -120,9 +120,7 @@
RollbackInfo rollback = getAvailableRollback(failedPackage);
if (rollback == null) {
- Slog.w(TAG, "Expected rollback but no valid rollback found for package: [ "
- + failedPackage.getPackageName() + "] with versionCode: ["
- + failedPackage.getVersionCode() + "]");
+ Slog.w(TAG, "Expected rollback but no valid rollback found for " + failedPackage);
return false;
}
rollbackPackage(rollback, failedPackage, rollbackReason);
@@ -212,11 +210,7 @@
RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
- boolean hasFailedPackage = packageRollback.getPackageName().equals(
- failedPackage.getPackageName())
- && packageRollback.getVersionRolledBackFrom().getVersionCode()
- == failedPackage.getVersionCode();
- if (hasFailedPackage) {
+ if (packageRollback.getVersionRolledBackFrom().equals(failedPackage)) {
return rollback;
}
}
@@ -361,15 +355,6 @@
}
}
- private VersionedPackage getVersionedPackage(String packageName) {
- try {
- return new VersionedPackage(packageName, mContext.getPackageManager().getPackageInfo(
- packageName, 0 /* flags */).getLongVersionCode());
- } catch (PackageManager.NameNotFoundException e) {
- return null;
- }
- }
-
/**
* Rolls back the session that owns {@code failedPackage}
*
@@ -432,14 +417,8 @@
List<RollbackInfo> rollbacks = rollbackManager.getAvailableRollbacks();
for (RollbackInfo rollback : rollbacks) {
- String samplePackageName = rollback.getPackages().get(0).getPackageName();
- VersionedPackage sampleVersionedPackage = getVersionedPackage(samplePackageName);
- if (sampleVersionedPackage == null) {
- Slog.e(TAG, "Failed to rollback " + samplePackageName);
- continue;
- }
- rollbackPackage(rollback, sampleVersionedPackage,
- PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
+ VersionedPackage sample = rollback.getPackages().get(0).getVersionRolledBackFrom();
+ rollbackPackage(rollback, sample, PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
}
}
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 550c754..df75a29 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -21,6 +21,7 @@
import static com.android.server.rollback.Rollback.rollbackStateFromString;
import android.annotation.NonNull;
+import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.PackageRollbackInfo.RestoreInfo;
@@ -345,6 +346,8 @@
json.put("installedUsers", convertToJsonArray(snapshottedUsers));
json.put("ceSnapshotInodes", ceSnapshotInodesToJson(info.getCeSnapshotInodes()));
+ json.put("rollbackDataPolicy", info.getRollbackDataPolicy());
+
return json;
}
@@ -367,8 +370,13 @@
final SparseLongArray ceSnapshotInodes = ceSnapshotInodesFromJson(
json.getJSONArray("ceSnapshotInodes"));
+ // Backward compatibility: no such field for old versions.
+ final int rollbackDataPolicy = json.optInt("rollbackDataPolicy",
+ PackageManager.RollbackDataPolicy.RESTORE);
+
return new PackageRollbackInfo(versionRolledBackFrom, versionRolledBackTo,
- pendingBackups, pendingRestores, isApex, snapshottedUsers, ceSnapshotInodes);
+ pendingBackups, pendingRestores, isApex, snapshottedUsers, ceSnapshotInodes,
+ rollbackDataPolicy);
}
private static JSONArray versionedPackagesToJson(List<VersionedPackage> packages)
diff --git a/services/core/java/com/android/server/security/FileIntegrityService.java b/services/core/java/com/android/server/security/FileIntegrityService.java
index 0bbb179..e90c02a 100644
--- a/services/core/java/com/android/server/security/FileIntegrityService.java
+++ b/services/core/java/com/android/server/security/FileIntegrityService.java
@@ -59,7 +59,7 @@
}
@Override
- public boolean isAppSourceCertificateTrusted(byte[] certificateBytes) {
+ public boolean isAppSourceCertificateTrusted(@Nullable byte[] certificateBytes) {
enforceAnyCallingPermissions(
android.Manifest.permission.REQUEST_INSTALL_PACKAGES,
android.Manifest.permission.INSTALL_PACKAGES);
@@ -67,7 +67,10 @@
if (!isApkVeritySupported()) {
return false;
}
-
+ if (certificateBytes == null) {
+ Slog.w(TAG, "Received a null certificate");
+ return false;
+ }
return mTrustedCertificates.contains(toCertificate(certificateBytes));
} catch (CertificateException e) {
Slog.e(TAG, "Failed to convert the certificate: " + e);
@@ -122,7 +125,12 @@
}
for (File cert : files) {
- collectCertificate(Files.readAllBytes(cert.toPath()));
+ byte[] certificateBytes = Files.readAllBytes(cert.toPath());
+ if (certificateBytes == null) {
+ Slog.w(TAG, "The certificate file is empty, ignoring " + cert);
+ continue;
+ }
+ collectCertificate(certificateBytes);
}
} catch (IOException e) {
Slog.wtf(TAG, "Failed to load fs-verity certificate from " + path, e);
@@ -146,10 +154,10 @@
* Tries to convert {@code bytes} into an X.509 certificate and store in memory.
* Errors need to be surpressed in order fo the next certificates to still be collected.
*/
- private void collectCertificate(@Nullable byte[] bytes) {
+ private void collectCertificate(@NonNull byte[] bytes) {
try {
mTrustedCertificates.add(toCertificate(bytes));
- } catch (CertificateException | AssertionError e) {
+ } catch (CertificateException e) {
Slog.e(TAG, "Invalid certificate, ignored: " + e);
}
}
@@ -159,7 +167,7 @@
* the rest. The rational is to make it harder to smuggle.
*/
@NonNull
- private static X509Certificate toCertificate(@Nullable byte[] bytes)
+ private static X509Certificate toCertificate(@NonNull byte[] bytes)
throws CertificateException {
Certificate certificate = sCertFactory.generateCertificate(new ByteArrayInputStream(bytes));
if (!(certificate instanceof X509Certificate)) {
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index 3b2f324..7c8c494 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -106,7 +106,7 @@
@VisibleForTesting
SliceManagerService(Context context, Looper looper) {
mContext = context;
- mPackageManagerInternal = Preconditions.checkNotNull(
+ mPackageManagerInternal = Objects.requireNonNull(
LocalServices.getService(PackageManagerInternal.class));
mAppOps = context.getSystemService(AppOpsManager.class);
mAssistUtils = new AssistUtils(context);
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
index a7cfe10..987c05f 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
@@ -42,6 +42,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -179,8 +180,8 @@
// Permission check.
checkPermissions();
// Input validation.
- Preconditions.checkNotNull(callback);
- Preconditions.checkNotNull(callback.asBinder());
+ Objects.requireNonNull(callback);
+ Objects.requireNonNull(callback.asBinder());
synchronized (this) {
// State validation.
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
index 4898e6b..43047d1 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ValidationUtil.java
@@ -29,6 +29,7 @@
import com.android.internal.util.Preconditions;
+import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -42,7 +43,7 @@
*/
public class ValidationUtil {
static void validateUuid(@Nullable String uuid) {
- Preconditions.checkNotNull(uuid);
+ Objects.requireNonNull(uuid);
Matcher matcher = UuidUtil.PATTERN.matcher(uuid);
if (!matcher.matches()) {
throw new IllegalArgumentException(
@@ -55,37 +56,37 @@
}
static void validateModel(@Nullable SoundModel model, int expectedType) {
- Preconditions.checkNotNull(model);
+ Objects.requireNonNull(model);
if (model.type != expectedType) {
throw new IllegalArgumentException("Invalid type");
}
validateUuid(model.uuid);
validateUuid(model.vendorUuid);
- Preconditions.checkNotNull(model.data);
+ Objects.requireNonNull(model.data);
}
static void validatePhraseModel(@Nullable PhraseSoundModel model) {
- Preconditions.checkNotNull(model);
+ Objects.requireNonNull(model);
validateModel(model.common, SoundModelType.KEYPHRASE);
- Preconditions.checkNotNull(model.phrases);
+ Objects.requireNonNull(model.phrases);
for (Phrase phrase : model.phrases) {
- Preconditions.checkNotNull(phrase);
+ Objects.requireNonNull(phrase);
if ((phrase.recognitionModes & ~(RecognitionMode.VOICE_TRIGGER
| RecognitionMode.USER_IDENTIFICATION | RecognitionMode.USER_AUTHENTICATION
| RecognitionMode.GENERIC_TRIGGER)) != 0) {
throw new IllegalArgumentException("Invalid recognitionModes");
}
- Preconditions.checkNotNull(phrase.users);
- Preconditions.checkNotNull(phrase.locale);
- Preconditions.checkNotNull(phrase.text);
+ Objects.requireNonNull(phrase.users);
+ Objects.requireNonNull(phrase.locale);
+ Objects.requireNonNull(phrase.text);
}
}
static void validateRecognitionConfig(@Nullable RecognitionConfig config) {
- Preconditions.checkNotNull(config);
- Preconditions.checkNotNull(config.phraseRecognitionExtras);
+ Objects.requireNonNull(config);
+ Objects.requireNonNull(config.phraseRecognitionExtras);
for (PhraseRecognitionExtra extra : config.phraseRecognitionExtras) {
- Preconditions.checkNotNull(extra);
+ Objects.requireNonNull(extra);
if ((extra.recognitionModes & ~(RecognitionMode.VOICE_TRIGGER
| RecognitionMode.USER_IDENTIFICATION | RecognitionMode.USER_AUTHENTICATION
| RecognitionMode.GENERIC_TRIGGER)) != 0) {
@@ -94,15 +95,15 @@
if (extra.confidenceLevel < 0 || extra.confidenceLevel > 100) {
throw new IllegalArgumentException("Invalid confidenceLevel");
}
- Preconditions.checkNotNull(extra.levels);
+ Objects.requireNonNull(extra.levels);
for (ConfidenceLevel level : extra.levels) {
- Preconditions.checkNotNull(level);
+ Objects.requireNonNull(level);
if (level.levelPercent < 0 || level.levelPercent > 100) {
throw new IllegalArgumentException("Invalid confidenceLevel");
}
}
}
- Preconditions.checkNotNull(config.data);
+ Objects.requireNonNull(config.data);
}
static void validateModelParameter(int modelParam) {
diff --git a/services/core/java/com/android/server/storage/AppCollector.java b/services/core/java/com/android/server/storage/AppCollector.java
index 0b51f9c..ecbc88f 100644
--- a/services/core/java/com/android/server/storage/AppCollector.java
+++ b/services/core/java/com/android/server/storage/AppCollector.java
@@ -59,7 +59,7 @@
* @param volume Volume to check for apps.
*/
public AppCollector(Context context, @NonNull VolumeInfo volume) {
- Preconditions.checkNotNull(volume);
+ Objects.requireNonNull(volume);
mBackgroundHandler = new BackgroundHandler(BackgroundThread.get().getLooper(),
volume,
diff --git a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
index 60de10c..aafadf9 100644
--- a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
+++ b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
@@ -66,6 +66,7 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* CacheQuotaStrategy is a strategy for determining cache quotas using usage stats and foreground
@@ -95,10 +96,10 @@
public CacheQuotaStrategy(
Context context, UsageStatsManagerInternal usageStatsManager, Installer installer,
ArrayMap<String, SparseLongArray> quotaMap) {
- mContext = Preconditions.checkNotNull(context);
- mUsageStats = Preconditions.checkNotNull(usageStatsManager);
- mInstaller = Preconditions.checkNotNull(installer);
- mQuotaMap = Preconditions.checkNotNull(quotaMap);
+ mContext = Objects.requireNonNull(context);
+ mUsageStats = Objects.requireNonNull(usageStatsManager);
+ mInstaller = Objects.requireNonNull(installer);
+ mQuotaMap = Objects.requireNonNull(quotaMap);
mPreviousValuesFile = new AtomicFile(new File(
new File(Environment.getDataDirectory(), "system"), "cachequota.xml"));
}
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index aa3ab63..f4fb93a 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -43,6 +43,7 @@
import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
+import java.util.Objects;
/**
* Controls storage sessions for users initiated by the {@link StorageManagerService}.
@@ -63,7 +64,7 @@
private volatile boolean mIsResetting;
public StorageSessionController(Context context, boolean isFuseEnabled) {
- mContext = Preconditions.checkNotNull(context);
+ mContext = Objects.requireNonNull(context);
mIsFuseEnabled = isFuseEnabled;
}
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index 10514ad..c02ded8 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -48,6 +48,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -69,7 +70,7 @@
@GuardedBy("mLock") private final Map<String, Session> mSessions = new HashMap<>();
public StorageUserConnection(Context context, int userId, StorageSessionController controller) {
- mContext = Preconditions.checkNotNull(context);
+ mContext = Objects.requireNonNull(context);
mUserId = Preconditions.checkArgumentNonnegative(userId);
mSessionController = controller;
}
@@ -83,10 +84,10 @@
*/
public void startSession(String sessionId, ParcelFileDescriptor pfd, String upperPath,
String lowerPath) throws ExternalStorageServiceException {
- Preconditions.checkNotNull(sessionId);
- Preconditions.checkNotNull(pfd);
- Preconditions.checkNotNull(upperPath);
- Preconditions.checkNotNull(lowerPath);
+ Objects.requireNonNull(sessionId);
+ Objects.requireNonNull(pfd);
+ Objects.requireNonNull(upperPath);
+ Objects.requireNonNull(lowerPath);
prepareRemote();
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 6a986b9..5283cc4 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -62,6 +62,7 @@
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.Map;
+import java.util.Objects;
import java.util.Queue;
/**
@@ -137,7 +138,7 @@
private TextClassificationConstants mSettings;
private TextClassificationManagerService(Context context) {
- mContext = Preconditions.checkNotNull(context);
+ mContext = Objects.requireNonNull(context);
mLock = new Object();
mSettingsListener = new TextClassifierSettingsListener(mContext);
}
@@ -156,8 +157,8 @@
@Nullable TextClassificationSessionId sessionId,
TextSelection.Request request, ITextClassifierCallback callback)
throws RemoteException {
- Preconditions.checkNotNull(request);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(request);
+ Objects.requireNonNull(callback);
final int userId = request.getUserId();
validateInput(mContext, request.getCallingPackageName(), userId);
@@ -186,8 +187,8 @@
@Nullable TextClassificationSessionId sessionId,
TextClassification.Request request, ITextClassifierCallback callback)
throws RemoteException {
- Preconditions.checkNotNull(request);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(request);
+ Objects.requireNonNull(callback);
final int userId = request.getUserId();
validateInput(mContext, request.getCallingPackageName(), userId);
@@ -215,8 +216,8 @@
@Nullable TextClassificationSessionId sessionId,
TextLinks.Request request, ITextClassifierCallback callback)
throws RemoteException {
- Preconditions.checkNotNull(request);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(request);
+ Objects.requireNonNull(callback);
final int userId = request.getUserId();
validateInput(mContext, request.getCallingPackageName(), userId);
@@ -244,7 +245,7 @@
public void onSelectionEvent(
@Nullable TextClassificationSessionId sessionId, SelectionEvent event)
throws RemoteException {
- Preconditions.checkNotNull(event);
+ Objects.requireNonNull(event);
final int userId = event.getUserId();
validateInput(mContext, event.getPackageName(), userId);
@@ -268,7 +269,7 @@
public void onTextClassifierEvent(
@Nullable TextClassificationSessionId sessionId,
TextClassifierEvent event) throws RemoteException {
- Preconditions.checkNotNull(event);
+ Objects.requireNonNull(event);
final String packageName = event.getEventContext() == null
? null
: event.getEventContext().getPackageName();
@@ -299,8 +300,8 @@
@Nullable TextClassificationSessionId sessionId,
TextLanguage.Request request,
ITextClassifierCallback callback) throws RemoteException {
- Preconditions.checkNotNull(request);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(request);
+ Objects.requireNonNull(callback);
final int userId = request.getUserId();
validateInput(mContext, request.getCallingPackageName(), userId);
@@ -329,8 +330,8 @@
@Nullable TextClassificationSessionId sessionId,
ConversationActions.Request request,
ITextClassifierCallback callback) throws RemoteException {
- Preconditions.checkNotNull(request);
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(request);
+ Objects.requireNonNull(callback);
final int userId = request.getUserId();
validateInput(mContext, request.getCallingPackageName(), userId);
@@ -360,8 +361,8 @@
public void onCreateTextClassificationSession(
TextClassificationContext classificationContext, TextClassificationSessionId sessionId)
throws RemoteException {
- Preconditions.checkNotNull(sessionId);
- Preconditions.checkNotNull(classificationContext);
+ Objects.requireNonNull(sessionId);
+ Objects.requireNonNull(classificationContext);
final int userId = classificationContext.getUserId();
validateInput(mContext, classificationContext.getPackageName(), userId);
@@ -391,7 +392,7 @@
@Override
public void onDestroyTextClassificationSession(TextClassificationSessionId sessionId)
throws RemoteException {
- Preconditions.checkNotNull(sessionId);
+ Objects.requireNonNull(sessionId);
synchronized (mLock) {
final int userId = mSessionUserIds.containsKey(sessionId)
@@ -514,7 +515,7 @@
UserState owningUser, int uid) {
mName = name;
mRequest =
- logOnFailure(Preconditions.checkNotNull(request), "handling pending request");
+ logOnFailure(Objects.requireNonNull(request), "handling pending request");
mOnServiceFailure =
logOnFailure(onServiceFailure, "notifying callback of service failure");
mBinder = binder;
@@ -604,8 +605,8 @@
private UserState(int userId, Context context, Object lock) {
mUserId = userId;
- mContext = Preconditions.checkNotNull(context);
- mLock = Preconditions.checkNotNull(lock);
+ mContext = Objects.requireNonNull(context);
+ mLock = Objects.requireNonNull(lock);
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 04839e1..e3b7c0a 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -103,6 +103,7 @@
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
/** Manages uri grants. */
public class UriGrantsManagerService extends IUriGrantsManager.Stub {
@@ -215,7 +216,7 @@
public ParceledListSlice<android.content.UriPermission> getUriPermissions(
String packageName, boolean incoming, boolean persistedOnly) {
enforceNotIsolatedCaller("getUriPermissions");
- Preconditions.checkNotNull(packageName, "packageName");
+ Objects.requireNonNull(packageName, "packageName");
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 76d18fa..d49270d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -521,7 +521,7 @@
static final int STARTING_WINDOW_SHOWN = 1;
static final int STARTING_WINDOW_REMOVED = 2;
int mStartingWindowState = STARTING_WINDOW_NOT_SHOWN;
- boolean mTaskOverlay = false; // Task is always on-top of other activities in the task.
+ private boolean mTaskOverlay = false; // Task is always on-top of other activities in the task.
// Marking the reason why this activity is being relaunched. Mainly used to track that this
// activity is being relaunched to fulfill a resize request due to compatibility issues, e.g. in
@@ -1222,7 +1222,7 @@
}
ActivityStack getStack() {
- return task != null ? task.getTaskStack() : null;
+ return task != null ? task.getStack() : null;
}
@Override
@@ -1269,8 +1269,8 @@
if (getDisplayContent() != null) {
getDisplayContent().mClosingApps.remove(this);
}
- } else if (mLastParent != null && mLastParent.getTaskStack() != null) {
- task.getTaskStack().mExitingActivities.remove(this);
+ } else if (mLastParent != null && mLastParent.getStack() != null) {
+ task.getStack().mExitingActivities.remove(this);
}
final ActivityStack stack = getStack();
@@ -5523,7 +5523,7 @@
if (stack == null) {
return INVALID_DISPLAY;
}
- return stack.mDisplayId;
+ return stack.getDisplayId();
}
final boolean isDestroyable() {
@@ -7451,6 +7451,15 @@
return this == rootActivity;
}
+ void setTaskOverlay(boolean taskOverlay) {
+ mTaskOverlay = taskOverlay;
+ setAlwaysOnTop(mTaskOverlay);
+ }
+
+ boolean isTaskOverlay() {
+ return mTaskOverlay;
+ }
+
@Override
public String toString() {
if (stringName != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 16245f0..842edb3 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -310,7 +310,7 @@
int mCurrentUser;
/** The attached Display's unique identifier, or -1 if detached */
- int mDisplayId;
+ private int mDisplayId;
// Id of the previous display the stack was on.
int mPrevDisplayId = INVALID_DISPLAY;
@@ -808,8 +808,8 @@
* @return {@code true} if the windowing mode is transient, {@code false} otherwise.
*/
private static boolean isTransientWindowingMode(int windowingMode) {
- // TODO(b/114842032): add PIP if/when it uses mode transitions instead of task reparenting
- return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ return windowingMode == WINDOWING_MODE_PINNED
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|| windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
}
@@ -1013,6 +1013,10 @@
return getDisplayContent();
}
+ int getDisplayId() {
+ return mDisplayId;
+ }
+
/**
* Defers updating the bounds of the stack. If the stack was resized/repositioned while
* deferring, the bounds will update in {@link #continueUpdateBounds()}.
@@ -1082,7 +1086,7 @@
}
private ActivityRecord topRunningNonOverlayTaskActivity() {
- return getActivity((r) -> (r.canBeTopRunning() && !r.mTaskOverlay));
+ return getActivity((r) -> (r.canBeTopRunning() && !r.isTaskOverlay()));
}
ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index a380efc4..88b5cd3 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -571,14 +571,14 @@
}
}
- void setNextTaskIdForUserLocked(int taskId, int userId) {
+ void setNextTaskIdForUser(int taskId, int userId) {
final int currentTaskId = mCurTaskIdForUser.get(userId, -1);
if (taskId > currentTaskId) {
mCurTaskIdForUser.put(userId, taskId);
}
}
- static int nextTaskIdForUser(int taskId, int userId) {
+ private static int nextTaskIdForUser(int taskId, int userId) {
int nextTaskId = taskId + 1;
if (nextTaskId == (userId + 1) * MAX_TASK_IDS_PER_USER) {
// Wrap around as there will be smaller task ids that are available now.
@@ -587,7 +587,11 @@
return nextTaskId;
}
- int getNextTaskIdForUserLocked(int userId) {
+ int getNextTaskIdForUser() {
+ return getNextTaskIdForUser(mRootWindowContainer.mCurrentUser);
+ }
+
+ int getNextTaskIdForUser(int userId) {
final int currentTaskId = mCurTaskIdForUser.get(userId, userId * MAX_TASK_IDS_PER_USER);
// for a userId u, a taskId can only be in the range
// [u*MAX_TASK_IDS_PER_USER, (u+1)*MAX_TASK_IDS_PER_USER-1], so if MAX_TASK_IDS_PER_USER
@@ -1211,8 +1215,8 @@
}
// TODO moltmann b/136595429: Set featureId from caller
- if (mService.getAppOpsService().noteOperation(opCode, callingUid, callingPackage, /* featureId */ null)
- != AppOpsManager.MODE_ALLOWED) {
+ if (mService.getAppOpsService().noteOperation(opCode, callingUid,
+ callingPackage, /* featureId */ null, false, "") != AppOpsManager.MODE_ALLOWED) {
if (!ignoreTargetSecurity) {
return ACTIVITY_RESTRICTION_APPOP;
}
@@ -1254,9 +1258,9 @@
return ACTIVITY_RESTRICTION_NONE;
}
- // TODO moltmann b/136595429: Set componentId from caller
- if (mService.getAppOpsService().noteOperation(opCode, callingUid, callingPackage, /* featureId */ null)
- != AppOpsManager.MODE_ALLOWED) {
+ // TODO moltmann b/136595429: Set featureId from caller
+ if (mService.getAppOpsService().noteOperation(opCode, callingUid,
+ callingPackage, /* featureId */ null, false, "") != AppOpsManager.MODE_ALLOWED) {
return ACTIVITY_RESTRICTION_APPOP;
}
@@ -1955,7 +1959,7 @@
// Ensure that we're not moving a task to a dynamic stack if device doesn't support
// multi-display.
- if (stack.mDisplayId != DEFAULT_DISPLAY && !mService.mSupportsMultiDisplay) {
+ if (stack.getDisplayId() != DEFAULT_DISPLAY && !mService.mSupportsMultiDisplay) {
throw new IllegalArgumentException("Device doesn't support multi-display, can not"
+ " reparent task=" + task + " to stackId=" + stackId);
}
@@ -2443,7 +2447,7 @@
// Handle incorrect launch/move to secondary display if needed.
if (isSecondaryDisplayPreferred) {
- final int actualDisplayId = task.getStack().mDisplayId;
+ final int actualDisplayId = task.getDisplayId();
if (!task.canBeLaunchedOnDisplay(actualDisplayId)) {
throw new IllegalStateException("Task resolved to incompatible display");
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index a2b9d95..c688612 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1073,7 +1073,8 @@
mRootWindowContainer.getTopDisplayFocusedStack();
Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
true, false) + "} from uid " + callingUid + " on display "
- + (focusedStack == null ? DEFAULT_DISPLAY : focusedStack.mDisplayId));
+ + (focusedStack == null ? DEFAULT_DISPLAY
+ : focusedStack.getDisplayId()));
}
}
}
@@ -1576,7 +1577,7 @@
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
if (!mTargetStack.isFocusable()
- || (topTaskActivity != null && topTaskActivity.mTaskOverlay
+ || (topTaskActivity != null && topTaskActivity.isTaskOverlay()
&& mStartActivity != topTaskActivity)) {
// If the activity is not focusable, we can't resume it, but still would like to
// make sure it becomes visible as it starts (this will also trigger entry
@@ -2044,7 +2045,7 @@
if (mOptions != null) {
if (mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
- r.mTaskOverlay = true;
+ r.setTaskOverlay(true);
if (!mOptions.canTaskOverlayResume()) {
final Task task = mRootWindowContainer.anyTaskForId(
mOptions.getLaunchTaskId());
@@ -2293,7 +2294,7 @@
// the same behavior as if a new instance was being started, which means not bringing it
// to the front if the caller is not itself in the front.
final boolean differentTopTask;
- if (mPreferredDisplayId == mTargetStack.mDisplayId) {
+ if (mPreferredDisplayId == mTargetStack.getDisplayId()) {
final ActivityStack focusStack = mTargetStack.getDisplay().getFocusedStack();
final ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
@@ -2343,7 +2344,7 @@
}
mMovedToFront = launchStack != launchStack.getDisplay()
.getTopStackInWindowingMode(launchStack.getWindowingMode());
- } else if (launchStack.mDisplayId != mTargetStack.mDisplayId) {
+ } else if (launchStack.getDisplayId() != mTargetStack.getDisplayId()) {
// Target and computed stacks are on different displays and we've
// found a matching task - move the existing instance to that display and
// move it to front.
@@ -2392,7 +2393,7 @@
private void setNewTask(Task taskToAffiliate) {
final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
final Task task = mTargetStack.createTask(
- mSupervisor.getNextTaskIdForUserLocked(mStartActivity.mUserId),
+ mSupervisor.getNextTaskIdForUser(mStartActivity.mUserId),
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
@@ -2545,12 +2546,12 @@
// Dynamic stacks behave similarly to the fullscreen stack and can contain any
// resizeable task.
canUseFocusedStack = !focusedStack.isOnHomeDisplay()
- && r.canBeLaunchedOnDisplay(focusedStack.mDisplayId);
+ && r.canBeLaunchedOnDisplay(focusedStack.getDisplayId());
}
}
return canUseFocusedStack && !newTask
// Using the focus stack isn't important enough to override the preferred display.
- && (mPreferredDisplayId == focusedStack.mDisplayId);
+ && (mPreferredDisplayId == focusedStack.getDisplayId());
}
private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, Task task,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index ac1dbc4..374af5a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -296,6 +296,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -901,7 +902,7 @@
boolean hasSystemAlertWindowPermission(int callingUid, int callingPid, String callingPackage) {
final int mode = getAppOpsService().noteOperation(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
- callingUid, callingPackage, /* featureId */ null);
+ callingUid, callingPackage, /* featureId */ null, false, "");
if (mode == AppOpsManager.MODE_DEFAULT) {
return checkPermission(Manifest.permission.SYSTEM_ALERT_WINDOW, callingPid, callingUid)
== PERMISSION_GRANTED;
@@ -2042,8 +2043,8 @@
public int getDisplayId(IBinder activityToken) throws RemoteException {
synchronized (mGlobalLock) {
final ActivityStack stack = ActivityRecord.getStackLocked(activityToken);
- if (stack != null && stack.mDisplayId != INVALID_DISPLAY) {
- return stack.mDisplayId;
+ if (stack != null && stack.getDisplayId() != INVALID_DISPLAY) {
+ return stack.getDisplayId();
}
return DEFAULT_DISPLAY;
}
@@ -3201,7 +3202,7 @@
final ActivityStack stack = r.getActivityStack();
final Task task = stack.createTask(
- mStackSupervisor.getNextTaskIdForUserLocked(r.mUserId), ainfo, intent,
+ mStackSupervisor.getNextTaskIdForUser(r.mUserId), ainfo, intent,
null /* voiceSession */, null /* voiceInteractor */, !ON_TOP);
if (!mRecentTasks.addToBottom(task)) {
// The app has too many tasks already and we can't add any more
@@ -4311,7 +4312,7 @@
if (params.hasSetAspectRatio()
&& !mWindowManager.isValidPictureInPictureAspectRatio(
- r.getActivityStack().mDisplayId, params.getAspectRatio())) {
+ r.getDisplayId(), params.getAspectRatio())) {
final float minAspectRatio = mContext.getResources().getFloat(
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
final float maxAspectRatio = mContext.getResources().getFloat(
@@ -6164,7 +6165,7 @@
final class LocalService extends ActivityTaskManagerInternal {
@Override
public SleepToken acquireSleepToken(String tag, int displayId) {
- Preconditions.checkNotNull(tag);
+ Objects.requireNonNull(tag);
return ActivityTaskManagerService.this.acquireSleepToken(tag, displayId);
}
@@ -6221,7 +6222,7 @@
@Override
public int startActivitiesAsPackage(String packageName, int userId, Intent[] intents,
Bundle bOptions) {
- Preconditions.checkNotNull(intents, "intents");
+ Objects.requireNonNull(intents, "intents");
final String[] resolvedTypes = new String[intents.length];
// UID of the package on user userId.
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 51742b9..896147e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -600,11 +600,6 @@
private final SparseArray<ShellRoot> mShellRoots = new SparseArray<>();
- /**
- * Counter for next free stack ID to use for dynamic activity stacks. Unique across displays.
- */
- private static int sNextFreeStackId = 0;
-
private RootWindowContainer mRootWindowContainer;
/**
@@ -5694,7 +5689,7 @@
@VisibleForTesting
int getNextStackId() {
- return sNextFreeStackId++;
+ return mAtmService.mStackSupervisor.getNextTaskIdForUser();
}
/**
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index d5f403f..999aab9 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -37,6 +37,7 @@
import com.android.internal.util.Preconditions;
import com.android.server.wm.WindowManagerInternal.IDragDropCallback;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -74,7 +75,7 @@
}
void registerCallback(IDragDropCallback callback) {
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(callback);
mCallback.set(callback);
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 255ef6e..a26dfdb 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -276,7 +276,6 @@
display.getDisplayId());
mDragWindowHandle.name = "drag";
mDragWindowHandle.token = mServerChannel.getToken();
- mDragWindowHandle.layer = getDragLayerLocked();
mDragWindowHandle.layoutParamsFlags = 0;
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutNanos =
@@ -345,12 +344,6 @@
}
}
- int getDragLayerLocked() {
- return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_DRAG)
- * WindowManagerService.TYPE_LAYER_MULTIPLIER
- + WindowManagerService.TYPE_LAYER_OFFSET;
- }
-
/* call out to each visible window/session informing it about the drag
*/
void broadcastDragStartedLocked(final float touchX, final float touchY) {
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index ebe9f08..c6183de 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -76,7 +76,6 @@
mWindowHandle.name = name;
mWindowHandle.token = mServerChannel.getToken();
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
- mWindowHandle.layer = getLayerLw(mWindowHandle.layoutParamsType);
mWindowHandle.layoutParamsFlags = 0;
mWindowHandle.dispatchingTimeoutNanos =
WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
@@ -150,12 +149,6 @@
t.setLayer(mInputSurface, layer);
}
- private int getLayerLw(int windowType) {
- return mService.mPolicy.getWindowLayerFromTypeLw(windowType)
- * WindowManagerService.TYPE_LAYER_MULTIPLIER
- + WindowManagerService.TYPE_LAYER_OFFSET;
- }
-
void disposeChannelsLw() {
mService.mInputManager.unregisterInputChannel(mServerChannel);
mClientChannel.dispose();
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index f9ff2e3..b9a9c12 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -264,7 +264,6 @@
inputWindowHandle.hasFocus = hasFocus;
inputWindowHandle.hasWallpaper = hasWallpaper;
inputWindowHandle.paused = child.mActivityRecord != null ? child.mActivityRecord.paused : false;
- inputWindowHandle.layer = child.mLayer;
inputWindowHandle.ownerPid = child.mSession.mPid;
inputWindowHandle.ownerUid = child.mSession.mUid;
inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;
@@ -499,8 +498,7 @@
}
}
- if (mAddInputConsumerHandle
- && inputWindowHandle.layer <= navInputConsumer.mWindowHandle.layer) {
+ if (mAddInputConsumerHandle) {
navInputConsumer.show(mInputTransaction, w);
mAddInputConsumerHandle = false;
}
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 0beae7e..f4e608e 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -222,9 +222,7 @@
private boolean saveTaskToLaunchParam(Task task, PersistableLaunchParams params) {
final ActivityStack stack = task.getStack();
- final int displayId = stack.mDisplayId;
- final DisplayContent display =
- mSupervisor.mRootWindowContainer.getDisplayContent(displayId);
+ final DisplayContent display = stack.getDisplayContent();
final DisplayInfo info = new DisplayInfo();
display.mDisplay.getDisplayInfo(info);
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index a18d541..5df80fc 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1382,7 +1382,7 @@
// Ignore tasks from different displays
// TODO (b/115289124): No Recents on non-default displays.
- if (stack.mDisplayId != DEFAULT_DISPLAY) {
+ if (stack.getDisplayId() != DEFAULT_DISPLAY) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index f78c82b..53d7688 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -135,7 +135,7 @@
+ r + " out to bottom task " + targetTask);
} else {
targetTask = mParent.createTask(
- mParent.mStackSupervisor.getNextTaskIdForUserLocked(r.mUserId),
+ mParent.mStackSupervisor.getNextTaskIdForUser(r.mUserId),
r.info, null /* intent */, null /* voiceSession */,
null /* voiceInteractor */, false /* toTop */);
targetTask.affinityIntent = r.intent;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 5470327..93362b9 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1495,7 +1495,7 @@
// Fallback to top focused display if the displayId is invalid.
if (displayId == INVALID_DISPLAY) {
final ActivityStack stack = getTopDisplayFocusedStack();
- displayId = stack != null ? stack.mDisplayId : DEFAULT_DISPLAY;
+ displayId = stack != null ? stack.getDisplayId() : DEFAULT_DISPLAY;
}
Intent homeIntent = null;
@@ -2148,7 +2148,7 @@
// ensures that all the necessary work to migrate states in the old and new stacks
// is also done.
final Task newTask = task.getStack().createTask(
- mStackSupervisor.getNextTaskIdForUserLocked(r.mUserId), r.info,
+ mStackSupervisor.getNextTaskIdForUser(r.mUserId), r.info,
r.intent, null, null, true);
r.reparent(newTask, MAX_VALUE, "moveActivityToStack");
@@ -2405,11 +2405,10 @@
}
private ActivityManager.StackInfo getStackInfo(ActivityStack stack) {
- final int displayId = stack.mDisplayId;
- final DisplayContent display = getDisplayContent(displayId);
+ final DisplayContent display = stack.getDisplayContent();
ActivityManager.StackInfo info = new ActivityManager.StackInfo();
stack.getBounds(info.bounds);
- info.displayId = displayId;
+ info.displayId = display.mDisplayId;
info.stackId = stack.mStackId;
info.stackToken = stack.mRemoteToken;
info.userId = stack.mCurrentUser;
@@ -2571,7 +2570,7 @@
}
ActivityStack findStackBehind(ActivityStack stack) {
- final DisplayContent display = getDisplayContent(stack.mDisplayId);
+ final DisplayContent display = getDisplayContent(stack.getDisplayId());
if (display != null) {
for (int i = display.getStackCount() - 1; i >= 0; i--) {
if (display.getStackAt(i) == stack && i > 0) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 987ecc5..06af095 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -54,6 +54,7 @@
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.SurfaceControl.METADATA_TASK_ID;
import static com.android.server.am.TaskRecordProto.ACTIVITIES;
@@ -127,7 +128,6 @@
import android.util.DisplayMetrics;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
-import android.view.Display;
import android.view.DisplayInfo;
import android.view.RemoteAnimationTarget;
import android.view.Surface;
@@ -268,9 +268,6 @@
int mLockTaskUid = -1; // The uid of the application that called startLockTask().
- /** Current stack. Setter must always be used to update the value. */
- private ActivityStack mStack;
-
/** The process that had previously hosted the root activity of this task.
* Used to know that we should try harder to keep this process around, in case the
* user wants to return to it. */
@@ -346,7 +343,7 @@
private final Rect mOverrideDisplayedBounds = new Rect();
/** ID of the display which rotation {@link #mRotation} has. */
- private int mLastRotationDisplayId = Display.INVALID_DISPLAY;
+ private int mLastRotationDisplayId = INVALID_DISPLAY;
/**
* Display rotation as of the last time {@link #setBounds(Rect)} was called or this task was
* moved to a new display.
@@ -678,7 +675,7 @@
if (toStack == sourceStack) {
return false;
}
- if (!canBeLaunchedOnDisplay(toStack.mDisplayId)) {
+ if (!canBeLaunchedOnDisplay(toStack.getDisplayId())) {
return false;
}
@@ -959,10 +956,6 @@
mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.mTaskId;
}
- ActivityStack getStack() {
- return mStack;
- }
-
@Override
void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
final ActivityStack oldStack = ((ActivityStack) oldParent);
@@ -973,8 +966,6 @@
cleanUpResourcesForDestroy();
}
- mStack = newStack;
-
super.onParentChanged(newParent, oldParent);
if (oldStack != null) {
@@ -1044,13 +1035,6 @@
mAtmService.mRootWindowContainer.invalidateTaskLayers();
}
- /**
- * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set.
- */
- int getStackId() {
- return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
- }
-
// Close up recents linked list.
private void closeRecentsChain() {
if (mPrevAffiliate != null) {
@@ -1261,7 +1245,7 @@
}
} else if (!mReuseTask) {
// Remove entire task if it doesn't have any activity left and it isn't marked for reuse
- mStack.removeChild(this, reason);
+ getStack().removeChild(this, reason);
EventLogTags.writeWmTaskRemoved(mTaskId,
"removeChild: last r=" + r + " in t=" + this);
removeIfPossible();
@@ -1278,9 +1262,9 @@
return false;
}
if (includeFinishing) {
- return getActivity((r) -> r.mTaskOverlay) != null;
+ return getActivity((r) -> r.isTaskOverlay()) != null;
}
- return getActivity((r) -> !r.finishing && r.mTaskOverlay) != null;
+ return getActivity((r) -> !r.finishing && r.isTaskOverlay()) != null;
}
private boolean autoRemoveFromRecents() {
@@ -1296,7 +1280,7 @@
*/
private void performClearTaskAtIndexLocked(String reason) {
// Broken down into to cases to avoid object create due to capturing mStack.
- if (mStack == null) {
+ if (getStack() == null) {
forAllActivities((r) -> {
if (r.finishing) return;
// Task was restored from persistent storage.
@@ -1525,7 +1509,7 @@
private static boolean setTaskDescriptionFromActivityAboveRoot(
ActivityRecord r, ActivityRecord root, TaskDescription td) {
- if (!r.mTaskOverlay && r.taskDescription != null) {
+ if (!r.isTaskOverlay() && r.taskDescription != null) {
final TaskDescription atd = r.taskDescription;
if (td.getLabel() == null) {
td.setLabel(atd.getLabel());
@@ -1579,11 +1563,10 @@
// If the task has no requested minimal size, we'd like to enforce a minimal size
// so that the user can not render the task too small to manipulate. We don't need
// to do this for the pinned stack as the bounds are controlled by the system.
- if (!inPinnedWindowingMode() && mStack != null) {
+ if (!inPinnedWindowingMode() && getDisplayContent() != null) {
final int defaultMinSizeDp =
mAtmService.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp;
- final DisplayContent display =
- mAtmService.mRootWindowContainer.getDisplayContent(mStack.mDisplayId);
+ final DisplayContent display = getDisplayContent();
final float density =
(float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
final int defaultMinSize = (int) (defaultMinSizeDp * density);
@@ -1820,7 +1803,7 @@
* @param bounds bounds to calculate smallestwidthdp for.
*/
private int getSmallestScreenWidthDpForDockedBounds(Rect bounds) {
- DisplayContent dc = mStack.getDisplay().mDisplayContent;
+ DisplayContent dc = getDisplayContent();
if (dc != null) {
return dc.getDockedDividerController().getSmallestWidthDpForBounds(bounds);
}
@@ -1884,9 +1867,9 @@
if (insideParentBounds && WindowConfiguration.isFloating(windowingMode)) {
mTmpNonDecorBounds.set(mTmpFullBounds);
mTmpStableBounds.set(mTmpFullBounds);
- } else if (insideParentBounds && mStack != null) {
+ } else if (insideParentBounds && getDisplayContent() != null) {
final DisplayInfo di = new DisplayInfo();
- mStack.getDisplay().mDisplay.getDisplayInfo(di);
+ getDisplayContent().mDisplay.getDisplayInfo(di);
// For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
// area, i.e. the screen area without the system bars.
@@ -1997,7 +1980,7 @@
((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
final Rect parentBounds =
new Rect(newParentConfig.windowConfiguration.getBounds());
- final DisplayContent display = mStack.getDisplay();
+ final DisplayContent display = getDisplayContent();
if (display != null && display.mDisplayContent != null) {
// If a freeform window moves below system bar, there is no way to move it again
// by touch. Because its caption is covered by system bar. So we exclude them
@@ -2077,7 +2060,8 @@
/** Updates the task's bounds and override configuration to match what is expected for the
* input stack. */
void updateOverrideConfigurationForStack(ActivityStack inStack) {
- if (mStack != null && mStack == inStack) {
+ final ActivityStack stack = getStack();
+ if (stack != null && stack == inStack) {
return;
}
@@ -2101,7 +2085,8 @@
/** Returns the bounds that should be used to launch this task. */
Rect getLaunchBounds() {
- if (mStack == null) {
+ final ActivityStack stack = getStack();
+ if (stack == null) {
return null;
}
@@ -2109,9 +2094,9 @@
if (!isActivityTypeStandardOrUndefined()
|| windowingMode == WINDOWING_MODE_FULLSCREEN
|| (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
- return isResizeable() ? mStack.getRequestedOverrideBounds() : null;
+ return isResizeable() ? stack.getRequestedOverrideBounds() : null;
} else if (!getWindowConfiguration().persistTaskBounds()) {
- return mStack.getRequestedOverrideBounds();
+ return stack.getRequestedOverrideBounds();
}
return mLastNonFullscreenBounds;
}
@@ -2134,19 +2119,32 @@
@Override
DisplayContent getDisplayContent() {
- return getTaskStack() != null ? getTaskStack().getDisplayContent() : null;
+ return getStack() != null ? getStack().getDisplayContent() : null;
}
- ActivityStack getTaskStack() {
+ int getDisplayId() {
+ final DisplayContent dc = getDisplayContent();
+ return dc != null ? dc.mDisplayId : INVALID_DISPLAY;
+ }
+
+ ActivityStack getStack() {
return (ActivityStack) getParent();
}
+ /**
+ * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set.
+ */
+ int getStackId() {
+ final ActivityStack stack = getStack();
+ return stack != null ? stack.mStackId : INVALID_STACK_ID;
+ }
+
// TODO(task-hierarchy): Needs to take a generic WindowManager when task contains other tasks.
int getAdjustedAddPosition(ActivityRecord r, int suggestedPosition) {
int maxPosition = mChildren.size();
- if (!r.mTaskOverlay) {
+ if (!r.isTaskOverlay()) {
// We want to place all non-overlay activities below overlays.
- final ActivityRecord bottomMostOverlay = getActivity((ar) -> ar.mTaskOverlay, false);
+ final ActivityRecord bottomMostOverlay = getActivity((ar) -> ar.isTaskOverlay(), false);
if (bottomMostOverlay != null) {
maxPosition = Math.max(mChildren.indexOf(bottomMostOverlay) - 1, 0);
}
@@ -2171,7 +2169,7 @@
// No reason to defer removal of a Task that doesn't have any child.
return false;
}
- return hasWindowsAlive() && getTaskStack().isAnimating(TRANSITION | CHILDREN);
+ return hasWindowsAlive() && getStack().isAnimating(TRANSITION | CHILDREN);
}
@Override
@@ -2184,7 +2182,7 @@
// TODO: Consolidate this with Task.reparent()
void reparent(ActivityStack stack, int position, boolean moveParents, String reason) {
if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
- + " from stack=" + getTaskStack());
+ + " from stack=" + getStack());
EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask:" + reason);
position = stack.findPositionForTask(this, position, showForAllUsers());
@@ -2214,8 +2212,8 @@
@Override
public int setBounds(Rect bounds) {
int rotation = Surface.ROTATION_0;
- final DisplayContent displayContent = getTaskStack() != null
- ? getTaskStack().getDisplayContent() : null;
+ final DisplayContent displayContent = getStack() != null
+ ? getStack().getDisplayContent() : null;
if (displayContent != null) {
rotation = displayContent.getDisplayInfo().rotation;
} else if (bounds == null) {
@@ -2256,7 +2254,7 @@
void onDisplayChanged(DisplayContent dc) {
adjustBoundsForDisplayChangeIfNeeded(dc);
super.onDisplayChanged(dc);
- final int displayId = (dc != null) ? dc.getDisplayId() : Display.INVALID_DISPLAY;
+ final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY;
mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged(
mTaskId, displayId);
}
@@ -2401,7 +2399,7 @@
/** Bounds of the task to be used for dimming, as well as touch related tests. */
public void getDimBounds(Rect out) {
- final DisplayContent displayContent = getTaskStack().getDisplayContent();
+ final DisplayContent displayContent = getStack().getDisplayContent();
// It doesn't matter if we in particular are part of the resize, since we couldn't have
// a DimLayer anyway if we weren't visible.
final boolean dockedResizing = displayContent != null
@@ -2424,9 +2422,9 @@
// stack bounds and so we don't even want to use them. Even if the app should not be
// resized the Dim should keep up with the divider.
if (dockedResizing) {
- getTaskStack().getBounds(out);
+ getStack().getBounds(out);
} else {
- getTaskStack().getBounds(mTmpRect);
+ getStack().getBounds(mTmpRect);
mTmpRect.intersect(getBounds());
out.set(mTmpRect);
}
@@ -2439,9 +2437,9 @@
void setDragResizing(boolean dragResizing, int dragResizeMode) {
if (mDragResizing != dragResizing) {
// No need to check if the mode is allowed if it's leaving dragResize
- if (dragResizing && !DragResizeMode.isModeAllowedForStack(getTaskStack(), dragResizeMode)) {
+ if (dragResizing && !DragResizeMode.isModeAllowedForStack(getStack(), dragResizeMode)) {
throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
- + getTaskStack().mStackId + " dragResizeMode=" + dragResizeMode);
+ + getStack().mStackId + " dragResizeMode=" + dragResizeMode);
}
mDragResizing = dragResizing;
mDragResizeMode = dragResizeMode;
@@ -2532,7 +2530,7 @@
*/
boolean isFloating() {
return getWindowConfiguration().tasksAreFloating()
- && !getTaskStack().isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState;
+ && !getStack().isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState;
}
@Override
@@ -2770,7 +2768,7 @@
info.userId = mUserId;
info.stackId = getStackId();
info.taskId = mTaskId;
- info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
+ info.displayId = getDisplayId();
info.isRunning = getTopNonFinishingActivity() != null;
info.baseIntent = new Intent(getBaseIntent());
info.baseActivity = mReuseActivitiesReport.base != null
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index b8f3abe..e6757e1 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -316,8 +316,8 @@
ActivityStack stack =
(displayId == INVALID_DISPLAY && task != null) ? task.getStack() : null;
if (stack != null) {
- if (DEBUG) appendLog("display-from-task=" + stack.mDisplayId);
- displayId = stack.mDisplayId;
+ if (DEBUG) appendLog("display-from-task=" + stack.getDisplayId());
+ displayId = stack.getDisplayId();
}
if (displayId == INVALID_DISPLAY && source != null) {
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index 8cff99b..20af250 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -339,7 +339,7 @@
+ userTasksDir.getAbsolutePath());
} else {
// Looks fine.
- mStackSupervisor.setNextTaskIdForUserLocked(taskId, userId);
+ mStackSupervisor.setNextTaskIdForUser(taskId, userId);
task.isPersistable = true;
tasks.add(task);
recoveredTaskIds.add(taskId);
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index a867a5d4..8bbb0d7 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -274,7 +274,6 @@
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, display.getDisplayId());
mDragWindowHandle.name = TAG;
mDragWindowHandle.token = mServerChannel.getToken();
- mDragWindowHandle.layer = mService.getDragLayerLocked();
mDragWindowHandle.layoutParamsFlags = 0;
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutNanos =
@@ -450,7 +449,7 @@
}
// This is a moving or scrolling operation.
- mTask.getTaskStack().getDimBounds(mTmpRect);
+ mTask.getStack().getDimBounds(mTmpRect);
// If a target window is covered by system bar, there is no way to move it again by touch.
// So we exclude them from stack bounds. and then it will be shown inside stable area.
Rect stableBounds = new Rect();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 5c02f46..62630a6 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1323,12 +1323,12 @@
if (includeOverlays) {
return getActivity((r) -> true);
}
- return getActivity((r) -> !r.mTaskOverlay);
+ return getActivity((r) -> !r.isTaskOverlay());
} else if (includeOverlays) {
return getActivity((r) -> !r.finishing);
}
- return getActivity((r) -> !r.finishing && !r.mTaskOverlay);
+ return getActivity((r) -> !r.finishing && !r.isTaskOverlay());
}
void forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index 74d5c04..b0c5dbc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -19,8 +19,6 @@
import static android.provider.AndroidDeviceConfig.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE;
import static android.provider.AndroidDeviceConfig.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import android.provider.AndroidDeviceConfig;
import android.provider.DeviceConfig;
@@ -28,6 +26,7 @@
import com.android.server.wm.utils.DeviceConfigInterface;
import java.io.PrintWriter;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -74,8 +73,8 @@
WindowManagerConstants(WindowManagerGlobalLock globalLock,
Runnable updateSystemGestureExclusionCallback,
DeviceConfigInterface deviceConfig) {
- mGlobalLock = checkNotNull(globalLock);
- mUpdateSystemGestureExclusionCallback = checkNotNull(updateSystemGestureExclusionCallback);
+ mGlobalLock = Objects.requireNonNull(globalLock);
+ mUpdateSystemGestureExclusionCallback = Objects.requireNonNull(updateSystemGestureExclusionCallback);
mDeviceConfig = deviceConfig;
mListenerAndroid = this::onAndroidPropertiesChanged;
mListenerWindowManager = this::onWindowPropertiesChanged;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ab3419c..8a91d9e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -59,7 +59,6 @@
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
@@ -297,6 +296,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -630,10 +630,6 @@
boolean mDisableTransitionAnimation;
- int getDragLayerLocked() {
- return mPolicy.getWindowLayerFromTypeLw(TYPE_DRAG) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
- }
-
class RotationWatcher {
final IRotationWatcher mWatcher;
final IBinder.DeathRecipient mDeathRecipient;
@@ -2869,7 +2865,7 @@
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires DISABLE_KEYGUARD permission");
}
- Preconditions.checkNotNull(token, "token is null");
+ Objects.requireNonNull(token, "token is null");
final int callingUid = Binder.getCallingUid();
final long origIdentity = Binder.clearCallingIdentity();
try {
@@ -4345,7 +4341,7 @@
final DisplayContent topFocusedDisplay = mRoot.getTopFocusedDisplayContent();
final ActivityRecord focusedApp = topFocusedDisplay.mFocusedApp;
return (focusedApp != null && focusedApp.getTask() != null)
- ? focusedApp.getTask().getTaskStack() : null;
+ ? focusedApp.getTask().getStack() : null;
}
public boolean detectSafeMode() {
@@ -7664,7 +7660,7 @@
return;
}
- final ActivityStack stack = task.getTaskStack();
+ final ActivityStack stack = task.getStack();
// We ignore home stack since we don't want home stack to move to front when touched.
// Specifically, in freeform we don't want tapping on home to cause the freeform apps to go
// behind home. See b/117376413
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index bb7c26c..b681923 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1287,7 +1287,7 @@
// notify the client of frame changes in this case. Not only is it a lot of churn, but
// the frame may not correspond to the surface size or the onscreen area at various
// phases in the animation, and the client will become sad and confused.
- if (task != null && task.getTaskStack().isAnimatingBounds()) {
+ if (task != null && task.getStack().isAnimatingBounds()) {
return;
}
@@ -1427,8 +1427,8 @@
ActivityStack getStack() {
Task task = getTask();
if (task != null) {
- if (task.getTaskStack() != null) {
- return task.getTaskStack();
+ if (task.getStack() != null) {
+ return task.getStack();
}
}
// Some system windows (e.g. "Power off" dialog) don't have a task, but we would still
@@ -1447,7 +1447,7 @@
bounds.setEmpty();
mTmpRect.setEmpty();
if (intersectWithStackBounds) {
- final ActivityStack stack = task.getTaskStack();
+ final ActivityStack stack = task.getStack();
if (stack != null) {
stack.getDimBounds(mTmpRect);
} else {
@@ -1879,8 +1879,8 @@
final int top = mWindowFrames.mFrame.top;
final Task task = getTask();
final boolean adjustedForMinimizedDockOrIme = task != null
- && (task.getTaskStack().isAdjustedForMinimizedDockedStack()
- || task.getTaskStack().isAdjustedForIme());
+ && (task.getStack().isAdjustedForMinimizedDockedStack()
+ || task.getStack().isAdjustedForIme());
if (mToken.okToAnimate()
&& (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
&& !isDragResizing() && !adjustedForMinimizedDockOrIme
@@ -1916,7 +1916,7 @@
boolean isObscuringDisplay() {
Task task = getTask();
- if (task != null && task.getTaskStack() != null && !task.getTaskStack().fillsParent()) {
+ if (task != null && task.getStack() != null && !task.getStack().fillsParent()) {
return false;
}
return isOpaqueDrawn() && fillsDisplay();
@@ -2349,8 +2349,8 @@
void applyAdjustForImeIfNeeded() {
final Task task = getTask();
- if (task != null && task.getTaskStack() != null && task.getTaskStack().isAdjustedForIme()) {
- task.getTaskStack().applyAdjustForImeIfNeeded(task);
+ if (task != null && task.getStack() != null && task.getStack().isAdjustedForIme()) {
+ task.getStack().applyAdjustForImeIfNeeded(task);
}
}
@@ -2694,7 +2694,7 @@
return false;
}
- return mActivityRecord.getTask().getTaskStack().shouldIgnoreInput()
+ return mActivityRecord.getTask().getStack().shouldIgnoreInput()
|| !mActivityRecord.mVisibleRequested
|| isRecentsAnimationConsumingAppInput();
}
@@ -3214,7 +3214,7 @@
return;
}
- final ActivityStack stack = task.getTaskStack();
+ final ActivityStack stack = task.getStack();
if (stack == null) {
return;
}
@@ -3228,7 +3228,7 @@
return;
}
- final ActivityStack stack = task.getTaskStack();
+ final ActivityStack stack = task.getStack();
if (stack == null) {
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 175fccb..1a11766 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -888,10 +888,10 @@
int posX = 0;
int posY = 0;
- task.getTaskStack().getDimBounds(mTmpStackBounds);
+ task.getStack().getDimBounds(mTmpStackBounds);
boolean allowStretching = false;
- task.getTaskStack().getFinalAnimationSourceHintBounds(mTmpSourceBounds);
+ task.getStack().getFinalAnimationSourceHintBounds(mTmpSourceBounds);
// If we don't have source bounds, we can attempt to use the content insets
// in the following scenario:
// 1. We have content insets.
@@ -901,8 +901,8 @@
// because of the force-scale until resize state.
if (mTmpSourceBounds.isEmpty() && (mWin.mLastRelayoutContentInsets.width() > 0
|| mWin.mLastRelayoutContentInsets.height() > 0)
- && !task.getTaskStack().lastAnimatingBoundsWasToFullscreen()) {
- mTmpSourceBounds.set(task.getTaskStack().mPreAnimationBounds);
+ && !task.getStack().lastAnimatingBoundsWasToFullscreen()) {
+ mTmpSourceBounds.set(task.getStack().mPreAnimationBounds);
mTmpSourceBounds.inset(mWin.mLastRelayoutContentInsets);
allowStretching = true;
}
@@ -916,7 +916,7 @@
if (!mTmpSourceBounds.isEmpty()) {
// Get the final target stack bounds, if we are not animating, this is just the
// current stack bounds
- task.getTaskStack().getFinalAnimationBounds(mTmpAnimatingBounds);
+ task.getStack().getFinalAnimationBounds(mTmpAnimatingBounds);
// Calculate the current progress and interpolate the difference between the target
// and source bounds
@@ -1495,7 +1495,7 @@
*/
boolean isForceScaled() {
final Task task = mWin.getTask();
- if (task != null && task.getTaskStack().isForceScaled()) {
+ if (task != null && task.getStack().isForceScaled()) {
return true;
}
return mForceScaleUntilResize;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1536816..272edf7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -303,6 +303,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -2266,23 +2267,23 @@
@VisibleForTesting
DevicePolicyManagerService(Injector injector) {
mInjector = injector;
- mContext = Preconditions.checkNotNull(injector.mContext);
- mHandler = new Handler(Preconditions.checkNotNull(injector.getMyLooper()));
+ mContext = Objects.requireNonNull(injector.mContext);
+ mHandler = new Handler(Objects.requireNonNull(injector.getMyLooper()));
mConstantsObserver = new DevicePolicyConstantsObserver(mHandler);
mConstantsObserver.register();
mConstants = loadConstants();
- mOwners = Preconditions.checkNotNull(injector.newOwners());
+ mOwners = Objects.requireNonNull(injector.newOwners());
- mUserManager = Preconditions.checkNotNull(injector.getUserManager());
- mUserManagerInternal = Preconditions.checkNotNull(injector.getUserManagerInternal());
- mUsageStatsManagerInternal = Preconditions.checkNotNull(
+ mUserManager = Objects.requireNonNull(injector.getUserManager());
+ mUserManagerInternal = Objects.requireNonNull(injector.getUserManagerInternal());
+ mUsageStatsManagerInternal = Objects.requireNonNull(
injector.getUsageStatsManagerInternal());
- mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
- mIPlatformCompat = Preconditions.checkNotNull(injector.getIPlatformCompat());
- mIPermissionManager = Preconditions.checkNotNull(injector.getIPermissionManager());
- mTelephonyManager = Preconditions.checkNotNull(injector.getTelephonyManager());
+ mIPackageManager = Objects.requireNonNull(injector.getIPackageManager());
+ mIPlatformCompat = Objects.requireNonNull(injector.getIPlatformCompat());
+ mIPermissionManager = Objects.requireNonNull(injector.getIPermissionManager());
+ mTelephonyManager = Objects.requireNonNull(injector.getTelephonyManager());
mLocalService = new LocalService();
mLockPatternUtils = injector.newLockPatternUtils();
@@ -4047,7 +4048,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(adminReceiver, "ComponentName is null");
+ Objects.requireNonNull(adminReceiver, "ComponentName is null");
enforceShell("forceRemoveActiveAdmin");
mInjector.binderWithCleanCallingIdentity(() -> {
synchronized (getLockObject()) {
@@ -4164,7 +4165,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
validateQualityConstant(quality);
final int userId = mInjector.userHandleGetCallingUserId();
@@ -4377,7 +4378,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4419,7 +4420,7 @@
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4451,7 +4452,7 @@
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkArgumentNonnegative(timeout, "Timeout must be >= 0 ms");
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
@@ -4633,7 +4634,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
final ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4663,7 +4664,7 @@
@Override
public void setPasswordMinimumLowerCase(ComponentName who, int length, boolean parent) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4696,7 +4697,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4728,7 +4729,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4760,7 +4761,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4792,7 +4793,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -5019,7 +5020,7 @@
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
// This API can only be called by an active device admin,
@@ -5259,7 +5260,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
final ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -5360,7 +5361,7 @@
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkArgument(timeoutMs >= 0, "Timeout must not be a negative number.");
// timeoutMs with value 0 means that the admin doesn't participate
// timeoutMs is clamped to the interval in case the internal constants change in the future
@@ -6108,7 +6109,7 @@
@Override
public void setDelegatedScopes(ComponentName who, String delegatePackage,
List<String> scopeList) throws SecurityException {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkStringNotEmpty(delegatePackage, "Delegate package is null or empty");
Preconditions.checkCollectionElementsNotNull(scopeList, "Scopes");
// Remove possible duplicates.
@@ -6206,7 +6207,7 @@
@NonNull
public List<String> getDelegatedScopes(ComponentName who,
String delegatePackage) throws SecurityException {
- Preconditions.checkNotNull(delegatePackage, "Delegate package is null");
+ Objects.requireNonNull(delegatePackage, "Delegate package is null");
// Retrieve the user ID of the calling process.
final int callingUid = mInjector.binderGetCallingUid();
@@ -6246,8 +6247,8 @@
@NonNull
public List<String> getDelegatePackages(ComponentName who, String scope)
throws SecurityException {
- Preconditions.checkNotNull(who, "ComponentName is null");
- Preconditions.checkNotNull(scope, "Scope is null");
+ Objects.requireNonNull(who, "ComponentName is null");
+ Objects.requireNonNull(scope, "Scope is null");
if (!Arrays.asList(DELEGATIONS).contains(scope)) {
throw new IllegalArgumentException("Unexpected delegation scope: " + scope);
}
@@ -6329,7 +6330,7 @@
* @return {@code true} if the calling process is a delegate of {@code scope}.
*/
private boolean isCallerDelegate(String callerPackage, int callerUid, String scope) {
- Preconditions.checkNotNull(callerPackage, "callerPackage is null");
+ Objects.requireNonNull(callerPackage, "callerPackage is null");
if (!Arrays.asList(DELEGATIONS).contains(scope)) {
throw new IllegalArgumentException("Unexpected delegation scope: " + scope);
}
@@ -6410,7 +6411,7 @@
*/
private void setDelegatedScopePreO(ComponentName who,
String delegatePackage, String scope) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
@@ -6938,7 +6939,7 @@
return null;
}
synchronized (getLockObject()) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
// Only check if system user has set global proxy. We don't allow other users to set it.
DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
@@ -7066,7 +7067,7 @@
if (!mHasFeature) {
return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userHandle = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
// Check for permissions
@@ -7220,7 +7221,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userHandle = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
@@ -7287,7 +7288,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userHandle = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -7347,7 +7348,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
// TODO (b/145286957) Refactor security checks
enforceDeviceOwnerOrProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
@@ -7369,7 +7370,7 @@
if (!mHasFeature) {
return false;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
enforceDeviceOwnerOrProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
return mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) > 0;
@@ -7383,7 +7384,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
// TODO (b/145286957) Refactor security checks
enforceDeviceOwnerOrProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
@@ -7405,7 +7406,7 @@
if (!mHasFeature) {
return false;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
enforceDeviceOwnerOrProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
return mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) > 0;
@@ -7416,7 +7417,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
// Allow setting this policy to true only if there is a split system user.
if (forceEphemeralUsers && !mInjector.userManagerIsSplitSystemUser()) {
throw new UnsupportedOperationException(
@@ -7443,7 +7444,7 @@
if (!mHasFeature) {
return false;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
final ActiveAdmin deviceOwner =
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
@@ -7472,7 +7473,7 @@
if (!mHasFeature) {
return false;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
// TODO: If an unaffiliated user is removed, the admin will be able to request a bugreport
// which could still contain data related to that user. Should we disallow that, e.g. until
@@ -7709,7 +7710,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
@@ -7779,7 +7780,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userHandle = mInjector.userHandleGetCallingUserId();
if (isManagedProfile(userHandle)) {
if (parent) {
@@ -7867,7 +7868,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(packageList, "packageList is null");
+ Objects.requireNonNull(packageList, "packageList is null");
final int userHandle = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
// Ensure the caller is a DO or a keep uninstalled packages delegate.
@@ -8104,7 +8105,7 @@
@Override
public void clearDeviceOwner(String packageName) {
- Preconditions.checkNotNull(packageName, "packageName is null");
+ Objects.requireNonNull(packageName, "packageName is null");
final int callingUid = mInjector.binderGetCallingUid();
try {
int uid = mInjector.getPackageManager().getPackageUidAsUser(packageName,
@@ -8259,7 +8260,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userId = mInjector.userHandleGetCallingUserId();
enforceNotManagedProfile(userId, "clear profile owner");
@@ -8300,7 +8301,7 @@
@Override
public void setDeviceOwnerLockScreenInfo(ComponentName who, CharSequence info) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
if (!mHasFeature) {
return;
}
@@ -8470,7 +8471,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
// Check if this is the profile owner who is calling
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8497,7 +8498,7 @@
@Override
public void setProfileName(ComponentName who, String profileName) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
enforceProfileOrDeviceOwner(who);
final int userId = UserHandle.getCallingUserId();
@@ -9090,7 +9091,7 @@
@Override
public void addPersistentPreferredActivity(ComponentName who, IntentFilter filter,
ComponentName activity) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userHandle = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -9116,7 +9117,7 @@
@Override
public void clearPackagePersistentPreferredActivities(ComponentName who, String packageName) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userHandle = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -9135,7 +9136,7 @@
@Override
public void setDefaultSmsApplication(ComponentName admin, String packageName) {
- Preconditions.checkNotNull(admin, "ComponentName is null");
+ Objects.requireNonNull(admin, "ComponentName is null");
enforceDeviceOwner(admin);
mInjector.binderWithCleanCallingIdentity(() ->
SmsApplication.setDefaultApplication(packageName, mContext));
@@ -9190,8 +9191,8 @@
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return;
}
- Preconditions.checkNotNull(admin, "admin is null");
- Preconditions.checkNotNull(agent, "agent is null");
+ Objects.requireNonNull(admin, "admin is null");
+ Objects.requireNonNull(agent, "agent is null");
final int userHandle = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(admin,
@@ -9207,7 +9208,7 @@
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return null;
}
- Preconditions.checkNotNull(agent, "agent null");
+ Objects.requireNonNull(agent, "agent null");
enforceFullCrossUsersPermission(userHandle);
synchronized (getLockObject()) {
@@ -9259,7 +9260,7 @@
@Override
public void setRestrictionsProvider(ComponentName who, ComponentName permissionProvider) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -9281,7 +9282,7 @@
@Override
public void addCrossProfileIntentFilter(ComponentName who, IntentFilter filter, int flags) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
int callingUserId = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -9330,7 +9331,7 @@
@Override
public void clearCrossProfileIntentFilters(ComponentName who) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
int callingUserId = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -9407,7 +9408,7 @@
if (!mHasFeature) {
return false;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
if (packageList != null) {
int userId = UserHandle.getCallingUserId();
@@ -9460,7 +9461,7 @@
if (!mHasFeature) {
return null;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -9536,7 +9537,7 @@
if (!mHasFeature) {
return true;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkStringNotEmpty(packageName, "packageName is null");
enforceSystemCaller("query if an accessibility service is disabled by admin");
@@ -9587,7 +9588,7 @@
if (!mHasFeature) {
return false;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int callingUserId = mInjector.userHandleGetCallingUserId();
if (packageList != null) {
List<InputMethodInfo> enabledImes = InputMethodManagerInternal.get()
@@ -9627,7 +9628,7 @@
if (!mHasFeature) {
return null;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -9681,7 +9682,7 @@
if (!mHasFeature) {
return true;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkStringNotEmpty(packageName, "packageName is null");
enforceSystemCaller("query if an input method is disabled by admin");
@@ -9704,7 +9705,7 @@
if (!mHasFeature) {
return false;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int callingUserId = mInjector.userHandleGetCallingUserId();
if (!isManagedProfile(callingUserId)) {
@@ -9725,7 +9726,7 @@
if (!mHasFeature) {
return null;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForCallerLocked(
@@ -9787,8 +9788,8 @@
@Override
public UserHandle createAndManageUser(ComponentName admin, String name,
ComponentName profileOwner, PersistableBundle adminExtras, int flags) {
- Preconditions.checkNotNull(admin, "admin is null");
- Preconditions.checkNotNull(profileOwner, "profileOwner is null");
+ Objects.requireNonNull(admin, "admin is null");
+ Objects.requireNonNull(profileOwner, "profileOwner is null");
if (!admin.getPackageName().equals(profileOwner.getPackageName())) {
throw new IllegalArgumentException("profileOwner " + profileOwner + " and admin "
+ admin + " are not in the same package");
@@ -9919,8 +9920,8 @@
@Override
public boolean removeUser(ComponentName who, UserHandle userHandle) {
- Preconditions.checkNotNull(who, "ComponentName is null");
- Preconditions.checkNotNull(userHandle, "UserHandle is null");
+ Objects.requireNonNull(who, "ComponentName is null");
+ Objects.requireNonNull(userHandle, "UserHandle is null");
enforceDeviceOwner(who);
final int callingUserId = mInjector.userHandleGetCallingUserId();
@@ -9953,7 +9954,7 @@
@Override
public boolean switchUser(ComponentName who, UserHandle userHandle) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
@@ -9976,8 +9977,8 @@
@Override
public int startUserInBackground(ComponentName who, UserHandle userHandle) {
- Preconditions.checkNotNull(who, "ComponentName is null");
- Preconditions.checkNotNull(userHandle, "UserHandle is null");
+ Objects.requireNonNull(who, "ComponentName is null");
+ Objects.requireNonNull(userHandle, "UserHandle is null");
enforceDeviceOwner(who);
final int userId = userHandle.getIdentifier();
@@ -10008,8 +10009,8 @@
@Override
public int stopUser(ComponentName who, UserHandle userHandle) {
- Preconditions.checkNotNull(who, "ComponentName is null");
- Preconditions.checkNotNull(userHandle, "UserHandle is null");
+ Objects.requireNonNull(who, "ComponentName is null");
+ Objects.requireNonNull(userHandle, "UserHandle is null");
enforceDeviceOwner(who);
final int userId = userHandle.getIdentifier();
@@ -10023,7 +10024,7 @@
@Override
public int logoutUser(ComponentName who) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int callingUserId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
@@ -10077,7 +10078,7 @@
@Override
public List<UserHandle> getSecondaryUsers(ComponentName who) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
enforceDeviceOwner(who);
return mInjector.binderWithCleanCallingIdentity(() -> {
@@ -10096,7 +10097,7 @@
@Override
public boolean isEphemeralUser(ComponentName who) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
enforceProfileOrDeviceOwner(who);
final int callingUserId = mInjector.userHandleGetCallingUserId();
@@ -10178,7 +10179,7 @@
@Override
public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner,
boolean parent) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
if (!UserRestrictionsUtils.isValidRestriction(key)) {
return;
}
@@ -10324,7 +10325,7 @@
if (!mHasFeature) {
return null;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
final ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(who,
@@ -10559,7 +10560,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10653,7 +10654,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10674,7 +10675,7 @@
if (!mHasFeature) {
return false;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10696,7 +10697,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10717,7 +10718,7 @@
if (!mHasFeature) {
return false;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10797,7 +10798,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10818,7 +10819,7 @@
if (!mHasFeature) {
return false;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10840,8 +10841,8 @@
@Override
public void setLockTaskPackages(ComponentName who, String[] packages)
throws SecurityException {
- Preconditions.checkNotNull(who, "ComponentName is null");
- Preconditions.checkNotNull(packages, "packages is null");
+ Objects.requireNonNull(who, "ComponentName is null");
+ Objects.requireNonNull(packages, "packages is null");
synchronized (getLockObject()) {
enforceCanCallLockTaskLocked(who);
@@ -10861,7 +10862,7 @@
@Override
public String[] getLockTaskPackages(ComponentName who) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
synchronized (getLockObject()) {
@@ -10881,7 +10882,7 @@
@Override
public void setLockTaskFeatures(ComponentName who, int flags) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
// Throw if Overview is used without Home.
boolean hasHome = (flags & LOCK_TASK_FEATURE_HOME) != 0;
@@ -10908,7 +10909,7 @@
@Override
public int getLockTaskFeatures(ComponentName who) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
enforceCanCallLockTaskLocked(who);
@@ -10978,7 +10979,7 @@
@Override
public void setGlobalSetting(ComponentName who, String setting, String value) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_GLOBAL_SETTING)
@@ -11018,7 +11019,7 @@
@Override
public void setSystemSetting(ComponentName who, String setting, String value) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkStringNotEmpty(setting, "String setting is null or empty");
synchronized (getLockObject()) {
@@ -11038,7 +11039,7 @@
@Override
public void setLocationEnabled(ComponentName who, boolean locationEnabled) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
enforceDeviceOwner(who);
UserHandle userHandle = mInjector.binderGetCallingUserHandle();
@@ -11057,7 +11058,7 @@
@Override
public boolean setTime(ComponentName who, long millis) {
- Preconditions.checkNotNull(who, "ComponentName is null in setTime");
+ Objects.requireNonNull(who, "ComponentName is null in setTime");
enforceDeviceOwner(who);
// Don't allow set time when auto time is on.
if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) == 1) {
@@ -11072,7 +11073,7 @@
@Override
public boolean setTimeZone(ComponentName who, String timeZone) {
- Preconditions.checkNotNull(who, "ComponentName is null in setTimeZone");
+ Objects.requireNonNull(who, "ComponentName is null in setTimeZone");
enforceDeviceOwner(who);
// Don't allow set timezone when auto timezone is on.
if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) == 1) {
@@ -11088,7 +11089,7 @@
@Override
public void setSecureSetting(ComponentName who, String setting, String value) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
int callingUserId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
@@ -11159,7 +11160,7 @@
@Override
public void setMasterVolumeMuted(ComponentName who, boolean on) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
setUserRestriction(who, UserManager.DISALLOW_UNMUTE_DEVICE, on, /* parent */ false);
@@ -11173,7 +11174,7 @@
@Override
public boolean isMasterVolumeMuted(ComponentName who) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -11186,7 +11187,7 @@
@Override
public void setUserIcon(ComponentName who, Bitmap icon) {
synchronized (getLockObject()) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
int userId = UserHandle.getCallingUserId();
@@ -11201,7 +11202,7 @@
@Override
public boolean setKeyguardDisabled(ComponentName who, boolean disabled) {
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -11664,7 +11665,7 @@
@Override
public Intent createAdminSupportIntent(String restriction) {
- Preconditions.checkNotNull(restriction);
+ Objects.requireNonNull(restriction);
final int uid = mInjector.binderGetCallingUid();
final int userId = UserHandle.getUserId(uid);
Intent intent = null;
@@ -11922,7 +11923,7 @@
@Override
public SystemUpdateInfo getPendingSystemUpdate(ComponentName admin) {
- Preconditions.checkNotNull(admin, "ComponentName is null");
+ Objects.requireNonNull(admin, "ComponentName is null");
enforceProfileOrDeviceOwner(admin);
return mOwners.getSystemUpdateInfo();
@@ -11964,7 +11965,7 @@
public void setPermissionGrantState(ComponentName admin, String callerPackage,
String packageName, String permission, int grantState, RemoteCallback callback)
throws RemoteException {
- Preconditions.checkNotNull(callback);
+ Objects.requireNonNull(callback);
UserHandle user = mInjector.binderGetCallingUserHandle();
synchronized (getLockObject()) {
@@ -12099,7 +12100,7 @@
@Override
public boolean isProvisioningAllowed(String action, String packageName) {
- Preconditions.checkNotNull(packageName);
+ Objects.requireNonNull(packageName);
final int callingUid = mInjector.binderGetCallingUid();
final long ident = mInjector.binderClearCallingIdentity();
@@ -12119,7 +12120,7 @@
@Override
public int checkProvisioningPreCondition(String action, String packageName) {
- Preconditions.checkNotNull(packageName);
+ Objects.requireNonNull(packageName);
enforceCanManageProfileAndDeviceOwners();
return checkProvisioningPreConditionSkipPermission(action, packageName);
}
@@ -12359,7 +12360,7 @@
@Override
public void reboot(ComponentName admin) {
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
// Make sure caller has DO.
enforceDeviceOwner(admin);
mInjector.binderWithCleanCallingIdentity(() -> {
@@ -12380,7 +12381,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForUidLocked(who, mInjector.binderGetCallingUid());
@@ -12400,7 +12401,7 @@
if (!mHasFeature) {
return null;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForUidLocked(who, mInjector.binderGetCallingUid());
return admin.shortSupportMessage;
@@ -12412,7 +12413,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForUidLocked(who, mInjector.binderGetCallingUid());
@@ -12432,7 +12433,7 @@
if (!mHasFeature) {
return null;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForUidLocked(who, mInjector.binderGetCallingUid());
return admin.longSupportMessage;
@@ -12444,7 +12445,7 @@
if (!mHasFeature) {
return null;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
enforceSystemCaller("query support message for user");
synchronized (getLockObject()) {
@@ -12461,7 +12462,7 @@
if (!mHasFeature) {
return null;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
enforceSystemCaller("query support message for user");
synchronized (getLockObject()) {
@@ -12478,7 +12479,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userHandle = mInjector.userHandleGetCallingUserId();
enforceManagedProfile(userHandle, "set organization color");
synchronized (getLockObject()) {
@@ -12513,7 +12514,7 @@
if (!mHasFeature) {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization color");
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -12542,7 +12543,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
@@ -12561,7 +12562,7 @@
if (!mHasFeature) {
return null;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization name");
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -12599,8 +12600,8 @@
@Override
public List<String> setMeteredDataDisabledPackages(ComponentName who, List<String> packageNames) {
- Preconditions.checkNotNull(who);
- Preconditions.checkNotNull(packageNames);
+ Objects.requireNonNull(who);
+ Objects.requireNonNull(packageNames);
if (!mHasFeature) {
return packageNames;
@@ -12646,7 +12647,7 @@
@Override
public List<String> getMeteredDataDisabledPackages(ComponentName who) {
- Preconditions.checkNotNull(who);
+ Objects.requireNonNull(who);
if (!mHasFeature) {
return new ArrayList<>();
@@ -12662,7 +12663,7 @@
@Override
public boolean isMeteredDataDisabledPackageForUser(ComponentName who,
String packageName, int userId) {
- Preconditions.checkNotNull(who);
+ Objects.requireNonNull(who);
if (!mHasFeature) {
return false;
@@ -12688,7 +12689,7 @@
public void markProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId) {
// As the caller is the system, it must specify the component name of the profile owner
// as a sanity / safety check.
- Preconditions.checkNotNull(who);
+ Objects.requireNonNull(who);
if (!mHasFeature) {
return;
@@ -12808,7 +12809,7 @@
return Collections.emptyList();
}
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
return new ArrayList<String>(
@@ -12877,7 +12878,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
@@ -12907,7 +12908,7 @@
synchronized (getLockObject()) {
if (!isCallerWithSystemUid()) {
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
}
return mInjector.securityLogGetLoggingEnabledProperty();
@@ -12931,7 +12932,7 @@
return null;
}
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
ensureDeviceOwnerAndAllUsersAffiliated(admin);
DevicePolicyEventLogger
@@ -12961,7 +12962,7 @@
return null;
}
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
ensureDeviceOwnerAndAllUsersAffiliated(admin);
if (!mInjector.securityLogGetLoggingEnabledProperty()) {
@@ -13206,7 +13207,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
enforceProfileOrDeviceOwner(admin);
int userId = mInjector.userHandleGetCallingUserId();
toggleBackupServiceActive(userId, enabled);
@@ -13214,7 +13215,7 @@
@Override
public boolean isBackupServiceEnabled(ComponentName admin) {
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
if (!mHasFeature) {
return true;
}
@@ -13239,14 +13240,14 @@
if (!mHasFeature) {
return false;
}
- Preconditions.checkNotNull(admin);
- Preconditions.checkNotNull(caller);
- Preconditions.checkNotNull(serviceIntent);
+ Objects.requireNonNull(admin);
+ Objects.requireNonNull(caller);
+ Objects.requireNonNull(serviceIntent);
Preconditions.checkArgument(
serviceIntent.getComponent() != null || serviceIntent.getPackage() != null,
"Service intent must be explicit (with a package name or component): "
+ serviceIntent);
- Preconditions.checkNotNull(connection);
+ Objects.requireNonNull(connection);
Preconditions.checkArgument(mInjector.userHandleGetCallingUserId() != targetUserId,
"target user id must be different from the calling user id");
@@ -13290,7 +13291,7 @@
if (!mHasFeature) {
return Collections.emptyList();
}
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -13755,7 +13756,7 @@
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return false;
}
- Preconditions.checkNotNull(token);
+ Objects.requireNonNull(token);
synchronized (getLockObject()) {
final int userHandle = mInjector.userHandleGetCallingUserId();
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -13791,9 +13792,9 @@
@Override
public void clearApplicationUserData(ComponentName admin, String packageName,
IPackageDataObserver callback) {
- Preconditions.checkNotNull(admin, "ComponentName is null");
- Preconditions.checkNotNull(packageName, "packageName is null");
- Preconditions.checkNotNull(callback, "callback is null");
+ Objects.requireNonNull(admin, "ComponentName is null");
+ Objects.requireNonNull(packageName, "packageName is null");
+ Objects.requireNonNull(callback, "callback is null");
enforceProfileOrDeviceOwner(admin);
final int userId = UserHandle.getCallingUserId();
@@ -13824,7 +13825,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
synchronized (getLockObject()) {
ActiveAdmin deviceOwner =
@@ -13865,8 +13866,8 @@
return;
}
- Preconditions.checkNotNull(admin, "Admin cannot be null.");
- Preconditions.checkNotNull(target, "Target cannot be null.");
+ Objects.requireNonNull(admin, "Admin cannot be null.");
+ Objects.requireNonNull(target, "Target cannot be null.");
enforceProfileOrDeviceOwner(admin);
@@ -14001,7 +14002,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
final String startUserSessionMessageString =
startUserSessionMessage != null ? startUserSessionMessage.toString() : null;
@@ -14026,7 +14027,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
final String endUserSessionMessageString =
endUserSessionMessage != null ? endUserSessionMessage.toString() : null;
@@ -14051,7 +14052,7 @@
if (!mHasFeature) {
return null;
}
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
synchronized (getLockObject()) {
final ActiveAdmin deviceOwner =
@@ -14065,7 +14066,7 @@
if (!mHasFeature) {
return null;
}
- Preconditions.checkNotNull(admin);
+ Objects.requireNonNull(admin);
synchronized (getLockObject()) {
final ActiveAdmin deviceOwner =
@@ -14108,8 +14109,8 @@
if (!mHasFeature || !mHasTelephonyFeature) {
return -1;
}
- Preconditions.checkNotNull(who, "ComponentName is null in addOverrideApn");
- Preconditions.checkNotNull(apnSetting, "ApnSetting is null in addOverrideApn");
+ Objects.requireNonNull(who, "ComponentName is null in addOverrideApn");
+ Objects.requireNonNull(apnSetting, "ApnSetting is null in addOverrideApn");
enforceDeviceOwner(who);
int operatedId = -1;
@@ -14132,8 +14133,8 @@
if (!mHasFeature || !mHasTelephonyFeature) {
return false;
}
- Preconditions.checkNotNull(who, "ComponentName is null in updateOverrideApn");
- Preconditions.checkNotNull(apnSetting, "ApnSetting is null in updateOverrideApn");
+ Objects.requireNonNull(who, "ComponentName is null in updateOverrideApn");
+ Objects.requireNonNull(apnSetting, "ApnSetting is null in updateOverrideApn");
enforceDeviceOwner(who);
if (apnId < 0) {
@@ -14150,7 +14151,7 @@
if (!mHasFeature || !mHasTelephonyFeature) {
return false;
}
- Preconditions.checkNotNull(who, "ComponentName is null in removeOverrideApn");
+ Objects.requireNonNull(who, "ComponentName is null in removeOverrideApn");
enforceDeviceOwner(who);
return removeOverrideApnUnchecked(apnId);
@@ -14171,7 +14172,7 @@
if (!mHasFeature || !mHasTelephonyFeature) {
return Collections.emptyList();
}
- Preconditions.checkNotNull(who, "ComponentName is null in getOverrideApns");
+ Objects.requireNonNull(who, "ComponentName is null in getOverrideApns");
enforceDeviceOwner(who);
return getOverrideApnsUnchecked();
@@ -14202,7 +14203,7 @@
if (!mHasFeature || !mHasTelephonyFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null in setOverrideApnEnabled");
+ Objects.requireNonNull(who, "ComponentName is null in setOverrideApnEnabled");
enforceDeviceOwner(who);
setOverrideApnsEnabledUnchecked(enabled);
@@ -14220,7 +14221,7 @@
if (!mHasFeature || !mHasTelephonyFeature) {
return false;
}
- Preconditions.checkNotNull(who, "ComponentName is null in isOverrideApnEnabled");
+ Objects.requireNonNull(who, "ComponentName is null in isOverrideApnEnabled");
enforceDeviceOwner(who);
Cursor enforceCursor = mInjector.binderWithCleanCallingIdentity(
@@ -14304,7 +14305,7 @@
return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
enforceDeviceOwner(who);
final int returnCode;
@@ -14342,7 +14343,7 @@
return PRIVATE_DNS_MODE_UNKNOWN;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
enforceDeviceOwner(who);
String currentMode = mInjector.settingsGlobalGetString(PRIVATE_DNS_MODE);
if (currentMode == null) {
@@ -14366,7 +14367,7 @@
return null;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
enforceDeviceOwner(who);
return mInjector.settingsGlobalGetString(PRIVATE_DNS_SPECIFIER);
@@ -14404,7 +14405,7 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
final ActiveAdmin admin = getActiveAdminForCallerLocked(
@@ -14425,7 +14426,7 @@
if (!mHasFeature) {
return Collections.emptyList();
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
final ActiveAdmin admin = getActiveAdminForCallerLocked(
@@ -14479,8 +14480,8 @@
if (!mHasFeature) {
return;
}
- Preconditions.checkNotNull(who, "ComponentName is null");
- Preconditions.checkNotNull(packageNames, "Package names is null");
+ Objects.requireNonNull(who, "ComponentName is null");
+ Objects.requireNonNull(packageNames, "Package names is null");
synchronized (getLockObject()) {
final ActiveAdmin admin =
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -14494,7 +14495,7 @@
if (!mHasFeature) {
return Collections.emptyList();
}
- Preconditions.checkNotNull(who, "ComponentName is null");
+ Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
final ActiveAdmin admin = getActiveAdminForCallerLocked(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
index dd3bfc3..4b66bea 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
@@ -39,6 +39,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.Objects;
/**
* Handles reading and writing of the owner transfer metadata file.
@@ -185,8 +186,8 @@
@NonNull int userId, @NonNull String adminType) {
this.sourceComponent = sourceComponent;
this.targetComponent = targetComponent;
- Preconditions.checkNotNull(sourceComponent);
- Preconditions.checkNotNull(targetComponent);
+ Objects.requireNonNull(sourceComponent);
+ Objects.requireNonNull(targetComponent);
Preconditions.checkStringNotEmpty(adminType);
this.userId = userId;
this.adminType = adminType;
@@ -199,7 +200,7 @@
}
private static ComponentName unflattenComponentUnchecked(String flatComponent) {
- Preconditions.checkNotNull(flatComponent);
+ Objects.requireNonNull(flatComponent);
return ComponentName.unflattenFromString(flatComponent);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 529339e..0504d14 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -48,6 +48,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.parsing.AndroidPackage;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
@@ -68,6 +69,7 @@
import org.mockito.quality.Strictness;
import java.io.File;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -138,11 +140,15 @@
.spyStatic(Settings.Global.class)
.startMocking();
- // Mock LocalServices.getService(PackageManagerInternal.class).getApplicationInfo dependency
+ // Mock LocalServices.getService(PackageManagerInternal.class).getPackage dependency
// needed by AppOpsService
PackageManagerInternal mockPackageManagerInternal = mock(PackageManagerInternal.class);
- when(mockPackageManagerInternal.getApplicationInfo(eq(sMyPackageName), anyInt(), anyInt(),
- anyInt())).thenReturn(sContext.getApplicationInfo());
+ AndroidPackage mockMyPkg = mock(AndroidPackage.class);
+ when(mockMyPkg.isPrivileged()).thenReturn(false);
+ when(mockMyPkg.getUid()).thenReturn(mMyUid);
+ when(mockMyPkg.getFeatures()).thenReturn(Collections.emptyList());
+
+ when(mockPackageManagerInternal.getPackage(sMyPackageName)).thenReturn(mockMyPkg);
doReturn(mockPackageManagerInternal).when(
() -> LocalServices.getService(PackageManagerInternal.class));
@@ -162,12 +168,12 @@
mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED);
// Note an op that's allowed.
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
List<PackageOps> loggedOps = getLoggedOps();
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
// Note another op that's not allowed.
- mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null);
+ mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null, false, null);
loggedOps = getLoggedOps();
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
@@ -183,16 +189,16 @@
// This op controls WIFI_SCAN
mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ALLOWED);
- assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null))
- .isEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null, false,
+ null)).isEqualTo(MODE_ALLOWED);
assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, -1,
MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
// Now set COARSE_LOCATION to ERRORED -> this will make WIFI_SCAN disabled as well.
mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ERRORED);
- assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null))
- .isEqualTo(MODE_ERRORED);
+ assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null, false,
+ null)).isEqualTo(MODE_ERRORED);
assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, mTestStartMillis,
MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
@@ -203,8 +209,8 @@
public void testStatePersistence() {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED);
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
- mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
+ mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null, false, null);
mAppOpsService.writeState();
// Create a new app ops service, and initialize its state from XML.
@@ -221,7 +227,7 @@
@Test
public void testShutdown() {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
mAppOpsService.shutdown();
// Create a new app ops service, and initialize its state from XML.
@@ -236,7 +242,7 @@
@Test
public void testGetOpsForPackage() {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
// Query all ops
List<PackageOps> loggedOps = mAppOpsService.getOpsForPackage(
@@ -265,7 +271,7 @@
@Test
public void testPackageRemoved() {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
List<PackageOps> loggedOps = getLoggedOps();
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
@@ -278,7 +284,7 @@
@Test
public void testPackageRemovedHistoricalOps() throws InterruptedException {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
AppOpsManager.HistoricalOps historicalOps = new AppOpsManager.HistoricalOps(0, 15000);
historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, sMyPackageName,
@@ -317,7 +323,7 @@
@Test
public void testUidRemoved() {
mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
List<PackageOps> loggedOps = getLoggedOps();
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
@@ -340,13 +346,13 @@
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
ActivityManager.PROCESS_CAPABILITY_NONE);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isNotEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isNotEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP,
ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
ActivityManager.PROCESS_CAPABILITY_NONE);
@@ -354,8 +360,8 @@
Thread.sleep(50);
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
ActivityManager.PROCESS_CAPABILITY_NONE);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isNotEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isNotEqualTo(MODE_ALLOWED);
}
@Test
@@ -363,13 +369,13 @@
setupProcStateTests();
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
ActivityManager.PROCESS_CAPABILITY_NONE);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isNotEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isNotEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
ActivityManager.PROCESS_CAPABILITY_NONE);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isNotEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isNotEqualTo(MODE_ALLOWED);
}
@Test
@@ -378,13 +384,13 @@
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
ActivityManager.PROCESS_CAPABILITY_NONE);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isNotEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isNotEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isEqualTo(MODE_ALLOWED);
}
@Test
@@ -393,13 +399,13 @@
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
ActivityManager.PROCESS_CAPABILITY_NONE);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isNotEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isNotEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP,
ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
ActivityManager.PROCESS_CAPABILITY_NONE);
@@ -407,8 +413,8 @@
Thread.sleep(50);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
ActivityManager.PROCESS_CAPABILITY_NONE);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isNotEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isNotEqualTo(MODE_ALLOWED);
}
@Test
@@ -417,13 +423,13 @@
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
ActivityManager.PROCESS_CAPABILITY_NONE);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isNotEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isNotEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP,
ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
@@ -431,8 +437,8 @@
Thread.sleep(50);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
ActivityManager.PROCESS_CAPABILITY_NONE);
@@ -440,8 +446,8 @@
Thread.sleep(50);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
ActivityManager.PROCESS_CAPABILITY_NONE);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
- .isNotEqualTo(MODE_ALLOWED);
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+ false, null)).isNotEqualTo(MODE_ALLOWED);
}
private List<PackageOps> getLoggedOps() {
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index d34f783..bbc6bdb 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -26,6 +26,11 @@
<option name="test-file-name" value="SimpleServiceTestApp.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="AppIntegrityManagerServiceTestApp.apk->/data/local/tmp/AppIntegrityManagerServiceTestApp.apk" />
+ </target_preparer>
+
<option name="test-tag" value="FrameworksServicesTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.frameworks.servicestests" />
diff --git a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/test.apk b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/test.apk
deleted file mode 100644
index 6345c98..0000000
--- a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/test.apk
+++ /dev/null
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 2ce17a1..f8bcff5 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -485,7 +485,7 @@
@Test
public void testDispatchUids_dispatchNeededChanges() throws RemoteException {
when(mAppOpsService.noteOperation(AppOpsManager.OP_GET_USAGE_STATS, Process.myUid(), null,
- null)).thenReturn(AppOpsManager.MODE_ALLOWED);
+ null, false, null)).thenReturn(AppOpsManager.MODE_ALLOWED);
final int[] changesToObserve = {
ActivityManager.UID_OBSERVER_PROCSTATE,
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
index 17e5832..09a6819 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -17,7 +17,6 @@
import com.google.common.base.Objects;
-import com.android.internal.util.Preconditions;
import com.android.server.pm.UserRestrictionsUtils;
import android.content.ComponentName;
@@ -107,7 +106,7 @@
}
public static Bundle checkUserRestrictions(String... keys) {
- final Bundle expected = DpmTestUtils.newRestrictions(Preconditions.checkNotNull(keys));
+ final Bundle expected = DpmTestUtils.newRestrictions(java.util.Objects.requireNonNull(keys));
final Matcher<Bundle> m = new BaseMatcher<Bundle>() {
@Override
public boolean matches(Object item) {
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index a2376a6..604efc4 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -32,6 +32,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -64,7 +65,6 @@
import com.android.server.integrity.model.IntegrityCheckResult;
import com.android.server.testutils.TestUtils;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -75,9 +75,6 @@
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -86,7 +83,8 @@
/** Unit test for {@link com.android.server.integrity.AppIntegrityManagerServiceImpl} */
@RunWith(AndroidJUnit4.class)
public class AppIntegrityManagerServiceImplTest {
- private static final String TEST_DIR = "AppIntegrityManagerServiceImplTest";
+ private static final String TEST_APP_PATH =
+ "/data/local/tmp/AppIntegrityManagerServiceTestApp.apk";
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
private static final String VERSION = "version";
@@ -97,13 +95,19 @@
private static final String INSTALLER = TEST_FRAMEWORK_PACKAGE;
// These are obtained by running the test and checking logcat.
private static final String APP_CERT =
- "949ADC6CB92FF09E3784D6E9504F26F9BEAC06E60D881D55A6A81160F9CD6FD1";
+ "301AA3CB081134501C45F1422ABC66C24224FD5DED5FDC8F17E697176FD866AA";
private static final String INSTALLER_CERT =
"301AA3CB081134501C45F1422ABC66C24224FD5DED5FDC8F17E697176FD866AA";
// We use SHA256 for package names longer than 32 characters.
private static final String INSTALLER_SHA256 =
"786933C28839603EB48C50B2A688DC6BE52C833627CB2731FF8466A2AE9F94CD";
+ private static final String PLAY_STORE_PKG = "com.android.vending";
+ private static final String ADB_INSTALLER = "adb";
+ private static final String PLAY_STORE_CERT =
+ "play_store_cert";
+ private static final String ADB_CERT = "";
+
@org.junit.Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock PackageManagerInternal mPackageManagerInternal;
@@ -122,11 +126,7 @@
@Before
public void setup() throws Exception {
- mTestApk = File.createTempFile("TestApk", /* suffix= */ null);
- mTestApk.deleteOnExit();
- try (InputStream inputStream = mRealContext.getAssets().open(TEST_DIR + "/test.apk")) {
- Files.copy(inputStream, mTestApk.toPath(), StandardCopyOption.REPLACE_EXISTING);
- }
+ mTestApk = new File(TEST_APP_PATH);
mService =
new AppIntegrityManagerServiceImpl(
@@ -141,11 +141,7 @@
when(mMockContext.getPackageManager()).thenReturn(mSpyPackageManager);
when(mMockContext.getResources()).thenReturn(mMockResources);
when(mMockResources.getStringArray(anyInt())).thenReturn(new String[] {});
- }
-
- @After
- public void tearDown() throws Exception {
- mTestApk.delete();
+ when(mIntegrityFileManager.initialized()).thenReturn(true);
}
// This is not a test of the class, but more of a safeguard that we don't block any install in
@@ -310,10 +306,10 @@
assertEquals(INSTALLER_CERT, appInstallMetadata.getInstallerCertificate());
assertEquals(VERSION_CODE, appInstallMetadata.getVersionCode());
assertFalse(appInstallMetadata.isPreInstalled());
- // These are hardcoded in the test apk
+ // These are hardcoded in the test apk android manifest
assertEquals(2, allowedInstallers.size());
- assertEquals("cert_1", allowedInstallers.get("store_1"));
- assertEquals("cert_2", allowedInstallers.get("store_2"));
+ assertEquals(PLAY_STORE_CERT, allowedInstallers.get(PLAY_STORE_PKG));
+ assertEquals(ADB_CERT, allowedInstallers.get(ADB_INSTALLER));
}
@Test
@@ -356,6 +352,25 @@
1, PackageManagerInternal.INTEGRITY_VERIFICATION_REJECT);
}
+ @Test
+ public void handleBroadcast_notInitialized() throws Exception {
+ when(mIntegrityFileManager.initialized()).thenReturn(false);
+ ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mMockContext)
+ .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
+ Intent intent = makeVerificationIntent();
+ when(mRuleEvaluationEngine.evaluate(any(), any())).thenReturn(IntegrityCheckResult.allow());
+
+ broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
+ runJobInHandler();
+
+ verify(mPackageManagerInternal)
+ .setIntegrityVerificationResult(
+ 1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
+ verify(mSpyPackageManager, never()).getPackageArchiveInfo(any(), anyInt());
+ }
+
private void whitelistUsAsRuleProvider() {
Resources mockResources = mock(Resources.class);
when(mockResources.getStringArray(R.array.config_integrityRuleProviderPackages))
diff --git a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
new file mode 100644
index 0000000..63189e7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasItems;
+import static org.junit.Assert.assertThat;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import android.content.integrity.AppInstallMetadata;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.AtomicFormula.IntAtomicFormula;
+import android.content.integrity.AtomicFormula.StringAtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Rule;
+import android.util.Slog;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.integrity.parser.RuleXmlParser;
+import com.android.server.integrity.serializer.RuleXmlSerializer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/** Unit test for {@link IntegrityFileManager} */
+@RunWith(AndroidJUnit4.class)
+public class IntegrityFileManagerTest {
+ private static final String TAG = "IntegrityFileManagerTest";
+
+ private static final String VERSION = "version";
+ private static final String RULE_PROVIDER = "rule_provider";
+
+ private File mTmpDir;
+
+ // under test
+ private IntegrityFileManager mIntegrityFileManager;
+
+ @Before
+ public void setUp() throws Exception {
+ mTmpDir = Files.createTempDirectory("IntegrityFileManagerTest").toFile();
+ Slog.i(TAG, "Using temp directory " + mTmpDir);
+
+ // Use Xml Parser/Serializer to help with debugging since we can just print the file.
+ mIntegrityFileManager =
+ new IntegrityFileManager(
+ new RuleXmlParser(), new RuleXmlSerializer(), mTmpDir);
+ Files.walk(mTmpDir.toPath())
+ .forEach(
+ path -> {
+ Slog.i(TAG, "before " + path);
+ });
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Files.walk(mTmpDir.toPath())
+ .forEach(
+ path -> {
+ Slog.i(TAG, "after " + path);
+ });
+ // Sorting paths in reverse order guarantees that we delete inside files before deleting
+ // directory.
+ Files.walk(mTmpDir.toPath())
+ .sorted(Comparator.reverseOrder())
+ .map(Path::toFile)
+ .forEach(File::delete);
+ }
+
+ @Test
+ public void testGetMetadata() throws Exception {
+ assertNull(mIntegrityFileManager.readMetadata());
+ mIntegrityFileManager.writeRules(VERSION, RULE_PROVIDER, Collections.EMPTY_LIST);
+
+ assertNotNull(mIntegrityFileManager.readMetadata());
+ assertEquals(VERSION, mIntegrityFileManager.readMetadata().getVersion());
+ assertEquals(RULE_PROVIDER, mIntegrityFileManager.readMetadata().getRuleProvider());
+ }
+
+ @Test
+ public void testGetRules() throws Exception {
+ String packageName = "package";
+ String packageCert = "cert";
+ int version = 123;
+ Rule packageNameRule =
+ new Rule(
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ packageName,
+ /* isHashedValue= */ false),
+ Rule.DENY);
+ Rule packageCertRule =
+ new Rule(
+ new StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE,
+ packageCert,
+ /* isHashedValue= */ false),
+ Rule.DENY);
+ Rule versionCodeRule =
+ new Rule(
+ new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, version),
+ Rule.DENY);
+ Rule randomRule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.OR,
+ Arrays.asList(
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "abc",
+ /* isHashedValue= */ false),
+ new IntAtomicFormula(
+ AtomicFormula.VERSION_CODE,
+ AtomicFormula.LE,
+ version))),
+ Rule.DENY);
+ // We will test the specifics of indexing in other classes. Here, we just require that all
+ // rules that are related to the given AppInstallMetadata are returned and do not assert
+ // anything on other rules.
+ List<Rule> rules =
+ Arrays.asList(packageNameRule, packageCertRule, versionCodeRule, randomRule);
+ mIntegrityFileManager.writeRules(VERSION, RULE_PROVIDER, rules);
+
+ AppInstallMetadata appInstallMetadata = new AppInstallMetadata.Builder()
+ .setPackageName(packageName)
+ .setAppCertificate(packageCert)
+ .setVersionCode(version)
+ .setInstallerName("abc")
+ .setInstallerCertificate("abc")
+ .setIsPreInstalled(true)
+ .build();
+ List<Rule> rulesFetched = mIntegrityFileManager.readRules(appInstallMetadata);
+
+ assertThat(rulesFetched, hasItems(
+ equalTo(packageNameRule),
+ equalTo(packageCertRule),
+ equalTo(versionCodeRule)
+ ));
+ }
+
+ @Test
+ public void testIsInitialized() throws Exception {
+ assertFalse(mIntegrityFileManager.initialized());
+ mIntegrityFileManager.writeRules(VERSION, RULE_PROVIDER, Collections.EMPTY_LIST);
+ assertTrue(mIntegrityFileManager.initialized());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java
index 94e11c6..55fada4 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java
@@ -38,8 +38,10 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.TreeMap;
/** Unit tests for {@link RuleIndexingDetailsIdentifier}. */
@RunWith(JUnit4.class)
@@ -138,14 +140,16 @@
List<Rule> ruleList = new ArrayList();
ruleList.add(RULE_WITH_PACKAGE_NAME);
- Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList);
+ Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
// Verify the resulting map content.
assertThat(result.keySet())
.containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
assertThat(result.get(NOT_INDEXED)).isEmpty();
assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty();
- assertThat(result.get(PACKAGE_NAME_INDEXED)).containsExactly(RULE_WITH_PACKAGE_NAME);
+ assertThat(result.get(PACKAGE_NAME_INDEXED).keySet()).containsExactly(SAMPLE_PACKAGE_NAME);
+ assertThat(result.get(PACKAGE_NAME_INDEXED).get(SAMPLE_PACKAGE_NAME))
+ .containsExactly(RULE_WITH_PACKAGE_NAME);
}
@Test
@@ -153,13 +157,16 @@
List<Rule> ruleList = new ArrayList();
ruleList.add(RULE_WITH_APP_CERTIFICATE);
- Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList);
+ Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
assertThat(result.keySet())
.containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
assertThat(result.get(NOT_INDEXED)).isEmpty();
assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty();
- assertThat(result.get(APP_CERTIFICATE_INDEXED)).containsExactly(RULE_WITH_APP_CERTIFICATE);
+ assertThat(result.get(APP_CERTIFICATE_INDEXED).keySet())
+ .containsExactly(SAMPLE_APP_CERTIFICATE);
+ assertThat(result.get(APP_CERTIFICATE_INDEXED).get(SAMPLE_APP_CERTIFICATE))
+ .containsExactly(RULE_WITH_APP_CERTIFICATE);
}
@Test
@@ -167,13 +174,14 @@
List<Rule> ruleList = new ArrayList();
ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS);
- Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList);
+ Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
assertThat(result.keySet())
.containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty();
assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty();
- assertThat(result.get(NOT_INDEXED)).containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS);
+ assertThat(result.get(NOT_INDEXED).get("N/A"))
+ .containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS);
}
@Test
@@ -181,13 +189,14 @@
List<Rule> ruleList = new ArrayList();
ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS);
- Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList);
+ Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
assertThat(result.keySet())
.containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty();
assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty();
- assertThat(result.get(NOT_INDEXED)).containsExactly(RULE_WITH_NONSTRING_RESTRICTIONS);
+ assertThat(result.get(NOT_INDEXED).get("N/A"))
+ .containsExactly(RULE_WITH_NONSTRING_RESTRICTIONS);
}
@Test
@@ -206,13 +215,13 @@
List<Rule> ruleList = new ArrayList();
ruleList.add(negatedRule);
- Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList);
+ Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
assertThat(result.keySet())
.containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty();
assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty();
- assertThat(result.get(NOT_INDEXED)).containsExactly(negatedRule);
+ assertThat(result.get(NOT_INDEXED).get("N/A")).containsExactly(negatedRule);
}
@Test
@@ -234,22 +243,36 @@
ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS);
ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS);
- Map<Integer, List<Rule>> result = splitRulesIntoIndexBuckets(ruleList);
+ Map<Integer, TreeMap<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
assertThat(result.keySet())
.containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
// We check asserts this way to ensure ordering based on package name.
- assertThat(result.get(PACKAGE_NAME_INDEXED).get(0)).isEqualTo(packageNameRuleA);
- assertThat(result.get(PACKAGE_NAME_INDEXED).get(1)).isEqualTo(packageNameRuleB);
- assertThat(result.get(PACKAGE_NAME_INDEXED).get(2)).isEqualTo(packageNameRuleC);
+ assertThat(result.get(PACKAGE_NAME_INDEXED).keySet()).containsExactly("aaa", "bbb", "ccc");
+ Iterator<String> keySetIterator = result.get(PACKAGE_NAME_INDEXED).keySet().iterator();
+ assertThat(keySetIterator.next()).isEqualTo("aaa");
+ assertThat(keySetIterator.next()).isEqualTo("bbb");
+ assertThat(keySetIterator.next()).isEqualTo("ccc");
+ assertThat(result.get(PACKAGE_NAME_INDEXED).get("aaa")).containsExactly(packageNameRuleA);
+ assertThat(result.get(PACKAGE_NAME_INDEXED).get("bbb")).containsExactly(packageNameRuleB);
+ assertThat(result.get(PACKAGE_NAME_INDEXED).get("ccc")).containsExactly(packageNameRuleC);
// We check asserts this way to ensure ordering based on app certificate.
- assertThat(result.get(APP_CERTIFICATE_INDEXED).get(0)).isEqualTo(certificateRule1);
- assertThat(result.get(APP_CERTIFICATE_INDEXED).get(1)).isEqualTo(certificateRule2);
- assertThat(result.get(APP_CERTIFICATE_INDEXED).get(2)).isEqualTo(certificateRule3);
+ assertThat(result.get(APP_CERTIFICATE_INDEXED).keySet()).containsExactly("cert1", "cert2",
+ "cert3");
+ keySetIterator = result.get(APP_CERTIFICATE_INDEXED).keySet().iterator();
+ assertThat(keySetIterator.next()).isEqualTo("cert1");
+ assertThat(keySetIterator.next()).isEqualTo("cert2");
+ assertThat(keySetIterator.next()).isEqualTo("cert3");
+ assertThat(result.get(APP_CERTIFICATE_INDEXED).get("cert1")).containsExactly(
+ certificateRule1);
+ assertThat(result.get(APP_CERTIFICATE_INDEXED).get("cert2")).containsExactly(
+ certificateRule2);
+ assertThat(result.get(APP_CERTIFICATE_INDEXED).get("cert3")).containsExactly(
+ certificateRule3);
- assertThat(result.get(NOT_INDEXED))
+ assertThat(result.get(NOT_INDEXED).get("N/A"))
.containsExactly(
RULE_WITH_INSTALLER_RESTRICTIONS,
RULE_WITH_NONSTRING_RESTRICTIONS);
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index f9fc3a1..41416f1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -88,7 +88,6 @@
import android.util.Log;
import android.util.Pair;
-import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.pm.LauncherAppsService.LauncherAppsImpl;
@@ -114,6 +113,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
@@ -1241,7 +1241,7 @@
protected void setCaller(String packageName, int userId) {
mInjectedClientPackage = packageName;
mInjectedCallingUid =
- Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false),
+ Objects.requireNonNull(getInjectedPackageInfo(packageName, userId, false),
"Unknown package").applicationInfo.uid;
// Set up LauncherApps for this caller.
diff --git a/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/Android.bp b/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/Android.bp
new file mode 100644
index 0000000..9aaa37d
--- /dev/null
+++ b/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/Android.bp
@@ -0,0 +1,21 @@
+// Copyright (C) 2017 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.
+
+android_test_helper_app {
+ name: "AppIntegrityManagerServiceTestApp",
+
+ test_suites: ["device-tests"],
+
+ certificate: "platform",
+}
diff --git a/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..f5dbf43
--- /dev/null
+++ b/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 Google Inc.
+ *
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.appintegritymanager.test.app"
+ android:versionCode="5000">
+
+ <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="28" />
+
+ <application android:hasCode="false">
+ <meta-data android:name="allowed-installers" android:value="com.android.vending|play_store_cert,adb|"/>
+ </application>
+</manifest>
+
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index c24ce2b..4e4020b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -236,7 +236,7 @@
// Overlay must be for a different user to prevent recognizing a matching top activity
final ActivityRecord taskOverlay = new ActivityBuilder(mService).setTask(task)
.setUid(UserHandle.PER_USER_RANGE * 2).build();
- taskOverlay.mTaskOverlay = true;
+ taskOverlay.setTaskOverlay(true);
final RootWindowContainer.FindTaskResult result =
new RootWindowContainer.FindTaskResult();
@@ -865,7 +865,7 @@
.setComponent(new ComponentName("package.overlay", ".OverlayActivity")).build();
// If the task only remains overlay activity, the task should also be removed.
// See {@link ActivityStack#removeFromHistory}.
- overlayActivity.mTaskOverlay = true;
+ overlayActivity.setTaskOverlay(true);
// The activity without an app means it will be removed immediately.
// See {@link ActivityStack#destroyActivityLocked}.
@@ -893,7 +893,7 @@
// Making the first activity a task overlay means it will be removed from the task's
// activities as well once second activity is removed as handleAppDied processes the
// activity list in reverse.
- firstActivity.mTaskOverlay = true;
+ firstActivity.setTaskOverlay(true);
firstActivity.app = null;
// second activity will be immediately removed as it has no state.
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index fc94c5e..8c2b293 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -61,7 +61,7 @@
public void setUpOnDisplay(DisplayContent dc) {
mActivity = createTestActivityRecord(dc, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD);
mTask = mActivity.getTask();
- mStack = mTask.getTaskStack();
+ mStack = mTask.getStack();
// Set a remote animator with snapshot disabled. Snapshots don't work in wmtests.
RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 0758eeb..73dd2df 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -126,7 +126,7 @@
waitUntilHandlersIdle();
exitingApp.mIsExiting = true;
- exitingApp.getTask().getTaskStack().mExitingActivities.add(exitingApp);
+ exitingApp.getTask().getStack().mExitingActivities.add(exitingApp);
assertForAllWindowsOrder(Arrays.asList(
mWallpaperWindow,
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index 31b658a..cf1f0a8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -424,7 +424,7 @@
void saveTask(Task task) {
final int userId = task.mUserId;
final ComponentName realActivity = task.realActivity;
- mTmpParams.mPreferredDisplayId = task.getStack().mDisplayId;
+ mTmpParams.mPreferredDisplayId = task.getDisplayId();
mTmpParams.mWindowingMode = task.getWindowingMode();
if (task.mLastNonFullscreenBounds != null) {
mTmpParams.mBounds.set(task.mLastNonFullscreenBounds);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 55a139a..79f808e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -421,6 +421,7 @@
@Test
public void testUsersTasks() {
mRecentTasks.setOnlyTestVisibleRange();
+ mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_0_ID);
// Setup some tasks for the users
mTaskPersister.mUserTaskIdsOverride = new SparseBooleanArray();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 9f092835..04d79ca 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -857,7 +857,7 @@
// Assert that the stack is returned as expected.
assertNotNull(result);
assertEquals("The display ID of the stack should same as secondary display ",
- secondaryDisplay.mDisplayId, result.mDisplayId);
+ secondaryDisplay.mDisplayId, result.getDisplayId());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index f90eca3..e27c724 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -433,7 +433,7 @@
doReturn(aos).when(this).getAppOpsService();
// Make sure permission checks aren't overridden.
doReturn(AppOpsManager.MODE_DEFAULT).when(aos).noteOperation(anyInt(), anyInt(),
- anyString(), nullable(String.class));
+ anyString(), nullable(String.class), anyBoolean(), nullable(String.class));
// UserManagerService
final UserManagerService ums = mock(UserManagerService.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 9f2bfa7..9562fa4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -345,6 +345,7 @@
spyOn(parentWindowContainer);
parentWindowContainer.setBounds(fullScreenBounds);
doReturn(parentWindowContainer).when(task).getParent();
+ doReturn(stack).when(task).getStack();
doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant();
// Setting app to fixed portrait fits within parent, but Task shouldn't adjust the
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 6c3410a..b4f5751 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -110,12 +110,12 @@
public void testStackRemoveImmediately() {
final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
final Task task = createTaskInStack(stack, 0 /* userId */);
- assertEquals(stack, task.getTaskStack());
+ assertEquals(stack, task.getStack());
// Remove stack and check if its child is also removed.
stack.removeImmediately();
assertNull(stack.getDisplayContent());
- assertNull(task.getTaskStack());
+ assertNull(task.getStack());
}
@Test
@@ -131,7 +131,7 @@
assertEquals(0, stack.getChildCount());
assertNull(stack.getDisplayContent());
assertNull(task.getDisplayContent());
- assertNull(task.getTaskStack());
+ assertNull(task.getStack());
}
@Test
diff --git a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
new file mode 100644
index 0000000..b75510b
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
@@ -0,0 +1,255 @@
+/*
+ * 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.google.android.startop.iorap;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.util.Log;
+
+import com.android.server.wm.ActivityMetricsLaunchObserver;
+
+/**
+ * A validator to check the correctness of event sequence during app startup.
+ *
+ * <p> A valid state transition of event sequence is shown as the following:
+ *
+ * <pre>
+ *
+ * +--------------------+
+ * | |
+ * | INIT |
+ * | |
+ * +--------------------+
+ * |
+ * |
+ * ↓
+ * +--------------------+
+ * | |
+ * +-------------------| INTENT_STARTED | ←--------------------------------+
+ * | | | |
+ * | +--------------------+ |
+ * | | |
+ * | | |
+ * ↓ ↓ |
+ * +--------------------+ +--------------------+ |
+ * | | | | |
+ * | INTENT_FAILED | | ACTIVITY_LAUNCHED |------------------+ |
+ * | | | | | |
+ * +--------------------+ +--------------------+ | |
+ * | | | |
+ * | ↓ ↓ |
+ * | +--------------------+ +--------------------+ |
+ * | | | | | |
+ * +------------------ | ACTIVITY_FINISHED | | ACTIVITY_CANCELLED | |
+ * | | | | | |
+ * | +--------------------+ +--------------------+ |
+ * | | | |
+ * | | | |
+ * | ↓ | |
+ * | +--------------------+ | |
+ * | | | | |
+ * | | REPORT_FULLY_DRAWN | | |
+ * | | | | |
+ * | +--------------------+ | |
+ * | | | |
+ * | | | |
+ * | ↓ | |
+ * | +--------------------+ | |
+ * | | | | |
+ * +-----------------→ | END |←-----------------+ |
+ * | | |
+ * +--------------------+ |
+ * | |
+ * | |
+ * | |
+ * +---------------------------------------------
+ *
+ * <p> END is not a real state in implementation. All states that points to END directly
+ * could transition to INTENT_STARTED.
+ *
+ * <p> If any bad transition happened, the state becomse UNKNOWN. The UNKNOWN state
+ * could be * accumulated, because during the UNKNOWN state more IntentStarted may
+ * be triggered. To recover from UNKNOWN to INIT, all the accumualted IntentStarted
+ * should termniate.
+ *
+ * <p> During UNKNOWN state, each IntentStarted increases the accumulation, and any of
+ * IntentFailed, ActivityLaunchCancelled and ActivityFinished decreases the accumulation.
+ * ReportFullyDrawn doesn't impact the accumulation.
+ */
+public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
+ static final String TAG = "EventSequenceValidator";
+
+ private State state = State.INIT;
+ private long accIntentStartedEvents = 0;
+
+ @Override
+ public void onIntentStarted(@NonNull Intent intent, long timestampNs) {
+ if (state == State.UNKNOWN) {
+ Log.e(TAG, "IntentStarted during UNKNOWN." + intent);
+ incAccIntentStartedEvents();
+ return;
+ }
+
+ if (state != State.INIT &&
+ state != State.INTENT_FAILED &&
+ state != State.ACTIVITY_CANCELLED &&
+ state != State.ACTIVITY_FINISHED &&
+ state != State.REPORT_FULLY_DRAWN) {
+ Log.e(TAG,
+ String.format("Cannot transition from %s to %s", state, State.INTENT_STARTED));
+ incAccIntentStartedEvents();
+ incAccIntentStartedEvents();
+ return;
+ }
+
+ Log.i(TAG, String.format("Tansition from %s to %s", state, State.INTENT_STARTED));
+ state = State.INTENT_STARTED;
+ }
+
+ @Override
+ public void onIntentFailed() {
+ if (state == State.UNKNOWN) {
+ Log.e(TAG, "IntentFailed during UNKNOWN.");
+ decAccIntentStartedEvents();
+ return;
+ }
+ if (state != State.INTENT_STARTED) {
+ Log.e(TAG,
+ String.format("Cannot transition from %s to %s", state, State.INTENT_FAILED));
+ incAccIntentStartedEvents();
+ return;
+ }
+
+ Log.i(TAG, String.format("Tansition from %s to %s", state, State.INTENT_FAILED));
+ state = State.INTENT_FAILED;
+ }
+
+ @Override
+ public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
+ @Temperature int temperature) {
+ if (state == State.UNKNOWN) {
+ Log.e(TAG, "onActivityLaunched during UNKNOWN.");
+ return;
+ }
+ if (state != State.INTENT_STARTED) {
+ Log.e(TAG,
+ String.format("Cannot transition from %s to %s", state, State.ACTIVITY_LAUNCHED));
+ incAccIntentStartedEvents();
+ return;
+ }
+
+ Log.i(TAG, String.format("Transition from %s to %s", state, State.ACTIVITY_LAUNCHED));
+ state = State.ACTIVITY_LAUNCHED;
+ }
+
+ @Override
+ public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] activity) {
+ if (state == State.UNKNOWN) {
+ Log.e(TAG, "onActivityLaunchCancelled during UNKNOWN.");
+ decAccIntentStartedEvents();
+ return;
+ }
+ if (state != State.ACTIVITY_LAUNCHED) {
+ Log.e(TAG,
+ String.format("Cannot transition from %s to %s", state, State.ACTIVITY_CANCELLED));
+ incAccIntentStartedEvents();
+ return;
+ }
+
+ Log.i(TAG, String.format("Transition from %s to %s", state, State.ACTIVITY_CANCELLED));
+ state = State.ACTIVITY_CANCELLED;
+ }
+
+ @Override
+ public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity,
+ long timestampNs) {
+ if (state == State.UNKNOWN) {
+ Log.e(TAG, "onActivityLaunchFinished during UNKNOWN.");
+ decAccIntentStartedEvents();
+ return;
+ }
+
+ if (state != State.ACTIVITY_LAUNCHED) {
+ Log.e(TAG,
+ String.format("Cannot transition from %s to %s", state, State.ACTIVITY_FINISHED));
+ incAccIntentStartedEvents();
+ return;
+ }
+
+ Log.i(TAG, String.format("Transition from %s to %s", state, State.ACTIVITY_FINISHED));
+ state = State.ACTIVITY_FINISHED;
+ }
+
+ @Override
+ public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity,
+ long timestampNs) {
+ if (state == State.UNKNOWN) {
+ Log.e(TAG, "onReportFullyDrawn during UNKNOWN.");
+ return;
+ }
+ if (state == State.INIT) {
+ return;
+ }
+
+ if (state != State.ACTIVITY_FINISHED) {
+ Log.e(TAG,
+ String.format("Cannot transition from %s to %s", state, State.REPORT_FULLY_DRAWN));
+ return;
+ }
+
+ Log.i(TAG, String.format("Transition from %s to %s", state, State.REPORT_FULLY_DRAWN));
+ state = State.REPORT_FULLY_DRAWN;
+ }
+
+ enum State {
+ INIT,
+ INTENT_STARTED,
+ INTENT_FAILED,
+ ACTIVITY_LAUNCHED,
+ ACTIVITY_CANCELLED,
+ ACTIVITY_FINISHED,
+ REPORT_FULLY_DRAWN,
+ UNKNOWN,
+ }
+
+ private void incAccIntentStartedEvents() {
+ if (accIntentStartedEvents < 0) {
+ throw new AssertionError(
+ String.format("The number of unknows cannot be negative"));
+ }
+ if (accIntentStartedEvents == 0) {
+ state = State.UNKNOWN;
+ }
+ ++accIntentStartedEvents;
+ Log.i(TAG,
+ String.format("inc AccIntentStartedEvents to %d", accIntentStartedEvents));
+ }
+
+ private void decAccIntentStartedEvents() {
+ if (accIntentStartedEvents <= 0) {
+ throw new AssertionError(
+ String.format("The number of unknows cannot be negative"));
+ }
+ if(accIntentStartedEvents == 1) {
+ state = State.INIT;
+ }
+ --accIntentStartedEvents;
+ Log.i(TAG,
+ String.format("dec AccIntentStartedEvents to %d", accIntentStartedEvents));
+ }
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
index f753548..badff7b 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
@@ -283,6 +283,7 @@
}
private final AppLaunchObserver mAppLaunchObserver = new AppLaunchObserver();
+ private final EventSequenceValidator mEventSequenceValidator = new EventSequenceValidator();
private boolean mRegisteredListeners = false;
private void registerInProcessListenersLocked() {
@@ -303,6 +304,7 @@
ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
provideLaunchObserverRegistry();
launchObserverRegistry.registerLaunchObserver(mAppLaunchObserver);
+ launchObserverRegistry.registerLaunchObserver(mEventSequenceValidator);
mRegisteredListeners = true;
}
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 0659665..9e6dfef 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -98,7 +98,13 @@
TelephonyManager.NETWORK_TYPE_GSM,
TelephonyManager.NETWORK_TYPE_TD_SCDMA,
TelephonyManager.NETWORK_TYPE_IWLAN,
- TelephonyManager.NETWORK_TYPE_LTE_CA,
+
+ //TODO: In order for @SystemApi methods to use this class, there cannot be any
+ // public hidden members. This network type is marked as hidden because it is not a
+ // true network type and we are looking to remove it completely from the available list
+ // of network types.
+ //TelephonyManager.NETWORK_TYPE_LTE_CA,
+
TelephonyManager.NETWORK_TYPE_NR,
})
@Retention(RetentionPolicy.SOURCE)
@@ -590,4 +596,17 @@
@Retention(RetentionPolicy.SOURCE)
public @interface ImsAudioCodec {
}
+
+ /**
+ * UICC SIM Application Types
+ */
+ @IntDef(prefix = { "APPTYPE_" }, value = {
+ TelephonyManager.APPTYPE_SIM,
+ TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.APPTYPE_RUIM,
+ TelephonyManager.APPTYPE_CSIM,
+ TelephonyManager.APPTYPE_ISIM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface UiccAppType{}
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index ab51d8a..599cd9f 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -379,15 +379,15 @@
/**
* Create a new ServiceState from a intent notifier Bundle
*
- * This method is used by PhoneStateIntentReceiver, CellBroadcastReceiver, and maybe by
- * external applications.
+ * This method is used to get ServiceState object from extras upon receiving
+ * {@link Intent#ACTION_SERVICE_STATE}.
*
* @param m Bundle from intent notifier
* @return newly created ServiceState
* @hide
*/
+ @SystemApi
@NonNull
- @UnsupportedAppUsage
public static ServiceState newFromBundle(@NonNull Bundle m) {
ServiceState ret;
ret = new ServiceState();
@@ -1281,11 +1281,15 @@
/**
* Set intent notifier Bundle based on service state.
*
+ * Put ServiceState object and its fields into bundle which is used by TelephonyRegistry
+ * to broadcast {@link Intent#ACTION_SERVICE_STATE}.
+ *
* @param m intent notifier Bundle
* @hide
+ *
*/
- @UnsupportedAppUsage
- public void fillInNotifierBundle(Bundle m) {
+ @SystemApi
+ public void fillInNotifierBundle(@NonNull Bundle m) {
m.putParcelable(Intent.EXTRA_SERVICE_STATE, this);
// serviceState already consists of below entries.
// for backward compatibility, we continue fill in below entries.
@@ -1950,9 +1954,18 @@
* Returns a copy of self with location-identifying information removed.
* Always clears the NetworkRegistrationInfo's CellIdentity fields, but if removeCoarseLocation
* is true, clears other info as well.
+ *
+ * @param removeCoarseLocation Whether to also remove coarse location information.
+ * if false, it only clears fine location information such as
+ * NetworkRegistrationInfo's CellIdentity fields; If true, it will
+ * also remove other location information such as operator's MCC
+ * and MNC.
+ * @return the copied ServiceState with location info sanitized.
* @hide
*/
- public ServiceState sanitizeLocationInfo(boolean removeCoarseLocation) {
+ @SystemApi
+ @NonNull
+ public ServiceState createLocationInfoSanitizedCopy(boolean removeCoarseLocation) {
ServiceState state = new ServiceState(this);
synchronized (state.mNetworkRegistrationInfos) {
List<NetworkRegistrationInfo> networkRegistrationInfos =
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 365ab22..ab44e8e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -73,6 +73,7 @@
import android.telephony.Annotation.NetworkType;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SimActivationState;
+import android.telephony.Annotation.UiccAppType;
import android.telephony.VisualVoicemailService.VisualVoicemailTask;
import android.telephony.data.ApnSetting.MvnoType;
import android.telephony.emergency.EmergencyNumber;
@@ -6781,19 +6782,6 @@
}
}
- /**
- * UICC SIM Application Types
- * @hide
- */
- @IntDef(prefix = { "APPTYPE_" }, value = {
- APPTYPE_SIM,
- APPTYPE_USIM,
- APPTYPE_RUIM,
- APPTYPE_CSIM,
- APPTYPE_ISIM
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface UiccAppType{}
/** UICC application type is SIM */
public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM;
/** UICC application type is USIM */
@@ -8213,9 +8201,9 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.supplyPin(pin);
+ return telephony.supplyPinForSubscriber(getSubId(), pin);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#supplyPin", e);
+ Log.e(TAG, "Error calling ITelephony#supplyPinForSubscriber", e);
}
return false;
}
@@ -8227,9 +8215,9 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.supplyPuk(puk, pin);
+ return telephony.supplyPukForSubscriber(getSubId(), puk, pin);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#supplyPuk", e);
+ Log.e(TAG, "Error calling ITelephony#supplyPukForSubscriber", e);
}
return false;
}
@@ -8241,9 +8229,9 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.supplyPinReportResult(pin);
+ return telephony.supplyPinReportResultForSubscriber(getSubId(), pin);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#supplyPinReportResult", e);
+ Log.e(TAG, "Error calling ITelephony#supplyPinReportResultForSubscriber", e);
}
return new int[0];
}
@@ -8255,7 +8243,7 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.supplyPukReportResult(puk, pin);
+ return telephony.supplyPukReportResultForSubscriber(getSubId(), puk, pin);
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#]", e);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 57fda9b1..9d721fc 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -117,13 +117,6 @@
*/
boolean isRadioOnForSubscriberWithFeature(int subId, String callingPackage, String callingFeatureId);
- /**
- * Supply a pin to unlock the SIM. Blocks until a result is determined.
- * @param pin The pin to check.
- * @return whether the operation was a success.
- */
- @UnsupportedAppUsage
- boolean supplyPin(String pin);
/**
* Supply a pin to unlock the SIM for particular subId.
@@ -139,15 +132,6 @@
* Blocks until a result is determined.
* @param puk The puk to check.
* pin The new pin to be set in SIM
- * @return whether the operation was a success.
- */
- boolean supplyPuk(String puk, String pin);
-
- /**
- * Supply puk to unlock the SIM and set SIM pin to new pin.
- * Blocks until a result is determined.
- * @param puk The puk to check.
- * pin The new pin to be set in SIM
* @param subId user preferred subId.
* @return whether the operation was a success.
*/
@@ -160,15 +144,6 @@
* @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
* retValue[1] = number of attempts remaining if known otherwise -1
*/
- int[] supplyPinReportResult(String pin);
-
- /**
- * Supply a pin to unlock the SIM. Blocks until a result is determined.
- * Returns a specific success/error code.
- * @param pin The pin to check.
- * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
- * retValue[1] = number of attempts remaining if known otherwise -1
- */
int[] supplyPinReportResultForSubscriber(int subId, String pin);
/**
@@ -180,17 +155,6 @@
* @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
* retValue[1] = number of attempts remaining if known otherwise -1
*/
- int[] supplyPukReportResult(String puk, String pin);
-
- /**
- * Supply puk to unlock the SIM and set SIM pin to new pin.
- * Blocks until a result is determined.
- * Returns a specific success/error code
- * @param puk The puk to check
- * pin The pin to check.
- * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
- * retValue[1] = number of attempts remaining if known otherwise -1
- */
int[] supplyPukReportResultForSubscriber(int subId, String puk, String pin);
/**
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index daa85bd..f6699fa 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -31,6 +31,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.UserManager;
@@ -1122,4 +1123,39 @@
InstallUtils.dropShellPermissionIdentity();
}
}
+
+ @Test
+ public void testRollbackDataPolicy() throws Exception {
+ try {
+ InstallUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
+
+ Uninstall.packages(TestApp.A, TestApp.B);
+ Install.multi(TestApp.A1, TestApp.B1).commit();
+ // Write user data version = 1
+ InstallUtils.processUserData(TestApp.A);
+ InstallUtils.processUserData(TestApp.B);
+
+ Install a2 = Install.single(TestApp.A2)
+ .setEnableRollback(PackageManager.RollbackDataPolicy.WIPE);
+ Install b2 = Install.single(TestApp.B2)
+ .setEnableRollback(PackageManager.RollbackDataPolicy.RESTORE);
+ Install.multi(a2, b2).setEnableRollback().commit();
+ // Write user data version = 2
+ InstallUtils.processUserData(TestApp.A);
+ InstallUtils.processUserData(TestApp.B);
+
+ RollbackInfo info = RollbackUtils.getAvailableRollback(TestApp.A);
+ RollbackUtils.rollback(info.getRollbackId());
+ // Read user data version from userdata.txt
+ // A's user data version is -1 for user data is wiped.
+ // B's user data version is 1 as rollback committed.
+ assertThat(InstallUtils.getUserDataVersion(TestApp.A)).isEqualTo(-1);
+ assertThat(InstallUtils.getUserDataVersion(TestApp.B)).isEqualTo(1);
+ } finally {
+ InstallUtils.dropShellPermissionIdentity();
+ }
+ }
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index bb3906d..40169b8 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -384,6 +384,44 @@
RollbackUtils.getRollbackManager().expireRollbackForPackage(getModuleMetadataPackageName());
}
+ @Test
+ public void testRollbackDataPolicy_Phase1() throws Exception {
+ Uninstall.packages(TestApp.A, TestApp.B);
+ Install.multi(TestApp.A1, TestApp.B1).commit();
+ // Write user data version = 1
+ InstallUtils.processUserData(TestApp.A);
+ InstallUtils.processUserData(TestApp.B);
+
+ Install a2 = Install.single(TestApp.A2).setStaged()
+ .setEnableRollback(PackageManager.RollbackDataPolicy.WIPE);
+ Install b2 = Install.single(TestApp.B2).setStaged()
+ .setEnableRollback(PackageManager.RollbackDataPolicy.RESTORE);
+ Install.multi(a2, b2).setEnableRollback().setStaged().commit();
+ }
+
+ @Test
+ public void testRollbackDataPolicy_Phase2() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2);
+ // Write user data version = 2
+ InstallUtils.processUserData(TestApp.A);
+ InstallUtils.processUserData(TestApp.B);
+
+ RollbackInfo info = RollbackUtils.getAvailableRollback(TestApp.A);
+ RollbackUtils.rollback(info.getRollbackId());
+ }
+
+ @Test
+ public void testRollbackDataPolicy_Phase3() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(1);
+ // Read user data version from userdata.txt
+ // A's user data version is -1 for user data is wiped.
+ // B's user data version is 1 as rollback committed.
+ assertThat(InstallUtils.getUserDataVersion(TestApp.A)).isEqualTo(-1);
+ assertThat(InstallUtils.getUserDataVersion(TestApp.B)).isEqualTo(1);
+ }
+
private static void runShellCommand(String cmd) {
ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
.executeShellCommand(cmd);
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 8ab4c4c..4644d8a 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -192,6 +192,15 @@
}
}
+ @Test
+ public void testRollbackDataPolicy() throws Exception {
+ runPhase("testRollbackDataPolicy_Phase1");
+ getDevice().reboot();
+ runPhase("testRollbackDataPolicy_Phase2");
+ getDevice().reboot();
+ runPhase("testRollbackDataPolicy_Phase3");
+ }
+
private void crashProcess(String processName, int numberOfCrashes) throws Exception {
String pid = "";
String lastPid = "invalid";
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index b725920..27960c8 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -365,6 +365,8 @@
});
manifest_action["instrumentation"]["meta-data"] = meta_data_action;
+ manifest_action["feature"];
+ manifest_action["feature"]["inherit-from"];
manifest_action["original-package"];
manifest_action["overlay"];
manifest_action["protected-broadcast"];
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 15c3278..d3958a6 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -25,6 +25,8 @@
"java_writer.cpp",
"java_writer_q.cpp",
"main.cpp",
+ "native_writer.cpp",
+ "native_writer_q.cpp",
"utils.cpp",
],
cflags: [
@@ -121,17 +123,5 @@
"libcutils",
],
static_libs: ["libstatssocket"],
- target: {
- android: {
- shared_libs: [
- "libutils",
- ],
- },
- host: {
- static_libs: [
- "libutils",
- ],
- },
- },
}
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index fa55601..0b82a3d 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -405,9 +405,9 @@
atomDecl.whitelisted = true;
}
- if (atomField->options().HasExtension(os::statsd::log_from_module)) {
+ if (atomField->options().HasExtension(os::statsd::module)) {
atomDecl.hasModule = true;
- atomDecl.moduleName = atomField->options().GetExtension(os::statsd::log_from_module);
+ atomDecl.moduleName = atomField->options().GetExtension(os::statsd::module);
}
vector<java_type_t> signature;
diff --git a/tools/stats_log_api_gen/atoms_info_writer.h b/tools/stats_log_api_gen/atoms_info_writer.h
index bc67782..12ac862 100644
--- a/tools/stats_log_api_gen/atoms_info_writer.h
+++ b/tools/stats_log_api_gen/atoms_info_writer.h
@@ -27,8 +27,7 @@
using namespace std;
int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr,
- const string& importHeader, const string& statslogHeader
-);
+ const string& importHeader, const string& statslogHeader);
int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr);
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index 712b48e..7f0872c 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -48,7 +48,8 @@
FILE* out,
const map<vector<java_type_t>, set<string>>& signatures_to_modules,
const AtomDecl &attributionDecl,
- const string& moduleName
+ const string& moduleName,
+ const bool supportQ
) {
for (auto signature_to_modules_it = signatures_to_modules.begin();
signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
@@ -82,8 +83,10 @@
// Print method body.
string indent("");
- if (DEFAULT_MODULE_NAME != moduleName) {
- fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {\n");
+ if (supportQ) {
+ // TODO(b/146235828): Use just SDK_INT check once it is incremented from Q.
+ fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q ||\n");
+ fprintf(out, " Build.VERSION.CODENAME.equals(\"R\")) {\n");
indent = " ";
}
@@ -193,7 +196,7 @@
fprintf(out, "%s StatsLog.write(builder.build());\n", indent.c_str());
// Add support for writing using Q schema if this is not the default module.
- if (DEFAULT_MODULE_NAME != moduleName) {
+ if (supportQ) {
fprintf(out, " } else {\n");
fprintf(out, " QLogger.write(code");
argIndex = 1;
@@ -225,15 +228,17 @@
int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
const string& moduleName, const string& javaClass,
- const string& javaPackage) {
+ const string& javaPackage, const bool supportQ) {
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
fprintf(out, "package %s;\n", javaPackage.c_str());
fprintf(out, "\n");
fprintf(out, "\n");
- fprintf(out, "import android.os.Build;\n");
- fprintf(out, "import android.os.SystemClock;\n");
+ if (supportQ) {
+ fprintf(out, "import android.os.Build;\n");
+ fprintf(out, "import android.os.SystemClock;\n");
+ }
if (DEFAULT_MODULE_NAME == moduleName) {
// Mainline modules don't use WorkSource logging.
@@ -271,12 +276,15 @@
// Print write methods.
fprintf(out, " // Write methods\n");
- errors += write_java_methods(out, atoms.signatures_to_modules, attributionDecl, moduleName);
+ errors += write_java_methods(
+ out, atoms.signatures_to_modules, attributionDecl, moduleName, supportQ);
errors += write_java_non_chained_methods(
out, atoms.non_chained_signatures_to_modules, moduleName);
if (DEFAULT_MODULE_NAME == moduleName) {
errors += write_java_work_source_methods(out, atoms.signatures_to_modules, moduleName);
- } else {
+ }
+
+ if (supportQ) {
errors += write_java_q_logger_class(
out, atoms.signatures_to_modules, attributionDecl, moduleName);
}
diff --git a/tools/stats_log_api_gen/java_writer.h b/tools/stats_log_api_gen/java_writer.h
index 031266b..9324b23 100644
--- a/tools/stats_log_api_gen/java_writer.h
+++ b/tools/stats_log_api_gen/java_writer.h
@@ -32,8 +32,7 @@
int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
const string& moduleName, const string& javaClass,
- const string& javaPackage
-);
+ const string& javaPackage, const bool supportQ);
} // namespace stats_log_api_gen
} // namespace android
diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h
index c8f4ccf..96ac745 100644
--- a/tools/stats_log_api_gen/java_writer_q.h
+++ b/tools/stats_log_api_gen/java_writer_q.h
@@ -37,22 +37,20 @@
const map<vector<java_type_t>, set<string>>& signatures_to_modules,
const AtomDecl &attributionDecl,
const string& moduleName,
- const string& indent
-);
+ const string& indent);
void write_java_helpers_for_q_schema_methods(
FILE * out,
const AtomDecl &attributionDecl,
const int requiredHelpers,
- const string& indent
-);
+ const string& indent);
#if defined(STATS_SCHEMA_LEGACY)
int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl);
-int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
- const string& moduleName, const string& javaClass,
- const string& javaPackage);
+int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
+ const AtomDecl &attributionDecl, const string& moduleName, const string& javaClass,
+ const string& javaPackage);
#endif
} // namespace stats_log_api_gen
} // namespace android
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index ad171da..00a3704 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -6,6 +6,7 @@
#include "java_writer.h"
#endif
#include "java_writer_q.h"
+#include "native_writer.h"
#include "utils.h"
#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
@@ -27,496 +28,6 @@
using android::os::statsd::Atom;
-static int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
- const string& moduleName, const string& cppNamespace,
- const string& importHeader) {
- // Print prelude
- fprintf(out, "// This file is autogenerated\n");
- fprintf(out, "\n");
-
- fprintf(out, "#include <mutex>\n");
- fprintf(out, "#include <chrono>\n");
- fprintf(out, "#include <thread>\n");
- fprintf(out, "#ifdef __ANDROID__\n");
- fprintf(out, "#include <cutils/properties.h>\n");
- fprintf(out, "#endif\n");
- fprintf(out, "#include <stats_event_list.h>\n");
- fprintf(out, "#include <log/log.h>\n");
- fprintf(out, "#include <%s>\n", importHeader.c_str());
- fprintf(out, "#include <utils/SystemClock.h>\n");
- fprintf(out, "\n");
-
- write_namespace(out, cppNamespace);
- fprintf(out, "// the single event tag id for all stats logs\n");
- fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
- fprintf(out, "#ifdef __ANDROID__\n");
- fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
- fprintf(out, "#else\n");
- fprintf(out, "const static bool kStatsdEnabled = false;\n");
- fprintf(out, "#endif\n");
-
- fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
- fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
- fprintf(out, "static std::mutex mLogdRetryMutex;\n");
-
- // Print write methods
- fprintf(out, "\n");
- for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
- signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
- if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
- continue;
- }
- vector<java_type_t> signature = signature_to_modules_it->first;
- int argIndex;
-
- fprintf(out, "int\n");
- fprintf(out, "try_stats_write(int32_t code");
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, ", const std::vector<%s>& %s",
- cpp_type_name(chainField.javaType),
- chainField.name.c_str());
- } else {
- fprintf(out, ", const %s* %s, size_t %s_length",
- cpp_type_name(chainField.javaType),
- chainField.name.c_str(), chainField.name.c_str());
- }
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
- "const std::map<int, int64_t>& arg%d_2, "
- "const std::map<int, char const*>& arg%d_3, "
- "const std::map<int, float>& arg%d_4",
- argIndex, argIndex, argIndex, argIndex);
- } else {
- fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
- }
- argIndex++;
- }
- fprintf(out, ")\n");
-
- fprintf(out, "{\n");
- argIndex = 1;
- fprintf(out, " if (kStatsdEnabled) {\n");
- fprintf(out, " stats_event_list event(kStatsEventTag);\n");
- fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
- fprintf(out, " event << code;\n\n");
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (const auto &chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, " if (%s_length != %s.size()) {\n",
- attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
- fprintf(out, " return -EINVAL;\n");
- fprintf(out, " }\n");
- }
- }
- fprintf(out, "\n event.begin();\n");
- fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
- attributionDecl.fields.front().name.c_str());
- fprintf(out, " event.begin();\n");
- for (const auto &chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, " if (%s[i] != NULL) {\n", chainField.name.c_str());
- fprintf(out, " event << %s[i];\n", chainField.name.c_str());
- fprintf(out, " } else {\n");
- fprintf(out, " event << \"\";\n");
- fprintf(out, " }\n");
- } else {
- fprintf(out, " event << %s[i];\n", chainField.name.c_str());
- }
- }
- fprintf(out, " event.end();\n");
- fprintf(out, " }\n");
- fprintf(out, " event.end();\n\n");
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, " event.begin();\n\n");
- fprintf(out, " for (const auto& it : arg%d_1) {\n", argIndex);
- fprintf(out, " event.begin();\n");
- fprintf(out, " event << it.first;\n");
- fprintf(out, " event << it.second;\n");
- fprintf(out, " event.end();\n");
- fprintf(out, " }\n");
-
- fprintf(out, " for (const auto& it : arg%d_2) {\n", argIndex);
- fprintf(out, " event.begin();\n");
- fprintf(out, " event << it.first;\n");
- fprintf(out, " event << it.second;\n");
- fprintf(out, " event.end();\n");
- fprintf(out, " }\n");
-
- fprintf(out, " for (const auto& it : arg%d_3) {\n", argIndex);
- fprintf(out, " event.begin();\n");
- fprintf(out, " event << it.first;\n");
- fprintf(out, " event << it.second;\n");
- fprintf(out, " event.end();\n");
- fprintf(out, " }\n");
-
- fprintf(out, " for (const auto& it : arg%d_4) {\n", argIndex);
- fprintf(out, " event.begin();\n");
- fprintf(out, " event << it.first;\n");
- fprintf(out, " event << it.second;\n");
- fprintf(out, " event.end();\n");
- fprintf(out, " }\n");
-
- fprintf(out, " event.end();\n\n");
- } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
- fprintf(out,
- " event.AppendCharArray(arg%d.arg, "
- "arg%d.arg_length);\n",
- argIndex, argIndex);
- } else {
- if (*arg == JAVA_TYPE_STRING) {
- fprintf(out, " if (arg%d == NULL) {\n", argIndex);
- fprintf(out, " arg%d = \"\";\n", argIndex);
- fprintf(out, " }\n");
- }
- fprintf(out, " event << arg%d;\n", argIndex);
- }
- argIndex++;
- }
-
- fprintf(out, " return event.write(LOG_ID_STATS);\n");
- fprintf(out, " } else {\n");
- fprintf(out, " return 1;\n");
- fprintf(out, " }\n");
- fprintf(out, "}\n");
- fprintf(out, "\n");
- }
-
- for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
- signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
- if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
- continue;
- }
- vector<java_type_t> signature = signature_to_modules_it->first;
- int argIndex;
-
- fprintf(out, "int\n");
- fprintf(out, "stats_write(int32_t code");
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, ", const std::vector<%s>& %s",
- cpp_type_name(chainField.javaType),
- chainField.name.c_str());
- } else {
- fprintf(out, ", const %s* %s, size_t %s_length",
- cpp_type_name(chainField.javaType),
- chainField.name.c_str(), chainField.name.c_str());
- }
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out,
- ", const std::map<int, int32_t>& arg%d_1, "
- "const std::map<int, int64_t>& arg%d_2, "
- "const std::map<int, char const*>& arg%d_3, "
- "const std::map<int, float>& arg%d_4",
- argIndex, argIndex, argIndex, argIndex);
- } else {
- fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
- }
- argIndex++;
- }
- fprintf(out, ")\n");
-
- fprintf(out, "{\n");
- fprintf(out, " int ret = 0;\n");
-
- fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n");
- fprintf(out, " ret = try_stats_write(code");
-
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, ", %s",
- chainField.name.c_str());
- } else {
- fprintf(out, ", %s, %s_length",
- chainField.name.c_str(), chainField.name.c_str());
- }
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex,
- argIndex, argIndex, argIndex);
- } else {
- fprintf(out, ", arg%d", argIndex);
- }
- argIndex++;
- }
- fprintf(out, ");\n");
- fprintf(out, " if (ret >= 0) { break; }\n");
-
- fprintf(out, " {\n");
- fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
- fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
- "kMinRetryIntervalNs) break;\n");
- fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
- fprintf(out, " }\n");
- fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
- fprintf(out, " }\n");
- fprintf(out, " if (ret < 0) {\n");
- fprintf(out, " note_log_drop(ret, code);\n");
- fprintf(out, " }\n");
- fprintf(out, " return ret;\n");
- fprintf(out, "}\n");
- fprintf(out, "\n");
- }
-
- for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
- signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
- if (!signature_needed_for_module(signature_it->second, moduleName)) {
- continue;
- }
- vector<java_type_t> signature = signature_it->first;
- int argIndex;
-
- fprintf(out, "int\n");
- fprintf(out, "try_stats_write_non_chained(int32_t code");
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
- argIndex++;
- }
- fprintf(out, ")\n");
-
- fprintf(out, "{\n");
- argIndex = 1;
- fprintf(out, " if (kStatsdEnabled) {\n");
- fprintf(out, " stats_event_list event(kStatsEventTag);\n");
- fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
- fprintf(out, " event << code;\n\n");
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (argIndex == 1) {
- fprintf(out, " event.begin();\n\n");
- fprintf(out, " event.begin();\n");
- }
- if (*arg == JAVA_TYPE_STRING) {
- fprintf(out, " if (arg%d == NULL) {\n", argIndex);
- fprintf(out, " arg%d = \"\";\n", argIndex);
- fprintf(out, " }\n");
- }
- if (*arg == JAVA_TYPE_BYTE_ARRAY) {
- fprintf(out,
- " event.AppendCharArray(arg%d.arg, "
- "arg%d.arg_length);",
- argIndex, argIndex);
- } else {
- fprintf(out, " event << arg%d;\n", argIndex);
- }
- if (argIndex == 2) {
- fprintf(out, " event.end();\n\n");
- fprintf(out, " event.end();\n\n");
- }
- argIndex++;
- }
-
- fprintf(out, " return event.write(LOG_ID_STATS);\n");
- fprintf(out, " } else {\n");
- fprintf(out, " return 1;\n");
- fprintf(out, " }\n");
- fprintf(out, "}\n");
- fprintf(out, "\n");
- }
-
- for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
- signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
- if (!signature_needed_for_module(signature_it->second, moduleName)) {
- continue;
- }
- vector<java_type_t> signature = signature_it->first;
- int argIndex;
-
- fprintf(out, "int\n");
- fprintf(out, "stats_write_non_chained(int32_t code");
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
- argIndex++;
- }
- fprintf(out, ")\n");
-
- fprintf(out, "{\n");
-
- fprintf(out, " int ret = 0;\n");
- fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n");
- fprintf(out, " ret = try_stats_write_non_chained(code");
-
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- fprintf(out, ", arg%d", argIndex);
- argIndex++;
- }
- fprintf(out, ");\n");
- fprintf(out, " if (ret >= 0) { break; }\n");
-
- fprintf(out, " {\n");
- fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
- fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
- "kMinRetryIntervalNs) break;\n");
- fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
- fprintf(out, " }\n");
-
- fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
- fprintf(out, " }\n");
- fprintf(out, " if (ret < 0) {\n");
- fprintf(out, " note_log_drop(ret, code);\n");
- fprintf(out, " }\n");
- fprintf(out, " return ret;\n\n");
- fprintf(out, "}\n");
-
- fprintf(out, "\n");
- }
-
-
- // Print footer
- fprintf(out, "\n");
- write_closing_namespace(out, cppNamespace);
-
- return 0;
-}
-
-static void write_cpp_method_header(
- FILE* out,
- const string& method_name,
- const map<vector<java_type_t>, set<string>>& signatures_to_modules,
- const AtomDecl &attributionDecl, const string& moduleName) {
-
- for (auto signature_to_modules_it = signatures_to_modules.begin();
- signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
- // Skip if this signature is not needed for the module.
- if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
- continue;
- }
-
- vector<java_type_t> signature = signature_to_modules_it->first;
- fprintf(out, "int %s(int32_t code", method_name.c_str());
- int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, ", const std::vector<%s>& %s",
- cpp_type_name(chainField.javaType), chainField.name.c_str());
- } else {
- fprintf(out, ", const %s* %s, size_t %s_length",
- cpp_type_name(chainField.javaType),
- chainField.name.c_str(), chainField.name.c_str());
- }
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
- "const std::map<int, int64_t>& arg%d_2, "
- "const std::map<int, char const*>& arg%d_3, "
- "const std::map<int, float>& arg%d_4",
- argIndex, argIndex, argIndex, argIndex);
- } else {
- fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
- }
- argIndex++;
- }
- fprintf(out, ");\n");
-
- }
-}
-
-static int
-write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
- const string& moduleName, const string& cppNamespace)
-{
- // Print prelude
- fprintf(out, "// This file is autogenerated\n");
- fprintf(out, "\n");
- fprintf(out, "#pragma once\n");
- fprintf(out, "\n");
- fprintf(out, "#include <stdint.h>\n");
- fprintf(out, "#include <vector>\n");
- fprintf(out, "#include <map>\n");
- fprintf(out, "#include <set>\n");
- fprintf(out, "\n");
-
- write_namespace(out, cppNamespace);
- fprintf(out, "\n");
- fprintf(out, "/*\n");
- fprintf(out, " * API For logging statistics events.\n");
- fprintf(out, " */\n");
- fprintf(out, "\n");
-
- write_native_atom_constants(out, atoms, attributionDecl, moduleName);
-
- // Print constants for the enum values.
- fprintf(out, "//\n");
- fprintf(out, "// Constants for enum values\n");
- fprintf(out, "//\n\n");
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
- // Skip if the atom is not needed for the module.
- if (!atom_needed_for_module(*atom, moduleName)) {
- continue;
- }
-
- for (vector<AtomField>::const_iterator field = atom->fields.begin();
- field != atom->fields.end(); field++) {
- if (field->javaType == JAVA_TYPE_ENUM) {
- fprintf(out, "// Values for %s.%s\n", atom->message.c_str(),
- field->name.c_str());
- for (map<int, string>::const_iterator value = field->enumValues.begin();
- value != field->enumValues.end(); value++) {
- fprintf(out, "const int32_t %s__%s__%s = %d;\n",
- make_constant_name(atom->message).c_str(),
- make_constant_name(field->name).c_str(),
- make_constant_name(value->second).c_str(),
- value->first);
- }
- fprintf(out, "\n");
- }
- }
- }
-
- fprintf(out, "struct BytesField {\n");
- fprintf(out,
- " BytesField(char const* array, size_t len) : arg(array), "
- "arg_length(len) {}\n");
- fprintf(out, " char const* arg;\n");
- fprintf(out, " size_t arg_length;\n");
- fprintf(out, "};\n");
- fprintf(out, "\n");
-
- // Print write methods
- fprintf(out, "//\n");
- fprintf(out, "// Write methods\n");
- fprintf(out, "//\n");
- write_cpp_method_header(out, "stats_write", atoms.signatures_to_modules, attributionDecl,
- moduleName);
-
- fprintf(out, "//\n");
- fprintf(out, "// Write flattened methods\n");
- fprintf(out, "//\n");
- write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures_to_modules,
- attributionDecl, moduleName);
-
- fprintf(out, "\n");
- write_closing_namespace(out, cppNamespace);
-
- return 0;
-}
-
// Hide the JNI write helpers that are not used in the new schema.
// TODO(b/145100015): Remove this and other JNI related functionality once StatsEvent migration is
// complete.
@@ -999,7 +510,9 @@
fprintf(stderr, " required for java with module\n");
fprintf(stderr, " --javaClass CLASS the class name of the java class.\n");
fprintf(stderr, " Optional for Java with module.\n");
- fprintf(stderr, " Default is \"StatsLogInternal\"\n");}
+ fprintf(stderr, " Default is \"StatsLogInternal\"\n");
+ fprintf(stderr, " --supportQ Include support for Android Q.\n");
+}
/**
* Do the argument parsing and execute the tasks.
@@ -1020,6 +533,7 @@
string atomsInfoCppHeaderImport = DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT;
string javaPackage = DEFAULT_JAVA_PACKAGE;
string javaClass = DEFAULT_JAVA_CLASS;
+ bool supportQ = false;
int index = 1;
while (index < argc) {
@@ -1110,6 +624,8 @@
return 1;
}
atomsInfoCppHeaderImport = argv[index];
+ } else if (0 == strcmp("--supportQ", argv[index])) {
+ supportQ = true;
}
index++;
@@ -1125,6 +641,12 @@
return 1;
}
+ if (DEFAULT_MODULE_NAME == moduleName && supportQ) {
+ // Support for Q schema is not needed for default module.
+ fprintf(stderr, "%s cannot support Q schema\n", moduleName.c_str());
+ return 1;
+ }
+
// Collate the parameters
Atoms atoms;
int errorCount = collate_atoms(Atom::descriptor(), &atoms);
@@ -1179,7 +701,7 @@
return 1;
}
errorCount = android::stats_log_api_gen::write_stats_log_cpp(
- out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport);
+ out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport, supportQ);
fclose(out);
}
@@ -1227,7 +749,7 @@
javaPackage = "android.util";
}
errorCount = android::stats_log_api_gen::write_stats_log_java(
- out, atoms, attributionDecl, moduleName, javaClass, javaPackage);
+ out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ);
#endif
fclose(out);
diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp
new file mode 100644
index 0000000..c7a34fe
--- /dev/null
+++ b/tools/stats_log_api_gen/native_writer.cpp
@@ -0,0 +1,342 @@
+/*
+ * 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.
+ */
+
+#include "native_writer.h"
+#include "native_writer_q.h"
+#include "utils.h"
+
+namespace android {
+namespace stats_log_api_gen {
+
+#if !defined(STATS_SCHEMA_LEGACY)
+static void write_native_key_value_pairs_for_type(FILE* out, const int argIndex,
+ const int typeIndex, const string& type, const string& valueFieldName) {
+ fprintf(out, " for (const auto& it : arg%d_%d) {\n", argIndex, typeIndex);
+ fprintf(out, " pairs.push_back("
+ "{ .key = it.first, .valueType = %s, .%s = it.second });\n",
+ type.c_str(), valueFieldName.c_str());
+ fprintf(out, " }\n");
+
+}
+
+static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
+ const AtomDecl& attributionDecl, const string& moduleName, const bool supportQ) {
+ fprintf(out, "\n");
+ for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
+ signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
+ if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+ continue;
+ }
+ vector<java_type_t> signature = signature_to_modules_it->first;
+
+ write_native_method_signature(out, "int stats_write", signature,
+ attributionDecl, " {");
+
+ int argIndex = 1;
+ if (supportQ) {
+ fprintf(out, " StatsEventCompat event;\n");
+ fprintf(out, " event.setAtomId(code);\n");
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ switch (*arg) {
+ 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, " event.writeAttributionChain(%s, %s_length, %s);\n",
+ uidName, uidName, tagName);
+ break;
+ }
+ case JAVA_TYPE_KEY_VALUE_PAIR:
+ fprintf(out, " event.writeKeyValuePairs("
+ "arg%d_1, arg%d_2, arg%d_3, arg%d_4);\n",
+ argIndex, argIndex, argIndex, argIndex);
+ break;
+ case JAVA_TYPE_BYTE_ARRAY:
+ fprintf(out, " event.writeByteArray(arg%d.arg, arg%d.arg_length);\n",
+ argIndex, argIndex);
+ break;
+ case JAVA_TYPE_BOOLEAN:
+ fprintf(out, " event.writeBool(arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_INT: // Fall through.
+ case JAVA_TYPE_ENUM:
+ fprintf(out, " event.writeInt32(arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_FLOAT:
+ fprintf(out, " event.writeFloat(arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_LONG:
+ fprintf(out, " event.writeInt64(arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_STRING:
+ fprintf(out, " event.writeString(arg%d);\n", argIndex);
+ break;
+ default:
+ // Unsupported types: OBJECT, DOUBLE.
+ fprintf(stderr, "Encountered unsupported type.");
+ return 1;
+ }
+ argIndex++;
+ }
+ fprintf(out, " return event.writeToSocket();\n");
+ } else {
+ fprintf(out, " struct stats_event* event = stats_event_obtain();\n");
+ fprintf(out, " stats_event_set_atom_id(event, code);\n");
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ switch (*arg) {
+ 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,
+ " stats_event_write_attribution_chain(event, "
+ "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
+ "static_cast<uint8_t>(%s_length));\n",
+ uidName, tagName, uidName);
+ break;
+ }
+ case JAVA_TYPE_KEY_VALUE_PAIR:
+ fprintf(out, " std::vector<key_value_pair> pairs;\n");
+ write_native_key_value_pairs_for_type(
+ out, argIndex, 1, "INT32_TYPE", "int32Value");
+ write_native_key_value_pairs_for_type(
+ out, argIndex, 2, "INT64_TYPE", "int64Value");
+ write_native_key_value_pairs_for_type(
+ out, argIndex, 3, "STRING_TYPE", "stringValue");
+ write_native_key_value_pairs_for_type(
+ out, argIndex, 4, "FLOAT_TYPE", "floatValue");
+ fprintf(out,
+ " stats_event_write_key_value_pairs(event, pairs.data(), "
+ "static_cast<uint8_t>(pairs.size()));\n");
+ break;
+ case JAVA_TYPE_BYTE_ARRAY:
+ fprintf(out,
+ " stats_event_write_byte_array(event, "
+ "reinterpret_cast<const uint8_t*>(arg%d.arg), arg%d.arg_length);\n",
+ argIndex, argIndex);
+ break;
+ case JAVA_TYPE_BOOLEAN:
+ fprintf(out, " stats_event_write_bool(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_INT: // Fall through.
+ case JAVA_TYPE_ENUM:
+ fprintf(out, " stats_event_write_int32(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_FLOAT:
+ fprintf(out, " stats_event_write_float(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_LONG:
+ fprintf(out, " stats_event_write_int64(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_STRING:
+ fprintf(out, " stats_event_write_string8(event, arg%d);\n", argIndex);
+ break;
+ default:
+ // Unsupported types: OBJECT, DOUBLE.
+ fprintf(stderr, "Encountered unsupported type.");
+ return 1;
+ }
+ argIndex++;
+ }
+ fprintf(out, " const int ret = stats_event_write(event);\n");
+ fprintf(out, " stats_event_release(event);\n");
+ fprintf(out, " return ret;\n");
+ }
+ fprintf(out, "}\n\n");
+ }
+ return 0;
+}
+
+static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms,
+ const AtomDecl& attributionDecl, const string& moduleName) {
+ fprintf(out, "\n");
+ for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
+ signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
+ if (!signature_needed_for_module(signature_it->second, moduleName)) {
+ continue;
+ }
+ vector<java_type_t> signature = signature_it->first;
+
+ write_native_method_signature(out, "int stats_write_non_chained", signature,
+ attributionDecl, " {");
+
+ vector<java_type_t> newSignature;
+
+ // First two args form the attribution node so size goes down by 1.
+ newSignature.reserve(signature.size() - 1);
+
+ // First arg is Attribution Chain.
+ newSignature.push_back(JAVA_TYPE_ATTRIBUTION_CHAIN);
+
+ // Followed by the originial signature except the first 2 args.
+ newSignature.insert(newSignature.end(), signature.begin() + 2, signature.end());
+
+ const char* uidName = attributionDecl.fields.front().name.c_str();
+ const char* tagName = attributionDecl.fields.back().name.c_str();
+ fprintf(out, " const int32_t* %s = &arg1;\n", uidName);
+ fprintf(out, " const size_t %s_length = 1;\n", uidName);
+ fprintf(out, " const std::vector<char const*> %s(1, arg2);\n", tagName);
+ fprintf(out, " return ");
+ write_native_method_call(out, "stats_write", newSignature, attributionDecl, 2);
+
+ fprintf(out, "}\n\n");
+ }
+
+}
+#endif
+
+static void write_native_method_header(
+ FILE* out,
+ const string& methodName,
+ const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+ const AtomDecl &attributionDecl, const string& moduleName) {
+
+ for (auto signature_to_modules_it = signatures_to_modules.begin();
+ signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+ // Skip if this signature is not needed for the module.
+ if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+ continue;
+ }
+
+ vector<java_type_t> signature = signature_to_modules_it->first;
+ write_native_method_signature(out, methodName, signature, attributionDecl, ";");
+ }
+}
+
+int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
+ const string& moduleName, const string& cppNamespace,
+ const string& importHeader, const bool supportQ) {
+ // Print prelude
+ fprintf(out, "// This file is autogenerated\n");
+ fprintf(out, "\n");
+
+ fprintf(out, "#include <%s>\n", importHeader.c_str());
+#if defined(STATS_SCHEMA_LEGACY)
+ (void)supportQ; // Workaround for unused parameter error.
+ write_native_cpp_includes_q(out);
+#else
+ if (supportQ) {
+ fprintf(out, "#include <StatsEventCompat.h>\n");
+ } else {
+ fprintf(out, "#include <stats_event.h>\n");
+ }
+#endif
+
+ fprintf(out, "\n");
+ write_namespace(out, cppNamespace);
+
+#if defined(STATS_SCHEMA_LEGACY)
+ write_native_stats_log_cpp_globals_q(out);
+ write_native_get_timestamp_ns_q(out);
+ write_native_try_stats_write_methods_q(out, atoms, attributionDecl, moduleName);
+ write_native_stats_write_methods_q(out, "int stats_write", atoms, attributionDecl, moduleName,
+ "try_stats_write");
+ write_native_try_stats_write_non_chained_methods_q(out, atoms, attributionDecl, moduleName);
+ write_native_stats_write_non_chained_methods_q(out, "int stats_write_non_chained", atoms,
+ attributionDecl, moduleName, "try_stats_write_non_chained");
+#else
+ write_native_stats_write_methods(out, atoms, attributionDecl, moduleName, supportQ);
+ write_native_stats_write_non_chained_methods(out, atoms, attributionDecl, moduleName);
+#endif
+
+ // Print footer
+ fprintf(out, "\n");
+ write_closing_namespace(out, cppNamespace);
+
+ return 0;
+}
+
+int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
+ const string& moduleName, const string& cppNamespace) {
+ // Print prelude
+ fprintf(out, "// This file is autogenerated\n");
+ fprintf(out, "\n");
+ fprintf(out, "#pragma once\n");
+ fprintf(out, "\n");
+ fprintf(out, "#include <stdint.h>\n");
+ fprintf(out, "#include <vector>\n");
+ fprintf(out, "#include <map>\n");
+ fprintf(out, "#include <set>\n");
+ fprintf(out, "\n");
+
+ write_namespace(out, cppNamespace);
+ fprintf(out, "\n");
+ fprintf(out, "/*\n");
+ fprintf(out, " * API For logging statistics events.\n");
+ fprintf(out, " */\n");
+ fprintf(out, "\n");
+
+ write_native_atom_constants(out, atoms, attributionDecl, moduleName);
+
+ // Print constants for the enum values.
+ fprintf(out, "//\n");
+ fprintf(out, "// Constants for enum values\n");
+ fprintf(out, "//\n\n");
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+ atom != atoms.decls.end(); atom++) {
+ // Skip if the atom is not needed for the module.
+ if (!atom_needed_for_module(*atom, moduleName)) {
+ continue;
+ }
+
+ for (vector<AtomField>::const_iterator field = atom->fields.begin();
+ field != atom->fields.end(); field++) {
+ if (field->javaType == JAVA_TYPE_ENUM) {
+ fprintf(out, "// Values for %s.%s\n", atom->message.c_str(),
+ field->name.c_str());
+ for (map<int, string>::const_iterator value = field->enumValues.begin();
+ value != field->enumValues.end(); value++) {
+ fprintf(out, "const int32_t %s__%s__%s = %d;\n",
+ make_constant_name(atom->message).c_str(),
+ make_constant_name(field->name).c_str(),
+ make_constant_name(value->second).c_str(),
+ value->first);
+ }
+ fprintf(out, "\n");
+ }
+ }
+ }
+
+ fprintf(out, "struct BytesField {\n");
+ fprintf(out,
+ " BytesField(char const* array, size_t len) : arg(array), "
+ "arg_length(len) {}\n");
+ fprintf(out, " char const* arg;\n");
+ fprintf(out, " size_t arg_length;\n");
+ fprintf(out, "};\n");
+ fprintf(out, "\n");
+
+ // Print write methods
+ fprintf(out, "//\n");
+ fprintf(out, "// Write methods\n");
+ fprintf(out, "//\n");
+ write_native_method_header(out, "int stats_write", atoms.signatures_to_modules, attributionDecl,
+ moduleName);
+
+ fprintf(out, "//\n");
+ fprintf(out, "// Write flattened methods\n");
+ fprintf(out, "//\n");
+ write_native_method_header(out, "int stats_write_non_chained",
+ atoms.non_chained_signatures_to_modules, attributionDecl, moduleName);
+
+ fprintf(out, "\n");
+ write_closing_namespace(out, cppNamespace);
+
+ return 0;
+}
+
+} // namespace stats_log_api_gen
+} // namespace android
diff --git a/tools/stats_log_api_gen/native_writer.h b/tools/stats_log_api_gen/native_writer.h
new file mode 100644
index 0000000..aafa96e
--- /dev/null
+++ b/tools/stats_log_api_gen/native_writer.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Collation.h"
+
+#include <stdio.h>
+#include <string.h>
+
+namespace android {
+namespace stats_log_api_gen {
+
+using namespace std;
+
+int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
+ const string& moduleName, const string& cppNamespace, const string& importHeader,
+ const bool supportQ);
+
+int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
+ const string& moduleName, const string& cppNamespace);
+
+} // namespace stats_log_api_gen
+} // namespace android
diff --git a/tools/stats_log_api_gen/native_writer_q.cpp b/tools/stats_log_api_gen/native_writer_q.cpp
new file mode 100644
index 0000000..299873d
--- /dev/null
+++ b/tools/stats_log_api_gen/native_writer_q.cpp
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ */
+
+#include "native_writer_q.h"
+#include "utils.h"
+
+namespace android {
+namespace stats_log_api_gen {
+
+static void write_native_stats_write_body_q(FILE* out, const vector<java_type_t>& signature,
+ const AtomDecl& attributionDecl, const string& indent, const string& tryMethodName) {
+ fprintf(out, "%sint ret = 0;\n", indent.c_str());
+
+ fprintf(out, "%sfor(int retry = 0; retry < 2; ++retry) {\n", indent.c_str());
+ fprintf(out, "%s ret = ", indent.c_str());
+ write_native_method_call(out, tryMethodName, signature, attributionDecl);
+ fprintf(out, "%s if (ret >= 0) { break; }\n", indent.c_str());
+
+ fprintf(out, "%s {\n", indent.c_str());
+ fprintf(out, "%s std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n", indent.c_str());
+ fprintf(out, "%s if ((get_elapsed_realtime_ns() - lastRetryTimestampNs) <= "
+ "kMinRetryIntervalNs) break;\n", indent.c_str());
+ fprintf(out, "%s lastRetryTimestampNs = get_elapsed_realtime_ns();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s std::this_thread::sleep_for(std::chrono::milliseconds(10));\n",
+ indent.c_str());
+ fprintf(out, "%s}\n", indent.c_str());
+ fprintf(out, "%sif (ret < 0) {\n", indent.c_str());
+ fprintf(out, "%s note_log_drop(ret, code);\n", indent.c_str());
+ fprintf(out, "%s}\n", indent.c_str());
+ fprintf(out, "%sreturn ret;\n", indent.c_str());
+}
+
+void write_native_cpp_includes_q(FILE* out) {
+ fprintf(out, "#include <mutex>\n");
+ fprintf(out, "#include <chrono>\n");
+ fprintf(out, "#include <thread>\n");
+ fprintf(out, "#ifdef __ANDROID__\n");
+ fprintf(out, "#include <cutils/properties.h>\n");
+ fprintf(out, "#endif\n");
+ fprintf(out, "#include <stats_event_list.h>\n");
+ fprintf(out, "#include <log/log.h>\n");
+ fprintf(out, "#include <time.h>\n");
+}
+
+void write_native_get_timestamp_ns_q(FILE* out) {
+ fprintf(out, "\n");
+ fprintf(out, "static int64_t get_elapsed_realtime_ns() {\n");
+ fprintf(out, " struct timespec t;\n");
+ fprintf(out, " t.tv_sec = t.tv_nsec = 0;\n");
+ fprintf(out, " clock_gettime(CLOCK_BOOTTIME, &t);\n");
+ fprintf(out, " return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;\n");
+ fprintf(out, "}\n");
+}
+
+void write_native_stats_log_cpp_globals_q(FILE* out) {
+ fprintf(out, "// the single event tag id for all stats logs\n");
+ fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
+ fprintf(out, "#ifdef __ANDROID__\n");
+ fprintf(out,
+ "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
+ fprintf(out, "#else\n");
+ fprintf(out, "const static bool kStatsdEnabled = false;\n");
+ fprintf(out, "#endif\n");
+
+ fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
+ fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
+ fprintf(out, "static std::mutex mLogdRetryMutex;\n");
+}
+
+void write_native_try_stats_write_methods_q(FILE* out, const Atoms& atoms,
+ const AtomDecl& attributionDecl, const string& moduleName) {
+ fprintf(out, "\n");
+ for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
+ signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
+ if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+ continue;
+ }
+ vector<java_type_t> signature = signature_to_modules_it->first;
+
+ write_native_method_signature(out, "static int try_stats_write", signature,
+ attributionDecl, " {");
+
+ int argIndex = 1;
+ fprintf(out, " if (kStatsdEnabled) {\n");
+ fprintf(out, " stats_event_list event(kStatsEventTag);\n");
+ fprintf(out, " event << get_elapsed_realtime_ns();\n\n");
+ fprintf(out, " event << code;\n\n");
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (const auto &chainField : attributionDecl.fields) {
+ if (chainField.javaType == JAVA_TYPE_STRING) {
+ fprintf(out, " if (%s_length != %s.size()) {\n",
+ attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
+ fprintf(out, " return -EINVAL;\n");
+ fprintf(out, " }\n");
+ }
+ }
+ fprintf(out, "\n event.begin();\n");
+ fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
+ attributionDecl.fields.front().name.c_str());
+ fprintf(out, " event.begin();\n");
+ for (const auto &chainField : attributionDecl.fields) {
+ if (chainField.javaType == JAVA_TYPE_STRING) {
+ fprintf(out, " if (%s[i] != NULL) {\n", chainField.name.c_str());
+ fprintf(out, " event << %s[i];\n", chainField.name.c_str());
+ fprintf(out, " } else {\n");
+ fprintf(out, " event << \"\";\n");
+ fprintf(out, " }\n");
+ } else {
+ fprintf(out, " event << %s[i];\n", chainField.name.c_str());
+ }
+ }
+ fprintf(out, " event.end();\n");
+ fprintf(out, " }\n");
+ fprintf(out, " event.end();\n\n");
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, " event.begin();\n\n");
+ fprintf(out, " for (const auto& it : arg%d_1) {\n", argIndex);
+ fprintf(out, " event.begin();\n");
+ fprintf(out, " event << it.first;\n");
+ fprintf(out, " event << it.second;\n");
+ fprintf(out, " event.end();\n");
+ fprintf(out, " }\n");
+
+ fprintf(out, " for (const auto& it : arg%d_2) {\n", argIndex);
+ fprintf(out, " event.begin();\n");
+ fprintf(out, " event << it.first;\n");
+ fprintf(out, " event << it.second;\n");
+ fprintf(out, " event.end();\n");
+ fprintf(out, " }\n");
+
+ fprintf(out, " for (const auto& it : arg%d_3) {\n", argIndex);
+ fprintf(out, " event.begin();\n");
+ fprintf(out, " event << it.first;\n");
+ fprintf(out, " event << it.second;\n");
+ fprintf(out, " event.end();\n");
+ fprintf(out, " }\n");
+
+ fprintf(out, " for (const auto& it : arg%d_4) {\n", argIndex);
+ fprintf(out, " event.begin();\n");
+ fprintf(out, " event << it.first;\n");
+ fprintf(out, " event << it.second;\n");
+ fprintf(out, " event.end();\n");
+ fprintf(out, " }\n");
+
+ fprintf(out, " event.end();\n\n");
+ } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+ fprintf(out,
+ " event.AppendCharArray(arg%d.arg, "
+ "arg%d.arg_length);\n",
+ argIndex, argIndex);
+ } else {
+ if (*arg == JAVA_TYPE_STRING) {
+ fprintf(out, " if (arg%d == NULL) {\n", argIndex);
+ fprintf(out, " arg%d = \"\";\n", argIndex);
+ fprintf(out, " }\n");
+ }
+ fprintf(out, " event << arg%d;\n", argIndex);
+ }
+ argIndex++;
+ }
+
+ fprintf(out, " return event.write(LOG_ID_STATS);\n");
+ fprintf(out, " } else {\n");
+ fprintf(out, " return 1;\n");
+ fprintf(out, " }\n");
+ fprintf(out, "}\n");
+ fprintf(out, "\n");
+ }
+
+}
+
+void write_native_stats_write_methods_q(FILE* out, const string& methodName, const Atoms& atoms,
+ const AtomDecl& attributionDecl, const string& moduleName, const string& tryMethodName) {
+ for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
+ signature_to_modules_it != atoms.signatures_to_modules.end();
+ signature_to_modules_it++) {
+ if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+ continue;
+ }
+ vector<java_type_t> signature = signature_to_modules_it->first;
+
+ write_native_method_signature(out, methodName, signature, attributionDecl, " {");
+
+ write_native_stats_write_body_q(out, signature, attributionDecl, " ", tryMethodName);
+ fprintf(out, "}\n\n");
+ }
+}
+
+void write_native_stats_write_non_chained_methods_q(FILE* out, const string& methodName,
+ const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName,
+ const string& tryMethodName) {
+ for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
+ signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
+ if (!signature_needed_for_module(signature_it->second, moduleName)) {
+ continue;
+ }
+ vector<java_type_t> signature = signature_it->first;
+
+ write_native_method_signature(out, methodName, signature, attributionDecl, " {");
+
+ write_native_stats_write_body_q(out, signature, attributionDecl, " ", tryMethodName);
+ fprintf(out, "}\n\n");
+ }
+}
+
+void write_native_try_stats_write_non_chained_methods_q(FILE* out, const Atoms& atoms,
+ const AtomDecl& attributionDecl, const string& moduleName) {
+ for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
+ signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
+ if (!signature_needed_for_module(signature_it->second, moduleName)) {
+ continue;
+ }
+ vector<java_type_t> signature = signature_it->first;
+
+ write_native_method_signature(out, "static int try_stats_write_non_chained", signature,
+ attributionDecl, " {");
+
+ int argIndex = 1;
+ fprintf(out, " if (kStatsdEnabled) {\n");
+ fprintf(out, " stats_event_list event(kStatsEventTag);\n");
+ fprintf(out, " event << get_elapsed_realtime_ns();\n\n");
+ fprintf(out, " event << code;\n\n");
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ if (argIndex == 1) {
+ fprintf(out, " event.begin();\n\n");
+ fprintf(out, " event.begin();\n");
+ }
+ if (*arg == JAVA_TYPE_STRING) {
+ fprintf(out, " if (arg%d == NULL) {\n", argIndex);
+ fprintf(out, " arg%d = \"\";\n", argIndex);
+ fprintf(out, " }\n");
+ }
+ if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+ fprintf(out,
+ " event.AppendCharArray(arg%d.arg, "
+ "arg%d.arg_length);\n",
+ argIndex, argIndex);
+ } else {
+ fprintf(out, " event << arg%d;\n", argIndex);
+ }
+ if (argIndex == 2) {
+ fprintf(out, " event.end();\n\n");
+ fprintf(out, " event.end();\n\n");
+ }
+ argIndex++;
+ }
+
+ fprintf(out, " return event.write(LOG_ID_STATS);\n");
+ fprintf(out, " } else {\n");
+ fprintf(out, " return 1;\n");
+ fprintf(out, " }\n");
+ fprintf(out, "}\n");
+ fprintf(out, "\n");
+ }
+}
+
+} // namespace stats_log_api_gen
+} // namespace android
diff --git a/tools/stats_log_api_gen/native_writer_q.h b/tools/stats_log_api_gen/native_writer_q.h
new file mode 100644
index 0000000..a2ab1ae
--- /dev/null
+++ b/tools/stats_log_api_gen/native_writer_q.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Collation.h"
+
+#include <stdio.h>
+#include <string.h>
+
+namespace android {
+namespace stats_log_api_gen {
+
+using namespace std;
+
+void write_native_cpp_includes_q(FILE* out);
+
+void write_native_stats_log_cpp_globals_q(FILE* out);
+
+void write_native_try_stats_write_methods_q(FILE* out, const Atoms& atoms,
+ const AtomDecl& attributionDecl, const string& moduleName);
+
+void write_native_stats_write_methods_q(FILE* out, const string& methodName, const Atoms& atoms,
+ const AtomDecl& attributionDecl, const string& moduleName, const string& tryMethodName);
+
+void write_native_try_stats_write_non_chained_methods_q(FILE* out, const Atoms& atoms,
+ const AtomDecl& attributionDecl, const string& moduleName);
+
+void write_native_stats_write_non_chained_methods_q(FILE* out, const string& methodName,
+ const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName,
+ const string& tryMethodName);
+
+void write_native_get_timestamp_ns_q(FILE* out);
+
+} // namespace stats_log_api_gen
+} // namespace android
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index c3e70382..c9a4763 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -229,8 +229,8 @@
message ModuleAtoms {
oneof event {
- ModuleOneAtom module_one_atom = 1 [(android.os.statsd.log_from_module) = "module1"];
- ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.log_from_module) = "module2"];
+ ModuleOneAtom module_one_atom = 1 [(android.os.statsd.module) = "module1"];
+ ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.module) = "module2"];
NoModuleAtom no_module_atom = 3;
}
-}
\ No newline at end of file
+}
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
index d6cfe95..c65d190 100644
--- a/tools/stats_log_api_gen/utils.cpp
+++ b/tools/stats_log_api_gen/utils.cpp
@@ -204,6 +204,65 @@
fprintf(out, "\n");
}
+void write_native_method_signature(FILE* out, const string& methodName,
+ const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
+ const string& closer) {
+ fprintf(out, "%s(int32_t code", methodName.c_str());
+ int argIndex = 1;
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ if (chainField.javaType == JAVA_TYPE_STRING) {
+ fprintf(out, ", const std::vector<%s>& %s",
+ cpp_type_name(chainField.javaType),
+ chainField.name.c_str());
+ } else {
+ fprintf(out, ", const %s* %s, size_t %s_length",
+ cpp_type_name(chainField.javaType),
+ chainField.name.c_str(), chainField.name.c_str());
+ }
+ }
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
+ "const std::map<int, int64_t>& arg%d_2, "
+ "const std::map<int, char const*>& arg%d_3, "
+ "const std::map<int, float>& arg%d_4",
+ argIndex, argIndex, argIndex, argIndex);
+ } else {
+ fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
+ }
+ argIndex++;
+ }
+ fprintf(out, ")%s\n", closer.c_str());
+}
+
+void write_native_method_call(FILE* out, const string& methodName,
+ const vector<java_type_t>& signature, const AtomDecl& attributionDecl, int argIndex) {
+ fprintf(out, "%s(code", methodName.c_str());
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ if (chainField.javaType == JAVA_TYPE_STRING) {
+ fprintf(out, ", %s",
+ chainField.name.c_str());
+ } else {
+ fprintf(out, ", %s, %s_length",
+ chainField.name.c_str(), chainField.name.c_str());
+ }
+ }
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex,
+ argIndex, argIndex, argIndex);
+ } else {
+ fprintf(out, ", arg%d", argIndex);
+ }
+ argIndex++;
+ }
+ fprintf(out, ");\n");
+}
+
// Java
void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleName) {
fprintf(out, " // Constants for atom codes.\n");
diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h
index a89387f..50737a6 100644
--- a/tools/stats_log_api_gen/utils.h
+++ b/tools/stats_log_api_gen/utils.h
@@ -56,8 +56,14 @@
void write_closing_namespace(FILE* out, const string& cppNamespaces);
void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
- const string& moduleName
-);
+ const string& moduleName);
+
+void write_native_method_signature(FILE* out, const string& methodName,
+ const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
+ const string& closer);
+
+void write_native_method_call(FILE* out, const string& methodName,
+ const vector<java_type_t>& signature, const AtomDecl& attributionDecl, int argIndex = 1);
// Common Java helpers.
void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleName);
@@ -69,14 +75,12 @@
int write_java_non_chained_methods(FILE* out, const map<vector<java_type_t>,
set<string>>& signatures_to_modules,
- const string& moduleName
-);
+ const string& moduleName);
int write_java_work_source_methods(
FILE* out,
const map<vector<java_type_t>, set<string>>& signatures_to_modules,
- const string& moduleName
-);
+ const string& moduleName);
} // namespace stats_log_api_gen
} // namespace android
diff --git a/wifi/Android.bp b/wifi/Android.bp
index fb1f866..35a892a 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -42,11 +42,21 @@
srcs: ["java/android/net/wifi/WifiAnnotations.java"],
}
+// list of tests that are allowed to access @hide APIs from framework-wifi
+test_access_hidden_api_whitelist = [
+ "//frameworks/base/wifi/tests",
+ "//frameworks/opt/net/wifi/tests/wifitests:__subpackages__",
+
+ "//frameworks/opt/net/wifi/libs/WifiTrackerLib/tests",
+]
+
java_library {
name: "framework-wifi",
- sdk_version: "core_platform", // TODO(b/140299412) should be core_current
+ // TODO(b/140299412) should be core_current once we build against framework-system-stubs
+ sdk_version: "core_platform",
libs: [
- "framework-minus-apex", // TODO(b/140299412) should be framework-system-stubs
+ // TODO(b/140299412) should be framework-system-stubs once we fix all @hide dependencies
+ "framework-minus-apex",
],
srcs: [
":framework-wifi-updatable-sources",
@@ -54,7 +64,12 @@
installable: true,
optimize: {
enabled: false
- }
+ },
+ visibility: [
+ "//frameworks/base", // TODO(b/140299412) remove once all dependencies are fixed
+ "//frameworks/opt/net/wifi/service:__subpackages__",
+ ] + test_access_hidden_api_whitelist,
+ plugins: ["java_api_finder"],
}
droidstubs {
@@ -84,3 +99,16 @@
installable: false,
}
+// defaults for tests that need to build against framework-wifi's @hide APIs
+java_defaults {
+ name: "framework-wifi-test-defaults",
+ sdk_version: "core_platform", // tests can use @CorePlatformApi's
+ libs: [
+ "framework-wifi",
+ "framework-minus-apex",
+
+ // if sdk_version="" this gets automatically included, but here we need to add manually.
+ "framework-res",
+ ],
+ visibility: test_access_hidden_api_whitelist,
+}
diff --git a/wifi/java/android/net/wifi/WifiClient.java b/wifi/java/android/net/wifi/WifiClient.java
index 3e09580..3794566 100644
--- a/wifi/java/android/net/wifi/WifiClient.java
+++ b/wifi/java/android/net/wifi/WifiClient.java
@@ -22,8 +22,6 @@
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.internal.util.Preconditions;
-
import java.util.Objects;
/** @hide */
@@ -46,7 +44,7 @@
/** @hide */
public WifiClient(@NonNull MacAddress macAddress) {
- Preconditions.checkNotNull(macAddress, "mMacAddress must not be null.");
+ Objects.requireNonNull(macAddress, "mMacAddress must not be null.");
this.mMacAddress = macAddress;
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index e3a945d..2a165d3 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2446,10 +2446,14 @@
return key;
}
- /** @hide */
- @UnsupportedAppUsage
+ /**
+ * Get the IpConfiguration object associated with this WifiConfiguration.
+ * @hide
+ */
+ @NonNull
+ @SystemApi
public IpConfiguration getIpConfiguration() {
- return mIpConfiguration;
+ return new IpConfiguration(mIpConfiguration);
}
/**
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
index be37c22..378549d 100755
--- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
+++ b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
@@ -29,11 +29,11 @@
import android.util.LruCache;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
+import java.util.Objects;
/**
* {@link INetworkScoreCache} implementation for Wifi Networks.
@@ -290,7 +290,7 @@
* This cannot be null.
*/
public CacheListener(@NonNull Handler handler) {
- Preconditions.checkNotNull(handler);
+ Objects.requireNonNull(handler);
mHandler = handler;
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 8badcc0..2c39c32a 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -40,7 +40,6 @@
import android.util.SparseArray;
import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.Preconditions;
import com.android.internal.util.Protocol;
import java.lang.annotation.Retention;
@@ -48,6 +47,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -840,8 +840,8 @@
@RequiresPermission(Manifest.permission.NETWORK_STACK)
public void registerScanListener(@NonNull @CallbackExecutor Executor executor,
@NonNull ScanListener listener) {
- Preconditions.checkNotNull(executor, "executor cannot be null");
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ Objects.requireNonNull(executor, "executor cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
int key = addListener(listener, executor);
if (key == INVALID_KEY) return;
validateChannel();
@@ -864,7 +864,7 @@
* #registerScanListener}
*/
public void unregisterScanListener(@NonNull ScanListener listener) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
@@ -894,7 +894,7 @@
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void startBackgroundScan(ScanSettings settings, ScanListener listener,
WorkSource workSource) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
int key = addListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
@@ -913,7 +913,7 @@
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void stopBackgroundScan(ScanListener listener) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
@@ -962,7 +962,7 @@
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
int key = addListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
@@ -981,7 +981,7 @@
*/
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public void stopScan(ScanListener listener) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
@@ -1036,8 +1036,8 @@
*/
public void startConnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
PnoScanListener listener) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
- Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
+ Objects.requireNonNull(pnoSettings, "pnoSettings cannot be null");
int key = addListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
@@ -1058,8 +1058,8 @@
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
public void startDisconnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
PnoScanListener listener) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
- Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
+ Objects.requireNonNull(pnoSettings, "pnoSettings cannot be null");
int key = addListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
@@ -1074,7 +1074,7 @@
*/
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
public void stopPnoScan(ScanListener listener) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
+ Objects.requireNonNull(listener, "listener cannot be null");
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();