diff options
186 files changed, 4468 insertions, 1822 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index e479c4874375..36680a171f35 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1635,7 +1635,7 @@ package android.content.pm { method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentServicesAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle); method public abstract void registerDexModule(@NonNull String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback); method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener); - method @Deprecated public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName); + method public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName); method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle); method public void sendDeviceCustomizationReadyBroadcast(); method @RequiresPermission(allOf={android.Manifest.permission.SET_PREFERRED_APPLICATIONS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract boolean setDefaultBrowserPackageNameAsUser(@Nullable String, int); diff --git a/api/test-current.txt b/api/test-current.txt index 77c3a94f1d10..aacf2c1fa9a6 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -3205,6 +3205,7 @@ package android.view { method public default void setShouldShowIme(int, boolean); method public default void setShouldShowSystemDecors(int, boolean); method public default void setShouldShowWithInsecureKeyguard(int, boolean); + method public default boolean shouldShowIme(int); method public default boolean shouldShowSystemDecors(int); } diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index a9f5208ef812..ec02b121d0dd 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -68,12 +68,8 @@ const int FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS = 6; const int FIELD_ID_DUMP_REPORT_REASON = 8; const int FIELD_ID_STRINGS = 9; -const int FIELD_ID_ACTIVE_CONFIG_LIST = 1; -const int FIELD_ID_CONFIG_ID = 1; -const int FIELD_ID_CONFIG_UID = 2; -const int FIELD_ID_ACTIVE_METRIC = 3; -const int FIELD_ID_METRIC_ID = 1; -const int FIELD_ID_TIME_TO_LIVE_NANOS = 2; +// for ActiveConfigList +const int FIELD_ID_ACTIVE_CONFIG_LIST_CONFIG = 1; #define NS_PER_HOUR 3600 * NS_PER_SEC @@ -523,7 +519,7 @@ void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) { std::lock_guard<std::mutex> lock(mMetricsMutex); auto it = mMetricsManagers.find(key); if (it != mMetricsManagers.end()) { - WriteDataToDiskLocked(key, getElapsedRealtimeNs(), CONFIG_REMOVED, + WriteDataToDiskLocked(key, getElapsedRealtimeNs(), CONFIG_REMOVED, NO_TIME_CONSTRAINTS); mMetricsManagers.erase(it); mUidMap->OnConfigRemoved(key); @@ -613,7 +609,7 @@ void StatsLogProcessor::WriteDataToDiskLocked(const ConfigKey& key, mOnDiskDataConfigs.insert(key); } -void StatsLogProcessor::WriteMetricsActivationToDisk(int64_t currentTimeNs) { +void StatsLogProcessor::SaveActiveConfigsToDisk(int64_t currentTimeNs) { std::lock_guard<std::mutex> lock(mMetricsMutex); const int64_t timeNs = getElapsedRealtimeNs(); @@ -629,28 +625,12 @@ void StatsLogProcessor::WriteMetricsActivationToDisk(int64_t currentTimeNs) { mLastActiveMetricsWriteNs = timeNs; ProtoOutputStream proto; - for (const auto& pair : mMetricsManagers) { - uint64_t activeConfigListToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | - FIELD_ID_ACTIVE_CONFIG_LIST); - proto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_ID, (long long)pair.first.GetId()); - proto.write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_UID, pair.first.GetUid()); - - vector<MetricProducer*> activeMetrics; - pair.second->prepForShutDown(currentTimeNs); - pair.second->getActiveMetrics(activeMetrics); - for (MetricProducer* metric : activeMetrics) { - if (metric->isActive()) { - uint64_t metricToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | - FIELD_ID_ACTIVE_METRIC); - proto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_ID, - (long long)metric->getMetricId()); - proto.write(FIELD_TYPE_INT64 | FIELD_ID_TIME_TO_LIVE_NANOS, - (long long)metric->getRemainingTtlNs(currentTimeNs)); - proto.end(metricToken); - } - } - proto.end(activeConfigListToken); + const sp<MetricsManager>& metricsManager = pair.second; + uint64_t configToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | + FIELD_ID_ACTIVE_CONFIG_LIST_CONFIG); + metricsManager->writeActiveConfigToProtoOutputStream(currentTimeNs, &proto); + proto.end(configToken); } string file_name = StringPrintf("%s/active_metrics", STATS_ACTIVE_METRIC_DIR); @@ -664,30 +644,45 @@ void StatsLogProcessor::WriteMetricsActivationToDisk(int64_t currentTimeNs) { proto.flush(fd.get()); } -void StatsLogProcessor::LoadMetricsActivationFromDisk() { +void StatsLogProcessor::LoadActiveConfigsFromDisk() { + std::lock_guard<std::mutex> lock(mMetricsMutex); + string file_name = StringPrintf("%s/active_metrics", STATS_ACTIVE_METRIC_DIR); int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC); - if (fd != -1) { - string content; - if (android::base::ReadFdToString(fd, &content)) { - ActiveConfigList activeConfigList; - if (activeConfigList.ParseFromString(content)) { - for (int i = 0; i < activeConfigList.active_config_size(); i++) { - const auto& config = activeConfigList.active_config(i); - ConfigKey key(config.uid(), config.config_id()); - auto it = mMetricsManagers.find(key); - if (it == mMetricsManagers.end()) { - ALOGE("No config found for config %s", key.ToString().c_str()); - continue; - } - VLOG("Setting active config %s", key.ToString().c_str()); - it->second->setActiveMetrics(config, mTimeBaseNs); - } - } - VLOG("Successfully loaded %d active configs.", activeConfigList.active_config_size()); - } + if (-1 == fd) { + VLOG("Attempt to read %s but failed", file_name.c_str()); + StorageManager::deleteFile(file_name.c_str()); + return; + } + string content; + if (!android::base::ReadFdToString(fd, &content)) { + ALOGE("Attempt to read %s but failed", file_name.c_str()); close(fd); + StorageManager::deleteFile(file_name.c_str()); + return; + } + + close(fd); + + ActiveConfigList activeConfigList; + if (!activeConfigList.ParseFromString(content)) { + ALOGE("Attempt to read %s but failed; failed to load active configs", file_name.c_str()); + StorageManager::deleteFile(file_name.c_str()); + return; + } + for (int i = 0; i < activeConfigList.config_size(); i++) { + const auto& config = activeConfigList.config(i); + ConfigKey key(config.uid(), config.id()); + auto it = mMetricsManagers.find(key); + if (it == mMetricsManagers.end()) { + ALOGE("No config found for config %s", key.ToString().c_str()); + continue; + } + VLOG("Setting active config %s", key.ToString().c_str()); + it->second->loadActiveConfig(config, mTimeBaseNs); } + VLOG("Successfully loaded %d active configs.", activeConfigList.config_size()); + StorageManager::deleteFile(file_name.c_str()); } @@ -709,7 +704,7 @@ void StatsLogProcessor::WriteDataToDiskLocked(const DumpReportReason dumpReportR } } -void StatsLogProcessor::WriteDataToDisk(const DumpReportReason dumpReportReason, +void StatsLogProcessor::WriteDataToDisk(const DumpReportReason dumpReportReason, const DumpLatency dumpLatency) { std::lock_guard<std::mutex> lock(mMetricsMutex); WriteDataToDiskLocked(dumpReportReason, dumpLatency); diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 6178a4bdf136..0dc597b4cb02 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -89,11 +89,11 @@ public: void WriteDataToDisk(const DumpReportReason dumpReportReason, const DumpLatency dumpLatency); - /* Persist metric activation status onto disk. */ - void WriteMetricsActivationToDisk(int64_t currentTimeNs); + /* Persist configs containing metrics with active activations to disk. */ + void SaveActiveConfigsToDisk(int64_t currentTimeNs); - /* Load metric activation status from disk. */ - void LoadMetricsActivationFromDisk(); + /* Load configs containing metrics with active activations from disk. */ + void LoadActiveConfigsFromDisk(); // Reset all configs. void resetConfigs(); @@ -221,6 +221,9 @@ private: FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge); FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead); FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot); + FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations); + FRIEND_TEST(StatsLogProcessorTest, + TestActivationOnBootMultipleActivationsDifferentActivationTypes); FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1); FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2); diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 4c97c3454e82..623a1f2cdafb 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -28,6 +28,7 @@ #include <android-base/file.h> #include <android-base/stringprintf.h> +#include <android-base/strings.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/PermissionController.h> @@ -394,6 +395,10 @@ status_t StatsService::command(int in, int out, int err, Vector<String8>& args, return cmd_log_app_breadcrumb(out, args); } + if (!args[0].compare(String8("log-binary-push"))) { + return cmd_log_binary_push(out, args); + } + if (!args[0].compare(String8("clear-puller-cache"))) { return cmd_clear_puller_cache(out); } @@ -461,6 +466,21 @@ void StatsService::print_cmd_help(int out) { dprintf(out, " STATE Integer in [0, 3], as per atoms.proto.\n"); dprintf(out, "\n"); dprintf(out, "\n"); + dprintf(out, + "usage: adb shell cmd stats log-binary-push NAME VERSION STAGING ROLLBACK_ENABLED " + "LOW_LATENCY STATE EXPERIMENT_IDS\n"); + dprintf(out, " Log a binary push state changed event.\n"); + dprintf(out, " NAME The train name.\n"); + dprintf(out, " VERSION The train version code.\n"); + dprintf(out, " STAGING If this train requires a restart.\n"); + dprintf(out, " ROLLBACK_ENABLED If rollback should be enabled for this install.\n"); + dprintf(out, " LOW_LATENCY If the train requires low latency monitoring.\n"); + dprintf(out, " STATE The status of the train push.\n"); + dprintf(out, " Integer value of the enum in atoms.proto.\n"); + dprintf(out, " EXPERIMENT_IDS Comma separated list of experiment ids.\n"); + dprintf(out, " Leave blank for none.\n"); + dprintf(out, "\n"); + dprintf(out, "\n"); dprintf(out, "usage: adb shell cmd stats config remove [UID] [NAME]\n"); dprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n"); dprintf(out, "\n"); @@ -506,7 +526,6 @@ void StatsService::print_cmd_help(int out) { dprintf(out, " --configs Send the list of configs in the name list instead of\n"); dprintf(out, " the currently active configs\n"); dprintf(out, " NAME LIST List of configuration names to be included in the broadcast.\n"); - dprintf(out, "\n"); dprintf(out, "\n"); dprintf(out, "usage: adb shell cmd stats print-stats\n"); @@ -821,6 +840,39 @@ status_t StatsService::cmd_log_app_breadcrumb(int out, const Vector<String8>& ar return NO_ERROR; } +status_t StatsService::cmd_log_binary_push(int out, const Vector<String8>& args) { + // Security checks are done in the sendBinaryPushStateChanged atom. + const int argCount = args.size(); + if (argCount != 7 && argCount != 8) { + dprintf(out, "Incorrect number of argument supplied\n"); + return UNKNOWN_ERROR; + } + android::String16 trainName = android::String16(args[1].c_str()); + int64_t trainVersion = strtoll(args[2].c_str(), nullptr, 10); + int options = 0; + if (args[3] == "1") { + options = options | IStatsManager::FLAG_REQUIRE_STAGING; + } + if (args[4] == "1") { + options = options | IStatsManager::FLAG_ROLLBACK_ENABLED; + } + if (args[5] == "1") { + options = options | IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR; + } + int32_t state = atoi(args[6].c_str()); + vector<int64_t> experimentIds; + if (argCount == 8) { + vector<string> experimentIdsString = android::base::Split(string(args[7].c_str()), ","); + for (string experimentIdString : experimentIdsString) { + int64_t experimentId = strtoll(experimentIdString.c_str(), nullptr, 10); + experimentIds.push_back(experimentId); + } + } + dprintf(out, "Logging BinaryPushStateChanged\n"); + sendBinaryPushStateChangedAtom(trainName, trainVersion, options, state, experimentIds); + return NO_ERROR; +} + status_t StatsService::cmd_print_pulled_metrics(int out, const Vector<String8>& args) { int s = atoi(args[1].c_str()); vector<shared_ptr<LogEvent> > stats; @@ -986,7 +1038,7 @@ Status StatsService::informDeviceShutdown() { ENFORCE_UID(AID_SYSTEM); VLOG("StatsService::informDeviceShutdown"); mProcessor->WriteDataToDisk(DEVICE_SHUTDOWN, FAST); - mProcessor->WriteMetricsActivationToDisk(getElapsedRealtimeNs()); + mProcessor->SaveActiveConfigsToDisk(getElapsedRealtimeNs()); return Status::ok(); } @@ -1021,14 +1073,14 @@ Status StatsService::statsCompanionReady() { void StatsService::Startup() { mConfigManager->Startup(); - mProcessor->LoadMetricsActivationFromDisk(); + mProcessor->LoadActiveConfigsFromDisk(); } void StatsService::Terminate() { ALOGI("StatsService::Terminating"); if (mProcessor != nullptr) { mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED, FAST); - mProcessor->WriteMetricsActivationToDisk(getElapsedRealtimeNs()); + mProcessor->SaveActiveConfigsToDisk(getElapsedRealtimeNs()); } } @@ -1207,22 +1259,25 @@ Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& tra const int options, const int32_t state, const std::vector<int64_t>& experimentIdsIn) { + // Note: We skip the usage stats op check here since we do not have a package name. + // This is ok since we are overloading the usage_stats permission. + // This method only sends data, it does not receive it. + pid_t pid = IPCThreadState::self()->getCallingPid(); uid_t uid = IPCThreadState::self()->getCallingUid(); - // For testing - if (uid == AID_ROOT || uid == AID_SYSTEM || uid == AID_SHELL) { - return ok(); - } - - // Caller must be granted these permissions - if (!checkCallingPermission(String16(kPermissionDump))) { - return exception(binder::Status::EX_SECURITY, - StringPrintf("UID %d lacks permission %s", uid, kPermissionDump)); - } - if (!checkCallingPermission(String16(kPermissionUsage))) { - return exception(binder::Status::EX_SECURITY, - StringPrintf("UID %d lacks permission %s", uid, kPermissionUsage)); + // Root, system, and shell always have access + if (uid != AID_ROOT && uid != AID_SYSTEM && uid != AID_SHELL) { + // Caller must be granted these permissions + if (!checkCallingPermission(String16(kPermissionDump))) { + return exception(binder::Status::EX_SECURITY, + StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, + kPermissionDump)); + } + if (!checkCallingPermission(String16(kPermissionUsage))) { + return exception(binder::Status::EX_SECURITY, + StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, + kPermissionUsage)); + } } - // TODO: add verifier permission bool readTrainInfoSuccess = false; InstallTrainInfo trainInfoOnDisk; diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 0b6df8b0997c..936f7db52c38 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -331,6 +331,11 @@ private: status_t cmd_log_app_breadcrumb(int outFd, const Vector<String8>& args); /** + * Write an BinaryPushStateChanged event, as if calling StatsLog.logBinaryPushStateChanged(). + */ + status_t cmd_log_binary_push(int outFd, const Vector<String8>& args); + + /** * Print contents of a pulled metrics source. */ status_t cmd_print_pulled_metrics(int outFd, const Vector<String8>& args); diff --git a/cmds/statsd/src/active_config_list.proto b/cmds/statsd/src/active_config_list.proto index 0e9ee03dd2cb..ef8e50bb2596 100644 --- a/cmds/statsd/src/active_config_list.proto +++ b/cmds/statsd/src/active_config_list.proto @@ -21,23 +21,26 @@ option java_package = "com.android.os"; option java_multiple_files = true; option java_outer_classname = "ActiveConfigProto"; +message ActiveEventActivation { + optional int32 atom_matcher_index = 1; + + // Time left in activation. When this proto is loaded after device boot, + // the activation should be set to active for this duration. + optional int64 remaining_ttl_nanos = 2; +} + message ActiveMetric { - // metric id - optional int64 metric_id = 1; - // Remaining time to live in nano seconds. -1 for infinity. - optional int64 time_to_live_nanos = 2; + optional int64 id = 1; + repeated ActiveEventActivation activation = 2; } message ActiveConfig { - // config id - optional int64 config_id = 1; - // config uid + optional int64 id = 1; optional int32 uid = 2; - // metrics - repeated ActiveMetric active_metric = 3; + repeated ActiveMetric metric = 3; } // all configs and their metrics on device. message ActiveConfigList { - repeated ActiveConfig active_config = 1; -}
\ No newline at end of file + repeated ActiveConfig config = 1; +} diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 2bd429976d4c..318d90ca9199 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -3296,7 +3296,10 @@ message BinaryPushStateChanged { INSTALL_STAGED_NOT_READY = 3; INSTALL_STAGED_READY = 4; INSTALL_SUCCESS = 5; - INSTALL_FAILURE = 6; + // Replaced by INSTALL_FAILURE_DOWNLOAD, INSTALL_FAILURE_STATE_MISMATCH, + // and INSTALL_FAILURE_COMMIT. + INSTALL_FAILURE = 6 [deprecated = true]; + // This enum is for installs that are manually cancelled via the Manual Update UI. INSTALL_CANCELLED = 7; INSTALLER_ROLLBACK_REQUESTED = 8; INSTALLER_ROLLBACK_INITIATED = 9; @@ -3313,6 +3316,9 @@ message BinaryPushStateChanged { INSTALL_STAGED_CANCEL_REQUESTED = 20; INSTALL_STAGED_CANCEL_SUCCESS = 21; INSTALL_STAGED_CANCEL_FAILURE = 22; + INSTALL_FAILURE_DOWNLOAD = 23; + INSTALL_FAILURE_STATE_MISMATCH = 24; + INSTALL_FAILURE_COMMIT = 25; } optional State state = 6; // Possible experiment ids for monitoring this push. @@ -5863,7 +5869,10 @@ message TrainInfo { INSTALL_STAGED_NOT_READY = 3; INSTALL_STAGED_READY = 4; INSTALL_SUCCESS = 5; - INSTALL_FAILURE = 6; + // Replaced by INSTALL_FAILURE_DOWNLOAD, INSTALL_FAILURE_STATE_MISMATCH, + // and INSTALL_FAILURE_COMMIT. + INSTALL_FAILURE = 6 [deprecated = true]; + // This enum is for installs that are manually cancelled via the Manual Update UI. INSTALL_CANCELLED = 7; INSTALLER_ROLLBACK_REQUESTED = 8; INSTALLER_ROLLBACK_INITIATED = 9; @@ -5880,6 +5889,9 @@ message TrainInfo { INSTALL_STAGED_CANCEL_REQUESTED = 20; INSTALL_STAGED_CANCEL_SUCCESS = 21; INSTALL_STAGED_CANCEL_FAILURE = 22; + INSTALL_FAILURE_DOWNLOAD = 23; + INSTALL_FAILURE_STATE_MISMATCH = 24; + INSTALL_FAILURE_COMMIT = 25; } optional Status status = 4; } diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp index e22b85370052..9ad7f09ab512 100644 --- a/cmds/statsd/src/metrics/MetricProducer.cpp +++ b/cmds/statsd/src/metrics/MetricProducer.cpp @@ -18,12 +18,26 @@ #include "Log.h" #include "MetricProducer.h" +using android::util::FIELD_COUNT_REPEATED; +using android::util::FIELD_TYPE_INT32; +using android::util::FIELD_TYPE_INT64; +using android::util::FIELD_TYPE_MESSAGE; +using android::util::ProtoOutputStream; + namespace android { namespace os { namespace statsd { using std::map; +// for ActiveMetric +const int FIELD_ID_ACTIVE_METRIC_ID = 1; +const int FIELD_ID_ACTIVE_METRIC_ACTIVATION = 2; + +// for ActiveEventActivation +const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX = 1; +const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS = 2; + void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) { if (!mIsActive) { return; @@ -74,7 +88,7 @@ bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) { bool isActive = mEventActivationMap.empty(); for (auto& it : mEventActivationMap) { if (it.second->state == ActivationState::kActive && - elapsedTimestampNs > it.second->ttl_ns + it.second->activation_ns) { + elapsedTimestampNs > it.second->ttl_ns + it.second->start_ns) { it.second->state = ActivationState::kNotActive; } if (it.second->state == ActivationState::kActive) { @@ -95,8 +109,8 @@ void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) { } } -void MetricProducer::addActivation(int activationTrackerIndex, int64_t ttl_seconds, - int deactivationTrackerIndex) { +void MetricProducer::addActivation(int activationTrackerIndex, const ActivationType& activationType, + int64_t ttl_seconds, int deactivationTrackerIndex) { std::lock_guard<std::mutex> lock(mMutex); // When a metric producer does not depend on any activation, its mIsActive is true. // Therefore, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not @@ -104,8 +118,8 @@ void MetricProducer::addActivation(int activationTrackerIndex, int64_t ttl_secon if (mEventActivationMap.empty()) { mIsActive = false; } - std::shared_ptr<Activation> activation = std::make_shared<Activation>(); - activation->ttl_ns = ttl_seconds * NS_PER_SEC; + std::shared_ptr<Activation> activation = + std::make_shared<Activation>(activationType, ttl_seconds * NS_PER_SEC); mEventActivationMap.emplace(activationTrackerIndex, activation); if (-1 != deactivationTrackerIndex) { mEventDeactivationMap.emplace(deactivationTrackerIndex, activation); @@ -117,13 +131,16 @@ void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedT if (it == mEventActivationMap.end()) { return; } - if (mActivationType == MetricActivation::ACTIVATE_ON_BOOT && - it->second->state == ActivationState::kNotActive) { - it->second->state = ActivationState::kActiveOnBoot; + auto& activation = it->second; + if (ACTIVATE_ON_BOOT == activation->activationType) { + if (ActivationState::kNotActive == activation->state) { + activation->state = ActivationState::kActiveOnBoot; + } + // If the Activation is already active or set to kActiveOnBoot, do nothing. return; } - it->second->activation_ns = elapsedTimestampNs; - it->second->state = ActivationState::kActive; + activation->start_ns = elapsedTimestampNs; + activation->state = ActivationState::kActive; mIsActive = true; } @@ -135,46 +152,55 @@ void MetricProducer::cancelEventActivationLocked(int deactivationTrackerIndex) { it->second->state = ActivationState::kNotActive; } -void MetricProducer::setActiveLocked(int64_t currentTimeNs, int64_t remainingTtlNs) { +void MetricProducer::loadActiveMetricLocked(const ActiveMetric& activeMetric, + int64_t currentTimeNs) { if (mEventActivationMap.size() == 0) { return; } - for (auto& pair : mEventActivationMap) { - auto& activation = pair.second; - if (activation->ttl_ns >= remainingTtlNs) { - activation->activation_ns = currentTimeNs + remainingTtlNs - activation->ttl_ns; - activation->state = kActive; - mIsActive = true; - VLOG("setting new activation->time to %lld, %lld, %lld", - (long long)activation->activation_ns, (long long)currentTimeNs, - (long long)remainingTtlNs); - return; + for (int i = 0; i < activeMetric.activation_size(); i++) { + const auto& activeEventActivation = activeMetric.activation(i); + auto it = mEventActivationMap.find(activeEventActivation.atom_matcher_index()); + if (it == mEventActivationMap.end()) { + ALOGE("Saved event activation not found"); + continue; } + auto& activation = it->second; + // We don't want to change the ttl for future activations, so we set the start_ns + // such that start_ns + ttl_ns == currentTimeNs + remaining_ttl_nanos + activation->start_ns = + currentTimeNs + activeEventActivation.remaining_ttl_nanos() - activation->ttl_ns; + activation->state = ActivationState::kActive; + mIsActive = true; } - ALOGE("Required ttl is longer than all possible activations."); } -int64_t MetricProducer::getRemainingTtlNsLocked(int64_t currentTimeNs) const { - int64_t maxTtl = 0; - for (const auto& activation : mEventActivationMap) { - if (activation.second->state == kActive) { - maxTtl = std::max(maxTtl, activation.second->ttl_ns + activation.second->activation_ns - - currentTimeNs); +void MetricProducer::writeActiveMetricToProtoOutputStream( + int64_t currentTimeNs, ProtoOutputStream* proto) { + proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_METRIC_ID, (long long)mMetricId); + for (auto& it : mEventActivationMap) { + const int atom_matcher_index = it.first; + const std::shared_ptr<Activation>& activation = it.second; + + if (ActivationState::kNotActive == activation->state || + (ActivationState::kActive == activation->state && + activation->start_ns + activation->ttl_ns < currentTimeNs)) { + continue; } - } - return maxTtl; -} -void MetricProducer::prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs) { - if (mActivationType != MetricActivation::ACTIVATE_ON_BOOT) { - return; - } - for (auto& activation : mEventActivationMap) { - if (activation.second->state == kActiveOnBoot) { - activation.second->state = kActive; - activation.second->activation_ns = currentTimeNs; - mIsActive = true; + const uint64_t activationToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | + FIELD_ID_ACTIVE_METRIC_ACTIVATION); + proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX, + atom_matcher_index); + if (ActivationState::kActive == activation->state) { + const int64_t remainingTtlNs = + activation->start_ns + activation->ttl_ns - currentTimeNs; + proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS, + (long long)remainingTtlNs); + } else if (ActivationState::kActiveOnBoot == activation->state) { + proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS, + (long long)activation->ttl_ns); } + proto->end(activationToken); } } diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index 750566dd8e64..7676f598f749 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -19,6 +19,7 @@ #include <shared_mutex> +#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h> #include "HashableDimensionKey.h" #include "anomaly/AnomalyTracker.h" #include "condition/ConditionWizard.h" @@ -198,15 +199,9 @@ public: return mMetricId; } - int64_t getRemainingTtlNs(int64_t currentTimeNs) const { + void loadActiveMetric(const ActiveMetric& activeMetric, int64_t currentTimeNs) { std::lock_guard<std::mutex> lock(mMutex); - return getRemainingTtlNsLocked(currentTimeNs); - } - - // Set metric to active for ttlNs. - void setActive(int64_t currentTimeNs, int64_t remainingTtlNs) { - std::lock_guard<std::mutex> lock(mMutex); - setActiveLocked(currentTimeNs, remainingTtlNs); + loadActiveMetricLocked(activeMetric, currentTimeNs); } // Let MetricProducer drop in-memory data to save memory. @@ -238,17 +233,8 @@ public: return isActiveLocked(); } - void prepActiveForBootIfNecessary(int64_t currentTimeNs) { - std::lock_guard<std::mutex> lock(mMutex); - prepActiveForBootIfNecessaryLocked(currentTimeNs); - } - - void addActivation(int activationTrackerIndex, int64_t ttl_seconds, - int deactivationTrackerIndex = -1); - - inline void setActivationType(const MetricActivation::ActivationType& activationType) { - mActivationType = activationType; - } + void addActivation(int activationTrackerIndex, const ActivationType& activationType, + int64_t ttl_seconds, int deactivationTrackerIndex = -1); void prepareFistBucket() { std::lock_guard<std::mutex> lock(mMutex); @@ -257,6 +243,8 @@ public: void flushIfExpire(int64_t elapsedTimestampNs); + void writeActiveMetricToProtoOutputStream( + int64_t currentTimeNs, ProtoOutputStream* proto); protected: virtual void onConditionChangedLocked(const bool condition, const int64_t eventTime) = 0; virtual void onSlicedConditionMayChangeLocked(bool overallCondition, @@ -282,9 +270,7 @@ protected: void prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs); - int64_t getRemainingTtlNsLocked(int64_t currentTimeNs) const; - - void setActiveLocked(int64_t currentTimeNs, int64_t remainingTtlNs); + void loadActiveMetricLocked(const ActiveMetric& activeMetric, int64_t currentTimeNs); virtual void prepareFistBucketLocked() {}; /** @@ -396,11 +382,16 @@ protected: mutable std::mutex mMutex; struct Activation { - Activation() : ttl_ns(0), activation_ns(0), state(ActivationState::kNotActive) {} - - int64_t ttl_ns; - int64_t activation_ns; + Activation(const ActivationType& activationType, const int64_t ttlNs) + : ttl_ns(ttlNs), + start_ns(0), + state(ActivationState::kNotActive), + activationType(activationType) {} + + const int64_t ttl_ns; + int64_t start_ns; ActivationState state; + const ActivationType activationType; }; // When the metric producer has multiple activations, these activations are ORed to determine // whether the metric producer is ready to generate metrics. @@ -411,8 +402,6 @@ protected: bool mIsActive; - MetricActivation::ActivationType mActivationType; - FRIEND_TEST(MetricActivationE2eTest, TestCountMetric); FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation); FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations); @@ -420,6 +409,9 @@ protected: FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead); FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot); + FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations); + FRIEND_TEST(StatsLogProcessorTest, + TestActivationOnBootMultipleActivationsDifferentActivationTypes); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index 6a55289bc8a2..947f37782fcc 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -54,6 +54,11 @@ const int FIELD_ID_ANNOTATIONS = 7; const int FIELD_ID_ANNOTATIONS_INT64 = 1; const int FIELD_ID_ANNOTATIONS_INT32 = 2; +// for ActiveConfig +const int FIELD_ID_ACTIVE_CONFIG_ID = 1; +const int FIELD_ID_ACTIVE_CONFIG_UID = 2; +const int FIELD_ID_ACTIVE_CONFIG_METRIC = 3; + MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs, const int64_t currentTimeNs, const sp<UidMap>& uidMap, @@ -503,25 +508,41 @@ size_t MetricsManager::byteSize() { return totalSize; } -void MetricsManager::setActiveMetrics(ActiveConfig config, int64_t currentTimeNs) { - if (config.active_metric_size() == 0) { +void MetricsManager::loadActiveConfig(const ActiveConfig& config, int64_t currentTimeNs) { + if (config.metric_size() == 0) { ALOGW("No active metric for config %s", mConfigKey.ToString().c_str()); return; } - for (int i = 0; i < config.active_metric_size(); i++) { - for (int metric : mMetricIndexesWithActivation) { - if (mAllMetricProducers[metric]->getMetricId() == config.active_metric(i).metric_id()) { - VLOG("Setting active metric: %lld", - (long long)mAllMetricProducers[metric]->getMetricId()); - mAllMetricProducers[metric]->setActive( - currentTimeNs, config.active_metric(i).time_to_live_nanos()); - mIsActive = true; + for (int i = 0; i < config.metric_size(); i++) { + const auto& activeMetric = config.metric(i); + for (int metricIndex : mMetricIndexesWithActivation) { + const auto& metric = mAllMetricProducers[metricIndex]; + if (metric->getMetricId() == activeMetric.id()) { + VLOG("Setting active metric: %lld", (long long)metric->getMetricId()); + metric->loadActiveMetric(activeMetric, currentTimeNs); + mIsActive |= metric->isActive(); } } } } +void MetricsManager::writeActiveConfigToProtoOutputStream( + int64_t currentTimeNs, ProtoOutputStream* proto) { + proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_CONFIG_ID, (long long)mConfigKey.GetId()); + proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_CONFIG_UID, mConfigKey.GetUid()); + for (int metricIndex : mMetricIndexesWithActivation) { + const auto& metric = mAllMetricProducers[metricIndex]; + const uint64_t metricToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | + FIELD_ID_ACTIVE_CONFIG_METRIC); + metric->writeActiveMetricToProtoOutputStream(currentTimeNs, proto); + proto->end(metricToken); + } +} + + + + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index d05bb8b164e8..818131efe138 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -16,7 +16,6 @@ #pragma once -#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h> #include "anomaly/AlarmMonitor.h" #include "anomaly/AlarmTracker.h" #include "anomaly/AnomalyTracker.h" @@ -139,21 +138,10 @@ public: return mIsActive; } - inline void getActiveMetrics(std::vector<MetricProducer*>& metrics) const { - for (const auto& metric : mAllMetricProducers) { - if (metric->isActive()) { - metrics.push_back(metric.get()); - } - } - } - - inline void prepForShutDown(int64_t currentTimeNs) { - for (const auto& metric : mAllMetricProducers) { - metric->prepActiveForBootIfNecessary(currentTimeNs); - } - } + void loadActiveConfig(const ActiveConfig& config, int64_t currentTimeNs); - void setActiveMetrics(ActiveConfig config, int64_t currentTimeNs); + void writeActiveConfigToProtoOutputStream( + int64_t currentTimeNs, ProtoOutputStream* proto); private: // For test only. @@ -299,6 +287,9 @@ private: FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead); FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot); + FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations); + FRIEND_TEST(StatsLogProcessorTest, + TestActivationOnBootMultipleActivationsDifferentActivationTypes); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index 31b424e8792e..b027fa0d13e8 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -727,7 +727,6 @@ bool initMetricActivations(const ConfigKey& key, const StatsdConfig& config, return false; } const sp<MetricProducer>& metric = allMetricProducers[metricTrackerIndex]; - metric->setActivationType(metric_activation.activation_type()); metricsWithActivation.push_back(metricTrackerIndex); for (int j = 0; j < metric_activation.event_activation_size(); ++j) { const EventActivation& activation = metric_activation.event_activation(j); @@ -740,6 +739,13 @@ bool initMetricActivations(const ConfigKey& key, const StatsdConfig& config, activationAtomTrackerToMetricMap[atomMatcherIndex].push_back( metricTrackerIndex); + ActivationType activationType; + if (activation.has_activation_type()) { + activationType = activation.activation_type(); + } else { + activationType = metric_activation.activation_type(); + } + if (activation.has_deactivation_atom_matcher_id()) { auto deactivationAtomMatcherIt = logEventTrackerMap.find(activation.deactivation_atom_matcher_id()); @@ -750,10 +756,10 @@ bool initMetricActivations(const ConfigKey& key, const StatsdConfig& config, const int deactivationMatcherIndex = deactivationAtomMatcherIt->second; deactivationAtomTrackerToMetricMap[deactivationMatcherIndex] .push_back(metricTrackerIndex); - metric->addActivation(atomMatcherIndex, activation.ttl_seconds(), + metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds(), deactivationMatcherIndex); } else { - metric->addActivation(atomMatcherIndex, activation.ttl_seconds()); + metric->addActivation(atomMatcherIndex, activationType, activation.ttl_seconds()); } } } diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index 2260b9b56d0b..4e419b6acddc 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -377,21 +377,23 @@ message Subscription { optional float probability_of_informing = 7 [default = 1.1]; } +enum ActivationType { + ACTIVATION_TYPE_UNKNOWN = 0; + ACTIVATE_IMMEDIATELY = 1; + ACTIVATE_ON_BOOT = 2; +} + message EventActivation { optional int64 atom_matcher_id = 1; optional int64 ttl_seconds = 2; optional int64 deactivation_atom_matcher_id = 3; + optional ActivationType activation_type = 4; } message MetricActivation { optional int64 metric_id = 1; - enum ActivationType { - UNKNOWN = 0; - ACTIVATE_IMMEDIATELY = 1; - ACTIVATE_ON_BOOT = 2; - } - optional ActivationType activation_type = 3; + optional ActivationType activation_type = 3 [deprecated = true]; repeated EventActivation event_activation = 2; } diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp index 91e282a7f796..49b4e904d93c 100644 --- a/cmds/statsd/tests/StatsLogProcessor_test.cpp +++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp @@ -339,6 +339,7 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) { auto metric3Activation = config2.add_metric_activation(); metric3Activation->set_metric_id(metricId3); + metric3Activation->set_activation_type(ACTIVATE_IMMEDIATELY); auto metric3ActivationTrigger = metric3Activation->add_event_activation(); metric3ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id()); metric3ActivationTrigger->set_ttl_seconds(100); @@ -366,12 +367,14 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) { auto metric5Activation = config3.add_metric_activation(); metric5Activation->set_metric_id(metricId5); + metric5Activation->set_activation_type(ACTIVATE_IMMEDIATELY); auto metric5ActivationTrigger = metric5Activation->add_event_activation(); metric5ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id()); metric5ActivationTrigger->set_ttl_seconds(100); auto metric6Activation = config3.add_metric_activation(); metric6Activation->set_metric_id(metricId6); + metric6Activation->set_activation_type(ACTIVATE_IMMEDIATELY); auto metric6ActivationTrigger = metric6Activation->add_event_activation(); metric6ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id()); metric6ActivationTrigger->set_ttl_seconds(200); @@ -507,17 +510,13 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) { // When we shut down, metrics 3 & 5 have 100ns remaining, metric 6 has 100s + 100ns. int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC; - EXPECT_TRUE(metricProducer3->isActive()); - int64_t ttl3 = metricProducer3->getRemainingTtlNs(shutDownTime); - EXPECT_EQ(100, ttl3); - EXPECT_TRUE(metricProducer5->isActive()); - int64_t ttl5 = metricProducer5->getRemainingTtlNs(shutDownTime); - EXPECT_EQ(100, ttl5); - EXPECT_TRUE(metricProducer6->isActive()); - int64_t ttl6 = metricProducer6->getRemainingTtlNs(shutDownTime); - EXPECT_EQ(100 + 100 * NS_PER_SEC, ttl6); - - processor.WriteMetricsActivationToDisk(shutDownTime); + processor.SaveActiveConfigsToDisk(shutDownTime); + const int64_t ttl3 = event->GetElapsedTimestampNs() + + metric3ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime; + const int64_t ttl5 = event->GetElapsedTimestampNs() + + metric5ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime; + const int64_t ttl6 = event->GetElapsedTimestampNs() + + metric6ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime; // Create a second StatsLogProcessor and push the same 3 configs. long timeBase2 = 1000; @@ -611,25 +610,25 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) { EXPECT_FALSE(metricProducer1003->isActive()); const auto& activation1003 = metricProducer1003->mEventActivationMap.begin()->second; EXPECT_EQ(100 * NS_PER_SEC, activation1003->ttl_ns); - EXPECT_EQ(0, activation1003->activation_ns); + EXPECT_EQ(0, activation1003->start_ns); EXPECT_FALSE(metricProducer1005->isActive()); const auto& activation1005 = metricProducer1005->mEventActivationMap.begin()->second; EXPECT_EQ(100 * NS_PER_SEC, activation1005->ttl_ns); - EXPECT_EQ(0, activation1005->activation_ns); + EXPECT_EQ(0, activation1005->start_ns); EXPECT_FALSE(metricProducer1006->isActive()); const auto& activation1006 = metricProducer1006->mEventActivationMap.begin()->second; EXPECT_EQ(200 * NS_PER_SEC, activation1006->ttl_ns); - EXPECT_EQ(0, activation1006->activation_ns); + EXPECT_EQ(0, activation1006->start_ns); - processor2->LoadMetricsActivationFromDisk(); + processor2->LoadActiveConfigsFromDisk(); // After loading activations from disk, assert that all 3 metrics are active. EXPECT_TRUE(metricProducer1003->isActive()); - EXPECT_EQ(timeBase2 + ttl3 - activation1003->ttl_ns, activation1003->activation_ns); + EXPECT_EQ(timeBase2 + ttl3 - activation1003->ttl_ns, activation1003->start_ns); EXPECT_TRUE(metricProducer1005->isActive()); - EXPECT_EQ(timeBase2 + ttl5 - activation1005->ttl_ns, activation1005->activation_ns); + EXPECT_EQ(timeBase2 + ttl5 - activation1005->ttl_ns, activation1005->start_ns); EXPECT_TRUE(metricProducer1006->isActive()); - EXPECT_EQ(timeBase2 + ttl6 - activation1006->ttl_ns, activation1003->activation_ns); + EXPECT_EQ(timeBase2 + ttl6 - activation1006->ttl_ns, activation1003->start_ns); // Make sure no more broadcasts have happened. EXPECT_EQ(broadcastCount, 1); @@ -638,7 +637,6 @@ TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) { TEST(StatsLogProcessorTest, TestActivationOnBoot) { int uid = 1111; - // Setup a simple config, no activation StatsdConfig config1; config1.set_id(12341); config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. @@ -659,7 +657,7 @@ TEST(StatsLogProcessorTest, TestActivationOnBoot) { auto metric1Activation = config1.add_metric_activation(); metric1Activation->set_metric_id(metricId1); - metric1Activation->set_activation_type(MetricActivation::ACTIVATE_ON_BOOT); + metric1Activation->set_activation_type(ACTIVATE_ON_BOOT); auto metric1ActivationTrigger = metric1Activation->add_event_activation(); metric1ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id()); metric1ActivationTrigger->set_ttl_seconds(100); @@ -697,7 +695,7 @@ TEST(StatsLogProcessorTest, TestActivationOnBoot) { const auto& activation1 = metricProducer1->mEventActivationMap.begin()->second; EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns); - EXPECT_EQ(0, activation1->activation_ns); + EXPECT_EQ(0, activation1->start_ns); EXPECT_EQ(kNotActive, activation1->state); std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")}; @@ -705,15 +703,13 @@ TEST(StatsLogProcessorTest, TestActivationOnBoot) { processor->OnLogEvent(event.get()); EXPECT_FALSE(metricProducer1->isActive()); - EXPECT_EQ(0, activation1->activation_ns); + EXPECT_EQ(0, activation1->start_ns); EXPECT_EQ(kActiveOnBoot, activation1->state); int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC; - - processor->WriteMetricsActivationToDisk(shutDownTime); - EXPECT_TRUE(metricProducer1->isActive()); - int64_t ttl1 = metricProducer1->getRemainingTtlNs(shutDownTime); - EXPECT_EQ(100 * NS_PER_SEC, ttl1); + processor->SaveActiveConfigsToDisk(shutDownTime); + EXPECT_FALSE(metricProducer1->isActive()); + const int64_t ttl1 = metric1ActivationTrigger->ttl_seconds() * NS_PER_SEC; long timeBase2 = 1000; sp<StatsLogProcessor> processor2 = @@ -747,13 +743,743 @@ TEST(StatsLogProcessorTest, TestActivationOnBoot) { const auto& activation1001 = metricProducer1001->mEventActivationMap.begin()->second; EXPECT_EQ(100 * NS_PER_SEC, activation1001->ttl_ns); - EXPECT_EQ(0, activation1001->activation_ns); + EXPECT_EQ(0, activation1001->start_ns); EXPECT_EQ(kNotActive, activation1001->state); - processor2->LoadMetricsActivationFromDisk(); + processor2->LoadActiveConfigsFromDisk(); + + EXPECT_TRUE(metricProducer1001->isActive()); + EXPECT_EQ(timeBase2 + ttl1 - activation1001->ttl_ns, activation1001->start_ns); + EXPECT_EQ(kActive, activation1001->state); +} + +TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) { + int uid = 1111; + + // Create config with 2 metrics: + // Metric 1: Activate on boot with 2 activations + // Metric 2: Always active + StatsdConfig config1; + config1.set_id(12341); + config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher(); + auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); + *config1.add_atom_matcher() = wakelockAcquireMatcher; + *config1.add_atom_matcher() = screenOnMatcher; + + long metricId1 = 1234561; + long metricId2 = 1234562; + + auto countMetric1 = config1.add_count_metric(); + countMetric1->set_id(metricId1); + countMetric1->set_what(wakelockAcquireMatcher.id()); + countMetric1->set_bucket(FIVE_MINUTES); + + auto countMetric2 = config1.add_count_metric(); + countMetric2->set_id(metricId2); + countMetric2->set_what(wakelockAcquireMatcher.id()); + countMetric2->set_bucket(FIVE_MINUTES); + + auto metric1Activation = config1.add_metric_activation(); + metric1Activation->set_metric_id(metricId1); + metric1Activation->set_activation_type(ACTIVATE_ON_BOOT); + auto metric1ActivationTrigger1 = metric1Activation->add_event_activation(); + metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id()); + metric1ActivationTrigger1->set_ttl_seconds(100); + auto metric1ActivationTrigger2 = metric1Activation->add_event_activation(); + metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id()); + metric1ActivationTrigger2->set_ttl_seconds(200); + + ConfigKey cfgKey1(uid, 12341); + long timeBase1 = 1; + sp<StatsLogProcessor> processor = + CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1); + + // Metric 1 is not active. + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_EQ(1, processor->mMetricsManagers.size()); + auto it = processor->mMetricsManagers.find(cfgKey1); + EXPECT_TRUE(it != processor->mMetricsManagers.end()); + auto& metricsManager1 = it->second; + EXPECT_TRUE(metricsManager1->isActive()); + + auto metricIt = metricsManager1->mAllMetricProducers.begin(); + for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId1) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end()); + auto& metricProducer1 = *metricIt; + EXPECT_FALSE(metricProducer1->isActive()); + + metricIt = metricsManager1->mAllMetricProducers.begin(); + for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId2) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end()); + auto& metricProducer2 = *metricIt; + EXPECT_TRUE(metricProducer2->isActive()); + + int i = 0; + for (; i < metricsManager1->mAllAtomMatchers.size(); i++) { + if (metricsManager1->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger1->atom_matcher_id()) { + break; + } + } + const auto& activation1 = metricProducer1->mEventActivationMap.at(i); + EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns); + EXPECT_EQ(0, activation1->start_ns); + EXPECT_EQ(kNotActive, activation1->state); + + i = 0; + for (; i < metricsManager1->mAllAtomMatchers.size(); i++) { + if (metricsManager1->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger2->atom_matcher_id()) { + break; + } + } + const auto& activation2 = metricProducer1->mEventActivationMap.at(i); + EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns); + EXPECT_EQ(0, activation2->start_ns); + EXPECT_EQ(kNotActive, activation2->state); + // }}}------------------------------------------------------------------------------ + + // Trigger Activation 1 for Metric 1 + std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")}; + auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1); + processor->OnLogEvent(event.get()); + + // Metric 1 is not active; Activation 1 set to kActiveOnBoot + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_FALSE(metricProducer1->isActive()); + EXPECT_EQ(0, activation1->start_ns); + EXPECT_EQ(kActiveOnBoot, activation1->state); + EXPECT_EQ(0, activation2->start_ns); + EXPECT_EQ(kNotActive, activation2->state); + + EXPECT_TRUE(metricProducer2->isActive()); + // }}}----------------------------------------------------------------------------- + + // Simulate shutdown by saving state to disk + int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC; + processor->SaveActiveConfigsToDisk(shutDownTime); + EXPECT_FALSE(metricProducer1->isActive()); + int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC; + + // Simulate device restarted state by creating new instance of StatsLogProcessor with the + // same config. + long timeBase2 = 1000; + sp<StatsLogProcessor> processor2 = + CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1); + + // Metric 1 is not active. + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_EQ(1, processor2->mMetricsManagers.size()); + it = processor2->mMetricsManagers.find(cfgKey1); + EXPECT_TRUE(it != processor2->mMetricsManagers.end()); + auto& metricsManager1001 = it->second; + EXPECT_TRUE(metricsManager1001->isActive()); + + metricIt = metricsManager1001->mAllMetricProducers.begin(); + for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId1) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end()); + auto& metricProducer1001 = *metricIt; + EXPECT_FALSE(metricProducer1001->isActive()); + + metricIt = metricsManager1001->mAllMetricProducers.begin(); + for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId2) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end()); + auto& metricProducer1002 = *metricIt; + EXPECT_TRUE(metricProducer1002->isActive()); + + i = 0; + for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) { + if (metricsManager1001->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger1->atom_matcher_id()) { + break; + } + } + const auto& activation1001_1 = metricProducer1001->mEventActivationMap.at(i); + EXPECT_EQ(100 * NS_PER_SEC, activation1001_1->ttl_ns); + EXPECT_EQ(0, activation1001_1->start_ns); + EXPECT_EQ(kNotActive, activation1001_1->state); + + i = 0; + for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) { + if (metricsManager1001->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger2->atom_matcher_id()) { + break; + } + } + + const auto& activation1001_2 = metricProducer1001->mEventActivationMap.at(i); + EXPECT_EQ(200 * NS_PER_SEC, activation1001_2->ttl_ns); + EXPECT_EQ(0, activation1001_2->start_ns); + EXPECT_EQ(kNotActive, activation1001_2->state); + // }}}----------------------------------------------------------------------------------- + + // Load saved state from disk. + processor2->LoadActiveConfigsFromDisk(); + + // Metric 1 active; Activation 1 is active, Activation 2 is not active + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_TRUE(metricProducer1001->isActive()); + EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns); + EXPECT_EQ(kActive, activation1001_1->state); + EXPECT_EQ(0, activation1001_2->start_ns); + EXPECT_EQ(kNotActive, activation1001_2->state); + + EXPECT_TRUE(metricProducer1002->isActive()); + // }}}-------------------------------------------------------------------------------- + + // Trigger Activation 2 for Metric 1. + auto screenOnEvent = CreateScreenStateChangedEvent( + android::view::DISPLAY_STATE_ON, + timeBase2 + 200 + ); + processor2->OnLogEvent(screenOnEvent.get()); + + // Metric 1 active; Activation 1 is active, Activation 2 is set to kActiveOnBoot + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_TRUE(metricProducer1001->isActive()); + EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns); + EXPECT_EQ(kActive, activation1001_1->state); + EXPECT_EQ(0, activation1001_2->start_ns); + EXPECT_EQ(kActiveOnBoot, activation1001_2->state); + + EXPECT_TRUE(metricProducer1002->isActive()); + // }}}--------------------------------------------------------------------------- + // Simulate shutdown by saving state to disk + shutDownTime = timeBase2 + 50 * NS_PER_SEC; + processor2->SaveActiveConfigsToDisk(shutDownTime); EXPECT_TRUE(metricProducer1001->isActive()); - EXPECT_EQ(timeBase2 + ttl1 - activation1001->ttl_ns, activation1001->activation_ns); + EXPECT_TRUE(metricProducer1002->isActive()); + ttl1 = timeBase2 + metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC - shutDownTime; + int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC; + + // Simulate device restarted state by creating new instance of StatsLogProcessor with the + // same config. + long timeBase3 = timeBase2 + 120 * NS_PER_SEC; + sp<StatsLogProcessor> processor3 = + CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1); + + // Metric 1 is not active. + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_EQ(1, processor3->mMetricsManagers.size()); + it = processor3->mMetricsManagers.find(cfgKey1); + EXPECT_TRUE(it != processor3->mMetricsManagers.end()); + auto& metricsManagerTimeBase3 = it->second; + EXPECT_TRUE(metricsManagerTimeBase3->isActive()); + + metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin(); + for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId1) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end()); + auto& metricProducerTimeBase3_1 = *metricIt; + EXPECT_FALSE(metricProducerTimeBase3_1->isActive()); + + metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin(); + for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId2) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end()); + auto& metricProducerTimeBase3_2 = *metricIt; + EXPECT_TRUE(metricProducerTimeBase3_2->isActive()); + + i = 0; + for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) { + if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger1->atom_matcher_id()) { + break; + } + } + const auto& activationTimeBase3_1 = metricProducerTimeBase3_1->mEventActivationMap.at(i); + EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase3_1->ttl_ns); + EXPECT_EQ(0, activationTimeBase3_1->start_ns); + EXPECT_EQ(kNotActive, activationTimeBase3_1->state); + + i = 0; + for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) { + if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger2->atom_matcher_id()) { + break; + } + } + + const auto& activationTimeBase3_2 = metricProducerTimeBase3_1->mEventActivationMap.at(i); + EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase3_2->ttl_ns); + EXPECT_EQ(0, activationTimeBase3_2->start_ns); + EXPECT_EQ(kNotActive, activationTimeBase3_2->state); + + EXPECT_TRUE(metricProducerTimeBase3_2->isActive()); + // }}}---------------------------------------------------------------------------------- + + // Load saved state from disk. + processor3->LoadActiveConfigsFromDisk(); + + // Metric 1 active: Activation 1 is active, Activation 2 is active + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_TRUE(metricProducerTimeBase3_1->isActive()); + EXPECT_EQ(timeBase3 + ttl1 - activationTimeBase3_1->ttl_ns, activationTimeBase3_1->start_ns); + EXPECT_EQ(kActive, activationTimeBase3_1->state); + EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns); + EXPECT_EQ(kActive, activationTimeBase3_2->state); + + EXPECT_TRUE(metricProducerTimeBase3_2->isActive()); + // }}}------------------------------------------------------------------------------- + + // Trigger Activation 2 for Metric 1 again. + screenOnEvent = CreateScreenStateChangedEvent( + android::view::DISPLAY_STATE_ON, + timeBase3 + 100 * NS_PER_SEC + ); + processor3->OnLogEvent(screenOnEvent.get()); + + // Metric 1 active; Activation 1 is not active, Activation 2 is set to active + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_TRUE(metricProducerTimeBase3_1->isActive()); + EXPECT_EQ(kNotActive, activationTimeBase3_1->state); + EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns); + EXPECT_EQ(kActive, activationTimeBase3_2->state); + + EXPECT_TRUE(metricProducerTimeBase3_2->isActive()); + // }}}--------------------------------------------------------------------------- + + // Simulate shutdown by saving state to disk. + shutDownTime = timeBase3 + 500 * NS_PER_SEC; + processor3->SaveActiveConfigsToDisk(shutDownTime); + EXPECT_TRUE(metricProducer1001->isActive()); + EXPECT_TRUE(metricProducer1002->isActive()); + ttl1 = timeBase3 + ttl1 - shutDownTime; + ttl2 = timeBase3 + metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC - shutDownTime; + + // Simulate device restarted state by creating new instance of StatsLogProcessor with the + // same config. + long timeBase4 = timeBase3 + 600 * NS_PER_SEC; + sp<StatsLogProcessor> processor4 = + CreateStatsLogProcessor(timeBase4, timeBase4, config1, cfgKey1); + + // Metric 1 is not active. + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_EQ(1, processor4->mMetricsManagers.size()); + it = processor4->mMetricsManagers.find(cfgKey1); + EXPECT_TRUE(it != processor4->mMetricsManagers.end()); + auto& metricsManagerTimeBase4 = it->second; + EXPECT_TRUE(metricsManagerTimeBase4->isActive()); + + metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin(); + for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId1) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end()); + auto& metricProducerTimeBase4_1 = *metricIt; + EXPECT_FALSE(metricProducerTimeBase4_1->isActive()); + + metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin(); + for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId2) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end()); + auto& metricProducerTimeBase4_2 = *metricIt; + EXPECT_TRUE(metricProducerTimeBase4_2->isActive()); + + i = 0; + for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) { + if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger1->atom_matcher_id()) { + break; + } + } + const auto& activationTimeBase4_1 = metricProducerTimeBase4_1->mEventActivationMap.at(i); + EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase4_1->ttl_ns); + EXPECT_EQ(0, activationTimeBase4_1->start_ns); + EXPECT_EQ(kNotActive, activationTimeBase4_1->state); + + i = 0; + for (; i < metricsManagerTimeBase4->mAllAtomMatchers.size(); i++) { + if (metricsManagerTimeBase4->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger2->atom_matcher_id()) { + break; + } + } + + const auto& activationTimeBase4_2 = metricProducerTimeBase4_1->mEventActivationMap.at(i); + EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase4_2->ttl_ns); + EXPECT_EQ(0, activationTimeBase4_2->start_ns); + EXPECT_EQ(kNotActive, activationTimeBase4_2->state); + + EXPECT_TRUE(metricProducerTimeBase4_2->isActive()); + // }}}---------------------------------------------------------------------------------- + + // Load saved state from disk. + processor4->LoadActiveConfigsFromDisk(); + + // Metric 1 active: Activation 1 is not active, Activation 2 is not active + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_FALSE(metricProducerTimeBase4_1->isActive()); + EXPECT_EQ(kNotActive, activationTimeBase4_1->state); + EXPECT_EQ(kNotActive, activationTimeBase4_2->state); + + EXPECT_TRUE(metricProducerTimeBase4_2->isActive()); + // }}}------------------------------------------------------------------------------- +} + +TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActivationTypes) { + int uid = 1111; + + // Create config with 2 metrics: + // Metric 1: Activate on boot with 2 activations + // Metric 2: Always active + StatsdConfig config1; + config1.set_id(12341); + config1.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. + auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher(); + auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher(); + *config1.add_atom_matcher() = wakelockAcquireMatcher; + *config1.add_atom_matcher() = screenOnMatcher; + + long metricId1 = 1234561; + long metricId2 = 1234562; + + auto countMetric1 = config1.add_count_metric(); + countMetric1->set_id(metricId1); + countMetric1->set_what(wakelockAcquireMatcher.id()); + countMetric1->set_bucket(FIVE_MINUTES); + + auto countMetric2 = config1.add_count_metric(); + countMetric2->set_id(metricId2); + countMetric2->set_what(wakelockAcquireMatcher.id()); + countMetric2->set_bucket(FIVE_MINUTES); + + auto metric1Activation = config1.add_metric_activation(); + metric1Activation->set_metric_id(metricId1); + metric1Activation->set_activation_type(ACTIVATE_ON_BOOT); + auto metric1ActivationTrigger1 = metric1Activation->add_event_activation(); + metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id()); + metric1ActivationTrigger1->set_ttl_seconds(100); + auto metric1ActivationTrigger2 = metric1Activation->add_event_activation(); + metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id()); + metric1ActivationTrigger2->set_ttl_seconds(200); + metric1ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY); + + ConfigKey cfgKey1(uid, 12341); + long timeBase1 = 1; + sp<StatsLogProcessor> processor = + CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1); + + // Metric 1 is not active. + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_EQ(1, processor->mMetricsManagers.size()); + auto it = processor->mMetricsManagers.find(cfgKey1); + EXPECT_TRUE(it != processor->mMetricsManagers.end()); + auto& metricsManager1 = it->second; + EXPECT_TRUE(metricsManager1->isActive()); + + auto metricIt = metricsManager1->mAllMetricProducers.begin(); + for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId1) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end()); + auto& metricProducer1 = *metricIt; + EXPECT_FALSE(metricProducer1->isActive()); + + metricIt = metricsManager1->mAllMetricProducers.begin(); + for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId2) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end()); + auto& metricProducer2 = *metricIt; + EXPECT_TRUE(metricProducer2->isActive()); + + int i = 0; + for (; i < metricsManager1->mAllAtomMatchers.size(); i++) { + if (metricsManager1->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger1->atom_matcher_id()) { + break; + } + } + const auto& activation1 = metricProducer1->mEventActivationMap.at(i); + EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns); + EXPECT_EQ(0, activation1->start_ns); + EXPECT_EQ(kNotActive, activation1->state); + EXPECT_EQ(ACTIVATE_ON_BOOT, activation1->activationType); + + i = 0; + for (; i < metricsManager1->mAllAtomMatchers.size(); i++) { + if (metricsManager1->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger2->atom_matcher_id()) { + break; + } + } + const auto& activation2 = metricProducer1->mEventActivationMap.at(i); + EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns); + EXPECT_EQ(0, activation2->start_ns); + EXPECT_EQ(kNotActive, activation2->state); + EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2->activationType); + // }}}------------------------------------------------------------------------------ + + // Trigger Activation 1 for Metric 1 + std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")}; + auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1); + processor->OnLogEvent(event.get()); + + // Metric 1 is not active; Activation 1 set to kActiveOnBoot + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_FALSE(metricProducer1->isActive()); + EXPECT_EQ(0, activation1->start_ns); + EXPECT_EQ(kActiveOnBoot, activation1->state); + EXPECT_EQ(0, activation2->start_ns); + EXPECT_EQ(kNotActive, activation2->state); + + EXPECT_TRUE(metricProducer2->isActive()); + // }}}----------------------------------------------------------------------------- + + // Simulate shutdown by saving state to disk + int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC; + processor->SaveActiveConfigsToDisk(shutDownTime); + EXPECT_FALSE(metricProducer1->isActive()); + int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC; + + // Simulate device restarted state by creating new instance of StatsLogProcessor with the + // same config. + long timeBase2 = 1000; + sp<StatsLogProcessor> processor2 = + CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1); + + // Metric 1 is not active. + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_EQ(1, processor2->mMetricsManagers.size()); + it = processor2->mMetricsManagers.find(cfgKey1); + EXPECT_TRUE(it != processor2->mMetricsManagers.end()); + auto& metricsManager1001 = it->second; + EXPECT_TRUE(metricsManager1001->isActive()); + + metricIt = metricsManager1001->mAllMetricProducers.begin(); + for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId1) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end()); + auto& metricProducer1001 = *metricIt; + EXPECT_FALSE(metricProducer1001->isActive()); + + metricIt = metricsManager1001->mAllMetricProducers.begin(); + for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId2) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end()); + auto& metricProducer1002 = *metricIt; + EXPECT_TRUE(metricProducer1002->isActive()); + + i = 0; + for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) { + if (metricsManager1001->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger1->atom_matcher_id()) { + break; + } + } + const auto& activation1001_1 = metricProducer1001->mEventActivationMap.at(i); + EXPECT_EQ(100 * NS_PER_SEC, activation1001_1->ttl_ns); + EXPECT_EQ(0, activation1001_1->start_ns); + EXPECT_EQ(kNotActive, activation1001_1->state); + EXPECT_EQ(ACTIVATE_ON_BOOT, activation1001_1->activationType); + + i = 0; + for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) { + if (metricsManager1001->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger2->atom_matcher_id()) { + break; + } + } + + const auto& activation1001_2 = metricProducer1001->mEventActivationMap.at(i); + EXPECT_EQ(200 * NS_PER_SEC, activation1001_2->ttl_ns); + EXPECT_EQ(0, activation1001_2->start_ns); + EXPECT_EQ(kNotActive, activation1001_2->state); + EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1001_2->activationType); + // }}}----------------------------------------------------------------------------------- + + // Load saved state from disk. + processor2->LoadActiveConfigsFromDisk(); + + // Metric 1 active; Activation 1 is active, Activation 2 is not active + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_TRUE(metricProducer1001->isActive()); + EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns); + EXPECT_EQ(kActive, activation1001_1->state); + EXPECT_EQ(0, activation1001_2->start_ns); + EXPECT_EQ(kNotActive, activation1001_2->state); + + EXPECT_TRUE(metricProducer1002->isActive()); + // }}}-------------------------------------------------------------------------------- + + // Trigger Activation 2 for Metric 1. + auto screenOnEvent = CreateScreenStateChangedEvent( + android::view::DISPLAY_STATE_ON, + timeBase2 + 200 + ); + processor2->OnLogEvent(screenOnEvent.get()); + + // Metric 1 active; Activation 1 is active, Activation 2 is active + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_TRUE(metricProducer1001->isActive()); + EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns); + EXPECT_EQ(kActive, activation1001_1->state); + EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation1001_2->start_ns); + EXPECT_EQ(kActive, activation1001_2->state); + + EXPECT_TRUE(metricProducer1002->isActive()); + // }}}--------------------------------------------------------------------------- + + // Simulate shutdown by saving state to disk + shutDownTime = timeBase2 + 50 * NS_PER_SEC; + processor2->SaveActiveConfigsToDisk(shutDownTime); + EXPECT_TRUE(metricProducer1001->isActive()); + EXPECT_TRUE(metricProducer1002->isActive()); + ttl1 = timeBase2 + metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC - shutDownTime; + int64_t ttl2 = screenOnEvent->GetElapsedTimestampNs() + + metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC - shutDownTime; + + // Simulate device restarted state by creating new instance of StatsLogProcessor with the + // same config. + long timeBase3 = timeBase2 + 120 * NS_PER_SEC; + sp<StatsLogProcessor> processor3 = + CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1); + + // Metric 1 is not active. + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_EQ(1, processor3->mMetricsManagers.size()); + it = processor3->mMetricsManagers.find(cfgKey1); + EXPECT_TRUE(it != processor3->mMetricsManagers.end()); + auto& metricsManagerTimeBase3 = it->second; + EXPECT_TRUE(metricsManagerTimeBase3->isActive()); + + metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin(); + for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId1) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end()); + auto& metricProducerTimeBase3_1 = *metricIt; + EXPECT_FALSE(metricProducerTimeBase3_1->isActive()); + + metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin(); + for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) { + if ((*metricIt)->getMetricId() == metricId2) { + break; + } + } + EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end()); + auto& metricProducerTimeBase3_2 = *metricIt; + EXPECT_TRUE(metricProducerTimeBase3_2->isActive()); + + i = 0; + for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) { + if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger1->atom_matcher_id()) { + break; + } + } + const auto& activationTimeBase3_1 = metricProducerTimeBase3_1->mEventActivationMap.at(i); + EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase3_1->ttl_ns); + EXPECT_EQ(0, activationTimeBase3_1->start_ns); + EXPECT_EQ(kNotActive, activationTimeBase3_1->state); + EXPECT_EQ(ACTIVATE_ON_BOOT, activationTimeBase3_1->activationType); + + i = 0; + for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) { + if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() == + metric1ActivationTrigger2->atom_matcher_id()) { + break; + } + } + + const auto& activationTimeBase3_2 = metricProducerTimeBase3_1->mEventActivationMap.at(i); + EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase3_2->ttl_ns); + EXPECT_EQ(0, activationTimeBase3_2->start_ns); + EXPECT_EQ(kNotActive, activationTimeBase3_2->state); + EXPECT_EQ(ACTIVATE_IMMEDIATELY, activationTimeBase3_2->activationType); + // }}}---------------------------------------------------------------------------------- + + // Load saved state from disk. + processor3->LoadActiveConfigsFromDisk(); + + // Metric 1 active: Activation 1 is active, Activation 2 is active + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_TRUE(metricProducerTimeBase3_1->isActive()); + EXPECT_EQ(timeBase3 + ttl1 - activationTimeBase3_1->ttl_ns, activationTimeBase3_1->start_ns); + EXPECT_EQ(kActive, activationTimeBase3_1->state); + EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns); + EXPECT_EQ(kActive, activationTimeBase3_2->state); + + EXPECT_TRUE(metricProducerTimeBase3_2->isActive()); + // }}}------------------------------------------------------------------------------- + + + // Trigger Activation 2 for Metric 1 again. + screenOnEvent = CreateScreenStateChangedEvent( + android::view::DISPLAY_STATE_ON, + timeBase3 + 100 * NS_PER_SEC + ); + processor3->OnLogEvent(screenOnEvent.get()); + + // Metric 1 active; Activation 1 is not active, Activation 2 is set to active + // Metric 2 is active. + // {{{--------------------------------------------------------------------------- + EXPECT_TRUE(metricProducerTimeBase3_1->isActive()); + EXPECT_EQ(kNotActive, activationTimeBase3_1->state); + EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activationTimeBase3_2->start_ns); + EXPECT_EQ(kActive, activationTimeBase3_2->state); + + EXPECT_TRUE(metricProducerTimeBase3_2->isActive()); + // }}}--------------------------------------------------------------------------- } #else diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp index f01ad0609295..6ec0a114b3ed 100644 --- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp +++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp @@ -418,7 +418,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) { const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets. auto metric_activation = config.add_metric_activation(); metric_activation->set_metric_id(metricId); - metric_activation->set_activation_type(MetricActivation::ACTIVATE_IMMEDIATELY); + metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY); auto event_activation = metric_activation->add_event_activation(); event_activation->set_atom_matcher_id(batterySaverStartMatcher.id()); event_activation->set_ttl_seconds(ttlNs / 1000000000); diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp index bf52bb04e71d..d99d281afc68 100644 --- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp @@ -245,10 +245,10 @@ TEST(MetricActivationE2eTest, TestCountMetric) { EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, 0); + EXPECT_EQ(eventActivationMap[0]->start_ns, 0); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, 0); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); std::unique_ptr<LogEvent> event; @@ -268,10 +268,10 @@ TEST(MetricActivationE2eTest, TestCountMetric) { EXPECT_EQ(activeConfigsBroadcast.size(), 1); EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, 0); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); // First processed event. @@ -285,10 +285,10 @@ TEST(MetricActivationE2eTest, TestCountMetric) { EXPECT_TRUE(metricsManager->isActive()); EXPECT_TRUE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); // 2nd processed event. @@ -298,10 +298,10 @@ TEST(MetricActivationE2eTest, TestCountMetric) { EXPECT_TRUE(metricsManager->isActive()); EXPECT_TRUE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); // No new broadcast since the config should still be active. EXPECT_EQ(broadcastCount, 1); @@ -319,10 +319,10 @@ TEST(MetricActivationE2eTest, TestCountMetric) { EXPECT_EQ(broadcastCount, 2); EXPECT_EQ(activeConfigsBroadcast.size(), 0); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); // Re-activate metric via screen on. @@ -335,10 +335,10 @@ TEST(MetricActivationE2eTest, TestCountMetric) { EXPECT_EQ(activeConfigsBroadcast.size(), 1); EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); // 4th processed event. @@ -460,10 +460,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, 0); + EXPECT_EQ(eventActivationMap[0]->start_ns, 0); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, 0); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap.size(), 1u); EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end()); @@ -486,10 +486,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { EXPECT_EQ(activeConfigsBroadcast.size(), 1); EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, 0); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); @@ -504,10 +504,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { EXPECT_TRUE(metricsManager->isActive()); EXPECT_TRUE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); @@ -518,10 +518,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { EXPECT_TRUE(metricsManager->isActive()); EXPECT_TRUE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); // No new broadcast since the config should still be active. @@ -540,10 +540,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { EXPECT_EQ(broadcastCount, 2); EXPECT_EQ(activeConfigsBroadcast.size(), 0); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); @@ -557,10 +557,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { EXPECT_EQ(activeConfigsBroadcast.size(), 1); EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); @@ -577,10 +577,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { EXPECT_EQ(activeConfigsBroadcast.size(), 1); EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); @@ -597,10 +597,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { EXPECT_EQ(activeConfigsBroadcast.size(), 1); EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); @@ -613,10 +613,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { EXPECT_EQ(broadcastCount, 4); EXPECT_EQ(activeConfigsBroadcast.size(), 0); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); @@ -632,10 +632,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { EXPECT_EQ(activeConfigsBroadcast.size(), 1); EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); @@ -647,10 +647,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { EXPECT_EQ(broadcastCount, 6); EXPECT_EQ(activeConfigsBroadcast.size(), 0); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); @@ -782,10 +782,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, 0); + EXPECT_EQ(eventActivationMap[0]->start_ns, 0); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, 0); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap.size(), 2u); EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end()); @@ -810,10 +810,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { EXPECT_EQ(activeConfigsBroadcast.size(), 1); EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, 0); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); @@ -829,10 +829,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { EXPECT_TRUE(metricsManager->isActive()); EXPECT_TRUE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); @@ -844,10 +844,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { EXPECT_TRUE(metricsManager->isActive()); EXPECT_TRUE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); @@ -867,10 +867,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { EXPECT_EQ(broadcastCount, 2); EXPECT_EQ(activeConfigsBroadcast.size(), 0); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); @@ -885,10 +885,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { EXPECT_EQ(activeConfigsBroadcast.size(), 1); EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); @@ -906,10 +906,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { EXPECT_EQ(activeConfigsBroadcast.size(), 1); EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); @@ -927,10 +927,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { EXPECT_EQ(broadcastCount, 4); EXPECT_EQ(activeConfigsBroadcast.size(), 0); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); @@ -943,10 +943,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { EXPECT_EQ(broadcastCount, 4); EXPECT_EQ(activeConfigsBroadcast.size(), 0); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); @@ -963,10 +963,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { EXPECT_EQ(activeConfigsBroadcast.size(), 1); EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); @@ -979,10 +979,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { EXPECT_EQ(broadcastCount, 6); EXPECT_EQ(activeConfigsBroadcast.size(), 0); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); @@ -1119,10 +1119,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end()); EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end()); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, 0); + EXPECT_EQ(eventActivationMap[0]->start_ns, 0); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, 0); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap.size(), 2u); EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end()); @@ -1134,10 +1134,10 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { EXPECT_TRUE(eventActivationMap2.find(0) != eventActivationMap2.end()); EXPECT_TRUE(eventActivationMap2.find(2) != eventActivationMap2.end()); EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[0]->activation_ns, 0); + EXPECT_EQ(eventActivationMap2[0]->start_ns, 0); EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[2]->activation_ns, 0); + EXPECT_EQ(eventActivationMap2[2]->start_ns, 0); EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap2.size(), 2u); EXPECT_TRUE(eventDeactivationMap2.find(3) != eventDeactivationMap2.end()); @@ -1165,19 +1165,19 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_TRUE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, 0); + EXPECT_EQ(eventActivationMap[2]->start_ns, 0); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); EXPECT_TRUE(metricProducer2->mIsActive); EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[2]->activation_ns, 0); + EXPECT_EQ(eventActivationMap2[2]->start_ns, 0); EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]); EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]); @@ -1195,19 +1195,19 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { EXPECT_TRUE(metricsManager->isActive()); EXPECT_TRUE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); EXPECT_TRUE(metricProducer2->mIsActive); EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]); EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]); @@ -1221,19 +1221,19 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { EXPECT_TRUE(metricsManager->isActive()); EXPECT_TRUE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); EXPECT_TRUE(metricProducer2->mIsActive); EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]); EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]); @@ -1257,19 +1257,19 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { EXPECT_EQ(activeConfigsBroadcast.size(), 0); EXPECT_FALSE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); EXPECT_FALSE(metricProducer2->mIsActive); EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + 20); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20); EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]); EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]); @@ -1284,19 +1284,19 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_TRUE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); EXPECT_TRUE(metricProducer2->mIsActive); EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + 10); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10); EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]); EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]); @@ -1316,19 +1316,19 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_TRUE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); EXPECT_TRUE(metricProducer2->mIsActive); EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]); EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]); @@ -1348,19 +1348,19 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { EXPECT_EQ(activeConfigsBroadcast.size(), 0); EXPECT_FALSE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); EXPECT_FALSE(metricProducer2->mIsActive); EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]); EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]); @@ -1375,19 +1375,19 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { EXPECT_EQ(activeConfigsBroadcast.size(), 0); EXPECT_FALSE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); EXPECT_FALSE(metricProducer2->mIsActive); EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15); EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]); EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]); @@ -1406,19 +1406,19 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { EXPECT_EQ(activeConfigsBroadcast[0], cfgId); EXPECT_TRUE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); EXPECT_TRUE(metricProducer2->mIsActive); EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive); - EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]); EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]); @@ -1431,19 +1431,19 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { EXPECT_EQ(activeConfigsBroadcast.size(), 0); EXPECT_FALSE(metricProducer->mIsActive); EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap[3], eventActivationMap[0]); EXPECT_EQ(eventDeactivationMap[4], eventActivationMap[2]); EXPECT_FALSE(metricProducer2->mIsActive); EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[0]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); + EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15); EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC); EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive); - EXPECT_EQ(eventActivationMap2[2]->activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); + EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10); EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC); EXPECT_EQ(eventDeactivationMap2[3], eventActivationMap2[0]); EXPECT_EQ(eventDeactivationMap2[4], eventActivationMap2[2]); diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp index e967eb34ab2e..ff6af38bd351 100644 --- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp @@ -279,7 +279,7 @@ TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) { const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets. auto metric_activation = config.add_metric_activation(); metric_activation->set_metric_id(metricId); - metric_activation->set_activation_type(MetricActivation::ACTIVATE_IMMEDIATELY); + metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY); auto event_activation = metric_activation->add_event_activation(); event_activation->set_atom_matcher_id(batterySaverStartMatcher.id()); event_activation->set_ttl_seconds(ttlNs / 1000000000); diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl index 722c128c0502..43a4fe5bc414 100644 --- a/core/java/android/content/om/IOverlayManager.aidl +++ b/core/java/android/content/om/IOverlayManager.aidl @@ -152,4 +152,9 @@ interface IOverlayManager { * @param userId The user for which to change the overlay. */ boolean setLowestPriority(in String packageName, in int userId); + + /** + * Returns the list of default overlay packages, or an empty array if there are none. + */ + String[] getDefaultOverlayPackages(); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index a95e094ce54c..33c0bb9dc9d0 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -6178,15 +6178,7 @@ public abstract class PackageManager { * @param activity The component name of the activity that is to be preferred. * * @hide - * - * @deprecated This function no longer does anything. It is the platform's - * responsibility to assign preferred activities and this cannot be modified - * directly. To determine the activities resolved by the platform, use - * {@link #resolveActivity} or {@link #queryIntentActivities}. To configure - * an app to be responsible for a particular role and to check current role - * holders, see {@link android.app.role.RoleManager}. */ - @Deprecated @SystemApi public void replacePreferredActivity(@NonNull IntentFilter filter, int match, @NonNull List<ComponentName> set, @NonNull ComponentName activity) { diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java index a52e96e249f8..b0d399c64ea9 100644 --- a/core/java/android/database/MatrixCursor.java +++ b/core/java/android/database/MatrixCursor.java @@ -18,6 +18,7 @@ package android.database; import android.annotation.UnsupportedAppUsage; import android.os.Build; + import java.util.ArrayList; /** @@ -240,6 +241,12 @@ public class MatrixCursor extends AbstractCursor { } return this; } + + /** @hide */ + public final RowBuilder add(int columnIndex, Object value) { + data[(row * columnCount) + columnIndex] = value; + return this; + } } // AbstractCursor implementation. diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 94c8b9116dd6..3a4741a97212 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -978,11 +978,6 @@ public class Build { */ public static final int Q = CUR_DEVELOPMENT; - /** - * Stub for a potential new API level after P. - * @hide - */ - public static final int P0 = Q; } /** The type of build, like "user" or "eng". */ diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 1aa5b0656935..2a41c2065c46 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -23,11 +23,8 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.content.pm.PermissionInfo; import android.os.RemoteException; import com.android.internal.annotations.Immutable; @@ -107,11 +104,11 @@ public final class PermissionManager { /** * Get set of permissions that have been split into more granular or dependent permissions. * - * <p>E.g. before {@link android.os.Build.VERSION_CODES#P0} an app that was granted + * <p>E.g. before {@link android.os.Build.VERSION_CODES#Q} an app that was granted * {@link Manifest.permission#ACCESS_COARSE_LOCATION} could access he location while it was in - * foreground and background. On platforms after {@link android.os.Build.VERSION_CODES#P0} + * foreground and background. On platforms after {@link android.os.Build.VERSION_CODES#Q} * the location permission only grants location access while the app is in foreground. This - * would break apps that target before {@link android.os.Build.VERSION_CODES#P0}. Hence whenever + * would break apps that target before {@link android.os.Build.VERSION_CODES#Q}. Hence whenever * such an old app asks for a location permission (i.e. the * {@link SplitPermissionInfo#getSplitPermission()}), then the * {@link Manifest.permission#ACCESS_BACKGROUND_LOCATION} permission (inside diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ced6115a2f2a..b0e980e7206f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1791,6 +1791,58 @@ public final class Settings { @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS"; + /** + * Broadcast to trigger notification of asking user to enable MMS. + * Need to specify {@link #EXTRA_ENABLE_MMS_DATA_REQUEST_REASON} and {@link #EXTRA_SUB_ID}. + * + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_ENABLE_MMS_DATA_REQUEST = + "android.settings.ENABLE_MMS_DATA_REQUEST"; + + /** + * Integer value that specifies the reason triggering enable MMS data notification. + * This must be passed as an extra field to the {@link #ACTION_ENABLE_MMS_DATA_REQUEST}. + * Extra with value of EnableMmsDataReason interface. + * @hide + */ + public static final String EXTRA_ENABLE_MMS_DATA_REQUEST_REASON = + "android.settings.extra.ENABLE_MMS_DATA_REQUEST_REASON"; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "ENABLE_MMS_DATA_REQUEST_REASON_" }, value = { + ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS, + ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS, + }) + public @interface EnableMmsDataReason{} + + /** + * Requesting to enable MMS data because there's an incoming MMS. + * @hide + */ + public static final int ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS = 0; + + /** + * Requesting to enable MMS data because user is sending MMS. + * @hide + */ + public static final int ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS = 1; + + /** + * Activity Action: Show screen of a cellular subscription and highlight the + * "enable MMS" toggle. + * <p> + * Input: {@link #EXTRA_SUB_ID}: Sub ID of the subscription. + * <p> + * Output: Nothing + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_MMS_MESSAGE_SETTING = "android.settings.MMS_MESSAGE_SETTING"; + // End of Intent actions for Settings /** @@ -11909,6 +11961,36 @@ public final class Settings { public static final String JOB_SCHEDULER_CONSTANTS = "job_scheduler_constants"; /** + * Job scheduler QuotaController specific settings. + * This is encoded as a key=value list, separated by commas. Ex: + * + * "max_job_count_working=5,max_job_count_rare=2" + * + * <p> + * Type: string + * + * @hide + * @see com.android.server.job.JobSchedulerService.Constants + */ + public static final String JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS = + "job_scheduler_quota_controller_constants"; + + /** + * Job scheduler TimeController specific settings. + * This is encoded as a key=value list, separated by commas. Ex: + * + * "skip_not_ready_jobs=true5,other_key=2" + * + * <p> + * Type: string + * + * @hide + * @see com.android.server.job.JobSchedulerService.Constants + */ + public static final String JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS = + "job_scheduler_time_controller_constants"; + + /** * ShortcutManager specific settings. * This is encoded as a key=value list, separated by commas. Ex: * diff --git a/core/java/android/service/watchdog/ExplicitHealthCheckService.java b/core/java/android/service/watchdog/ExplicitHealthCheckService.java index eeefb4ae10fa..dc9c85808240 100644 --- a/core/java/android/service/watchdog/ExplicitHealthCheckService.java +++ b/core/java/android/service/watchdog/ExplicitHealthCheckService.java @@ -183,7 +183,6 @@ public abstract class ExplicitHealthCheckService extends Service { */ @SystemApi public static final class PackageConfig implements Parcelable { - // TODO: Receive from DeviceConfig flag private static final long DEFAULT_HEALTH_CHECK_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(1); private final String mPackageName; diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index c2aec6a40ff4..a25f2eede905 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -508,14 +508,25 @@ public interface WindowManager extends ViewManager { * * @param displayId Display ID. * @param shouldShow Indicates that the display should show IME. - * @see KeyguardManager#isDeviceSecure() - * @see KeyguardManager#isDeviceLocked() * @hide */ @TestApi default void setShouldShowIme(int displayId, boolean shouldShow) { } + /** + * Indicates that the display should show IME. + * + * @param displayId The id of the display. + * @return {@code true} if the display should show IME when an input field becomes + * focused on it. + * @hide + */ + @TestApi + default boolean shouldShowIme(int displayId) { + return false; + } + public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable { /** * X position for this window. With the default gravity it is ignored. diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 2e4db5c4eef9..c3494432ebcb 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -192,4 +192,13 @@ public final class WindowManagerImpl implements WindowManager { } catch (RemoteException e) { } } + + @Override + public boolean shouldShowIme(int displayId) { + try { + return WindowManagerGlobal.getWindowManagerService().shouldShowIme(displayId); + } catch (RemoteException e) { + } + return false; + } } diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java index 417c6e7f3c75..042b943c60a3 100644 --- a/core/java/android/view/textclassifier/TextClassificationManager.java +++ b/core/java/android/view/textclassifier/TextClassificationManager.java @@ -25,6 +25,7 @@ import android.content.Context; import android.database.ContentObserver; import android.os.ServiceManager; import android.provider.DeviceConfig; +import android.provider.DeviceConfig.Properties; import android.provider.Settings; import android.service.textclassifier.TextClassifierService; import android.view.textclassifier.TextClassifier.TextClassifierType; @@ -199,7 +200,7 @@ public final class TextClassificationManager { getApplicationContext().getContentResolver() .unregisterContentObserver(mSettingsObserver); if (ConfigParser.ENABLE_DEVICE_CONFIG) { - DeviceConfig.removeOnPropertyChangedListener(mSettingsObserver); + DeviceConfig.removeOnPropertiesChangedListener(mSettingsObserver); } } } finally { @@ -286,7 +287,7 @@ public final class TextClassificationManager { } private static final class SettingsObserver extends ContentObserver - implements DeviceConfig.OnPropertyChangedListener { + implements DeviceConfig.OnPropertiesChangedListener { private final WeakReference<TextClassificationManager> mTcm; @@ -298,7 +299,7 @@ public final class TextClassificationManager { false /* notifyForDescendants */, this); if (ConfigParser.ENABLE_DEVICE_CONFIG) { - DeviceConfig.addOnPropertyChangedListener( + DeviceConfig.addOnPropertiesChangedListener( DeviceConfig.NAMESPACE_TEXTCLASSIFIER, ActivityThread.currentApplication().getMainExecutor(), this); @@ -311,7 +312,7 @@ public final class TextClassificationManager { } @Override - public void onPropertyChanged(String namespace, String name, String value) { + public void onPropertiesChanged(Properties properties) { invalidateSettings(); } diff --git a/core/java/com/android/internal/app/AbstractResolverComparator.java b/core/java/com/android/internal/app/AbstractResolverComparator.java index b7276a0450cc..87d80d408924 100644 --- a/core/java/com/android/internal/app/AbstractResolverComparator.java +++ b/core/java/com/android/internal/app/AbstractResolverComparator.java @@ -22,9 +22,14 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.UserHandle; import android.util.Log; + import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; + import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -35,6 +40,8 @@ import java.util.List; abstract class AbstractResolverComparator implements Comparator<ResolvedComponentInfo> { private static final int NUM_OF_TOP_ANNOTATIONS_TO_USE = 3; + private static final boolean DEBUG = false; + private static final String TAG = "AbstractResolverComp"; private AfterCompute mAfterCompute; protected final PackageManager mPm; @@ -47,6 +54,46 @@ abstract class AbstractResolverComparator implements Comparator<ResolvedComponen // can be null if mHttp == false or current user has no default browser package private final String mDefaultBrowserPackageName; + // message types + static final int RANKER_SERVICE_RESULT = 0; + static final int RANKER_RESULT_TIMEOUT = 1; + + // timeout for establishing connections with a ResolverRankerService, collecting features and + // predicting ranking scores. + private static final int WATCHDOG_TIMEOUT_MILLIS = 500; + + protected final Handler mHandler = new Handler(Looper.getMainLooper()) { + public void handleMessage(Message msg) { + switch (msg.what) { + case RANKER_SERVICE_RESULT: + if (DEBUG) { + Log.d(TAG, "RANKER_SERVICE_RESULT"); + } + if (mHandler.hasMessages(RANKER_RESULT_TIMEOUT)) { + if (msg.obj != null) { + handleResultMessage(msg); + } else { + Log.e(TAG, "Receiving null prediction results."); + } + mHandler.removeMessages(RANKER_RESULT_TIMEOUT); + afterCompute(); + } + break; + + case RANKER_RESULT_TIMEOUT: + if (DEBUG) { + Log.d(TAG, "RANKER_RESULT_TIMEOUT; unbinding services"); + } + mHandler.removeMessages(RANKER_SERVICE_RESULT); + afterCompute(); + break; + + default: + super.handleMessage(msg); + } + } + }; + AbstractResolverComparator(Context context, Intent intent) { String scheme = intent.getScheme(); mHttp = "http".equals(scheme) || "https".equals(scheme); @@ -142,9 +189,16 @@ abstract class AbstractResolverComparator implements Comparator<ResolvedComponen * #getScore(ComponentName)} or {@link #compare(Object, Object)}, in order to prepare the * comparator for those calls. Note that {@link #getScore(ComponentName)} uses {@link * ComponentName}, so the implementation will have to be prepared to identify a {@link - * ResolvedComponentInfo} by {@link ComponentName}. + * ResolvedComponentInfo} by {@link ComponentName}. {@link #beforeCompute()} will be called + * before doing any computing. */ - abstract void compute(List<ResolvedComponentInfo> targets); + final void compute(List<ResolvedComponentInfo> targets) { + beforeCompute(); + doCompute(targets); + } + + /** Implementation of compute called after {@link #beforeCompute()}. */ + abstract void doCompute(List<ResolvedComponentInfo> targets); /** * Returns the score that was calculated for the corresponding {@link ResolvedComponentInfo} @@ -152,6 +206,9 @@ abstract class AbstractResolverComparator implements Comparator<ResolvedComponen */ abstract float getScore(ComponentName name); + /** Handles result message sent to mHandler. */ + abstract void handleResultMessage(Message message); + /** * Reports to UsageStats what was chosen. */ @@ -172,10 +229,26 @@ abstract class AbstractResolverComparator implements Comparator<ResolvedComponen void updateModel(ComponentName componentName) { } + /** Called before {@link #doCompute(List)}. Sets up 500ms timeout. */ + void beforeCompute() { + if (DEBUG) Log.d(TAG, "Setting watchdog timer for " + WATCHDOG_TIMEOUT_MILLIS + "ms"); + if (mHandler == null) { + Log.d(TAG, "Error: Handler is Null; Needs to be initialized."); + return; + } + mHandler.sendEmptyMessageDelayed(RANKER_RESULT_TIMEOUT, WATCHDOG_TIMEOUT_MILLIS); + } + /** - * Called when the {@link ResolverActivity} is destroyed. + * Called when the {@link ResolverActivity} is destroyed. This calls {@link #afterCompute()}. If + * this call needs to happen at a different time during destroy, the method should be + * overridden. */ - abstract void destroy(); + void destroy() { + mHandler.removeMessages(RANKER_SERVICE_RESULT); + mHandler.removeMessages(RANKER_RESULT_TIMEOUT); + afterCompute(); + } private boolean isDefaultBrowser(ResolveInfo ri) { // It makes sense to prefer the default browser diff --git a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java index cb44c67c8c9b..3b4e1a0618a1 100644 --- a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java +++ b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java @@ -26,6 +26,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; +import android.os.Message; import android.os.UserHandle; import android.view.textclassifier.Log; @@ -73,7 +74,7 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator } @Override - void compute(List<ResolvedComponentInfo> targets) { + void doCompute(List<ResolvedComponentInfo> targets) { List<AppTarget> appTargets = new ArrayList<>(); for (ResolvedComponentInfo target : targets) { appTargets.add(new AppTarget.Builder(new AppTargetId(target.name.flattenToString())) @@ -82,15 +83,24 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator } mAppPredictor.sortTargets(appTargets, mContext.getMainExecutor(), sortedAppTargets -> { - for (int i = 0; i < sortedAppTargets.size(); i++) { - mTargetRanks.put(new ComponentName(sortedAppTargets.get(i).getPackageName(), - sortedAppTargets.get(i).getClassName()), i); - } - afterCompute(); + Message msg = + Message.obtain(mHandler, RANKER_SERVICE_RESULT, sortedAppTargets); + msg.sendToTarget(); }); } @Override + void handleResultMessage(Message msg) { + if (msg.what == RANKER_SERVICE_RESULT) { + final List<AppTarget> sortedAppTargets = (List<AppTarget>) msg.obj; + for (int i = 0; i < sortedAppTargets.size(); i++) { + mTargetRanks.put(new ComponentName(sortedAppTargets.get(i).getPackageName(), + sortedAppTargets.get(i).getClassName()), i); + } + } + } + + @Override float getScore(ComponentName name) { Integer rank = mTargetRanks.get(name); if (rank == null) { @@ -111,9 +121,4 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator .setClassName(componentName.getClassName()).build(), ACTION_LAUNCH).build()); } - - @Override - void destroy() { - // Do nothing. App Predictor destruction is handled by caller. - } } diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 204012f04cba..1eabbd8bd00e 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -114,6 +114,7 @@ import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.ImageUtils; +import com.android.internal.widget.ResolverDrawerLayout; import com.google.android.collect.Lists; @@ -143,6 +144,8 @@ public class ChooserActivity extends ResolverActivity { public static final String EXTRA_PRIVATE_RETAIN_IN_ON_STOP = "com.android.internal.app.ChooserActivity.EXTRA_PRIVATE_RETAIN_IN_ON_STOP"; + private static final String PREF_NUM_SHEET_EXPANSIONS = "pref_num_sheet_expansions"; + private static final boolean DEBUG = false; /** @@ -502,6 +505,21 @@ public class ChooserActivity extends ResolverActivity { chooserHeader.setElevation(defaultElevation); } }); + + mResolverDrawerLayout.setOnCollapsedChangedListener( + new ResolverDrawerLayout.OnCollapsedChangedListener() { + + // Only consider one expansion per activity creation + private boolean mWrittenOnce = false; + + @Override + public void onCollapsedChanged(boolean isCollapsed) { + if (!isCollapsed && !mWrittenOnce) { + incrementNumSheetExpansions(); + mWrittenOnce = true; + } + } + }); } if (DEBUG) { @@ -881,6 +899,15 @@ public class ChooserActivity extends ResolverActivity { return CONTENT_PREVIEW_TEXT; } + private int getNumSheetExpansions() { + return getPreferences(Context.MODE_PRIVATE).getInt(PREF_NUM_SHEET_EXPANSIONS, 0); + } + + private void incrementNumSheetExpansions() { + getPreferences(Context.MODE_PRIVATE).edit().putInt(PREF_NUM_SHEET_EXPANSIONS, + getNumSheetExpansions() + 1).apply(); + } + @Override protected void onDestroy() { super.onDestroy(); @@ -2030,7 +2057,8 @@ public class ChooserActivity extends ResolverActivity { public static final int TARGET_STANDARD_AZ = 3; private static final int MAX_SUGGESTED_APP_TARGETS = 4; - private static final int MAX_TARGETS_PER_SERVICE = 2; + private static final int MAX_CHOOSER_TARGETS_PER_APP = 2; + private static final int MAX_SHORTCUT_TARGETS_PER_APP = 8; private static final int MAX_SERVICE_TARGETS = 8; @@ -2356,9 +2384,11 @@ public class ChooserActivity extends ResolverActivity { final float baseScore = getBaseScore(origTarget, isShortcutResult); Collections.sort(targets, mBaseTargetComparator); + final int maxTargets = isShortcutResult ? MAX_SHORTCUT_TARGETS_PER_APP + : MAX_CHOOSER_TARGETS_PER_APP; float lastScore = 0; boolean shouldNotify = false; - for (int i = 0, N = Math.min(targets.size(), MAX_TARGETS_PER_SERVICE); i < N; i++) { + for (int i = 0, count = Math.min(targets.size(), maxTargets); i < count; i++) { final ChooserTarget target = targets.get(i); float targetScore = target.getScore(); targetScore *= baseScore; @@ -2491,19 +2521,25 @@ public class ChooserActivity extends ResolverActivity { private DirectShareViewHolder mDirectShareViewHolder; private int mChooserTargetWidth = 0; + private boolean mShowAzLabelIfPoss; private static final int VIEW_TYPE_DIRECT_SHARE = 0; private static final int VIEW_TYPE_NORMAL = 1; private static final int VIEW_TYPE_CONTENT_PREVIEW = 2; private static final int VIEW_TYPE_PROFILE = 3; + private static final int VIEW_TYPE_AZ_LABEL = 4; private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4; private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8; + private static final int NUM_EXPANSIONS_TO_HIDE_AZ_LABEL = 20; + public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) { mChooserListAdapter = wrappedAdapter; mLayoutInflater = LayoutInflater.from(ChooserActivity.this); + mShowAzLabelIfPoss = getNumSheetExpansions() < NUM_EXPANSIONS_TO_HIDE_AZ_LABEL; + wrappedAdapter.registerDataSetObserver(new DataSetObserver() { @Override public void onChanged() { @@ -2550,12 +2586,27 @@ public class ChooserActivity extends ResolverActivity { } @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int position) { + int viewType = getItemViewType(position); + if (viewType == VIEW_TYPE_CONTENT_PREVIEW) { + return false; + } + return true; + } + + @Override public int getCount() { return (int) ( getContentPreviewRowCount() + getProfileRowCount() + getServiceTargetRowCount() + getCallerAndRankedTargetRowCount() + + getAzLabelRowCount() + Math.ceil( (float) mChooserListAdapter.getAlphaTargetCount() / getMaxTargetsPerRow()) @@ -2593,6 +2644,11 @@ public class ChooserActivity extends ResolverActivity { return 0; } + public int getAzLabelRowCount() { + // Only show a label if the a-z list is showing + return (mShowAzLabelIfPoss && mChooserListAdapter.getAlphaTargetCount() > 0) ? 1 : 0; + } + @Override public Object getItem(int position) { // We have nothing useful to return here. @@ -2617,6 +2673,10 @@ public class ChooserActivity extends ResolverActivity { return createProfileView(convertView, parent); } + if (viewType == VIEW_TYPE_AZ_LABEL) { + return createAzLabelView(parent); + } + if (convertView == null) { holder = createViewHolder(viewType, parent); } else { @@ -2630,27 +2690,29 @@ public class ChooserActivity extends ResolverActivity { @Override public int getItemViewType(int position) { - if (position == 0 && getContentPreviewRowCount() == 1) { - return VIEW_TYPE_CONTENT_PREVIEW; - } + int count; - if (getProfileRowCount() == 1 && position == getContentPreviewRowCount()) { - return VIEW_TYPE_PROFILE; - } + int countSum = (count = getContentPreviewRowCount()); + if (count > 0 && position < countSum) return VIEW_TYPE_CONTENT_PREVIEW; - final int start = getFirstRowPosition(position); - final int startType = mChooserListAdapter.getPositionTargetType(start); + countSum += (count = getProfileRowCount()); + if (count > 0 && position < countSum) return VIEW_TYPE_PROFILE; - if (startType == ChooserListAdapter.TARGET_SERVICE) { - return VIEW_TYPE_DIRECT_SHARE; - } + countSum += (count = getServiceTargetRowCount()); + if (count > 0 && position < countSum) return VIEW_TYPE_DIRECT_SHARE; + + countSum += (count = getCallerAndRankedTargetRowCount()); + if (count > 0 && position < countSum) return VIEW_TYPE_NORMAL; + + countSum += (count = getAzLabelRowCount()); + if (count > 0 && position < countSum) return VIEW_TYPE_AZ_LABEL; return VIEW_TYPE_NORMAL; } @Override public int getViewTypeCount() { - return 4; + return 5; } private ViewGroup createContentPreviewView(View convertView, ViewGroup parent) { @@ -2677,6 +2739,10 @@ public class ChooserActivity extends ResolverActivity { return profileRow; } + private View createAzLabelView(ViewGroup parent) { + return mLayoutInflater.inflate(R.layout.chooser_az_label_row, parent, false); + } + private RowViewHolder loadViewsIntoRow(RowViewHolder holder) { final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); final int exactSpec = MeasureSpec.makeMeasureSpec(mChooserTargetWidth, @@ -2775,16 +2841,24 @@ public class ChooserActivity extends ResolverActivity { } /** - * Need to merge CALLER + ranked STANDARD into a single row. All other types - * are placed into their own row as determined by their target type, and dividers - * are added in the list to separate each type. + * Need to merge CALLER + ranked STANDARD into a single row and prevent a separator from + * showing on top of the AZ list if the AZ label is visible. All other types are placed into + * their own row as determined by their target type, and dividers are added in the list to + * separate each type. */ int getRowType(int rowPosition) { + // Merge caller and ranked standard into a single row int positionType = mChooserListAdapter.getPositionTargetType(rowPosition); if (positionType == ChooserListAdapter.TARGET_CALLER) { return ChooserListAdapter.TARGET_STANDARD; } + // If an the A-Z label is shown, prevent a separator from appearing by making the A-Z + // row type the same as the suggestion row type + if (getAzLabelRowCount() > 0 && positionType == ChooserListAdapter.TARGET_STANDARD_AZ) { + return ChooserListAdapter.TARGET_STANDARD; + } + return positionType; } @@ -2864,6 +2938,8 @@ public class ChooserActivity extends ResolverActivity { return serviceCount + (row - serviceRows) * getMaxTargetsPerRow(); } + row -= getAzLabelRowCount(); + return callerAndRankedCount + serviceCount + (row - callerAndRankedRows - serviceRows) * getMaxTargetsPerRow(); } diff --git a/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java index 726b186d8edb..a7819070ee98 100644 --- a/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java +++ b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java @@ -18,7 +18,6 @@ package com.android.internal.app; import android.app.usage.UsageStats; -import android.app.usage.UsageStatsManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -28,9 +27,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.metrics.LogMaker; -import android.os.Handler; import android.os.IBinder; -import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; @@ -67,10 +64,6 @@ class ResolverRankerServiceResolverComparator extends AbstractResolverComparator private static final float RECENCY_MULTIPLIER = 2.f; - // message types - private static final int RESOLVER_RANKER_SERVICE_RESULT = 0; - private static final int RESOLVER_RANKER_RESULT_TIMEOUT = 1; - // timeout for establishing connections with a ResolverRankerService. private static final int CONNECTION_COST_TIMEOUT_MILLIS = 200; // timeout for establishing connections with a ResolverRankerService, collecting features and @@ -93,57 +86,6 @@ class ResolverRankerServiceResolverComparator extends AbstractResolverComparator private Context mContext; private CountDownLatch mConnectSignal; - private final Handler mHandler = new Handler(Looper.getMainLooper()) { - public void handleMessage(Message msg) { - switch (msg.what) { - case RESOLVER_RANKER_SERVICE_RESULT: - if (DEBUG) { - Log.d(TAG, "RESOLVER_RANKER_SERVICE_RESULT"); - } - if (mHandler.hasMessages(RESOLVER_RANKER_RESULT_TIMEOUT)) { - if (msg.obj != null) { - final List<ResolverTarget> receivedTargets = - (List<ResolverTarget>) msg.obj; - if (receivedTargets != null && mTargets != null - && receivedTargets.size() == mTargets.size()) { - final int size = mTargets.size(); - boolean isUpdated = false; - for (int i = 0; i < size; ++i) { - final float predictedProb = - receivedTargets.get(i).getSelectProbability(); - if (predictedProb != mTargets.get(i).getSelectProbability()) { - mTargets.get(i).setSelectProbability(predictedProb); - isUpdated = true; - } - } - if (isUpdated) { - mRankerServiceName = mResolvedRankerName; - } - } else { - Log.e(TAG, "Sizes of sent and received ResolverTargets diff."); - } - } else { - Log.e(TAG, "Receiving null prediction results."); - } - mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT); - afterCompute(); - } - break; - - case RESOLVER_RANKER_RESULT_TIMEOUT: - if (DEBUG) { - Log.d(TAG, "RESOLVER_RANKER_RESULT_TIMEOUT; unbinding services"); - } - mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT); - afterCompute(); - break; - - default: - super.handleMessage(msg); - } - } - }; - public ResolverRankerServiceResolverComparator(Context context, Intent intent, String referrerPackage, AfterCompute afterCompute) { super(context, intent); @@ -159,11 +101,35 @@ class ResolverRankerServiceResolverComparator extends AbstractResolverComparator setCallBack(afterCompute); } - // compute features for each target according to usage stats of targets. @Override - public void compute(List<ResolvedComponentInfo> targets) { - reset(); + public void handleResultMessage(Message msg) { + if (msg.what != RANKER_SERVICE_RESULT) { + return; + } + final List<ResolverTarget> receivedTargets = (List<ResolverTarget>) msg.obj; + if (receivedTargets != null && mTargets != null + && receivedTargets.size() == mTargets.size()) { + final int size = mTargets.size(); + boolean isUpdated = false; + for (int i = 0; i < size; ++i) { + final float predictedProb = + receivedTargets.get(i).getSelectProbability(); + if (predictedProb != mTargets.get(i).getSelectProbability()) { + mTargets.get(i).setSelectProbability(predictedProb); + isUpdated = true; + } + } + if (isUpdated) { + mRankerServiceName = mResolvedRankerName; + } + } else { + Log.e(TAG, "Sizes of sent and received ResolverTargets diff."); + } + } + // compute features for each target according to usage stats of targets. + @Override + public void doCompute(List<ResolvedComponentInfo> targets) { final long recentSinceTime = mCurrentTime - RECENCY_TIME_PERIOD; float mostRecencyScore = 1.0f; @@ -322,8 +288,8 @@ class ResolverRankerServiceResolverComparator extends AbstractResolverComparator // unbind the service and clear unhandled messges. @Override public void destroy() { - mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT); - mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT); + mHandler.removeMessages(RANKER_SERVICE_RESULT); + mHandler.removeMessages(RANKER_RESULT_TIMEOUT); if (mConnection != null) { mContext.unbindService(mConnection); mConnection.destroy(); @@ -417,15 +383,6 @@ class ResolverRankerServiceResolverComparator extends AbstractResolverComparator return null; } - // set a watchdog, to avoid waiting for ranking service for too long. - private void startWatchDog(int timeOutLimit) { - if (DEBUG) Log.d(TAG, "Setting watchdog timer for " + timeOutLimit + "ms"); - if (mHandler == null) { - Log.d(TAG, "Error: Handler is Null; Needs to be initialized."); - } - mHandler.sendEmptyMessageDelayed(RESOLVER_RANKER_RESULT_TIMEOUT, timeOutLimit); - } - private class ResolverRankerServiceConnection implements ServiceConnection { private final CountDownLatch mConnectSignal; @@ -442,7 +399,7 @@ class ResolverRankerServiceResolverComparator extends AbstractResolverComparator } synchronized (mLock) { final Message msg = Message.obtain(); - msg.what = RESOLVER_RANKER_SERVICE_RESULT; + msg.what = RANKER_SERVICE_RESULT; msg.obj = targets; mHandler.sendMessage(msg); } @@ -477,12 +434,13 @@ class ResolverRankerServiceResolverComparator extends AbstractResolverComparator } } - private void reset() { + @Override + void beforeCompute() { + super.beforeCompute(); mTargetsDict.clear(); mTargets = null; mRankerServiceName = new ComponentName(mContext, this.getClass()); mResolvedRankerName = null; - startWatchDog(WATCHDOG_TIMEOUT_MILLIS); initRanker(mContext); } diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java index 76826d3ce787..9e8bd640026b 100644 --- a/core/java/com/android/internal/content/FileSystemProvider.java +++ b/core/java/com/android/internal/content/FileSystemProvider.java @@ -45,6 +45,7 @@ import android.util.Log; import android.webkit.MimeTypeMap; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.ArrayUtils; import libcore.io.IoUtils; @@ -450,7 +451,11 @@ public abstract class FileSystemProvider extends DocumentsProvider { @Override public String getDocumentType(String documentId) throws FileNotFoundException { - final File file = getFileForDocId(documentId); + return getDocumentType(documentId, getFileForDocId(documentId)); + } + + private String getDocumentType(final String documentId, final File file) + throws FileNotFoundException { if (file.isDirectory()) { return Document.MIME_TYPE_DIR; } else { @@ -532,51 +537,63 @@ public abstract class FileSystemProvider extends DocumentsProvider { return DocumentsContract.openImageThumbnail(file); } - protected RowBuilder includeFile(MatrixCursor result, String docId, File file) + protected RowBuilder includeFile(final MatrixCursor result, String docId, File file) throws FileNotFoundException { + final String[] columns = result.getColumnNames(); + final RowBuilder row = result.newRow(); + if (docId == null) { docId = getDocIdForFile(file); } else { file = getFileForDocId(docId); } + final String mimeType = getDocumentType(docId, file); + row.add(Document.COLUMN_DOCUMENT_ID, docId); + row.add(Document.COLUMN_MIME_TYPE, mimeType); - int flags = 0; + final int flagIndex = ArrayUtils.indexOf(columns, Document.COLUMN_FLAGS); + if (flagIndex != -1) { + int flags = 0; + if (file.canWrite()) { + if (mimeType.equals(Document.MIME_TYPE_DIR)) { + flags |= Document.FLAG_DIR_SUPPORTS_CREATE; + flags |= Document.FLAG_SUPPORTS_DELETE; + flags |= Document.FLAG_SUPPORTS_RENAME; + flags |= Document.FLAG_SUPPORTS_MOVE; + } else { + flags |= Document.FLAG_SUPPORTS_WRITE; + flags |= Document.FLAG_SUPPORTS_DELETE; + flags |= Document.FLAG_SUPPORTS_RENAME; + flags |= Document.FLAG_SUPPORTS_MOVE; + } + } - if (file.canWrite()) { - if (file.isDirectory()) { - flags |= Document.FLAG_DIR_SUPPORTS_CREATE; - flags |= Document.FLAG_SUPPORTS_DELETE; - flags |= Document.FLAG_SUPPORTS_RENAME; - flags |= Document.FLAG_SUPPORTS_MOVE; - } else { - flags |= Document.FLAG_SUPPORTS_WRITE; - flags |= Document.FLAG_SUPPORTS_DELETE; - flags |= Document.FLAG_SUPPORTS_RENAME; - flags |= Document.FLAG_SUPPORTS_MOVE; + if (mimeType.startsWith("image/")) { + flags |= Document.FLAG_SUPPORTS_THUMBNAIL; } - } - final String mimeType = getDocumentType(docId); - final String displayName = file.getName(); - if (mimeType.startsWith("image/")) { - flags |= Document.FLAG_SUPPORTS_THUMBNAIL; + if (typeSupportsMetadata(mimeType)) { + flags |= Document.FLAG_SUPPORTS_METADATA; + } + row.add(flagIndex, flags); } - if (typeSupportsMetadata(mimeType)) { - flags |= Document.FLAG_SUPPORTS_METADATA; + final int displayNameIndex = ArrayUtils.indexOf(columns, Document.COLUMN_DISPLAY_NAME); + if (displayNameIndex != -1) { + row.add(displayNameIndex, file.getName()); } - final RowBuilder row = result.newRow(); - row.add(Document.COLUMN_DOCUMENT_ID, docId); - row.add(Document.COLUMN_DISPLAY_NAME, displayName); - row.add(Document.COLUMN_SIZE, file.length()); - row.add(Document.COLUMN_MIME_TYPE, mimeType); - row.add(Document.COLUMN_FLAGS, flags); - - // Only publish dates reasonably after epoch - long lastModified = file.lastModified(); - if (lastModified > 31536000000L) { - row.add(Document.COLUMN_LAST_MODIFIED, lastModified); + final int lastModifiedIndex = ArrayUtils.indexOf(columns, Document.COLUMN_LAST_MODIFIED); + if (lastModifiedIndex != -1) { + final long lastModified = file.lastModified(); + // Only publish dates reasonably after epoch + if (lastModified > 31536000000L) { + row.add(lastModifiedIndex, lastModified); + } + } + final int sizeIndex = ArrayUtils.indexOf(columns, Document.COLUMN_SIZE); + if (sizeIndex != -1) { + row.add(sizeIndex, file.length()); } // Return the row builder just in case any subclass want to add more stuff to it. diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index cfc32cf67016..7e501d27d30f 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -50,9 +50,11 @@ oneway interface IStatusBar * @param mask which flags to change * @param fullscreenBounds the current bounds of the fullscreen stack, in screen coordinates * @param dockedBounds the current bounds of the docked stack, in screen coordinates + * @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME. */ void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis, - int mask, in Rect fullscreenBounds, in Rect dockedBounds); + int mask, in Rect fullscreenBounds, in Rect dockedBounds, + boolean navbarColorManagedByIme); void topAppWindowChanged(int displayId, boolean menuVisible); void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition, diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java index ff94264d9b90..6b0f8b2f5dc9 100644 --- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java +++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java @@ -39,12 +39,13 @@ public final class RegisterStatusBarResult implements Parcelable { public final IBinder mImeToken; public final Rect mFullscreenStackBounds; public final Rect mDockedStackBounds; + public final boolean mNavbarColorManagedByIme; public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1, int systemUiVisibility, boolean menuVisible, int imeWindowVis, int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2, int fullscreenStackSysUiVisibility, int dockedStackSysUiVisibility, IBinder imeToken, Rect fullscreenStackBounds, - Rect dockedStackBounds) { + Rect dockedStackBounds, boolean navbarColorManagedByIme) { mIcons = new ArrayMap<>(icons); mDisabledFlags1 = disabledFlags1; mSystemUiVisibility = systemUiVisibility; @@ -58,6 +59,7 @@ public final class RegisterStatusBarResult implements Parcelable { mImeToken = imeToken; mFullscreenStackBounds = fullscreenStackBounds; mDockedStackBounds = dockedStackBounds; + mNavbarColorManagedByIme = navbarColorManagedByIme; } @Override @@ -80,6 +82,7 @@ public final class RegisterStatusBarResult implements Parcelable { dest.writeStrongBinder(mImeToken); dest.writeTypedObject(mFullscreenStackBounds, flags); dest.writeTypedObject(mDockedStackBounds, flags); + dest.writeBoolean(mNavbarColorManagedByIme); } /** @@ -103,11 +106,12 @@ public final class RegisterStatusBarResult implements Parcelable { final IBinder imeToken = source.readStrongBinder(); final Rect fullscreenStackBounds = source.readTypedObject(Rect.CREATOR); final Rect dockedStackBounds = source.readTypedObject(Rect.CREATOR); + final boolean navbarColorManagedByIme = source.readBoolean(); return new RegisterStatusBarResult(icons, disabledFlags1, systemUiVisibility, menuVisible, imeWindowVis, imeBackDisposition, showImeSwitcher, disabledFlags2, fullscreenStackSysUiVisibility, dockedStackSysUiVisibility, imeToken, fullscreenStackBounds, - dockedStackBounds); + dockedStackBounds, navbarColorManagedByIme); } @Override diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java index 6b0d85ef0b95..3adb36f5e54b 100644 --- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java +++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java @@ -104,6 +104,7 @@ public class ResolverDrawerLayout extends ViewGroup { private OnDismissedListener mOnDismissedListener; private RunOnDismissedListener mRunOnDismissedListener; + private OnCollapsedChangedListener mOnCollapsedChangedListener; private boolean mDismissLocked; @@ -267,6 +268,10 @@ public class ResolverDrawerLayout extends ViewGroup { return mOnDismissedListener != null && !mDismissLocked; } + public void setOnCollapsedChangedListener(OnCollapsedChangedListener listener) { + mOnCollapsedChangedListener = listener; + } + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getActionMasked(); @@ -548,6 +553,10 @@ public class ResolverDrawerLayout extends ViewGroup { if (mScrollIndicatorDrawable != null) { setWillNotDraw(!isCollapsed); } + + if (mOnCollapsedChangedListener != null) { + mOnCollapsedChangedListener.onCollapsedChanged(isCollapsed); + } } void dispatchOnDismissed() { @@ -1078,8 +1087,25 @@ public class ResolverDrawerLayout extends ViewGroup { }; } + /** + * Listener for sheet dismissed events. + */ public interface OnDismissedListener { - public void onDismissed(); + /** + * Callback when the sheet is dismissed by the user. + */ + void onDismissed(); + } + + /** + * Listener for sheet collapsed / expanded events. + */ + public interface OnCollapsedChangedListener { + /** + * Callback when the sheet is either fully expanded or collapsed. + * @param isCollapsed true when collapsed, false when expanded. + */ + void onCollapsedChanged(boolean isCollapsed); } private class RunOnDismissedListener implements Runnable { diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index 1ff7418a3ef8..9cffb2bf1601 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -2354,4 +2354,11 @@ enum PageId { // OPEN: Settings > Pick preferred SIM dialog DIALOG_PREFERRED_SIM_PICKER = 1709; + + // OPEN: Settings > Network & internet > Mobile network > Delete sim + DIALOG_DELETE_SIM_CONFIRMATION = 1713; + + // OPEN: Settings > Network & internet > Mobile network > Delete sim > (answer yes to + // confirmation) + DIALOG_DELETE_SIM_PROGRESS = 1714; } diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index b47097da0cdd..8f16b418f7db 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -501,7 +501,10 @@ message GlobalSettingsProto { } optional IntentFirewall intent_firewall = 65; - optional SettingProto job_scheduler_constants = 66; + optional SettingProto job_scheduler_constants = 66 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto job_scheduler_quota_controller_constants = 149 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto job_scheduler_time_controller_constants = 150 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto keep_profile_in_background = 67 [ (android.privacy).dest = DEST_AUTOMATIC ]; message LangId { @@ -1049,5 +1052,5 @@ message GlobalSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 149; + // Next tag = 151; } diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto index 0db74243222c..0821d147044d 100644 --- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto +++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto @@ -149,4 +149,6 @@ enum EventId { PROVISIONING_PREPARE_STARTED = 122; PROVISIONING_PREPARE_COMPLETED = 123; PROVISIONING_FLOW_TYPE = 124; + CROSS_PROFILE_APPS_GET_TARGET_USER_PROFILES = 125; + CROSS_PROFILE_APPS_START_ACTIVITY_AS_USER = 126; } diff --git a/core/res/res/layout/chooser_az_label_row.xml b/core/res/res/layout/chooser_az_label_row.xml new file mode 100644 index 000000000000..1b733fc907cc --- /dev/null +++ b/core/res/res/layout/chooser_az_label_row.xml @@ -0,0 +1,31 @@ +<?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 + --> + +<!-- Separator applied as background --> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:text="@string/chooser_all_apps_button_label" + android:contentDescription="@string/chooser_all_apps_button_label" + android:background="@drawable/chooser_row_layer_list" + android:textAppearance="?attr/textAppearanceSmall" + android:textColor="?attr/textColorSecondary" + android:textSize="14sp" + android:singleLine="true" + android:paddingTop="16dp" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center"/> + diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml index 8727f4c9e0ef..17b5f50669a2 100644 --- a/core/res/res/layout/chooser_grid.xml +++ b/core/res/res/layout/chooser_grid.xml @@ -37,8 +37,8 @@ android:layout_width="24dp" android:layout_height="4dp" android:src="@drawable/ic_drag_handle" - android:clickable="true" android:layout_marginTop="@dimen/chooser_edge_margin_thin" + android:layout_marginBottom="@dimen/chooser_edge_margin_thin" android:tint="@color/lighter_gray" android:layout_centerHorizontal="true" android:layout_alignParentTop="true" /> @@ -46,11 +46,8 @@ <TextView android:id="@+id/title" android:layout_height="wrap_content" android:layout_width="wrap_content" - android:textAppearance="?attr/textAppearanceMedium" - android:textSize="20sp" - android:textColor="?attr/textColorPrimary" + android:textAppearance="@style/TextAppearance.DeviceDefault.WindowTitle" android:gravity="center" - android:paddingTop="@dimen/chooser_edge_margin_thin" android:paddingBottom="@dimen/chooser_view_spacing" android:paddingLeft="24dp" android:paddingRight="24dp" diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml index f3ca0af767b1..e889e8584fec 100644 --- a/core/res/res/layout/chooser_grid_preview_text.xml +++ b/core/res/res/layout/chooser_grid_preview_text.xml @@ -44,6 +44,7 @@ android:layout_toStartOf="@id/copy_button" android:layout_centerVertical="true" android:ellipsize="end" + android:fontFamily="@android:string/config_headlineFontFamily" android:textColor="?android:attr/textColorPrimary" android:maxLines="2"/> @@ -112,8 +113,8 @@ android:layout_gravity="center_vertical" android:ellipsize="end" android:maxLines="2" - android:textSize="20sp" - android:textColor="?android:attr/textColorPrimary"/> + android:textAppearance="@style/TextAppearance.DeviceDefault.WindowTitle" + android:fontFamily="@android:string/config_headlineFontFamily"/> </LinearLayout> </LinearLayout> diff --git a/core/res/res/layout/chooser_profile_row.xml b/core/res/res/layout/chooser_profile_row.xml index 1a24a073a122..fe4f9496be30 100644 --- a/core/res/res/layout/chooser_profile_row.xml +++ b/core/res/res/layout/chooser_profile_row.xml @@ -20,7 +20,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center"> - <TextView + <Button android:id="@+id/profile_button" android:layout_width="wrap_content" android:layout_height="48dp" diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index ef834aa01a36..75fd3a0c04b7 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -5373,4 +5373,7 @@ <!-- ChooserActivity - No direct share targets are available. [CHAR LIMIT=NONE] --> <string name="chooser_no_direct_share_targets">Direct share not available</string> + <!-- ChooserActivity - Alphabetically sorted apps list label. [CHAR LIMIT=NONE] --> + <string name="chooser_all_apps_button_label">Apps list</string> + </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index bb560d324809..fbe340ed61d3 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3771,4 +3771,6 @@ <java-symbol type="color" name="chooser_gradient_highlight" /> <java-symbol type="drawable" name="chooser_direct_share_label_placeholder" /> <java-symbol type="dimen" name="chooser_direct_share_label_placeholder_max_width" /> + <java-symbol type="layout" name="chooser_az_label_row" /> + <java-symbol type="string" name="chooser_all_apps_button_label" /> </resources> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index f4d3c8163e9c..61fb8112dbfc 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -294,6 +294,8 @@ public class SettingsBackupTest { Settings.Global.INTENT_FIREWALL_UPDATE_CONTENT_URL, Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL, Settings.Global.JOB_SCHEDULER_CONSTANTS, + Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS, + Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS, Settings.Global.KEEP_PROFILE_IN_BACKGROUND, Settings.Global.KERNEL_CPU_THREAD_READER, Settings.Global.LANG_ID_UPDATE_CONTENT_URL, diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java index 3cb1e187fef1..b93c3a7a17e2 100644 --- a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java +++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java @@ -57,7 +57,8 @@ public class RegisterStatusBarResultTest { 0x80 /* dockedStackSysUiVisibility */, new Binder() /* imeToken */, new Rect(0x100, 0x200, 0x400, 0x800) /* fullscreenStackBounds */, - new Rect(0x1000, 0x2000, 0x4000, 0x8000) /* dockedStackBounds */); + new Rect(0x1000, 0x2000, 0x4000, 0x8000) /* dockedStackBounds */, + true /* navbarColorManagedByIme */); final RegisterStatusBarResult copy = clone(original); @@ -80,6 +81,7 @@ public class RegisterStatusBarResultTest { assertThat(copy.mImeToken).isSameAs(original.mImeToken); assertThat(copy.mFullscreenStackBounds).isEqualTo(original.mFullscreenStackBounds); assertThat(copy.mDockedStackBounds).isEqualTo(original.mDockedStackBounds); + assertThat(copy.mNavbarColorManagedByIme).isEqualTo(original.mNavbarColorManagedByIme); } private RegisterStatusBarResult clone(RegisterStatusBarResult original) { diff --git a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java index 46288bb67b4c..296db46d2624 100644 --- a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java +++ b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java @@ -102,10 +102,10 @@ final class AssistantSettings extends ContentObserver { } private void registerDeviceConfigs() { - DeviceConfig.addOnPropertyChangedListener( + DeviceConfig.addOnPropertiesChangedListener( DeviceConfig.NAMESPACE_SYSTEMUI, this::postToHandler, - this::onDeviceConfigPropertyChanged); + (properties) -> onDeviceConfigPropertiesChanged(properties.getNamespace())); // Update the fields in this class from the current state of the device config. updateFromDeviceConfigFlags(); @@ -116,10 +116,10 @@ final class AssistantSettings extends ContentObserver { } @VisibleForTesting - void onDeviceConfigPropertyChanged(String namespace, String name, String value) { + void onDeviceConfigPropertiesChanged(String namespace) { if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) { Log.e(LOG_TAG, "Received update from DeviceConfig for unrelated namespace: " - + namespace + " " + name + "=" + value); + + namespace); return; } diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java index ad52e2b9504b..5c877de23816 100644 --- a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java +++ b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java @@ -96,10 +96,7 @@ public class AssistantSettingsTest { SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES, "false", false /* makeDefault */)); - mAssistantSettings.onDeviceConfigPropertyChanged( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES, - "false"); + mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI); assertFalse(mAssistantSettings.mGenerateReplies); } @@ -111,10 +108,7 @@ public class AssistantSettingsTest { SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES, "true", false /* makeDefault */)); - mAssistantSettings.onDeviceConfigPropertyChanged( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES, - "true"); + mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI); assertTrue(mAssistantSettings.mGenerateReplies); } @@ -126,10 +120,7 @@ public class AssistantSettingsTest { SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES, "false", false /* makeDefault */)); - mAssistantSettings.onDeviceConfigPropertyChanged( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES, - "false"); + mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI); assertFalse(mAssistantSettings.mGenerateReplies); @@ -138,10 +129,7 @@ public class AssistantSettingsTest { SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES, null, false /* makeDefault */)); - mAssistantSettings.onDeviceConfigPropertyChanged( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES, - null); + mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI); // Go back to the default value. assertTrue(mAssistantSettings.mGenerateReplies); @@ -154,10 +142,7 @@ public class AssistantSettingsTest { SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS, "false", false /* makeDefault */)); - mAssistantSettings.onDeviceConfigPropertyChanged( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS, - "false"); + mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI); assertFalse(mAssistantSettings.mGenerateActions); } @@ -169,10 +154,7 @@ public class AssistantSettingsTest { SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS, "true", false /* makeDefault */)); - mAssistantSettings.onDeviceConfigPropertyChanged( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS, - "true"); + mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI); assertTrue(mAssistantSettings.mGenerateActions); } @@ -184,10 +166,7 @@ public class AssistantSettingsTest { SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS, "false", false /* makeDefault */)); - mAssistantSettings.onDeviceConfigPropertyChanged( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS, - "false"); + mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI); assertFalse(mAssistantSettings.mGenerateActions); @@ -196,10 +175,7 @@ public class AssistantSettingsTest { SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS, null, false /* makeDefault */)); - mAssistantSettings.onDeviceConfigPropertyChanged( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS, - null); + mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI); // Go back to the default value. assertTrue(mAssistantSettings.mGenerateActions); @@ -212,10 +188,7 @@ public class AssistantSettingsTest { SystemUiDeviceConfigFlags.NAS_MAX_MESSAGES_TO_EXTRACT, "10", false /* makeDefault */)); - mAssistantSettings.onDeviceConfigPropertyChanged( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.NAS_MAX_MESSAGES_TO_EXTRACT, - "10"); + mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI); assertEquals(10, mAssistantSettings.mMaxMessagesToExtract); } @@ -227,20 +200,14 @@ public class AssistantSettingsTest { SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS, "5", false /* makeDefault */)); - mAssistantSettings.onDeviceConfigPropertyChanged( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS, - "5"); + mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI); assertEquals(5, mAssistantSettings.mMaxSuggestions); } @Test public void testMaxSuggestionsEmpty() { - mAssistantSettings.onDeviceConfigPropertyChanged( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS, - ""); + mAssistantSettings.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI); assertEquals(DEFAULT_MAX_SUGGESTIONS, mAssistantSettings.mMaxSuggestions); } diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp index e0bb862c5362..62de2ba45455 100644 --- a/packages/NetworkStack/Android.bp +++ b/packages/NetworkStack/Android.bp @@ -56,15 +56,24 @@ cc_library_shared { srcs: [ "jni/network_stack_utils_jni.cpp" ], - + sdk_version: "current", shared_libs: [ "liblog", - "libcutils", - "libnativehelper", - ], - static_libs: [ - "libpcap", + "libnativehelper_compat_libc++", ], + + // We cannot use plain "libc++" here to link libc++ dynamically because it results in: + // java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found + // even if "libc++" is added into jni_libs below. Adding "libc++_shared" into jni_libs doesn't + // build because soong complains of: + // module NetworkStack missing dependencies: libc++_shared + // + // So, link libc++ statically. This means that we also need to ensure that all the C++ libraries + // we depend on do not dynamically link libc++. This is currently the case, because liblog is + // C-only and libnativehelper_compat_libc also uses stl: "c++_static". + // + // TODO: find a better solution for this in R. + stl: "c++_static", cflags: [ "-Wall", "-Werror", @@ -79,7 +88,10 @@ java_defaults { static_libs: [ "NetworkStackBase", ], - jni_libs: ["libnetworkstackutilsjni"], + jni_libs: [ + "libnativehelper_compat_libc++", + "libnetworkstackutilsjni", + ], // Resources already included in NetworkStackBase resource_dirs: [], jarjar_rules: "jarjar-rules-shared.txt", diff --git a/packages/NetworkStack/jni/network_stack_utils_jni.cpp b/packages/NetworkStack/jni/network_stack_utils_jni.cpp index 5544eaa809e7..f2ba5757ed80 100644 --- a/packages/NetworkStack/jni/network_stack_utils_jni.cpp +++ b/packages/NetworkStack/jni/network_stack_utils_jni.cpp @@ -31,7 +31,7 @@ #include <string> #include <nativehelper/JNIHelp.h> -#include <utils/Log.h> +#include <android/log.h> namespace android { constexpr const char NETWORKSTACKUTILS_PKG_NAME[] = "android/net/util/NetworkStackUtils"; @@ -249,7 +249,7 @@ static const JNINativeMethod gNetworkStackUtilsMethods[] = { extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { JNIEnv *env; if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { - ALOGE("ERROR: GetEnv failed"); + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed"); return JNI_ERR; } @@ -261,4 +261,4 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { return JNI_VERSION_1_6; } -}; // namespace android
\ No newline at end of file +}; // namespace android diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp index fe3c1e8eb3e5..039f6bf791fb 100644 --- a/packages/NetworkStack/tests/Android.bp +++ b/packages/NetworkStack/tests/Android.bp @@ -56,6 +56,7 @@ android_test { "liblog", "liblzma", "libnativehelper", + "libnativehelper_compat_libc++", "libnetworkstacktestsjni", "libnetworkstackutilsjni", "libpackagelistparser", @@ -99,5 +100,4 @@ cc_library_shared { "libapf", "libpcap", ], - } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index cd4f6cf26850..c94ee0e56cba 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -797,6 +797,12 @@ class SettingsProtoDumpUtil { Settings.Global.JOB_SCHEDULER_CONSTANTS, GlobalSettingsProto.JOB_SCHEDULER_CONSTANTS); dumpSetting(s, p, + Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS, + GlobalSettingsProto.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS); + dumpSetting(s, p, + Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS, + GlobalSettingsProto.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS); + dumpSetting(s, p, Settings.Global.KEEP_PROFILE_IN_BACKGROUND, GlobalSettingsProto.KEEP_PROFILE_IN_BACKGROUND); diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java index 66d5d1160bf6..25a3fa2f5f20 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java @@ -17,6 +17,7 @@ package com.android.systemui.plugins; import android.annotation.Nullable; import android.app.PendingIntent; import android.content.Intent; +import android.view.View; import com.android.systemui.plugins.annotations.ProvidesInterface; @@ -32,13 +33,20 @@ public interface ActivityStarter { void startPendingIntentDismissingKeyguard(PendingIntent intent); /** - * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent, Runnable)}, but allows + * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent)}, but allows * you to specify the callback that is executed on the UI thread after the intent is sent. */ void startPendingIntentDismissingKeyguard(PendingIntent intent, Runnable intentSentUiThreadCallback); /** + * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent, Runnable)}, but also + * specifies an associated view that should be used for the activity launch animation. + */ + void startPendingIntentDismissingKeyguard(PendingIntent intent, + Runnable intentSentUiThreadCallback, View associatedView); + + /** * The intent flag can be specified in startActivity(). */ void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags); diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml index d8f543f1f710..112dde6bfdc2 100644 --- a/packages/SystemUI/res-keyguard/values/dimens.xml +++ b/packages/SystemUI/res-keyguard/values/dimens.xml @@ -53,7 +53,7 @@ <!-- Clock with header --> <dimen name="widget_small_font_size">22dp</dimen> <dimen name="widget_vertical_padding">32dp</dimen> - <dimen name="widget_vertical_padding_clock">30dp</dimen> + <dimen name="widget_vertical_padding_clock">12dp</dimen> <!-- Subtitle paddings --> <dimen name="widget_horizontal_padding">8dp</dimen> <dimen name="widget_icon_size">16dp</dimen> diff --git a/packages/SystemUI/res/drawable/button_border_selected.xml b/packages/SystemUI/res/drawable/button_border_selected.xml index d9299ec0622b..1e40adefca2a 100644 --- a/packages/SystemUI/res/drawable/button_border_selected.xml +++ b/packages/SystemUI/res/drawable/button_border_selected.xml @@ -20,6 +20,6 @@ android:color="@color/notification_guts_selection_bg" /> <stroke android:width="2dp" - android:color="?android:attr/colorAccent"/> + android:color="@color/GM2_grey_300"/> <corners android:radius="@dimen/rect_button_radius" /> </shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index 58af4a2c24b6..087e0bd8089f 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -103,7 +103,6 @@ asked for it --> android:id="@+id/channel_info" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/notification_guts_button_spacing" android:paddingEnd="@*android:dimen/notification_content_margin_end" android:gravity="center" android:orientation="vertical"> @@ -127,6 +126,7 @@ asked for it --> android:id="@+id/blocking_helper" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="@dimen/notification_guts_button_spacing" android:layout_marginBottom="@dimen/notification_guts_button_spacing" android:paddingEnd="@*android:dimen/notification_content_margin_end" android:clipChildren="false" @@ -216,67 +216,107 @@ asked for it --> android:id="@+id/interruptiveness_settings" android:layout_width="match_parent" android:layout_height="wrap_content" + android:gravity="center" android:orientation="vertical"> - <LinearLayout - android:id="@+id/buttons" + <RelativeLayout + android:id="@+id/alert" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal" - android:gravity="center"> - - <Button - android:id="@+id/alert" - android:minWidth="@dimen/notification_importance_button_width" + android:padding="@dimen/notification_importance_button_padding" + android:clickable="true" + android:focusable="true"> + <ImageView + android:id="@+id/alert_icon" + android:src="@drawable/ic_notification_interruptive" + android:background="@android:color/transparent" + android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:minHeight="@dimen/notification_importance_toggle_size" - android:paddingStart="@dimen/notification_importance_button_horiz_padding" - android:paddingEnd="@dimen/notification_importance_button_horiz_padding" - android:drawablePadding="@dimen/notification_importance_drawable_padding" - android:foreground="@drawable/button_ripple_radius" - android:drawableLeft="@drawable/ic_notification_interruptive" - android:text="@string/notification_alert_title" /> - - <Button - android:id="@+id/silence" - android:minWidth="@dimen/notification_importance_button_width" - android:layout_width="wrap_content" + android:clickable="false" + android:focusable="false"/> + <TextView + android:id="@+id/alert_label" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:minHeight="@dimen/notification_importance_toggle_size" - android:paddingStart="@dimen/notification_importance_button_horiz_padding" - android:paddingEnd="@dimen/notification_importance_button_horiz_padding" - android:drawablePadding="@dimen/notification_importance_drawable_padding" - android:foreground="@drawable/button_ripple_radius" - android:layout_marginStart="@dimen/notification_importance_button_separation" - android:drawableLeft="@drawable/ic_notification_gentle" - android:text="@string/notification_silence_title" /> - </LinearLayout> + android:ellipsize="end" + android:maxLines="1" + android:clickable="false" + android:focusable="false" + android:layout_toEndOf="@id/alert_icon" + android:layout_marginStart="@dimen/notification_importance_drawable_padding" + android:textAppearance="@style/TextAppearance.NotificationImportanceButton.Unselected" + android:text="@string/notification_alert_title"/> + <TextView + android:id="@+id/alert_summary" + android:paddingTop="@dimen/notification_importance_button_padding" + android:text="@string/notification_channel_summary_default" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clickable="false" + android:focusable="false" + android:ellipsize="end" + android:maxLines="2" + android:layout_below="@id/alert_icon" + android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/> + </RelativeLayout> - <TextView - android:id="@+id/description" + <RelativeLayout + android:id="@+id/silence" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/notification_alert_title" - android:gravity="center" - android:layout_marginTop="@dimen/notification_importance_text_marginTop" - android:paddingStart="@dimen/notification_importance_description_padding" - android:paddingEnd="@dimen/notification_importance_description_padding" - android:textAppearance="@style/TextAppearance.NotificationImportanceDetail" /> + android:padding="@dimen/notification_importance_button_padding" + android:layout_marginTop="@dimen/notification_importance_button_separation" + android:clickable="true" + android:focusable="true"> + <ImageView + android:id="@+id/silence_icon" + android:src="@drawable/ic_notification_gentle" + android:background="@android:color/transparent" + android:layout_gravity="center" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:clickable="false" + android:focusable="false"/> + <TextView + android:id="@+id/silence_label" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="end" + android:maxLines="1" + android:clickable="false" + android:focusable="false" + android:layout_toEndOf="@id/silence_icon" + android:layout_marginStart="@dimen/notification_importance_drawable_padding" + android:textAppearance="@style/TextAppearance.NotificationImportanceButton.Unselected" + android:text="@string/notification_silence_title"/> + <TextView + android:id="@+id/silence_summary" + android:paddingTop="@dimen/notification_importance_button_padding" + android:text="@string/notification_channel_summary_default" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clickable="false" + android:focusable="false" + android:ellipsize="end" + android:maxLines="2" + android:layout_below="@id/silence_icon" + android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/> + </RelativeLayout> + </LinearLayout> <RelativeLayout android:id="@+id/bottom_buttons" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingTop="@dimen/notification_guts_button_spacing" > + android:layout_marginTop="@dimen/notification_guts_button_spacing" > <TextView android:id="@+id/turn_off_notifications" android:text="@string/inline_turn_off_notifications" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentStart="true" - android:layout_centerVertical="true" android:minWidth="@dimen/notification_importance_toggle_size" android:minHeight="@dimen/notification_importance_toggle_size" android:maxWidth="200dp" @@ -286,11 +326,11 @@ asked for it --> android:text="@string/inline_ok_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_centerVertical="true" + android:layout_alignParentEnd="true" + android:gravity="center_vertical|end" android:maxWidth="125dp" android:minWidth="@dimen/notification_importance_toggle_size" android:minHeight="@dimen/notification_importance_toggle_size" - android:layout_alignParentEnd="true" style="@style/TextAppearance.NotificationInfo.Button"/> </RelativeLayout> diff --git a/packages/SystemUI/res/layout/qs_carrier.xml b/packages/SystemUI/res/layout/qs_carrier.xml index 8f748069aa40..8dd06f040d09 100644 --- a/packages/SystemUI/res/layout/qs_carrier.xml +++ b/packages/SystemUI/res/layout/qs_carrier.xml @@ -42,6 +42,7 @@ android:layout_weight="1" android:textAppearance="@style/TextAppearance.QS.Status" android:textDirection="locale" + android:marqueeRepeatLimit="marquee_forever" android:singleLine="true" android:maxEms="7"/> diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml index 7f69cf4d239c..5b7e7e7d59a3 100644 --- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml +++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml @@ -19,8 +19,8 @@ android:id="@+id/quick_qs_status_icons" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/qs_header_top_margin" - android:layout_marginBottom="14dp" + android:paddingTop="@dimen/qs_header_top_padding" + android:paddingBottom="@dimen/qs_header_bottom_padding" android:paddingStart="@dimen/status_bar_padding_start" android:paddingEnd="@dimen/status_bar_padding_end" android:layout_below="@id/quick_status_bar_system_icons" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 955cfb022125..ce958ab3f739 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -212,7 +212,7 @@ <dimen name="notification_guts_option_horizontal_padding">15dp</dimen> <!-- The vertical space between items in the alert selections in the inline settings --> - <dimen name="notification_guts_option_vertical_padding">24dp</dimen> + <dimen name="notification_guts_option_vertical_padding">20dp</dimen> <!-- The vertical space between the alert selections in the inline settings --> <dimen name="notification_guts_option_vertical_margin">6dp</dimen> @@ -226,10 +226,12 @@ <dimen name="notification_importance_button_horiz_padding">28dp</dimen> <dimen name="notification_importance_drawable_padding">8dp</dimen> <dimen name="notification_importance_description_padding">20dp</dimen> - <dimen name="notification_importance_description_text">12sp</dimen> + <dimen name="notification_importance_header_text">12sp</dimen> + <dimen name="notification_importance_description_text">14sp</dimen> <dimen name="notification_importance_channel_text">16sp</dimen> <dimen name="notification_importance_channel_group_text">14sp</dimen> <dimen name="notification_importance_button_text">16sp</dimen> + <dimen name="notification_importance_button_padding">14dp</dimen> <dimen name="rect_button_radius">8dp</dimen> <!-- The minimum height for the snackbar shown after the snooze option has been chosen. --> @@ -492,7 +494,8 @@ <dimen name="qs_footer_padding_end">16dp</dimen> <dimen name="qs_footer_icon_size">16dp</dimen> <dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen> - <dimen name="qs_header_top_margin">15dp</dimen> + <dimen name="qs_header_top_padding">15dp</dimen> + <dimen name="qs_header_bottom_padding">14dp</dimen> <dimen name="qs_notif_collapsed_space">64dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 60d71260058f..cea336c82327 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1659,19 +1659,19 @@ <string name="notification_alert_title">Prioritized</string> <!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary --> - <string name="notification_channel_summary_low">Always silent. Displays in pull-down shade.</string> + <string name="notification_channel_summary_low">Helps you focus with notifications only in the pull-down shade. Always silent.</string> <!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary --> - <string name="notification_channel_summary_low_status">Always silent. Displays in pull-down shade & status bar.</string> + <string name="notification_channel_summary_low_status">Displays below priority notifications. Always silent.</string> <!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary --> - <string name="notification_channel_summary_low_lock">Always silent. Displays in pull-down shade & on lock screen.</string> + <string name="notification_channel_summary_low_lock">Displays below priority notifications. Always silent.</string> <!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary --> - <string name="notification_channel_summary_low_status_lock">Always silent. Displays in pull-down shade, status bar & on lock screen.</string> + <string name="notification_channel_summary_low_status_lock">Displays below priority notifications. Always silent.</string> <!-- [CHAR LIMIT=150] Notification Importance title: normal importance level summary --> - <string name="notification_channel_summary_default">Makes sound and displays in pull-down shade, status bar & on lock screen.</string> + <string name="notification_channel_summary_default">Gets your attention with sound & a status bar icon. Shows on lock screen.</string> <!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. --> <string name="notification_unblockable_desc">These notifications can\'t be modified.</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index d765f0c157bd..23de2acf14c9 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -473,7 +473,7 @@ </style> <style name="TextAppearance.NotificationImportanceHeader"> - <item name="android:textSize">@dimen/notification_importance_description_text</item> + <item name="android:textSize">@dimen/notification_importance_header_text</item> <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> <item name="android:textColor">@color/notification_guts_header_text_color</item> </style> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java index 1a684a0ffb8f..40d98c1c08e4 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java @@ -295,8 +295,10 @@ public class PluginInstanceManager<T extends Plugin> { info.serviceInfo.name); PluginInfo<T> t = handleLoadPlugin(name); if (t == null) continue; - mMainHandler.obtainMessage(mMainHandler.PLUGIN_CONNECTED, t).sendToTarget(); + + // add plugin before sending PLUGIN_CONNECTED message mPlugins.add(t); + mMainHandler.obtainMessage(mMainHandler.PLUGIN_CONNECTED, t).sendToTarget(); } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index 2c5fa60d3516..b826b30f3245 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -38,11 +38,6 @@ interface ISystemUiProxy { void startScreenPinning(int taskId) = 1; /** - * Enables/disables launcher/overview interaction features {@link InteractionType}. - */ - void setInteractionState(int flags) = 4; - - /** * Notifies SystemUI that split screen has been invoked. */ void onSplitScreenInvoked() = 5; diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java deleted file mode 100644 index 8d6f830c6d8e..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.shared.system; - -import android.annotation.IntDef; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -public class NavigationBarCompat extends QuickStepContract { - - @Retention(RetentionPolicy.SOURCE) - @IntDef({HIT_TARGET_NONE, HIT_TARGET_BACK, HIT_TARGET_HOME, HIT_TARGET_OVERVIEW}) - public @interface HitTarget{} - - public static final int HIT_TARGET_NONE = 0; - public static final int HIT_TARGET_BACK = 1; - public static final int HIT_TARGET_HOME = 2; - public static final int HIT_TARGET_OVERVIEW = 3; - public static final int HIT_TARGET_ROTATION = 4; - public static final int HIT_TARGET_DEAD_ZONE = 5; - - @Retention(RetentionPolicy.SOURCE) - @IntDef({FLAG_DISABLE_SWIPE_UP, - FLAG_DISABLE_QUICK_SCRUB, - FLAG_SHOW_OVERVIEW_BUTTON - }) - public @interface InteractionType {} - - /** - * Interaction type: whether the gesture to swipe up from the navigation bar will trigger - * launcher to show overview - */ - public static final int FLAG_DISABLE_SWIPE_UP = 0x1; - /** - * Interaction type: enable quick scrub interaction on the home button - */ - public static final int FLAG_DISABLE_QUICK_SCRUB = 0x2; - - /** - * Interaction type: show/hide the overview button while this service is connected to launcher - */ - public static final int FLAG_SHOW_OVERVIEW_BUTTON = 0x4; - - -} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java index 0a6885c0ae69..037a8d3146d2 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java @@ -59,14 +59,22 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp private ColorStateList mDefaultColorState; private CharSequence mMessage; private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR); + private boolean mBouncerVisible; private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { public void onFinishedGoingToSleep(int why) { setSelected(false); - }; + } + public void onStartedWakingUp() { setSelected(true); - }; + } + + @Override + public void onKeyguardBouncerChanged(boolean bouncer) { + mBouncerVisible = bouncer; + update(); + } }; public KeyguardMessageArea(Context context) { @@ -188,7 +196,7 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp private void update() { CharSequence status = mMessage; - setVisibility(TextUtils.isEmpty(status) ? INVISIBLE : VISIBLE); + setVisibility(TextUtils.isEmpty(status) || !mBouncerVisible ? INVISIBLE : VISIBLE); setText(status); ColorStateList colorState = mDefaultColorState; if (mNextMessageColorState.getDefaultColor() != DEFAULT_COLOR) { diff --git a/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java index 123e1380db0a..eec1d701cb5c 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java @@ -189,6 +189,7 @@ public class AnalogClockController implements ClockPlugin { @Override public void setDarkAmount(float darkAmount) { mClockPosition.setDarkAmount(darkAmount); + mBigClockView.setDarkAmount(darkAmount); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java index 8db61b827f3c..5fec61b419fc 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java @@ -181,6 +181,7 @@ public class BubbleClockController implements ClockPlugin { @Override public void setDarkAmount(float darkAmount) { mClockPosition.setDarkAmount(darkAmount); + mView.setDarkAmount(darkAmount); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java index 962b8f832fb7..19083459a87c 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java @@ -20,6 +20,7 @@ import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; import android.content.Context; import android.content.res.Resources; import android.util.AttributeSet; +import android.util.MathUtils; import android.view.View; import android.widget.FrameLayout; @@ -43,6 +44,8 @@ public class ClockLayout extends FrameLayout { private int mBurnInPreventionOffsetX; private int mBurnInPreventionOffsetY; + private float mDarkAmount; + public ClockLayout(Context context) { this(context, null); } @@ -78,11 +81,21 @@ public class ClockLayout extends FrameLayout { positionChildren(); } + /** + * See {@link com.android.systemui.plugins.ClockPlugin#setDarkAmount(float)}. + */ + void setDarkAmount(float darkAmount) { + mDarkAmount = darkAmount; + positionChildren(); + } + private void positionChildren() { - final float offsetX = getBurnInOffset(mBurnInPreventionOffsetX * 2, true) - - mBurnInPreventionOffsetX; - final float offsetY = getBurnInOffset(mBurnInPreventionOffsetY * 2, false) - - mBurnInPreventionOffsetY; + final float offsetX = MathUtils.lerp(0f, + getBurnInOffset(mBurnInPreventionOffsetX * 2, true) - mBurnInPreventionOffsetX, + mDarkAmount); + final float offsetY = MathUtils.lerp(0f, + getBurnInOffset(mBurnInPreventionOffsetY * 2, false) - mBurnInPreventionOffsetY, + mDarkAmount); // Put the analog clock in the middle of the screen. if (mAnalogClock != null) { diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java index 04f887bb6b2f..41a7bc43eaa0 100644 --- a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java @@ -16,6 +16,7 @@ package com.android.systemui; import android.app.PendingIntent; import android.content.Intent; +import android.view.View; import com.android.systemui.plugins.ActivityStarter; @@ -53,6 +54,16 @@ public class ActivityStarterDelegate implements ActivityStarter { } @Override + public void startPendingIntentDismissingKeyguard(PendingIntent intent, + Runnable intentSentCallback, View associatedView) { + if (mActualStarter == null) { + return; + } + mActualStarter.startPendingIntentDismissingKeyguard(intent, intentSentCallback, + associatedView); + } + + @Override public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade, int flags) { if (mActualStarter == null) { diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 1feb63d884fd..4b6306ad8fc0 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -35,6 +35,7 @@ import com.android.systemui.appops.AppOpsController; import com.android.systemui.assist.AssistManager; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.dock.DockManager; import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; @@ -296,6 +297,7 @@ public class Dependency extends SystemUI { @Inject Lazy<PackageManagerWrapper> mPackageManagerWrapper; @Inject Lazy<SensorPrivacyController> mSensorPrivacyController; @Inject Lazy<DumpController> mDumpController; + @Inject Lazy<DockManager> mDockManager; @Inject public Dependency() { @@ -470,6 +472,7 @@ public class Dependency extends SystemUI { mProviders.put(PackageManagerWrapper.class, mPackageManagerWrapper::get); mProviders.put(SensorPrivacyController.class, mSensorPrivacyController::get); mProviders.put(DumpController.class, mDumpController::get); + mProviders.put(DockManager.class, mDockManager::get); // TODO(b/118592525): to support multi-display , we start to add something which is // per-display, while others may be global. I think it's time to add diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index 27975707bd8d..10ae3434daaa 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -57,7 +57,6 @@ public final class Prefs { Key.SEEN_RINGER_GUIDANCE_COUNT, Key.QS_HAS_TURNED_OFF_MOBILE_DATA, Key.TOUCHED_RINGER_TOGGLE, - Key.QUICK_STEP_INTERACTION_FLAGS, Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP }) public @interface Key { @@ -103,7 +102,6 @@ public final class Prefs { String QS_TILE_SPECS_REVEALED = "QsTileSpecsRevealed"; String QS_HAS_TURNED_OFF_MOBILE_DATA = "QsHasTurnedOffMobileData"; String TOUCHED_RINGER_TOGGLE = "TouchedRingerToggle"; - String QUICK_STEP_INTERACTION_FLAGS = "QuickStepInteractionFlags"; String HAS_SEEN_ODI_CAPTIONS_TOOLTIP = "HasSeenODICaptionsTooltip"; } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index ffb5e810fb29..f9926f3550ec 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -34,6 +34,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.assist.AssistManager; import com.android.systemui.classifier.FalsingManager; +import com.android.systemui.dock.DockManager; import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -179,6 +180,13 @@ public class SystemUIFactory { @Singleton @Provides + @Nullable + public DockManager provideDockManager(Context context) { + return null; + } + + @Singleton + @Provides public NotificationEntryManager provideNotificationEntryManager(Context context) { return new NotificationEntryManager(context); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java index 060765495f48..5196ec639453 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java @@ -27,7 +27,6 @@ import android.os.Handler; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.SysUiServiceProvider; import com.android.systemui.SystemUIApplication; import com.android.systemui.classifier.FalsingManager; import com.android.systemui.dock.DockManager; @@ -46,7 +45,7 @@ public class DozeFactory { Context context = dozeService; SensorManager sensorManager = Dependency.get(AsyncSensorManager.class); AlarmManager alarmManager = context.getSystemService(AlarmManager.class); - DockManager dockManager = SysUiServiceProvider.getComponent(context, DockManager.class); + DockManager dockManager = Dependency.get(DockManager.class); DozeHost host = getHost(dozeService); AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(context); diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java index 89ecc6abd623..d50f294e4999 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java @@ -43,7 +43,7 @@ import com.android.systemui.util.NotificationChannels; */ public class PipNotification { private static final String TAG = "PipNotification"; - private static final String NOTIFICATION_TAG = PipNotification.class.getName(); + private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName(); private static final boolean DEBUG = PipManager.DEBUG; private static final String ACTION_MENU = "PipNotification.menu"; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 6adce8347da1..9431f20ba764 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -38,6 +38,7 @@ import android.provider.Settings; import android.service.notification.ZenModeConfig; import android.text.format.DateUtils; import android.util.AttributeSet; +import android.util.Log; import android.util.Pair; import android.util.StatsLog; import android.view.ContextThemeWrapper; @@ -524,11 +525,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements mActivityStarter.postStartActivityDismissingKeyguard(new Intent( AlarmClock.ACTION_SHOW_ALARMS), 0); } else if (v == mNextAlarmContainer) { - if (mNextAlarm.getShowIntent() != null - && mNextAlarm.getShowIntent().getIntent() != null) { + if (mNextAlarm.getShowIntent() != null) { mActivityStarter.postStartActivityDismissingKeyguard( - mNextAlarm.getShowIntent().getIntent(), 0); + mNextAlarm.getShowIntent()); } else { + Log.d(TAG, "No PendingIntent for next alarm. Using default intent"); mActivityStarter.postStartActivityDismissingKeyguard(new Intent( AlarmClock.ACTION_SHOW_ALARMS), 0); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 5ed6a429cc2f..4fb4999b1a5e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -22,9 +22,6 @@ import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_UP; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; -import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP; -import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON; -import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; @@ -61,7 +58,6 @@ import android.view.accessibility.AccessibilityManager; import com.android.internal.policy.ScreenDecorationsUtils; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; -import com.android.systemui.Prefs; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener; import com.android.systemui.shared.recents.IOverviewProxy; @@ -103,10 +99,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis // Max backoff caps at 5 mins private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000; - // Default interaction flags if swipe up is disabled before connecting to launcher - private static final int DEFAULT_DISABLE_SWIPE_UP_STATE = FLAG_DISABLE_SWIPE_UP - | FLAG_SHOW_OVERVIEW_BUTTON; - private final Context mContext; private final Handler mHandler; private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser; @@ -119,7 +111,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private IOverviewProxy mOverviewProxy; private int mConnectionBackoffAttempts; - private @InteractionType int mInteractionFlags; private @SystemUiStateFlags int mSysUiStateFlags; private boolean mBound; private boolean mIsEnabled; @@ -233,27 +224,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } @Override - public void setInteractionState(@InteractionType int flags) { - if (!verifyCaller("setInteractionState")) { - return; - } - long token = Binder.clearCallingIdentity(); - try { - if (mInteractionFlags != flags) { - mInteractionFlags = flags; - mHandler.post(() -> { - for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { - mConnectionCallbacks.get(i).onInteractionFlagsChanged(flags); - } - }); - } - } finally { - Prefs.putInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, mInteractionFlags); - Binder.restoreCallingIdentity(token); - } - } - - @Override public Rect getNonMinimizedSplitScreenSecondaryBounds() { if (!verifyCaller("getNonMinimizedSplitScreenSecondaryBounds")) { return null; @@ -380,12 +350,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis public void onReceive(Context context, Intent intent) { updateEnabledState(); - // When launcher service is disabled, reset interaction flags because it is inactive - if (!isEnabled()) { - mInteractionFlags = getDefaultInteractionFlags(); - Prefs.remove(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS); - } - // Reconnect immediately, instead of waiting for resume to arrive. startConnectionToCurrentUser(); } @@ -479,8 +443,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis com.android.internal.R.string.config_recentsComponentName)); mQuickStepIntent = new Intent(ACTION_QUICKSTEP) .setPackage(mRecentsComponentName.getPackageName()); - mInteractionFlags = Prefs.getInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, - getDefaultInteractionFlags()); mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()); mSupportsRoundedCornersOnWindows = ScreenDecorationsUtils .supportsRoundedCornersOnWindows(mContext.getResources()); @@ -653,7 +615,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis public void addCallback(OverviewProxyListener listener) { mConnectionCallbacks.add(listener); listener.onConnectionChanged(mOverviewProxy != null); - listener.onInteractionFlagsChanged(mInteractionFlags); listener.onBackButtonAlphaChanged(mBackButtonAlpha, false); } @@ -663,7 +624,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } public boolean shouldShowSwipeUpUI() { - return isEnabled() && ((mInteractionFlags & FLAG_DISABLE_SWIPE_UP) == 0); + return isEnabled() && !QuickStepContract.isLegacyMode(mNavBarMode); } public boolean isEnabled() { @@ -674,10 +635,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis return mOverviewProxy; } - public int getInteractionFlags() { - return mInteractionFlags; - } - private void disconnectFromLauncherService() { if (mBound) { // Always unbind the service (ie. if called through onNullBinding or onBindingDied) @@ -693,13 +650,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } - private int getDefaultInteractionFlags() { - // If there is no settings available use device default or get it from settings - return QuickStepContract.isLegacyMode(mNavBarMode) - ? DEFAULT_DISABLE_SWIPE_UP_STATE - : 0; - } - private void notifyBackButtonAlphaChanged(float alpha, boolean animate) { for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { mConnectionCallbacks.get(i).onBackButtonAlphaChanged(alpha, animate); @@ -765,7 +715,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis pw.print(" isCurrentUserSetup="); pw.println(mDeviceProvisionedController .isCurrentUserSetup()); pw.print(" connectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts); - pw.print(" interactionFlags="); pw.println(mInteractionFlags); pw.print(" quickStepIntent="); pw.println(mQuickStepIntent); pw.print(" quickStepIntentResolved="); pw.println(isEnabled()); @@ -775,7 +724,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis public interface OverviewProxyListener { default void onConnectionChanged(boolean isConnected) {} default void onQuickStepStarted() {} - default void onInteractionFlagsChanged(@InteractionType int flags) {} default void onOverviewShown(boolean fromHome) {} default void onQuickScrubStarted() {} default void onBackButtonAlphaChanged(float alpha, boolean animate) {} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index a688f36b47a6..9f8ab61306e5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -175,9 +175,11 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< * @param fullscreenStackBounds The current bounds of the fullscreen stack, in screen * coordinates. * @param dockedStackBounds The current bounds of the docked stack, in screen coordinates. + * @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME. */ default void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, - int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) { + int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, + boolean navbarColorManagedByIme) { } /** @@ -459,7 +461,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< @Override public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, - int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) { + int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, + boolean navbarColorManagedByIme) { synchronized (mLock) { // Don't coalesce these, since it might have one time flags set such as // STATUS_BAR_UNHIDE which might get lost. @@ -469,6 +472,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< args.argi3 = fullscreenStackVis; args.argi4 = dockedStackVis; args.argi5 = mask; + args.argi6 = navbarColorManagedByIme ? 1 : 0; args.arg1 = fullscreenStackBounds; args.arg2 = dockedStackBounds; mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, args).sendToTarget(); @@ -879,7 +883,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< args = (SomeArgs) msg.obj; for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).setSystemUiVisibility(args.argi1, args.argi2, args.argi3, - args.argi4, args.argi5, (Rect) args.arg1, (Rect) args.arg2); + args.argi4, args.argi5, (Rect) args.arg1, (Rect) args.arg2, + args.argi6 == 1); } args.recycle(); break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java index 85848cafbfcb..bd25209d5c0f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java @@ -53,7 +53,7 @@ import javax.inject.Singleton; @Singleton public class NavigationBarController implements Callbacks { - private static final String TAG = NavigationBarController.class.getName(); + private static final String TAG = NavigationBarController.class.getSimpleName(); private final Context mContext; private final Handler mHandler; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index fa223670208b..1615e657d498 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -39,6 +39,7 @@ import android.os.Handler; import android.os.Trace; import android.os.UserHandle; import android.provider.DeviceConfig; +import android.provider.DeviceConfig.Properties; import android.util.Log; import android.view.View; import android.widget.ImageView; @@ -118,15 +119,18 @@ public class NotificationMediaManager implements Dumpable { private ImageView mBackdropBack; private boolean mShowCompactMediaSeekbar; - private final DeviceConfig.OnPropertyChangedListener mPropertyChangedListener = - new DeviceConfig.OnPropertyChangedListener() { + private final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener = + new DeviceConfig.OnPropertiesChangedListener() { @Override - public void onPropertyChanged(String namespace, String name, String value) { - if (SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED.equals(name)) { - if (DEBUG_MEDIA) { - Log.v(TAG, "DEBUG_MEDIA: compact media seekbar flag updated: " + value); + public void onPropertiesChanged(Properties properties) { + for (String name : properties.getKeyset()) { + if (SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED.equals(name)) { + String value = properties.getString(name, null); + if (DEBUG_MEDIA) { + Log.v(TAG, "DEBUG_MEDIA: compact media seekbar flag updated: " + value); + } + mShowCompactMediaSeekbar = "true".equals(value); } - mShowCompactMediaSeekbar = "true".equals(value); } } }; @@ -189,9 +193,9 @@ public class NotificationMediaManager implements Dumpable { DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED)); - DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mContext.getMainExecutor(), - mPropertyChangedListener); + mPropertiesChangedListener); } public void setUpWithPresenter(NotificationPresenter presenter) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java index 333239e77d1b..0d9f4e7b909d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java @@ -30,6 +30,7 @@ import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.SyncRtSurfaceTransactionApplier; import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams; +import android.view.View; import com.android.internal.policy.ScreenDecorationsUtils; import com.android.systemui.Interpolators; @@ -79,11 +80,12 @@ public class ActivityLaunchAnimator { } public RemoteAnimationAdapter getLaunchAnimation( - ExpandableNotificationRow sourceNotification, boolean occluded) { - if (!mCallback.areLaunchAnimationsEnabled() || occluded) { + View sourceView, boolean occluded) { + if (!(sourceView instanceof ExpandableNotificationRow) || !mCallback.areLaunchAnimationsEnabled() || occluded) { return null; } - AnimationRunner animationRunner = new AnimationRunner(sourceNotification); + AnimationRunner animationRunner = new AnimationRunner( + (ExpandableNotificationRow) sourceView); return new RemoteAnimationAdapter(animationRunner, ANIMATION_DURATION, ANIMATION_DURATION - 150 /* statusBarTransitionDelay */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index 1f8ca37315bf..d49f1685e34a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -40,8 +40,11 @@ import android.graphics.drawable.Drawable; import android.metrics.LogMaker; import android.os.Handler; import android.os.RemoteException; +import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.text.TextUtils; +import android.transition.AutoTransition; +import android.transition.TransitionManager; import android.util.AttributeSet; import android.util.Log; import android.view.View; @@ -88,6 +91,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G // standard controls private static final int ACTION_ALERT = 5; + private static final int BUTTON_ANIM_TIME_MS = 200; + private INotificationManager mINotificationManager; private PackageManager mPm; private MetricsLogger mMetricsLogger; @@ -102,6 +107,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private boolean mWasShownHighPriority; private boolean mShowOnLockscreen; private boolean mShowInStatusBar; + private boolean mPressedApply; + /** * The last importance level chosen by the user. Null if the user has not chosen an importance * level; non-null once the user takes an action which indicates an explicit preference. @@ -132,7 +139,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private OnClickListener mOnAlert = v -> { mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING; mChosenImportance = IMPORTANCE_DEFAULT; - setImportanceSummary(ACTION_ALERT); + setImportanceSummary(ACTION_ALERT, true); updateButtons(ACTION_ALERT); }; @@ -140,12 +147,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private OnClickListener mOnSilent = v -> { mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY; mChosenImportance = IMPORTANCE_LOW; - setImportanceSummary(ACTION_TOGGLE_SILENT); + setImportanceSummary(ACTION_TOGGLE_SILENT, true); updateButtons(ACTION_TOGGLE_SILENT); }; // used by standard ui private OnClickListener mOnDismissSettings = v -> { + mPressedApply = true; closeControls(v); }; @@ -294,7 +302,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G mShowInStatusBar = !mINotificationManager.shouldHideSilentStatusIcons( mContext.getPackageName()); - // TODO: b/128445911 use show on lockscreen setting + mShowOnLockscreen = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0) == 1; bindHeader(); bindChannelDetails(); @@ -334,6 +343,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE); findViewById(R.id.interruptiveness_settings).setVisibility(GONE); ((TextView) findViewById(R.id.done)).setText(R.string.inline_done_button); + findViewById(R.id.turn_off_notifications).setVisibility(GONE); } else if (mNumUniqueChannelsInRow > 1) { findViewById(R.id.non_configurable_text).setVisibility(GONE); findViewById(R.id.interruptiveness_settings).setVisibility(GONE); @@ -360,10 +370,10 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G if (mWasShownHighPriority) { updateButtons(ACTION_ALERT); - setImportanceSummary(ACTION_ALERT); + setImportanceSummary(ACTION_ALERT, false); } else { updateButtons(ACTION_TOGGLE_SILENT); - setImportanceSummary(ACTION_TOGGLE_SILENT); + setImportanceSummary(ACTION_TOGGLE_SILENT, false); } } @@ -484,14 +494,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } - private boolean hasImportanceChanged() { - return mSingleNotificationChannel != null - && mChosenImportance != null - && (mStartingChannelImportance == IMPORTANCE_UNSPECIFIED - || (mWasShownHighPriority && mChosenImportance < IMPORTANCE_DEFAULT) - || (!mWasShownHighPriority && mChosenImportance >= IMPORTANCE_DEFAULT)); - } - private void saveImportance() { if (!mIsNonblockable || mExitReason != NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS) { @@ -526,8 +528,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } private void updateButtons(int blockState) { - TextView silence = findViewById(R.id.silence); - TextView alert = findViewById(R.id.alert); + View silence = findViewById(R.id.silence); + View alert = findViewById(R.id.alert); TextView done = findViewById(R.id.done); switch (blockState) { case ACTION_TOGGLE_SILENT: @@ -549,22 +551,28 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } - private void updateButtons(TextView selected, TextView unselected) { + private void updateButtons(View selected, View unselected) { selected.setBackground(mSelectedBackground); selected.setSelected(true); - selected.setTextAppearance( - R.style.TextAppearance_NotificationImportanceButton_Selected); unselected.setBackground(mUnselectedBackground); unselected.setSelected(false); - unselected.setTextAppearance( - R.style.TextAppearance_NotificationImportanceButton_Unselected); } - void setImportanceSummary(int blockState) { - TextView view = findViewById(R.id.description); + void setImportanceSummary(int blockState, boolean userTriggered) { + if (userTriggered) { + AutoTransition transition = new AutoTransition(); + transition.setDuration(BUTTON_ANIM_TIME_MS); + TransitionManager.beginDelayedTransition(this, transition); + } if (blockState == ACTION_ALERT) { + TextView view = findViewById(R.id.alert_summary); + view.setVisibility(VISIBLE); + findViewById(R.id.silence_summary).setVisibility(GONE); view.setText(R.string.notification_channel_summary_default); } else { + TextView view = findViewById(R.id.silence_summary); + view.setVisibility(VISIBLE); + findViewById(R.id.alert_summary).setVisibility(GONE); if (mShowInStatusBar) { if (mShowOnLockscreen) { view.setText(R.string.notification_channel_summary_low_status_lock); @@ -742,12 +750,12 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G @Override public boolean willBeRemoved() { - return hasImportanceChanged(); + return false; } @Override public boolean shouldBeSaved() { - return hasImportanceChanged(); + return mPressedApply; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java index ef7d20c11c56..73f7732fe4ab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java @@ -42,7 +42,6 @@ import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.AlphaOptimizedImageView; -import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; @@ -80,7 +79,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl private OnMenuEventListener mMenuListener; private boolean mDismissRtl; private boolean mIsForeground; - private final boolean mIsUsingNewInterruptionModel; + private final boolean mIsUsingBidirectionalSwipe; private ValueAnimator mFadeAnimator; private boolean mAnimating; @@ -113,12 +112,19 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl private boolean mIsUserTouching; public NotificationMenuRow(Context context) { + //TODO: (b/131242807) not using bidirectional swipe for now + this(context, false); + } + + // Only needed for testing until we want to turn bidirectional swipe back on + @VisibleForTesting + NotificationMenuRow(Context context, boolean isUsingBidirectionalSwipe) { mContext = context; mShouldShowMenu = context.getResources().getBoolean(R.bool.config_showNotificationGear); mHandler = new Handler(Looper.getMainLooper()); mLeftMenuItems = new ArrayList<>(); mRightMenuItems = new ArrayList<>(); - mIsUsingNewInterruptionModel = NotificationUtils.useNewInterruptionModel(mContext); + mIsUsingBidirectionalSwipe = isUsingBidirectionalSwipe; } @Override @@ -255,13 +261,13 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl mSnoozeItem = createSnoozeItem(mContext); } mAppOpsItem = createAppOpsItem(mContext); - if (mIsUsingNewInterruptionModel) { + if (mIsUsingBidirectionalSwipe) { mInfoItem = createInfoItem(mContext, !mParent.getEntry().isHighPriority()); } else { mInfoItem = createInfoItem(mContext); } - if (!mIsUsingNewInterruptionModel) { + if (!mIsUsingBidirectionalSwipe) { if (!isForeground) { mRightMenuItems.add(mSnoozeItem); } @@ -618,12 +624,12 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl @Override public boolean shouldShowGutsOnSnapOpen() { - return mIsUsingNewInterruptionModel; + return mIsUsingBidirectionalSwipe; } @Override public MenuItem menuItemToExposeOnSnap() { - return mIsUsingNewInterruptionModel ? mInfoItem : null; + return mIsUsingBidirectionalSwipe ? mInfoItem : null; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index ebda5852faea..7a9da6bf9ab7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -6355,13 +6355,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) { - boolean isValidDirection; - if (NotificationUtils.useNewInterruptionModel(mContext)) { - isValidDirection = mDismissRtl ? !isRightOrDown : isRightOrDown; - } else { - isValidDirection = true; - } - return isValidDirection && canChildBeDismissed(v); + //TODO: b/131242807 for why this doesn't do anything with direction + return canChildBeDismissed(v); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java index fdf8ccee3f62..5912cd7b6433 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java @@ -95,7 +95,8 @@ public class AutoHideController implements CommandQueue.Callbacks { @Override public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, - int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) { + int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, + boolean navbarColorManagedByIme) { if (displayId != mDisplayId) { return; } @@ -119,7 +120,7 @@ public class AutoHideController implements CommandQueue.Callbacks { if (mSystemUiVisibility != newVal) { mCommandQueue.setSystemUiVisibility(mDisplayId, mSystemUiVisibility, fullscreenStackVis, dockedStackVis, mask, fullscreenStackBounds, - dockedStackBounds); + dockedStackBounds, navbarColorManagedByIme); } notifySystemUiVisibilityChanged(mSystemUiVisibility); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java index b590ca7f4df0..b0b656a1a951 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java @@ -79,6 +79,9 @@ public class LightBarController implements BatteryController.BatteryStateChangeC private final Rect mLastDockedBounds = new Rect(); private boolean mQsCustomizing; + private boolean mDirectReplying; + private boolean mNavbarColorManagedByIme; + @Inject public LightBarController(Context ctx, DarkIconDispatcher darkIconDispatcher, BatteryController batteryController) { @@ -100,7 +103,7 @@ public class LightBarController implements BatteryController.BatteryStateChangeC public void onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, boolean sbModeChanged, - int statusBarMode) { + int statusBarMode, boolean navbarColorManagedByIme) { int oldFullscreen = mFullscreenStackVisibility; int newFullscreen = (oldFullscreen & ~mask) | (fullscreenStackVis & mask); int diffFullscreen = newFullscreen ^ oldFullscreen; @@ -122,12 +125,13 @@ public class LightBarController implements BatteryController.BatteryStateChangeC mFullscreenStackVisibility = newFullscreen; mDockedStackVisibility = newDocked; mLastStatusBarMode = statusBarMode; + mNavbarColorManagedByIme = navbarColorManagedByIme; mLastFullscreenBounds.set(fullscreenStackBounds); mLastDockedBounds.set(dockedStackBounds); } public void onNavigationVisibilityChanged(int vis, int mask, boolean nbModeChanged, - int navigationBarMode) { + int navigationBarMode, boolean navbarColorManagedByIme) { int oldVis = mSystemUiVisibility; int newVis = (oldVis & ~mask) | (vis & mask); int diffVis = newVis ^ oldVis; @@ -136,21 +140,24 @@ public class LightBarController implements BatteryController.BatteryStateChangeC boolean last = mNavigationLight; mHasLightNavigationBar = isLight(vis, navigationBarMode, View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR); - mNavigationLight = mHasLightNavigationBar && !mForceDarkForScrim && !mQsCustomizing; + mNavigationLight = mHasLightNavigationBar + && (mDirectReplying && mNavbarColorManagedByIme || !mForceDarkForScrim) + && !mQsCustomizing; if (mNavigationLight != last) { updateNavigation(); } } mSystemUiVisibility = newVis; mLastNavigationBarMode = navigationBarMode; + mNavbarColorManagedByIme = navbarColorManagedByIme; } private void reevaluate() { onSystemUiVisibilityChanged(mFullscreenStackVisibility, mDockedStackVisibility, 0 /* mask */, mLastFullscreenBounds, mLastDockedBounds, - true /* sbModeChange*/, mLastStatusBarMode); + true /* sbModeChange*/, mLastStatusBarMode, mNavbarColorManagedByIme); onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */, true /* nbModeChanged */, - mLastNavigationBarMode); + mLastNavigationBarMode, mNavbarColorManagedByIme); } public void setQsCustomizing(boolean customizing) { @@ -159,6 +166,16 @@ public class LightBarController implements BatteryController.BatteryStateChangeC reevaluate(); } + /** + * Sets whether the direct-reply is in use or not. + * @param directReplying {@code true} when the direct-reply is in-use. + */ + public void setDirectReplying(boolean directReplying) { + if (mDirectReplying == directReplying) return; + mDirectReplying = directReplying; + reevaluate(); + } + public void setScrimState(ScrimState scrimState, float scrimBehindAlpha, GradientColors scrimInFrontColor) { boolean forceDarkForScrimLast = mForceDarkForScrim; @@ -260,7 +277,9 @@ public class LightBarController implements BatteryController.BatteryStateChangeC pw.print(" mLastNavigationBarMode="); pw.println(mLastNavigationBarMode); pw.print(" mForceDarkForScrim="); pw.print(mForceDarkForScrim); - pw.print(" mQsCustomizing="); pw.println(mQsCustomizing); + pw.print(" mQsCustomizing="); pw.print(mQsCustomizing); + pw.print(" mDirectReplying="); pw.println(mDirectReplying); + pw.print(" mNavbarColorManagedByIme="); pw.println(mNavbarColorManagedByIme); pw.println(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java index 586e82c612c8..a831a5d29a79 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java @@ -31,10 +31,13 @@ import android.util.AttributeSet; import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; +import androidx.annotation.Nullable; + import com.android.internal.graphics.ColorUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.R; +import com.android.systemui.dock.DockManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.policy.AccessibilityController; @@ -62,6 +65,7 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange private final UnlockMethodCache mUnlockMethodCache; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final AccessibilityController mAccessibilityController; + private final DockManager mDockManager; private int mLastState = 0; private boolean mTransientBiometricsError; @@ -72,13 +76,26 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange private boolean mPulsing; private boolean mDozing; private boolean mBouncerVisible; + private boolean mDocked; private boolean mLastDozing; private boolean mLastPulsing; private boolean mLastBouncerVisible; private int mIconColor; + private float mDozeAmount; private final Runnable mDrawOffTimeout = () -> update(true /* forceUpdate */); - private float mDozeAmount; + private final DockManager.DockEventListener mDockEventListener = + new DockManager.DockEventListener() { + @Override + public void onEvent(int event) { + boolean docked = event == DockManager.STATE_DOCKED + || event == DockManager.STATE_DOCKED_HIDE; + if (docked != mDocked) { + mDocked = docked; + update(true /* force */); + } + } + }; private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { @@ -115,7 +132,8 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange public LockIcon(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, StatusBarStateController statusBarStateController, ConfigurationController configurationController, - AccessibilityController accessibilityController) { + AccessibilityController accessibilityController, + @Nullable DockManager dockManager) { super(context, attrs); mContext = context; mUnlockMethodCache = UnlockMethodCache.getInstance(context); @@ -123,6 +141,7 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange mAccessibilityController = accessibilityController; mConfigurationController = configurationController; mStatusBarStateController = statusBarStateController; + mDockManager = dockManager; } @Override @@ -132,6 +151,9 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange mConfigurationController.addCallback(this); mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback); mUnlockMethodCache.addListener(this); + if (mDockManager != null) { + mDockManager.addListener(mDockEventListener); + } onThemeChanged(); } @@ -142,6 +164,9 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange mConfigurationController.removeCallback(this); mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback); mUnlockMethodCache.removeListener(this); + if (mDockManager != null) { + mDockManager.removeListener(mDockEventListener); + } } @Override @@ -237,7 +262,8 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange mLastBouncerVisible = mBouncerVisible; } - setVisibility(mDozing && !mPulsing ? INVISIBLE : VISIBLE); + boolean invisible = mDozing && (!mPulsing || mDocked); + setVisibility(invisible ? INVISIBLE : VISIBLE); updateClickability(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index de57066d80ba..d43f06da618e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -24,7 +24,6 @@ import static android.app.StatusBarManager.windowStateToString; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener; -import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN; @@ -197,12 +196,6 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } @Override - public void onInteractionFlagsChanged(@InteractionType int flags) { - mNavigationBarView.updateStates(); - updateScreenPinningGestures(); - } - - @Override public void startAssistant(Bundle bundle) { mAssistManager.startAssist(bundle); } @@ -512,12 +505,13 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mAutoHideController.touchAutoHide(); mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */, - true /* nbModeChanged */, mNavigationBarMode); + true /* nbModeChanged */, mNavigationBarMode, false /* navbarColorManagedByIme */); } @Override public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, - int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) { + int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, + boolean navbarColorManagedByIme) { if (displayId != mDisplayId) { return; } @@ -545,7 +539,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } } mLightBarController.onNavigationVisibilityChanged( - vis, mask, nbModeChanged, mNavigationBarMode); + vis, mask, nbModeChanged, mNavigationBarMode, navbarColorManagedByIme); } private @TransitionMode int computeBarMode(int oldVis, int newVis) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 4333200e702a..22636deccb33 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.phone; import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; -import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE; @@ -637,10 +636,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav // as they are used for exiting. final boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive(); if (mOverviewProxyService.isEnabled()) { - // Use interaction flags to show/hide navigation buttons but will be shown if required - // to exit screen pinning. - final int flags = mOverviewProxyService.getInteractionFlags(); - disableRecent |= (flags & FLAG_SHOW_OVERVIEW_BUTTON) == 0; if (pinningActive) { disableBack = disableHome = false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java index a00feeb6c116..fa2263fb97ad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java @@ -17,8 +17,10 @@ package com.android.systemui.statusbar.phone; import static android.content.Intent.ACTION_OVERLAY_CHANGED; -import static android.content.Intent.ACTION_USER_SWITCHED; +import static android.os.UserHandle.USER_CURRENT; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; +import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY; +import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY; import android.content.BroadcastReceiver; import android.content.Context; @@ -28,16 +30,21 @@ import android.content.om.IOverlayManager; import android.content.pm.PackageManager; import android.content.res.ApkAssets; import android.os.PatternMatcher; +import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.util.Log; +import android.util.SparseBooleanArray; import com.android.systemui.Dumpable; +import com.android.systemui.UiOffloadThread; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import javax.inject.Inject; import javax.inject.Singleton; @@ -48,7 +55,7 @@ import javax.inject.Singleton; @Singleton public class NavigationModeController implements Dumpable { - private static final String TAG = NavigationModeController.class.getName(); + private static final String TAG = NavigationModeController.class.getSimpleName(); private static final boolean DEBUG = true; public interface ModeChangedListener { @@ -57,6 +64,10 @@ public class NavigationModeController implements Dumpable { private final Context mContext; private final IOverlayManager mOverlayManager; + private final DeviceProvisionedController mDeviceProvisionedController; + private final UiOffloadThread mUiOffloadThread; + + private SparseBooleanArray mRestoreGesturalNavBarMode = new SparseBooleanArray(); private int mMode = NAV_BAR_MODE_3BUTTON; private ArrayList<ModeChangedListener> mListeners = new ArrayList<>(); @@ -64,36 +75,90 @@ public class NavigationModeController implements Dumpable { private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - context = getCurrentUserContext(); - int mode = getCurrentInteractionMode(context); - mMode = mode; - if (DEBUG) { - Log.e(TAG, "ACTION_OVERLAY_CHANGED: mode=" + mMode - + " contextUser=" + context.getUserId()); - dumpAssetPaths(context); - } - - for (int i = 0; i < mListeners.size(); i++) { - mListeners.get(i).onNavigationModeChanged(mode); + if (intent.getAction().equals(ACTION_OVERLAY_CHANGED)) { + if (DEBUG) { + Log.d(TAG, "ACTION_OVERLAY_CHANGED"); + } + updateCurrentInteractionMode(true /* notify */); } } }; + private final DeviceProvisionedController.DeviceProvisionedListener mDeviceProvisionedCallback = + new DeviceProvisionedController.DeviceProvisionedListener() { + @Override + public void onDeviceProvisionedChanged() { + if (DEBUG) { + Log.d(TAG, "onDeviceProvisionedChanged: " + + mDeviceProvisionedController.isDeviceProvisioned()); + } + // Once the device has been provisioned, check if we can restore gestural nav + restoreGesturalNavOverlayIfNecessary(); + } + + @Override + public void onUserSetupChanged() { + if (DEBUG) { + Log.d(TAG, "onUserSetupChanged: " + + mDeviceProvisionedController.isCurrentUserSetup()); + } + // Once the user has been setup, check if we can restore gestural nav + restoreGesturalNavOverlayIfNecessary(); + } + + @Override + public void onUserSwitched() { + if (DEBUG) { + Log.d(TAG, "onUserSwitched: " + + ActivityManagerWrapper.getInstance().getCurrentUserId()); + } + + // Update the nav mode for the current user + updateCurrentInteractionMode(true /* notify */); + + // When switching users, defer enabling the gestural nav overlay until the user + // is all set up + deferGesturalNavOverlayIfNecessary(); + } + }; + @Inject - public NavigationModeController(Context context) { + public NavigationModeController(Context context, + DeviceProvisionedController deviceProvisionedController, + UiOffloadThread uiOffloadThread) { mContext = context; mOverlayManager = IOverlayManager.Stub.asInterface( ServiceManager.getService(Context.OVERLAY_SERVICE)); + mUiOffloadThread = uiOffloadThread; + mDeviceProvisionedController = deviceProvisionedController; + mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback); IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED); overlayFilter.addDataScheme("package"); overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL); mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, overlayFilter, null, null); - IntentFilter userFilter = new IntentFilter(ACTION_USER_SWITCHED); - mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, userFilter, null, null); + updateCurrentInteractionMode(false /* notify */); - mMode = getCurrentInteractionMode(getCurrentUserContext()); + // Check if we need to defer enabling gestural nav + deferGesturalNavOverlayIfNecessary(); + } + + public void updateCurrentInteractionMode(boolean notify) { + Context context = getCurrentUserContext(); + int mode = getCurrentInteractionMode(context); + mMode = mode; + if (DEBUG) { + Log.e(TAG, "updateCurrentInteractionMode: mode=" + mMode + + " contextUser=" + context.getUserId()); + dumpAssetPaths(context); + } + + if (notify) { + for (int i = 0; i < mListeners.size(); i++) { + mListeners.get(i).onNavigationModeChanged(mode); + } + } } public int addListener(ModeChangedListener listener) { @@ -129,10 +194,77 @@ public class NavigationModeController implements Dumpable { } } + private void deferGesturalNavOverlayIfNecessary() { + final int userId = mDeviceProvisionedController.getCurrentUser(); + mRestoreGesturalNavBarMode.put(userId, false); + if (mDeviceProvisionedController.isDeviceProvisioned() + && mDeviceProvisionedController.isCurrentUserSetup()) { + // User is already setup and device is provisioned, nothing to do + if (DEBUG) { + Log.d(TAG, "deferGesturalNavOverlayIfNecessary: device is provisioned and user is " + + "setup"); + } + return; + } + + ArrayList<String> defaultOverlays = new ArrayList<>(); + try { + defaultOverlays.addAll(Arrays.asList(mOverlayManager.getDefaultOverlayPackages())); + } catch (RemoteException e) { + Log.e(TAG, "deferGesturalNavOverlayIfNecessary: failed to fetch default overlays"); + } + if (!defaultOverlays.contains(NAV_BAR_MODE_GESTURAL_OVERLAY)) { + // No default gesture nav overlay + if (DEBUG) { + Log.d(TAG, "deferGesturalNavOverlayIfNecessary: no default gestural overlay, " + + "default=" + defaultOverlays); + } + return; + } + + // If the default is gestural, force-enable three button mode until the device is + // provisioned + setModeOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY, USER_CURRENT); + mRestoreGesturalNavBarMode.put(userId, true); + if (DEBUG) { + Log.d(TAG, "deferGesturalNavOverlayIfNecessary: setting to 3 button mode"); + } + } + + private void restoreGesturalNavOverlayIfNecessary() { + if (DEBUG) { + Log.d(TAG, "restoreGesturalNavOverlayIfNecessary: needs restore=" + + mRestoreGesturalNavBarMode); + } + final int userId = mDeviceProvisionedController.getCurrentUser(); + if (mRestoreGesturalNavBarMode.get(userId)) { + // Restore the gestural state if necessary + setModeOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY, USER_CURRENT); + mRestoreGesturalNavBarMode.put(userId, false); + } + } + + public void setModeOverlay(String overlayPkg, int userId) { + mUiOffloadThread.submit(() -> { + try { + mOverlayManager.setEnabledExclusiveInCategory(overlayPkg, userId); + } catch (RemoteException e) { + Log.e(TAG, "Failed to enable overlay " + overlayPkg + " for user " + userId); + } + }); + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("NavigationModeController:"); pw.println(" mode=" + mMode); + String defaultOverlays = ""; + try { + defaultOverlays = String.join(", ", mOverlayManager.getDefaultOverlayPackages()); + } catch (RemoteException e) { + defaultOverlays = "failed_to_fetch"; + } + pw.println(" defaultOverlays=" + defaultOverlays); dumpAssetPaths(getCurrentUserContext()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index d5706e36bd21..27368deac847 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -44,6 +44,7 @@ import com.android.systemui.SysUiServiceProvider; import com.android.systemui.UiOffloadThread; import com.android.systemui.privacy.PrivacyItem; import com.android.systemui.privacy.PrivacyItemController; +import com.android.systemui.privacy.PrivacyType; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.RotationLockTile; import com.android.systemui.statusbar.CommandQueue; @@ -229,9 +230,11 @@ public class PhoneStatusBarPolicy mIconController.setIconVisibility(mSlotDataSaver, false); // privacy items - mIconController.setIcon(mSlotMicrophone, R.drawable.stat_sys_mic_none, null); + mIconController.setIcon(mSlotMicrophone, R.drawable.stat_sys_mic_none, + PrivacyType.TYPE_MICROPHONE.getName(mContext)); mIconController.setIconVisibility(mSlotMicrophone, false); - mIconController.setIcon(mSlotCamera, R.drawable.stat_sys_camera, null); + mIconController.setIcon(mSlotCamera, R.drawable.stat_sys_camera, + PrivacyType.TYPE_CAMERA.getName(mContext)); mIconController.setIconVisibility(mSlotCamera, false); mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID, mContext.getString(R.string.accessibility_location_active)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 93db82d8e119..c42882664d05 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -593,6 +593,7 @@ public class StatusBar extends SystemUI implements DemoMode, updateScrimController(); }; private ActivityIntentHelper mActivityIntentHelper; + private ShadeController mShadeController; @Override public void onActiveStateChanged(int code, int uid, String packageName, boolean active) { @@ -710,7 +711,8 @@ public class StatusBar extends SystemUI implements DemoMode, setSystemUiVisibility(mDisplayId, result.mSystemUiVisibility, result.mFullscreenStackSysUiVisibility, result.mDockedStackSysUiVisibility, - 0xffffffff, result.mFullscreenStackBounds, result.mDockedStackBounds); + 0xffffffff, result.mFullscreenStackBounds, result.mDockedStackBounds, + result.mNavbarColorManagedByIme); topAppWindowChanged(mDisplayId, result.mMenuVisible); // StatusBarManagerService has a back up of IME token and it's restored here. setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis, @@ -1062,7 +1064,7 @@ public class StatusBar extends SystemUI implements DemoMode, final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback = (StatusBarRemoteInputCallback) Dependency.get( NotificationRemoteInputManager.Callback.class); - final ShadeController shadeController = Dependency.get(ShadeController.class); + mShadeController = Dependency.get(ShadeController.class); final ActivityStarter activityStarter = Dependency.get(ActivityStarter.class); mNotificationActivityStarter = new StatusBarNotificationActivityStarter(mContext, @@ -1070,7 +1072,7 @@ public class StatusBar extends SystemUI implements DemoMode, mHeadsUpManager, activityStarter, mActivityLaunchAnimator, mBarService, mStatusBarStateController, mKeyguardManager, mDreamManager, mRemoteInputManager, mStatusBarRemoteInputCallback, mGroupManager, - mLockscreenUserManager, shadeController, mKeyguardMonitor, + mLockscreenUserManager, mShadeController, mKeyguardMonitor, mNotificationInterruptionStateProvider, mMetricsLogger, new LockPatternUtils(mContext), Dependency.get(MAIN_HANDLER), Dependency.get(BG_HANDLER), mActivityIntentHelper, mBubbleController); @@ -2077,7 +2079,8 @@ public class StatusBar extends SystemUI implements DemoMode, @Override // CommandQueue public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, - int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) { + int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, + boolean navbarColorManagedByIme) { if (displayId != mDisplayId) { return; } @@ -2114,7 +2117,8 @@ public class StatusBar extends SystemUI implements DemoMode, } } mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis, - mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode); + mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode, + navbarColorManagedByIme); } @Override @@ -2235,11 +2239,12 @@ public class StatusBar extends SystemUI implements DemoMode, Log.v(TAG, "setLightsOn(" + on + ")"); if (on) { setSystemUiVisibility(mDisplayId, 0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE, - mLastFullscreenStackBounds, mLastDockedStackBounds); + mLastFullscreenStackBounds, mLastDockedStackBounds, + false /* navbarColorManagedByIme */); } else { setSystemUiVisibility(mDisplayId, View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds, - mLastDockedStackBounds); + mLastDockedStackBounds, false /* navbarColorManagedByIme */); } } @@ -4344,6 +4349,13 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void startPendingIntentDismissingKeyguard( final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback) { + startPendingIntentDismissingKeyguard(intent, intentSentUiThreadCallback, null /* row */); + } + + @Override + public void startPendingIntentDismissingKeyguard( + final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback, + View associatedView) { final boolean afterKeyguardGone = intent.isActivity() && mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(), mLockscreenUserManager.getCurrentUserId()); @@ -4351,7 +4363,8 @@ public class StatusBar extends SystemUI implements DemoMode, executeActionDismissingKeyguard(() -> { try { intent.send(null, 0, null, null, null, null, getActivityOptions( - null /* animationAdapter */)); + mActivityLaunchAnimator.getLaunchAnimation(associatedView, + mShadeController.isOccluded()))); } catch (PendingIntent.CanceledException e) { // the stack trace isn't very helpful here. // Just log the exception message. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index 9923ec9d8a75..41fa34608ee8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -56,7 +56,7 @@ import com.android.systemui.R; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface; import com.android.systemui.recents.OverviewProxyService; -import com.android.systemui.shared.system.NavigationBarCompat; +import com.android.systemui.shared.system.QuickStepContract; public class KeyButtonView extends ImageView implements ButtonInterface { private static final String TAG = KeyButtonView.class.getSimpleName(); @@ -244,11 +244,11 @@ public class KeyButtonView extends ImageView implements ButtonInterface { y = (int)ev.getRawY(); boolean exceededTouchSlopX = Math.abs(x - mTouchDownX) > (mIsVertical - ? NavigationBarCompat.getQuickScrubTouchSlopPx() - : NavigationBarCompat.getQuickStepTouchSlopPx()); + ? QuickStepContract.getQuickScrubTouchSlopPx() + : QuickStepContract.getQuickStepTouchSlopPx()); boolean exceededTouchSlopY = Math.abs(y - mTouchDownY) > (mIsVertical - ? NavigationBarCompat.getQuickStepTouchSlopPx() - : NavigationBarCompat.getQuickScrubTouchSlopPx()); + ? QuickStepContract.getQuickStepTouchSlopPx() + : QuickStepContract.getQuickScrubTouchSlopPx()); if (exceededTouchSlopX || exceededTouchSlopY) { // When quick step is enabled, prevent animating the ripple triggered by // setPressed and decide to run it on touch up diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 11e5625f8538..c398ad82e0a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -94,8 +94,7 @@ public class MobileSignalController extends SignalController< mPhone = phone; mDefaults = defaults; mSubscriptionInfo = info; - mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId(), - receiverLooper); + mPhoneStateListener = new MobilePhoneStateListener(receiverLooper); mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator); mNetworkNameDefault = getStringIfExists( com.android.internal.R.string.lockscreen_carrier_default); @@ -574,8 +573,8 @@ public class MobileSignalController extends SignalController< } class MobilePhoneStateListener extends PhoneStateListener { - public MobilePhoneStateListener(int subId, Looper looper) { - super(subId, looper); + public MobilePhoneStateListener(Looper looper) { + super(looper); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index faf63c838259..950f07d5cffa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -662,8 +662,9 @@ public class NetworkControllerImpl extends BroadcastReceiver cachedControllers.remove(subId); } else { MobileSignalController controller = new MobileSignalController(mContext, mConfig, - mHasMobileDataFeature, mPhone, mCallbackHandler, - this, subscriptions.get(i), mSubDefaults, mReceiverHandler.getLooper()); + mHasMobileDataFeature, mPhone.createForSubscriptionId(subId), + mCallbackHandler, this, subscriptions.get(i), + mSubDefaults, mReceiverHandler.getLooper()); controller.setUserSetupComplete(mUserSetup); mMobileSignalControllers.put(subId, controller); if (subscriptions.get(i).getSimSlotIndex() == 0) { @@ -1049,7 +1050,8 @@ public class NetworkControllerImpl extends BroadcastReceiver SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0, null, null, null, "", false, null, null); MobileSignalController controller = new MobileSignalController(mContext, - mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info, + mConfig, mHasMobileDataFeature, + mPhone.createForSubscriptionId(info.getSubscriptionId()), mCallbackHandler, this, info, mSubDefaults, mReceiverHandler.getLooper()); mMobileSignalControllers.put(id, controller); controller.getState().userSetup = true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java index c1950a21d10f..43795dc08c91 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java @@ -63,6 +63,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; +import com.android.systemui.statusbar.phone.LightBarController; import java.util.function.Consumer; @@ -516,10 +517,12 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene private final Drawable mBackground; private RemoteInputView mRemoteInputView; boolean mShowImeOnInputConnection; + private LightBarController mLightBarController; public RemoteEditText(Context context, AttributeSet attrs) { super(context, attrs); mBackground = getBackground(); + mLightBarController = Dependency.get(LightBarController.class); } private void defocusIfNeeded(boolean animate) { @@ -558,6 +561,9 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene if (!focused) { defocusIfNeeded(true /* animate */); } + if (!mRemoteInputView.mRemoved) { + mLightBarController.setDirectReplying(focused); + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java index f02b5441a737..655c29cbf687 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java @@ -93,10 +93,10 @@ public final class SmartReplyConstants { } private void registerDeviceConfigListener() { - DeviceConfig.addOnPropertyChangedListener( + DeviceConfig.addOnPropertiesChangedListener( DeviceConfig.NAMESPACE_SYSTEMUI, this::postToHandler, - this::onDeviceConfigPropertyChanged); + (properties) -> onDeviceConfigPropertiesChanged(properties.getNamespace())); } private void postToHandler(Runnable r) { @@ -104,10 +104,10 @@ public final class SmartReplyConstants { } @VisibleForTesting - void onDeviceConfigPropertyChanged(String namespace, String name, String value) { + void onDeviceConfigPropertiesChanged(String namespace) { if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) { Log.e(TAG, "Received update from DeviceConfig for unrelated namespace: " - + namespace + " " + name + "=" + value); + + namespace); return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java index 0f7a0f09b2e1..640f0f0cc3f6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java @@ -349,7 +349,7 @@ public class SmartReplyView extends ViewGroup { smartReplyController.smartActionClicked( entry, actionIndex, action, smartActions.fromAssistant); headsUpManager.removeNotification(entry.key, true); - }); + }, entry.getRow()); if (useDelayedOnClickListener) { onClickListener = new DelayedOnClickListener(onClickListener, smartReplyView.mConstants.getOnClickInitDelay()); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java index 212c8f52a19e..e312990c7f8e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java @@ -189,10 +189,6 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); - // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the - // same answer as KeyguardUpdateMonitor. Remove when this is addressed - when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); - mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = @@ -217,10 +213,6 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); - // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the - // same answer as KeyguardUpdateMonitor. Remove when this is addressed - when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); - mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = @@ -243,11 +235,6 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); - // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the - // same answer as KeyguardUpdateMonitor. Remove when this is addressed - when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn( - new ArrayList<>()); - ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( CarrierTextController.CarrierTextCallbackInfo.class); @@ -271,10 +258,6 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); - // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the - // same answer as KeyguardUpdateMonitor. Remove when this is addressed - when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); - mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = @@ -300,10 +283,6 @@ public class CarrierTextControllerTest extends SysuiTestCase { .thenReturn(IccCardConstants.State.NOT_READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); - // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the - // same answer as KeyguardUpdateMonitor. Remove when this is addressed - when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); - mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = @@ -329,10 +308,6 @@ public class CarrierTextControllerTest extends SysuiTestCase { .thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); - // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the - // same answer as KeyguardUpdateMonitor. Remove when this is addressed - when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); - mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = @@ -361,10 +336,6 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the - // same answer as KeyguardUpdateMonitor. Remove when this is addressed - when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); - ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( CarrierTextController.CarrierTextCallbackInfo.class); @@ -385,12 +356,9 @@ public class CarrierTextControllerTest extends SysuiTestCase { list.add(TEST_SUBSCRIPTION_2); when(mKeyguardUpdateMonitor.getSimState(anyInt())) .thenReturn(IccCardConstants.State.READY); - when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); mCarrierTextController.updateDisplayOpportunisticSubscriptionCarrierText(); - - // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the - // same answer as KeyguardUpdateMonitor. Remove when this is addressed when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index c2f55e2f9b99..2bde5f678c3b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -112,19 +112,19 @@ public class CommandQueueTest extends SysuiTestCase { @Test public void testSetSystemUiVisibility() { Rect r = new Rect(); - mCommandQueue.setSystemUiVisibility(DEFAULT_DISPLAY, 1, 2, 3, 4, null, r); + mCommandQueue.setSystemUiVisibility(DEFAULT_DISPLAY, 1, 2, 3, 4, null, r, false); waitForIdleSync(); verify(mCallbacks).setSystemUiVisibility(eq(DEFAULT_DISPLAY), eq(1), eq(2), eq(3), eq(4), - eq(null), eq(r)); + eq(null), eq(r), eq(false)); } @Test public void testSetSystemUiVisibilityForSecondaryDisplay() { Rect r = new Rect(); - mCommandQueue.setSystemUiVisibility(SECONDARY_DISPLAY, 1, 2, 3, 4, null, r); + mCommandQueue.setSystemUiVisibility(SECONDARY_DISPLAY, 1, 2, 3, 4, null, r, false); waitForIdleSync(); verify(mCallbacks).setSystemUiVisibility(eq(SECONDARY_DISPLAY), eq(1), eq(2), eq(3), eq(4), - eq(null), eq(r)); + eq(null), eq(r), eq(false)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java index 25995eb59d80..7bd25808a9c5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java @@ -891,7 +891,31 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testWillBeRemovedReturnsFalseBeforeBind() throws Exception { + public void testCloseControls_withoutHittingApply() throws Exception { + mNotificationChannel.setImportance(IMPORTANCE_LOW); + mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, + (Runnable saveImportance, StatusBarNotification sbn) -> { + saveImportance.run(); + }, null, null, true, false, IMPORTANCE_LOW, false + ); + + mNotificationInfo.findViewById(R.id.alert).performClick(); + + assertFalse(mNotificationInfo.shouldBeSaved()); + } + + @Test + public void testWillBeRemovedReturnsFalse() throws Exception { + assertFalse(mNotificationInfo.willBeRemoved()); + + mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, + (Runnable saveImportance, StatusBarNotification sbn) -> { + saveImportance.run(); + }, null, null, true, false, IMPORTANCE_LOW, false + ); + assertFalse(mNotificationInfo.willBeRemoved()); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java index c62a802e25e4..43ea92f13c8d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java @@ -112,11 +112,8 @@ public class NotificationMenuRowTest extends LeakCheckedTest { } @Test - public void testNoAppOpsInSlowSwipe_newInterruptionModel() { - Settings.Secure.putInt(mContext.getContentResolver(), - NOTIFICATION_NEW_INTERRUPTION_MODEL, 1); - - NotificationMenuRow row = new NotificationMenuRow(mContext); + public void testNoAppOpsInSlowSwipe_biDirectionalSwipe() { + NotificationMenuRow row = new NotificationMenuRow(mContext, true); row.createMenu(mRow, null); ViewGroup container = (ViewGroup) row.getMenuView(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java index 1b34a7584994..f614354a7691 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java @@ -70,7 +70,7 @@ public class AutoHideControllerTest extends SysuiTestCase { @Test public void testSetSystemUiVisibilityEarlyReturnWithDifferentDisplay() { - mAutoHideController.setSystemUiVisibility(1, 1, 2, 3, 4, null, new Rect()); + mAutoHideController.setSystemUiVisibility(1, 1, 2, 3, 4, null, new Rect(), false); verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt()); } @@ -78,7 +78,8 @@ public class AutoHideControllerTest extends SysuiTestCase { @Test public void testSetSystemUiVisibilityEarlyReturnWithSameVisibility() { mAutoHideController - .setSystemUiVisibility(DEFAULT_DISPLAY, View.VISIBLE, 2, 3, 4, null, new Rect()); + .setSystemUiVisibility( + DEFAULT_DISPLAY, View.VISIBLE, 2, 3, 4, null, new Rect(), false); verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt()); } @@ -92,7 +93,7 @@ public class AutoHideControllerTest extends SysuiTestCase { View.SYSTEM_UI_FLAG_FULLSCREEN | View.STATUS_BAR_UNHIDE; mAutoHideController.setSystemUiVisibility( - DEFAULT_DISPLAY, expectedStatus, 2, 3, FULL_MASK, null, new Rect()); + DEFAULT_DISPLAY, expectedStatus, 2, 3, FULL_MASK, null, new Rect(), false); assertEquals("System UI visibility should not be changed", expectedStatus, mAutoHideController.mSystemUiVisibility); @@ -109,7 +110,7 @@ public class AutoHideControllerTest extends SysuiTestCase { mAutoHideController.setSystemUiVisibility( DEFAULT_DISPLAY, View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE, - 2, 3, FULL_MASK, null, new Rect()); + 2, 3, FULL_MASK, null, new Rect(), false); int expectedStatus = View.VISIBLE; assertEquals(expectedStatus, mAutoHideController.mSystemUiVisibility); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index ce5bfced961b..616b46a6d316 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -130,6 +130,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true); when(mMockCm.getDefaultNetworkCapabilitiesForUser(0)).thenReturn( new NetworkCapabilities[] { mNetCapabilities }); + when(mMockTm.createForSubscriptionId(anyInt())).thenReturn(mMockTm); mSignalStrength = mock(SignalStrength.class); mServiceState = mock(ServiceState.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java index 8bf1606d5b7b..bc468bf2fb82 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java @@ -42,6 +42,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationTestHelper; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.util.Assert; import org.junit.After; @@ -67,6 +68,7 @@ public class RemoteInputViewTest extends SysuiTestCase { @Mock private RemoteInputController mController; @Mock private ShortcutManager mShortcutManager; @Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; + @Mock private LightBarController mLightBarController; private BlockingQueueIntentReceiver mReceiver; private RemoteInputView mView; @@ -77,6 +79,8 @@ public class RemoteInputViewTest extends SysuiTestCase { mDependency.injectTestDependency(RemoteInputQuickSettingsDisabler.class, mRemoteInputQuickSettingsDisabler); + mDependency.injectTestDependency(LightBarController.class, + mLightBarController); mReceiver = new BlockingQueueIntentReceiver(); mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION), null, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java index fb2b7dced7c2..c761a44170c3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java @@ -229,8 +229,7 @@ public class SmartReplyConstantsTest extends SysuiTestCase { } private void triggerConstantsOnChange() { - mConstants.onDeviceConfigPropertyChanged(DeviceConfig.NAMESPACE_SYSTEMUI, - "" /* name */, "" /* value */); + mConstants.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI); } private void resetAllDeviceConfigFlags() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java index 01f3c923832f..8c5fac47885f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java @@ -634,7 +634,8 @@ public class SmartReplyViewTest extends SysuiTestCase { mView.getChildAt(2).performClick(); - verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any()); + verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any(), + any()); } @Test @@ -645,7 +646,7 @@ public class SmartReplyViewTest extends SysuiTestCase { mView.getChildAt(2).performClick(); - verify(mActivityStarter, never()).startPendingIntentDismissingKeyguard(any(), any()); + verify(mActivityStarter, never()).startPendingIntentDismissingKeyguard(any(), any(), any()); } @Test @@ -657,7 +658,8 @@ public class SmartReplyViewTest extends SysuiTestCase { Thread.sleep(delayMs); mView.getChildAt(2).performClick(); - verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any()); + verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any(), + any()); } @Test @@ -668,7 +670,8 @@ public class SmartReplyViewTest extends SysuiTestCase { mView.getChildAt(2).performClick(); - verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any()); + verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any(), + any()); } @Test diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index 21c6035da038..fe92d45b297d 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -7206,6 +7206,13 @@ message MetricsEvent { // ACTION: Share Wi-Fi hotspot by generating a QR code ACTION_SETTINGS_SHARE_WIFI_HOTSPOT_QR_CODE = 1712; + // OPEN: Settings > Network & internet > Mobile network > Delete sim + DIALOG_DELETE_SIM_CONFIRMATION = 1713; + + // OPEN: Settings > Network & internet > Mobile network > Delete sim > (answer yes to + // confirmation) + DIALOG_DELETE_SIM_PROGRESS = 1714; + // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index a94d1dc7f243..a64f4e475b7d 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -94,6 +94,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; /** * Entry point service for autofill management. @@ -192,9 +193,9 @@ public final class AutofillManagerService mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext()); mAm = LocalServices.getService(ActivityManagerInternal.class); - DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_AUTOFILL, + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_AUTOFILL, ActivityThread.currentApplication().getMainExecutor(), - (namespace, key, value) -> onDeviceConfigChange(key)); + (properties) -> onDeviceConfigChange(properties.getKeyset())); setLogLevelFromSettings(); setMaxPartitionsFromSettings(); @@ -270,15 +271,17 @@ public final class AutofillManagerService } } - private void onDeviceConfigChange(@NonNull String key) { - switch (key) { - case AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES: - case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT: - case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT: - setDeviceConfigProperties(); - break; - default: - Slog.i(mTag, "Ignoring change on " + key); + private void onDeviceConfigChange(@NonNull Set<String> keys) { + for (String key : keys) { + switch (key) { + case AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES: + case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT: + case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT: + setDeviceConfigProperties(); + break; + default: + Slog.i(mTag, "Ignoring change on " + key); + } } } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index f1963b37a6cf..386dec472019 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -57,6 +57,7 @@ import android.service.autofill.FillEventHistory; import android.service.autofill.FillEventHistory.Event; import android.service.autofill.FillResponse; import android.service.autofill.IAutoFillService; +import android.service.autofill.SaveInfo; import android.service.autofill.UserData; import android.util.ArrayMap; import android.util.ArraySet; @@ -595,8 +596,8 @@ final class AutofillManagerServiceImpl ArrayList<Session> previousSessions = null; for (int i = 0; i < size; i++) { final Session previousSession = mSessions.valueAt(i); - // TODO(b/113281366): only return sessions asked to be kept alive / add CTS test - if (previousSession.taskId == session.taskId && previousSession.id != session.id) { + if (previousSession.taskId == session.taskId && previousSession.id != session.id + && (previousSession.getSaveInfoFlagsLocked() & SaveInfo.FLAG_DELAY_SAVE) != 0) { if (previousSessions == null) { previousSessions = new ArrayList<>(size); } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 9eda9db1910f..7b973536b3bd 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -1203,9 +1203,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") @Nullable - private FillResponse getLastResponseLocked(@Nullable String logPrefix) { + private FillResponse getLastResponseLocked(@Nullable String logPrefixFmt) { + final String logPrefix = sDebug && logPrefixFmt != null + ? String.format(logPrefixFmt, this.id) + : null; if (mContexts == null) { - if (sDebug && logPrefix != null) Slog.d(TAG, logPrefix + ": no contexts"); + if (logPrefix != null) Slog.d(TAG, logPrefix + ": no contexts"); return null; } if (mResponses == null) { @@ -1241,6 +1244,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return response == null ? null : response.getSaveInfo(); } + @GuardedBy("mLock") + int getSaveInfoFlagsLocked() { + final SaveInfo saveInfo = getSaveInfoLocked(); + return saveInfo == null ? 0 : saveInfo.getFlags(); + } + /** * Generates a {@link android.service.autofill.FillEventHistory.Event#TYPE_CONTEXT_COMMITTED} * when necessary. @@ -1252,7 +1261,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private void handleLogContextCommitted() { final FillResponse lastResponse; synchronized (mLock) { - lastResponse = getLastResponseLocked("logContextCommited()"); + lastResponse = getLastResponseLocked("logContextCommited(%s)"); } if (lastResponse == null) { @@ -1295,7 +1304,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private void logContextCommittedLocked(@Nullable ArrayList<AutofillId> detectedFieldIds, @Nullable ArrayList<FieldClassification> detectedFieldClassifications) { - final FillResponse lastResponse = getLastResponseLocked("logContextCommited()"); + final FillResponse lastResponse = getLastResponseLocked("logContextCommited(%s)"); if (lastResponse == null) return; final int flags = lastResponse.getFlags(); @@ -1610,7 +1619,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + id + " destroyed"); return false; } - final FillResponse response = getLastResponseLocked("showSaveLocked()"); + final FillResponse response = getLastResponseLocked("showSaveLocked(%s)"); final SaveInfo saveInfo = response == null ? null : response.getSaveInfo(); /* @@ -1624,13 +1633,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState * - server didn't ask to keep session alive */ if (saveInfo == null) { - if (sVerbose) Slog.v(TAG, "showSaveLocked(): no saveInfo from service"); + if (sVerbose) Slog.v(TAG, "showSaveLocked(" + this.id + "): no saveInfo from service"); return true; } if ((saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) != 0) { // TODO(b/113281366): log metrics - if (sDebug) Slog.v(TAG, "showSaveLocked(): service asked to delay save"); + if (sDebug) Slog.v(TAG, "showSaveLocked(" + this.id + "): service asked to delay save"); return false; } @@ -1962,7 +1971,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (node != null) { final AutofillValue value = node.getAutofillValue(); if (sDebug) { - Slog.d(TAG, "getValueFromContexts(" + autofillId + ") at " + i + ": " + value); + Slog.d(TAG, "getValueFromContexts(" + this.id + "/" + autofillId + ") at " + + i + ": " + value); } if (value != null && !value.isEmpty()) { return value; @@ -2066,7 +2076,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } - if (sVerbose) Slog.v(TAG, "callSaveLocked(): mViewStates=" + mViewStates); + if (sVerbose) Slog.v(TAG, "callSaveLocked(" + this.id + "): mViewStates=" + mViewStates); if (mContexts == null) { Slog.w(TAG, "callSaveLocked(): no contexts"); @@ -2109,15 +2119,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final ArrayList<FillContext> contexts; if (previousSessions != null) { if (sDebug) { - Slog.d(TAG, "mergeSessions(): Merging the content of " + previousSessions.size() - + " sessions for task " + taskId); + Slog.d(TAG, "mergeSessions(" + this.id + "): Merging the content of " + + previousSessions.size() + " sessions for task " + taskId); } contexts = new ArrayList<>(); for (int i = 0; i < previousSessions.size(); i++) { final Session previousSession = previousSessions.get(i); final ArrayList<FillContext> previousContexts = previousSession.mContexts; if (previousContexts == null) { - Slog.w(TAG, "mergeSessions(): Not merging null contexts from " + Slog.w(TAG, "mergeSessions(" + this.id + "): Not merging null contexts from " + previousSession.id); continue; } @@ -2125,14 +2135,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState previousSession.updateValuesForSaveLocked(); } if (sDebug) { - Slog.d(TAG, "mergeSessions(): adding " + previousContexts.size() + Slog.d(TAG, "mergeSessions(" + this.id + "): adding " + previousContexts.size() + " context from previous session #" + previousSession.id); } contexts.addAll(previousContexts); if (mClientState == null && previousSession.mClientState != null) { if (sDebug) { - Slog.d(TAG, "mergeSessions(): setting client state from previous session" - + previousSession.id); + Slog.d(TAG, "mergeSessions(" + this.id + "): setting client state from " + + "previous session" + previousSession.id); } mClientState = previousSession.mClientState; } @@ -2250,8 +2260,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } if (sVerbose) { - Slog.v(TAG, "updateLocked(): id=" + id + ", action=" + actionAsString(action) - + ", flags=" + flags); + Slog.v(TAG, "updateLocked(" + this.id + "): id=" + id + ", action=" + + actionAsString(action) + ", flags=" + flags); } ViewState viewState = mViewStates.get(id); @@ -3291,7 +3301,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState */ @GuardedBy("mLock") void removeSelfLocked() { - if (sVerbose) Slog.v(TAG, "removeSelfLocked(): " + mPendingSaveUi); + if (sVerbose) Slog.v(TAG, "removeSelfLocked(" + this.id + "): " + mPendingSaveUi); if (mDestroyed) { Slog.w(TAG, "Call to Session#removeSelfLocked() rejected - session: " + id + " destroyed"); diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java index 33a2e5059ddf..e1b089cf28b2 100644 --- a/services/autofill/java/com/android/server/autofill/ViewState.java +++ b/services/autofill/java/com/android/server/autofill/ViewState.java @@ -214,7 +214,7 @@ final class ViewState { if (mDatasetId != null) { builder.append(", datasetId:" ).append(mDatasetId); } - builder.append("state:" ).append(getStateAsString()); + builder.append(", state:").append(getStateAsString()); if (mCurrentValue != null) { builder.append(", currentValue:" ).append(mCurrentValue); } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index a2d3d4c25b1d..5c6258ffe4cb 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -50,6 +50,7 @@ import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManager; import android.provider.DeviceConfig; +import android.provider.DeviceConfig.Properties; import android.provider.Settings; import android.service.contentcapture.ActivityEvent.ActivityEventType; import android.util.ArraySet; @@ -131,9 +132,9 @@ public final class ContentCaptureManagerService extends com.android.internal.R.string.config_defaultContentCaptureService), UserManager.DISALLOW_CONTENT_CAPTURE, /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_NO_REFRESH); - DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE, + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE, ActivityThread.currentApplication().getMainExecutor(), - (namespace, key, value) -> onDeviceConfigChange(key, value)); + (properties) -> onDeviceConfigChange(properties)); setDeviceConfigProperties(); if (mDevCfgLogHistorySize > 0) { @@ -255,23 +256,25 @@ public final class ContentCaptureManagerService extends return enabled; } - private void onDeviceConfigChange(@NonNull String key, @Nullable String value) { - switch (key) { - case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED: - setDisabledByDeviceConfig(value); - return; - case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL: - setLoggingLevelFromDeviceConfig(); - return; - case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE: - case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY: - case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE: - case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY: - case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT: - setFineTuneParamsFromDeviceConfig(); - return; - default: - Slog.i(mTag, "Ignoring change on " + key); + private void onDeviceConfigChange(@NonNull Properties properties) { + for (String key : properties.getKeyset()) { + switch (key) { + case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED: + setDisabledByDeviceConfig(properties.getString(key, null)); + return; + case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL: + setLoggingLevelFromDeviceConfig(); + return; + case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE: + case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY: + case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE: + case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY: + case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT: + setFineTuneParamsFromDeviceConfig(); + return; + default: + Slog.i(mTag, "Ignoring change on " + key); + } } } diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index b44009fd6880..7b5b419a7aa0 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -29,6 +29,7 @@ import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; +import android.provider.DeviceConfig; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -61,6 +62,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; /** * Monitors the health of packages on the system and notifies interested observers when packages @@ -69,10 +71,22 @@ import java.util.Set; */ public class PackageWatchdog { private static final String TAG = "PackageWatchdog"; + + static final String PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS = + "watchdog_trigger_failure_duration_millis"; + static final String PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT = + "watchdog_trigger_failure_count"; + static final String PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED = + "watchdog_explicit_health_check_enabled"; + // Duration to count package failures before it resets to 0 - private static final int TRIGGER_DURATION_MS = 60000; + private static final int DEFAULT_TRIGGER_FAILURE_DURATION_MS = + (int) TimeUnit.MINUTES.toMillis(1); // Number of package failures within the duration above before we notify observers - static final int TRIGGER_FAILURE_COUNT = 5; + private static final int DEFAULT_TRIGGER_FAILURE_COUNT = 5; + // Whether explicit health checks are enabled or not + private static final boolean DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED = true; + private static final int DB_VERSION = 1; private static final String TAG_PACKAGE_WATCHDOG = "package-watchdog"; private static final String TAG_PACKAGE = "package"; @@ -83,6 +97,7 @@ public class PackageWatchdog { private static final String ATTR_EXPLICIT_HEALTH_CHECK_DURATION = "health-check-duration"; private static final String ATTR_PASSED_HEALTH_CHECK = "passed-health-check"; + @GuardedBy("PackageWatchdog.class") private static PackageWatchdog sPackageWatchdog; private final Object mLock = new Object(); @@ -100,11 +115,15 @@ public class PackageWatchdog { // File containing the XML data of monitored packages /data/system/package-watchdog.xml private final AtomicFile mPolicyFile; private final ExplicitHealthCheckController mHealthCheckController; + @GuardedBy("mLock") + private boolean mIsPackagesReady; // Flag to control whether explicit health checks are supported or not @GuardedBy("mLock") - private boolean mIsHealthCheckEnabled = true; + private boolean mIsHealthCheckEnabled = DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED; @GuardedBy("mLock") - private boolean mIsPackagesReady; + private int mTriggerFailureDurationMs = DEFAULT_TRIGGER_FAILURE_DURATION_MS; + @GuardedBy("mLock") + private int mTriggerFailureCount = DEFAULT_TRIGGER_FAILURE_COUNT; // SystemClock#uptimeMillis when we last executed #syncState // 0 if no prune is scheduled. @GuardedBy("mLock") @@ -153,8 +172,8 @@ public class PackageWatchdog { mHealthCheckController.setCallbacks(packageName -> onHealthCheckPassed(packageName), packages -> onSupportedPackages(packages), () -> syncRequestsAsync()); - // Controller is initially disabled until here where we may enable it and sync our state - setExplicitHealthCheckEnabled(mIsHealthCheckEnabled); + setPropertyChangedListenerLocked(); + updateConfigs(); } } @@ -332,14 +351,13 @@ public class PackageWatchdog { } } - // TODO(b/120598832): Set depending on DeviceConfig flag /** * Enables or disables explicit health checks. * <p> If explicit health checks are enabled, the health check service is started. * <p> If explicit health checks are disabled, pending explicit health check requests are * passed and the health check service is stopped. */ - public void setExplicitHealthCheckEnabled(boolean enabled) { + private void setExplicitHealthCheckEnabled(boolean enabled) { synchronized (mLock) { mIsHealthCheckEnabled = enabled; mHealthCheckController.setEnabled(enabled); @@ -390,6 +408,12 @@ public class PackageWatchdog { String getName(); } + long getTriggerFailureCount() { + synchronized (mLock) { + return mTriggerFailureCount; + } + } + /** * Serializes and syncs health check requests with the {@link ExplicitHealthCheckController}. */ @@ -646,7 +670,7 @@ public class PackageWatchdog { XmlUtils.beginDocument(parser, TAG_PACKAGE_WATCHDOG); int outerDepth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, outerDepth)) { - ObserverInternal observer = ObserverInternal.read(parser); + ObserverInternal observer = ObserverInternal.read(parser, this); if (observer != null) { mAllObservers.put(observer.mName, observer); } @@ -661,6 +685,48 @@ public class PackageWatchdog { } } + /** Adds a {@link DeviceConfig#OnPropertyChangedListener}. */ + private void setPropertyChangedListenerLocked() { + DeviceConfig.addOnPropertyChangedListener( + DeviceConfig.NAMESPACE_ROLLBACK, + mContext.getMainExecutor(), + (namespace, name, value) -> { + if (!DeviceConfig.NAMESPACE_ROLLBACK.equals(namespace)) { + return; + } + updateConfigs(); + }); + } + + /** + * Health check is enabled or disabled after reading the flags + * from DeviceConfig. + */ + private void updateConfigs() { + synchronized (mLock) { + mTriggerFailureCount = DeviceConfig.getInt( + DeviceConfig.NAMESPACE_ROLLBACK, + PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT, + DEFAULT_TRIGGER_FAILURE_COUNT); + if (mTriggerFailureCount <= 0) { + mTriggerFailureCount = DEFAULT_TRIGGER_FAILURE_COUNT; + } + + mTriggerFailureDurationMs = DeviceConfig.getInt( + DeviceConfig.NAMESPACE_ROLLBACK, + PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS, + DEFAULT_TRIGGER_FAILURE_DURATION_MS); + if (mTriggerFailureDurationMs <= 0) { + mTriggerFailureDurationMs = DEFAULT_TRIGGER_FAILURE_COUNT; + } + + setExplicitHealthCheckEnabled(DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_ROLLBACK, + PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED, + DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED)); + } + } + /** * Persists mAllObservers to file. Threshold information is ignored. */ @@ -805,7 +871,7 @@ public class PackageWatchdog { * #loadFromFile which in turn is only called on construction of the * singleton PackageWatchdog. **/ - public static ObserverInternal read(XmlPullParser parser) { + public static ObserverInternal read(XmlPullParser parser, PackageWatchdog watchdog) { String observerName = null; if (TAG_OBSERVER.equals(parser.getName())) { observerName = parser.getAttributeValue(null, ATTR_NAME); @@ -829,7 +895,7 @@ public class PackageWatchdog { boolean hasPassedHealthCheck = Boolean.parseBoolean( parser.getAttributeValue(null, ATTR_PASSED_HEALTH_CHECK)); if (!TextUtils.isEmpty(packageName)) { - packages.add(new MonitoredPackage(packageName, duration, + packages.add(watchdog.new MonitoredPackage(packageName, duration, healthCheckDuration, hasPassedHealthCheck)); } } catch (NumberFormatException e) { @@ -856,7 +922,7 @@ public class PackageWatchdog { * <p> Note, the PackageWatchdog#mLock must always be held when reading or writing * instances of this class. */ - static class MonitoredPackage { + class MonitoredPackage { // Health check states // TODO(b/120598832): Prefix with HEALTH_CHECK // mName has not passed health check but has requested a health check @@ -931,7 +997,7 @@ public class PackageWatchdog { public boolean onFailureLocked() { final long now = SystemClock.uptimeMillis(); final long duration = now - mUptimeStartMs; - if (duration > TRIGGER_DURATION_MS) { + if (duration > mTriggerFailureDurationMs) { // TODO(b/120598832): Reseting to 1 is not correct // because there may be more than 1 failure in the last trigger window from now // This is the RescueParty impl, will leave for now @@ -940,7 +1006,7 @@ public class PackageWatchdog { } else { mFailures++; } - boolean failed = mFailures >= TRIGGER_FAILURE_COUNT; + boolean failed = mFailures >= mTriggerFailureCount; if (failed) { mFailures = 0; } @@ -1065,7 +1131,7 @@ public class PackageWatchdog { } /** Returns a {@link String} representation of the current health check state. */ - private static String toString(int state) { + private String toString(int state) { switch (state) { case STATE_ACTIVE: return "ACTIVE"; @@ -1081,7 +1147,7 @@ public class PackageWatchdog { } /** Returns {@code value} if it is greater than 0 or {@link Long#MAX_VALUE} otherwise. */ - private static long toPositive(long value) { + private long toPositive(long value) { return value > 0 ? value : Long.MAX_VALUE; } } diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java index 1fe0271ac1ec..fb1a962c0ef3 100644 --- a/services/core/java/com/android/server/RescueParty.java +++ b/services/core/java/com/android/server/RescueParty.java @@ -72,8 +72,12 @@ public class RescueParty { static final int LEVEL_FACTORY_RESET = 4; @VisibleForTesting static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count"; + /** + * The boot trigger window size must always be greater than Watchdog's deadlock timeout + * {@link Watchdog#DEFAULT_TIMEOUT}. + */ @VisibleForTesting - static final long BOOT_TRIGGER_WINDOW_MILLIS = 300 * DateUtils.SECOND_IN_MILLIS; + static final long BOOT_TRIGGER_WINDOW_MILLIS = 600 * DateUtils.SECOND_IN_MILLIS; @VisibleForTesting static final long PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS = 30 * DateUtils.SECOND_IN_MILLIS; @VisibleForTesting diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 6c1ffa7225f0..baec3ccd953f 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -802,8 +802,8 @@ class StorageManagerService extends IStorageManager.Stub } }); // For now, simply clone property when it changes - DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_STORAGE, - mContext.getMainExecutor(), (namespace, name, value) -> { + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE, + mContext.getMainExecutor(), (properties) -> { refreshIsolatedStorageSettings(); }); refreshIsolatedStorageSettings(); @@ -1063,11 +1063,7 @@ class StorageManagerService extends IStorageManager.Stub } private boolean supportsBlockCheckpoint() throws RemoteException { - // Only the system process is permitted to start checkpoints - if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { - throw new SecurityException("no permission to check block based checkpoint support"); - } - + enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); return mVold.supportsBlockCheckpoint(); } @@ -2726,11 +2722,7 @@ class StorageManagerService extends IStorageManager.Stub */ @Override public boolean needsCheckpoint() throws RemoteException { - // Only the system process is permitted to commit checkpoints - if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { - throw new SecurityException("no permission to commit checkpoint changes"); - } - + enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); return mVold.needsCheckpoint(); } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 76136dfc81a0..df92106ae0d0 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -634,7 +634,7 @@ public final class ActiveServices { } if (allowBackgroundActivityStarts) { - r.hasStartedWhitelistingBgActivityStarts = true; + r.setHasStartedWhitelistingBgActivityStarts(true); scheduleCleanUpHasStartedWhitelistingBgActivityStartsLocked(r); } @@ -761,11 +761,6 @@ public final class ActiveServices { } service.callStart = false; - // the service will not necessarily be brought down, so only clear the whitelisting state - // for start-based bg activity starts now, and drop any existing future cleanup callback - service.setHasStartedWhitelistingBgActivityStarts(false); - mAm.mHandler.removeCallbacks(service.startedWhitelistingBgActivityStartsCleanUp); - bringDownServiceIfNeededLocked(service, false, false); } @@ -1768,12 +1763,7 @@ public final class ActiveServices { callerApp.uid, callerApp.processName, callingPackage); IBinder binder = connection.asBinder(); - ArrayList<ConnectionRecord> clist = s.getConnections().get(binder); - if (clist == null) { - clist = new ArrayList<ConnectionRecord>(); - s.putConnection(binder, clist); - } - clist.add(c); + s.addConnection(binder, c); b.connections.add(c); if (activity != null) { activity.addConnection(c); @@ -1792,9 +1782,9 @@ public final class ActiveServices { if (s.app != null) { updateServiceClientActivitiesLocked(s.app, c, true); } - clist = mServiceConnections.get(binder); + ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder); if (clist == null) { - clist = new ArrayList<ConnectionRecord>(); + clist = new ArrayList<>(); mServiceConnections.put(binder, clist); } clist.add(c); @@ -3828,8 +3818,8 @@ public final class ActiveServices { public PendingIntent getRunningServiceControlPanelLocked(ComponentName name) { int userId = UserHandle.getUserId(Binder.getCallingUid()); ServiceRecord r = getServiceByNameLocked(name, userId); - ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections(); if (r != null) { + ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections(); for (int conni = connections.size() - 1; conni >= 0; conni--) { ArrayList<ConnectionRecord> conn = connections.valueAt(conni); for (int i=0; i<conn.size(); i++) { diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index d7decb4126fc..0da39e7aee76 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -26,7 +26,8 @@ import android.net.Uri; import android.os.Build; import android.os.Handler; import android.provider.DeviceConfig; -import android.provider.DeviceConfig.OnPropertyChangedListener; +import android.provider.DeviceConfig.OnPropertiesChangedListener; +import android.provider.DeviceConfig.Properties; import android.provider.Settings; import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; @@ -315,23 +316,25 @@ final class ActivityManagerConstants extends ContentObserver { private static final Uri ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI = Settings.Global.getUriFor(Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS); - private final OnPropertyChangedListener mOnDeviceConfigChangedListener = - new OnPropertyChangedListener() { + private final OnPropertiesChangedListener mOnDeviceConfigChangedListener = + new OnPropertiesChangedListener() { @Override - public void onPropertyChanged(String namespace, String name, String value) { - if (name == null) { - return; - } - switch (name) { - case KEY_MAX_CACHED_PROCESSES: - updateMaxCachedProcesses(); - break; - case KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED: - case KEY_BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST: - updateBackgroundActivityStarts(); - break; - default: - break; + public void onPropertiesChanged(Properties properties) { + for (String name : properties.getKeyset()) { + if (name == null) { + return; + } + switch (name) { + case KEY_MAX_CACHED_PROCESSES: + updateMaxCachedProcesses(); + break; + case KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED: + case KEY_BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST: + updateBackgroundActivityStarts(); + break; + default: + break; + } } } }; @@ -362,7 +365,7 @@ final class ActivityManagerConstants extends ContentObserver { if (mSystemServerAutomaticHeapDumpEnabled) { updateEnableAutomaticSystemServerHeapDumps(); } - DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, ActivityThread.currentApplication().getMainExecutor(), mOnDeviceConfigChangedListener); updateMaxCachedProcesses(); diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java index 13b55dbcad48..b0f8f86ada6b 100644 --- a/services/core/java/com/android/server/am/AppCompactor.java +++ b/services/core/java/com/android/server/am/AppCompactor.java @@ -30,7 +30,8 @@ import android.os.Process; import android.os.SystemClock; import android.os.Trace; import android.provider.DeviceConfig; -import android.provider.DeviceConfig.OnPropertyChangedListener; +import android.provider.DeviceConfig.OnPropertiesChangedListener; +import android.provider.DeviceConfig.Properties; import android.text.TextUtils; import android.util.EventLog; import android.util.Slog; @@ -126,29 +127,31 @@ public final class AppCompactor { private final ArrayList<ProcessRecord> mPendingCompactionProcesses = new ArrayList<ProcessRecord>(); private final ActivityManagerService mAm; - private final OnPropertyChangedListener mOnFlagsChangedListener = - new OnPropertyChangedListener() { + private final OnPropertiesChangedListener mOnFlagsChangedListener = + new OnPropertiesChangedListener() { @Override - public void onPropertyChanged(String namespace, String name, String value) { + public void onPropertiesChanged(Properties properties) { synchronized (mPhenotypeFlagLock) { - if (KEY_USE_COMPACTION.equals(name)) { - updateUseCompaction(); - } else if (KEY_COMPACT_ACTION_1.equals(name) - || KEY_COMPACT_ACTION_2.equals(name)) { - updateCompactionActions(); - } else if (KEY_COMPACT_THROTTLE_1.equals(name) - || KEY_COMPACT_THROTTLE_2.equals(name) - || KEY_COMPACT_THROTTLE_3.equals(name) - || KEY_COMPACT_THROTTLE_4.equals(name)) { - updateCompactionThrottles(); - } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) { - updateStatsdSampleRate(); - } else if (KEY_COMPACT_FULL_RSS_THROTTLE_KB.equals(name)) { - updateFullRssThrottle(); - } else if (KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB.equals(name)) { - updateFullDeltaRssThrottle(); - } else if (KEY_COMPACT_PROC_STATE_THROTTLE.equals(name)) { - updateProcStateThrottle(); + for (String name : properties.getKeyset()) { + if (KEY_USE_COMPACTION.equals(name)) { + updateUseCompaction(); + } else if (KEY_COMPACT_ACTION_1.equals(name) + || KEY_COMPACT_ACTION_2.equals(name)) { + updateCompactionActions(); + } else if (KEY_COMPACT_THROTTLE_1.equals(name) + || KEY_COMPACT_THROTTLE_2.equals(name) + || KEY_COMPACT_THROTTLE_3.equals(name) + || KEY_COMPACT_THROTTLE_4.equals(name)) { + updateCompactionThrottles(); + } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) { + updateStatsdSampleRate(); + } else if (KEY_COMPACT_FULL_RSS_THROTTLE_KB.equals(name)) { + updateFullRssThrottle(); + } else if (KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB.equals(name)) { + updateFullDeltaRssThrottle(); + } else if (KEY_COMPACT_PROC_STATE_THROTTLE.equals(name)) { + updateProcStateThrottle(); + } } } if (mTestCallback != null) { @@ -229,7 +232,7 @@ public final class AppCompactor { * starts the background thread if necessary. */ public void init() { - DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, ActivityThread.currentApplication().getMainExecutor(), mOnFlagsChangedListener); synchronized (mPhenotypeFlagLock) { updateUseCompaction(); diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index e891e6e450ba..563b2f3bfb32 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -1186,8 +1186,8 @@ class ProcessRecord implements WindowProcessListener { !mAllowBackgroundActivityStartsTokens.isEmpty()); } - void addBoundClientUids(ArraySet<Integer> clientUids) { - mBoundClientUids.addAll(clientUids); + void addBoundClientUid(int clientUid) { + mBoundClientUids.add(clientUid); mWindowProcessController.setBoundClientUids(mBoundClientUids); } diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 27c62d03f960..0426ec1d9771 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -38,7 +38,6 @@ import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.util.ArrayMap; -import android.util.ArraySet; import android.util.Slog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; @@ -131,10 +130,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN int pendingConnectionImportance; // To be filled in to ProcessRecord once it connects // any current binding to this service has BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS flag? - private boolean hasBindingWhitelistingBgActivityStarts; + private boolean mHasBindingWhitelistingBgActivityStarts; // is this service currently whitelisted to start activities from background by providing // allowBackgroundActivityStarts=true to startServiceLocked()? - boolean hasStartedWhitelistingBgActivityStarts; + private boolean mHasStartedWhitelistingBgActivityStarts; // used to clean up the state of hasStartedWhitelistingBgActivityStarts after a timeout Runnable startedWhitelistingBgActivityStartsCleanUp; @@ -384,13 +383,13 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN if (whitelistManager) { pw.print(prefix); pw.print("whitelistManager="); pw.println(whitelistManager); } - if (hasBindingWhitelistingBgActivityStarts) { + if (mHasBindingWhitelistingBgActivityStarts) { pw.print(prefix); pw.print("hasBindingWhitelistingBgActivityStarts="); - pw.println(hasBindingWhitelistingBgActivityStarts); + pw.println(mHasBindingWhitelistingBgActivityStarts); } - if (hasStartedWhitelistingBgActivityStarts) { + if (mHasStartedWhitelistingBgActivityStarts) { pw.print(prefix); pw.print("hasStartedWhitelistingBgActivityStarts="); - pw.println(hasStartedWhitelistingBgActivityStarts); + pw.println(mHasStartedWhitelistingBgActivityStarts); } if (delayed) { pw.print(prefix); pw.print("delayed="); pw.println(delayed); @@ -542,7 +541,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN public void setProcess(ProcessRecord _proc) { if (_proc != null) { - if (hasStartedWhitelistingBgActivityStarts || hasBindingWhitelistingBgActivityStarts) { + if (mHasStartedWhitelistingBgActivityStarts + || mHasBindingWhitelistingBgActivityStarts) { _proc.addAllowBackgroundActivityStartsToken(this); } else { _proc.removeAllowBackgroundActivityStartsToken(this); @@ -580,15 +580,17 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN return connections; } - void putConnection(IBinder binder, ArrayList<ConnectionRecord> clist) { - connections.put(binder, clist); - // if we have a process attached, add bound client uids of this connection to it + void addConnection(IBinder binder, ConnectionRecord c) { + ArrayList<ConnectionRecord> clist = connections.get(binder); + if (clist == null) { + clist = new ArrayList<>(); + connections.put(binder, clist); + } + clist.add(c); + + // if we have a process attached, add bound client uid of this connection to it if (app != null) { - ArraySet<Integer> boundClientUids = new ArraySet<>(); - for (int i = 0; i < clist.size(); i++) { - boundClientUids.add(clist.get(i).clientUid); - } - app.addBoundClientUids(boundClientUids); + app.addBoundClientUid(c.clientUid); } } @@ -614,22 +616,22 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN break; } } - if (hasBindingWhitelistingBgActivityStarts != hasWhitelistingBinding) { - hasBindingWhitelistingBgActivityStarts = hasWhitelistingBinding; + if (mHasBindingWhitelistingBgActivityStarts != hasWhitelistingBinding) { + mHasBindingWhitelistingBgActivityStarts = hasWhitelistingBinding; updateParentProcessBgActivityStartsWhitelistingToken(); } } void setHasBindingWhitelistingBgActivityStarts(boolean newValue) { - if (hasBindingWhitelistingBgActivityStarts != newValue) { - hasBindingWhitelistingBgActivityStarts = newValue; + if (mHasBindingWhitelistingBgActivityStarts != newValue) { + mHasBindingWhitelistingBgActivityStarts = newValue; updateParentProcessBgActivityStartsWhitelistingToken(); } } void setHasStartedWhitelistingBgActivityStarts(boolean newValue) { - if (hasStartedWhitelistingBgActivityStarts != newValue) { - hasStartedWhitelistingBgActivityStarts = newValue; + if (mHasStartedWhitelistingBgActivityStarts != newValue) { + mHasStartedWhitelistingBgActivityStarts = newValue; updateParentProcessBgActivityStartsWhitelistingToken(); } } @@ -647,7 +649,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN if (app == null) { return; } - if (hasStartedWhitelistingBgActivityStarts || hasBindingWhitelistingBgActivityStarts) { + if (mHasStartedWhitelistingBgActivityStarts || mHasBindingWhitelistingBgActivityStarts) { // if the token is already there it's safe to "re-add it" - we're deadling with // a set of Binder objects app.addAllowBackgroundActivityStartsToken(this); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 507f398d2422..d5109123ab12 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1825,14 +1825,28 @@ public class AudioService extends IAudioService.Stub && streamTypeAlias == AudioSystem.STREAM_MUSIC // vol change on a full volume device && ((device & mFullVolumeDevices) != 0)) { - int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN : - KeyEvent.KEYCODE_VOLUME_UP; - final long ident = Binder.clearCallingIdentity(); - try { - mHdmiPlaybackClient.sendKeyEvent(keyCode, true); - mHdmiPlaybackClient.sendKeyEvent(keyCode, false); - } finally { - Binder.restoreCallingIdentity(ident); + int keyCode = KeyEvent.KEYCODE_UNKNOWN; + switch (direction) { + case AudioManager.ADJUST_RAISE: + keyCode = KeyEvent.KEYCODE_VOLUME_UP; + break; + case AudioManager.ADJUST_LOWER: + keyCode = KeyEvent.KEYCODE_VOLUME_DOWN; + break; + case AudioManager.ADJUST_TOGGLE_MUTE: + keyCode = KeyEvent.KEYCODE_VOLUME_MUTE; + break; + default: + break; + } + if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { + final long ident = Binder.clearCallingIdentity(); + try { + mHdmiPlaybackClient.sendKeyEvent(keyCode, true); + mHdmiPlaybackClient.sendKeyEvent(keyCode, false); + } finally { + Binder.restoreCallingIdentity(ident); + } } } diff --git a/services/core/java/com/android/server/gpu/GpuService.java b/services/core/java/com/android/server/gpu/GpuService.java index 0f73f379900b..d4396534d067 100644 --- a/services/core/java/com/android/server/gpu/GpuService.java +++ b/services/core/java/com/android/server/gpu/GpuService.java @@ -37,6 +37,7 @@ import android.os.Handler; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.DeviceConfig; +import android.provider.DeviceConfig.Properties; import android.provider.Settings; import android.util.Base64; import android.util.Slog; @@ -138,18 +139,19 @@ public class GpuService extends SystemService { } } - private final class DeviceConfigListener implements DeviceConfig.OnPropertyChangedListener { + private final class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener { DeviceConfigListener() { super(); - DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_GAME_DRIVER, + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_GAME_DRIVER, mContext.getMainExecutor(), this); } @Override - public void onPropertyChanged(String namespace, String name, String value) { + public void onPropertiesChanged(Properties properties) { synchronized (mDeviceConfigLock) { - if (Settings.Global.GAME_DRIVER_BLACKLISTS.equals(name)) { - parseBlacklists(value != null ? value : ""); + if (properties.getKeyset().contains(Settings.Global.GAME_DRIVER_BLACKLISTS)) { + parseBlacklists( + properties.getString(Settings.Global.GAME_DRIVER_BLACKLISTS, "")); setBlacklist(); } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 651ce7d431fe..30d244f1bcce 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -1409,7 +1409,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mIWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService(Context.WINDOW_SERVICE)); mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); - mImeDisplayValidator = mWindowManagerInternal::shouldShowSystemDecorOnDisplay; + mImeDisplayValidator = displayId -> mWindowManagerInternal.shouldShowIme(displayId); mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() { @Override public void executeMessage(Message msg) { @@ -2139,7 +2139,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) { return FALLBACK_DISPLAY_ID; } - // Show IME window on fallback display when the display is not allowed. + + // Show IME window on fallback display when the display doesn't support system decorations + // or the display is virtual and isn't owned by system for security concern. return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID; } diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index 580150ed887e..e0b8e71ef713 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -79,6 +79,9 @@ import com.android.internal.inputmethod.StartInputReason; import com.android.internal.inputmethod.UnbindReason; import com.android.internal.messages.nano.SystemMessageProto; import com.android.internal.notification.SystemNotificationChannels; +import com.android.internal.os.TransferPipe; +import com.android.internal.util.DumpUtils; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethodClient; @@ -90,6 +93,8 @@ import com.android.server.SystemService; import com.android.server.wm.WindowManagerInternal; import java.io.FileDescriptor; +import java.io.IOException; +import java.io.PrintWriter; import java.lang.annotation.Retention; import java.util.Collections; import java.util.List; @@ -645,6 +650,14 @@ public final class MultiClientInputMethodManagerService { mSelfReportedDisplayId = selfReportedDisplayId; mClientId = InputMethodClientIdSource.getNext(); } + + @GuardedBy("PerUserData.mLock") + void dumpLocked(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) { + ipw.println("mState=" + mState + ",mBindingSequence=" + mBindingSequence + + ",mWriteChannel=" + mWriteChannel + + ",mInputMethodSession=" + mInputMethodSession + + ",mMSInputMethodSession=" + mMSInputMethodSession); + } } private static final class UserDataMap { @@ -673,6 +686,22 @@ public final class MultiClientInputMethodManagerService { return mMap.removeReturnOld(userId); } } + + @AnyThread + void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) { + synchronized (mMap) { + for (int i = 0; i < mMap.size(); i++) { + int userId = mMap.keyAt(i); + PerUserData data = mMap.valueAt(i); + ipw.println("userId=" + userId + ", data="); + if (data != null) { + ipw.increaseIndent(); + data.dump(fd, ipw, args); + ipw.decreaseIndent(); + } + } + } + } } private static final class TokenInfo { @@ -967,6 +996,71 @@ public final class MultiClientInputMethodManagerService { } } + @AnyThread + void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) { + synchronized (mLock) { + ipw.println("mState=" + mState + + ",mCurrentInputMethod=" + mCurrentInputMethod + + ",mCurrentInputMethodInfo=" + mCurrentInputMethodInfo); + + if (mCurrentInputMethod != null) { + // indentation will not be kept. So add visual separator here. + ipw.println(">>Dump CurrentInputMethod>>"); + ipw.flush(); + try { + TransferPipe.dumpAsync(mCurrentInputMethod.asBinder(), fd, args); + } catch (IOException | RemoteException e) { + ipw.println("Failed to dump input method service: " + e); + } + ipw.println("<<Dump CurrentInputMethod<<"); + } + + ipw.println("mDisplayIdToImeWindowTokenMap="); + for (TokenInfo info : mDisplayIdToImeWindowTokenMap) { + ipw.println(" display=" + info.mDisplayId + ",token=" + + info.mToken); + } + ipw.println("mClientMap="); + ipw.increaseIndent(); + for (int i = 0; i < mClientMap.size(); i++) { + + ipw.println("binder=" + mClientMap.keyAt(i)); + ipw.println(" InputMethodClientInfo="); + InputMethodClientInfo info = mClientMap.valueAt(i); + if (info != null) { + ipw.increaseIndent(); + info.dumpLocked(fd, ipw, args); + ipw.decreaseIndent(); + } + } + ipw.decreaseIndent(); + ipw.println("mClientIdToClientMap="); + ipw.increaseIndent(); + for (int i = 0; i < mClientIdToClientMap.size(); i++) { + ipw.println("clientId=" + mClientIdToClientMap.keyAt(i)); + ipw.println(" InputMethodClientInfo="); + InputMethodClientInfo info = mClientIdToClientMap.valueAt(i); + if (info != null) { + ipw.increaseIndent(); + info.dumpLocked(fd, ipw, args); + ipw.decreaseIndent(); + } + if (info.mClient != null) { + // indentation will not be kept. So add visual separator here. + ipw.println(">>DumpClientStart>>"); + ipw.flush(); // all writes should be flushed to guarantee order. + try { + TransferPipe.dumpAsync(info.mClient.asBinder(), fd, args); + } catch (IOException | RemoteException e) { + ipw.println(" Failed to dump client:" + e); + } + ipw.println("<<DumpClientEnd<<"); + } + } + ipw.decreaseIndent(); + } + } + private static final class ClientDeathRecipient implements IBinder.DeathRecipient { private final PerUserData mPerUserData; private final IInputMethodClient mClient; @@ -1106,6 +1200,16 @@ public final class MultiClientInputMethodManagerService { } return Collections.singletonList(info); } + + @AnyThread + void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) { + synchronized (mArray) { + for (int i = 0; i < mArray.size(); i++) { + ipw.println("userId=" + mArray.keyAt(i)); + ipw.println(" InputMethodInfo=" + mArray.valueAt(i)); + } + } + } } /** @@ -1601,5 +1705,19 @@ public final class MultiClientInputMethodManagerService { @Nullable FileDescriptor err, String[] args, @Nullable ShellCallback callback, ResultReceiver resultReceiver) { } + + @BinderThread + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; + final String prefixChild = " "; + pw.println("Current Multi Client Input Method Manager state:"); + IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); + ipw.println("mUserDataMap="); + if (mUserDataMap != null) { + ipw.increaseIndent(); + mUserDataMap.dump(fd, ipw, args); + } + } } } diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index d5883bb3befb..b676618f4cd3 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -18,6 +18,7 @@ package com.android.server.job; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; +import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import android.annotation.NonNull; import android.annotation.UserIdInt; @@ -463,32 +464,6 @@ public class JobSchedulerService extends com.android.server.SystemService private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac"; private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac"; private static final String KEY_USE_HEARTBEATS = "use_heartbeats"; - private static final String KEY_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = - "tc_skip_not_ready_jobs"; - private static final String KEY_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = - "qc_allowed_time_per_period_ms"; - private static final String KEY_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = - "qc_in_quota_buffer_ms"; - private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = - "qc_window_size_active_ms"; - private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = - "qc_window_size_working_ms"; - private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = - "qc_window_size_frequent_ms"; - private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = - "qc_window_size_rare_ms"; - private static final String KEY_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = - "qc_max_execution_time_ms"; - private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = - "qc_max_job_count_active"; - private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = - "qc_max_job_count_working"; - private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = - "qc_max_job_count_frequent"; - private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = - "qc_max_job_count_rare"; - private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = - "qc_max_count_per_allowed_time"; private static final int DEFAULT_MIN_IDLE_COUNT = 1; private static final int DEFAULT_MIN_CHARGING_COUNT = 1; @@ -510,30 +485,6 @@ public class JobSchedulerService extends com.android.server.SystemService private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f; private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f; private static final boolean DEFAULT_USE_HEARTBEATS = false; - private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; - private static final long DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = - 10 * 60 * 1000L; // 10 minutes - private static final long DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = - 30 * 1000L; // 30 seconds - private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = - 10 * 60 * 1000L; // 10 minutes for ACTIVE -- ACTIVE apps can run jobs at any time - private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = - 2 * 60 * 60 * 1000L; // 2 hours - private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = - 8 * 60 * 60 * 1000L; // 8 hours - private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = - 24 * 60 * 60 * 1000L; // 24 hours - private static final long DEFAULT_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = - 4 * 60 * 60 * 1000L; // 4 hours - private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = - 200; // 1200/hr - private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = - 1200; // 600/hr - private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = - 1800; // 225/hr - private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = - 2400; // 100/hr - private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = 20; /** * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things @@ -680,97 +631,6 @@ public class JobSchedulerService extends com.android.server.SystemService */ public boolean USE_HEARTBEATS = DEFAULT_USE_HEARTBEATS; - /** - * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't - * ready now. - */ - public boolean TIME_CONTROLLER_SKIP_NOT_READY_JOBS = - DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS; - - /** How much time each app will have to run jobs within their standby bucket window. */ - public long QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = - DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS; - - /** - * How much time the package should have before transitioning from out-of-quota to in-quota. - * This should not affect processing if the package is already in-quota. - */ - public long QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = - DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; - - /** - * The quota window size of the particular standby bucket. Apps in this standby bucket are - * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past - * WINDOW_SIZE_MS. - */ - public long QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = - DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS; - - /** - * The quota window size of the particular standby bucket. Apps in this standby bucket are - * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past - * WINDOW_SIZE_MS. - */ - public long QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = - DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS; - - /** - * The quota window size of the particular standby bucket. Apps in this standby bucket are - * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past - * WINDOW_SIZE_MS. - */ - public long QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = - DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS; - - /** - * The quota window size of the particular standby bucket. Apps in this standby bucket are - * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past - * WINDOW_SIZE_MS. - */ - public long QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = - DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS; - - /** - * The maximum amount of time an app can have its jobs running within a 24 hour window. - */ - public long QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = - DEFAULT_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS; - - /** - * The maximum number of jobs an app can run within this particular standby bucket's - * window size. - */ - public int QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = - DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE; - - /** - * The maximum number of jobs an app can run within this particular standby bucket's - * window size. - */ - public int QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = - DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING; - - /** - * The maximum number of jobs an app can run within this particular standby bucket's - * window size. - */ - public int QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = - DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT; - - /** - * The maximum number of jobs an app can run within this particular standby bucket's - * window size. - */ - public int QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = - DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE; - - /** - * The maximum number of jobs that can run within the past - * {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS}. - */ - public int QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = - DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME; - private final KeyValueListParser mParser = new KeyValueListParser(','); void updateConstantsLocked(String value) { @@ -834,45 +694,6 @@ public class JobSchedulerService extends com.android.server.SystemService CONN_PREFETCH_RELAX_FRAC = mParser.getFloat(KEY_CONN_PREFETCH_RELAX_FRAC, DEFAULT_CONN_PREFETCH_RELAX_FRAC); USE_HEARTBEATS = mParser.getBoolean(KEY_USE_HEARTBEATS, DEFAULT_USE_HEARTBEATS); - TIME_CONTROLLER_SKIP_NOT_READY_JOBS = mParser.getBoolean( - KEY_TIME_CONTROLLER_SKIP_NOT_READY_JOBS, - DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS); - QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = mParser.getDurationMillis( - KEY_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS, - DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS); - QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = mParser.getDurationMillis( - KEY_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS, - DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS); - QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = mParser.getDurationMillis( - KEY_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS, - DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS); - QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = mParser.getDurationMillis( - KEY_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS, - DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS); - QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = mParser.getDurationMillis( - KEY_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS, - DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS); - QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = mParser.getDurationMillis( - KEY_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS, - DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS); - QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = mParser.getDurationMillis( - KEY_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS, - DEFAULT_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS); - QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = mParser.getInt( - KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE, - DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE); - QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = mParser.getInt( - KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING, - DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING); - QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = mParser.getInt( - KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT, - DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT); - QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = mParser.getInt( - KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE, - DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE); - QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = mParser.getInt( - KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME, - DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME); } void dump(IndentingPrintWriter pw) { @@ -915,37 +736,11 @@ public class JobSchedulerService extends com.android.server.SystemService pw.printPair(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println(); pw.printPair(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println(); pw.printPair(KEY_USE_HEARTBEATS, USE_HEARTBEATS).println(); - pw.printPair(KEY_TIME_CONTROLLER_SKIP_NOT_READY_JOBS, - TIME_CONTROLLER_SKIP_NOT_READY_JOBS).println(); - pw.printPair(KEY_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS, - QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS).println(); - pw.printPair(KEY_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS, - QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS).println(); - pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS, - QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS).println(); - pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS, - QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS).println(); - pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS, - QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS).println(); - pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS, - QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS).println(); - pw.printPair(KEY_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS, - QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS).println(); - pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE, - QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE).println(); - pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING, - QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING).println(); - pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT, - QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT).println(); - pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE, - QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE).println(); - pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME, - QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME).println(); + pw.decreaseIndent(); } - void dump(ProtoOutputStream proto, long fieldId) { - final long token = proto.start(fieldId); + void dump(ProtoOutputStream proto) { proto.write(ConstantsProto.MIN_IDLE_COUNT, MIN_IDLE_COUNT); proto.write(ConstantsProto.MIN_CHARGING_COUNT, MIN_CHARGING_COUNT); proto.write(ConstantsProto.MIN_BATTERY_NOT_LOW_COUNT, MIN_BATTERY_NOT_LOW_COUNT); @@ -973,40 +768,6 @@ public class JobSchedulerService extends com.android.server.SystemService proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC); proto.write(ConstantsProto.CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC); proto.write(ConstantsProto.USE_HEARTBEATS, USE_HEARTBEATS); - - final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER); - proto.write(ConstantsProto.TimeController.SKIP_NOT_READY_JOBS, - TIME_CONTROLLER_SKIP_NOT_READY_JOBS); - proto.end(tcToken); - - final long qcToken = proto.start(ConstantsProto.QUOTA_CONTROLLER); - proto.write(ConstantsProto.QuotaController.ALLOWED_TIME_PER_PERIOD_MS, - QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS); - proto.write(ConstantsProto.QuotaController.IN_QUOTA_BUFFER_MS, - QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS); - proto.write(ConstantsProto.QuotaController.ACTIVE_WINDOW_SIZE_MS, - QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS); - proto.write(ConstantsProto.QuotaController.WORKING_WINDOW_SIZE_MS, - QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS); - proto.write(ConstantsProto.QuotaController.FREQUENT_WINDOW_SIZE_MS, - QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS); - proto.write(ConstantsProto.QuotaController.RARE_WINDOW_SIZE_MS, - QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS); - proto.write(ConstantsProto.QuotaController.MAX_EXECUTION_TIME_MS, - QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS); - proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_ACTIVE, - QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE); - proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_WORKING, - QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING); - proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_FREQUENT, - QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT); - proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_RARE, - QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE); - proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_PER_ALLOWED_TIME, - QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME); - proto.end(qcToken); - - proto.end(token); } } @@ -1636,6 +1397,9 @@ public class JobSchedulerService extends com.android.server.SystemService public void onBootPhase(int phase) { if (PHASE_SYSTEM_SERVICES_READY == phase) { mConstantsObserver.start(getContext().getContentResolver()); + for (StateController controller : mControllers) { + controller.onSystemServicesReady(); + } mAppStateTracker = Preconditions.checkNotNull( LocalServices.getService(AppStateTracker.class)); @@ -1801,7 +1565,8 @@ public class JobSchedulerService extends com.android.server.SystemService * * @see #maybeQueueReadyJobsForExecutionLocked */ - private JobStatus getRescheduleJobForFailureLocked(JobStatus failureToReschedule) { + @VisibleForTesting + JobStatus getRescheduleJobForFailureLocked(JobStatus failureToReschedule) { final long elapsedNowMillis = sElapsedRealtimeClock.millis(); final JobInfo job = failureToReschedule.getJob(); @@ -1848,6 +1613,10 @@ public class JobSchedulerService extends com.android.server.SystemService elapsedNowMillis + delayMillis, JobStatus.NO_LATEST_RUNTIME, backoffAttempts, failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis()); + if (job.isPeriodic()) { + newJob.setOriginalLatestRunTimeElapsed( + failureToReschedule.getOriginalLatestRunTimeElapsed()); + } for (int ic=0; ic<mControllers.size(); ic++) { StateController controller = mControllers.get(ic); controller.rescheduleForFailureLocked(newJob, failureToReschedule); @@ -1868,23 +1637,41 @@ public class JobSchedulerService extends com.android.server.SystemService * @return A new job representing the execution criteria for this instantiation of the * recurring job. */ - private JobStatus getRescheduleJobForPeriodic(JobStatus periodicToReschedule) { + @VisibleForTesting + JobStatus getRescheduleJobForPeriodic(JobStatus periodicToReschedule) { final long elapsedNow = sElapsedRealtimeClock.millis(); - // Compute how much of the period is remaining. - long runEarly = 0L; - - // If this periodic was rescheduled it won't have a deadline. - if (periodicToReschedule.hasDeadlineConstraint()) { - runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0L); + final long newLatestRuntimeElapsed; + final long period = periodicToReschedule.getJob().getIntervalMillis(); + final long latestRunTimeElapsed = periodicToReschedule.getOriginalLatestRunTimeElapsed(); + final long flex = periodicToReschedule.getJob().getFlexMillis(); + + if (elapsedNow > latestRunTimeElapsed) { + // The job ran past its expected run window. Have it count towards the current window + // and schedule a new job for the next window. + if (DEBUG) { + Slog.i(TAG, "Periodic job ran after its intended window."); + } + final long diffMs = (elapsedNow - latestRunTimeElapsed); + int numSkippedWindows = (int) (diffMs / period) + 1; // +1 to include original window + if (period != flex && diffMs > Math.min(30 * MINUTE_IN_MILLIS, (period - flex) / 2)) { + if (DEBUG) { + Slog.d(TAG, "Custom flex job ran too close to next window."); + } + // For custom flex periods, if the job was run too close to the next window, + // skip the next window and schedule for the following one. + numSkippedWindows += 1; + } + newLatestRuntimeElapsed = latestRunTimeElapsed + (period * numSkippedWindows); + } else { + newLatestRuntimeElapsed = latestRunTimeElapsed + period; } - long flex = periodicToReschedule.getJob().getFlexMillis(); - long period = periodicToReschedule.getJob().getIntervalMillis(); - long newLatestRuntimeElapsed = elapsedNow + runEarly + period; - long newEarliestRunTimeElapsed = newLatestRuntimeElapsed - flex; + + final long newEarliestRunTimeElapsed = newLatestRuntimeElapsed - flex; if (DEBUG) { Slog.v(TAG, "Rescheduling executed periodic. New execution window [" + - newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s"); + newEarliestRunTimeElapsed / 1000 + ", " + newLatestRuntimeElapsed / 1000 + + "]s"); } return new JobStatus(periodicToReschedule, getCurrentHeartbeat(), newEarliestRunTimeElapsed, newLatestRuntimeElapsed, @@ -3424,6 +3211,11 @@ public class JobSchedulerService extends com.android.server.SystemService }; synchronized (mLock) { mConstants.dump(pw); + for (StateController controller : mControllers) { + pw.increaseIndent(); + controller.dumpConstants(pw); + pw.decreaseIndent(); + } pw.println(); pw.println(" Heartbeat:"); @@ -3614,7 +3406,13 @@ public class JobSchedulerService extends com.android.server.SystemService }; synchronized (mLock) { - mConstants.dump(proto, JobSchedulerServiceDumpProto.SETTINGS); + final long settingsToken = proto.start(JobSchedulerServiceDumpProto.SETTINGS); + mConstants.dump(proto); + for (StateController controller : mControllers) { + controller.dumpConstants(proto); + } + proto.end(settingsToken); + proto.write(JobSchedulerServiceDumpProto.CURRENT_HEARTBEAT, mHeartbeat); proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[0]); proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT, mNextBucketHeartbeat[1]); diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java index 48f21e446edc..fd20e116d82a 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -161,6 +161,12 @@ public final class JobStatus { */ private final long latestRunTimeElapsedMillis; + /** + * Valid only for periodic jobs. The original latest point in the future at which this + * job was expected to run. + */ + private long mOriginalLatestRunTimeElapsedMillis; + /** How many times this job has failed, used to compute back-off. */ private final int numFailures; @@ -394,6 +400,7 @@ public final class JobStatus { this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis; this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis; + this.mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsedMillis; this.numFailures = numFailures; int requiredConstraints = job.getConstraintFlags(); @@ -871,6 +878,14 @@ public final class JobStatus { return latestRunTimeElapsedMillis; } + public long getOriginalLatestRunTimeElapsed() { + return mOriginalLatestRunTimeElapsedMillis; + } + + public void setOriginalLatestRunTimeElapsed(long latestRunTimeElapsed) { + mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsed; + } + /** * Return the fractional position of "now" within the "run time" window of * this job. diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java index 11f0939a27d6..2a9d3f30c782 100644 --- a/services/core/java/com/android/server/job/controllers/QuotaController.java +++ b/services/core/java/com/android/server/job/controllers/QuotaController.java @@ -34,9 +34,12 @@ import android.app.IUidObserver; import android.app.usage.UsageStatsManagerInternal; import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.database.ContentObserver; +import android.net.Uri; import android.os.BatteryManager; import android.os.BatteryManagerInternal; import android.os.Handler; @@ -44,8 +47,10 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; +import android.provider.Settings; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.KeyValueListParser; import android.util.Log; import android.util.Slog; import android.util.SparseArray; @@ -57,6 +62,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; +import com.android.server.job.ConstantsProto; import com.android.server.job.JobSchedulerService; import com.android.server.job.StateControllerProto; @@ -354,6 +360,7 @@ public final class QuotaController extends StateController { private final AlarmManager mAlarmManager; private final ChargingTracker mChargeTracker; private final Handler mHandler; + private final QcConstants mQcConstants; private volatile boolean mInParole; @@ -489,6 +496,7 @@ public final class QuotaController extends StateController { mChargeTracker.startTracking(); mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); + mQcConstants = new QcConstants(mHandler); final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); mContext.registerReceiverAsUser(mPackageAddedReceiver, UserHandle.ALL, filter, null, null); @@ -506,7 +514,12 @@ public final class QuotaController extends StateController { // ignored; both services live in system_server } - onConstantsUpdatedLocked(); + mShouldThrottle = !mConstants.USE_HEARTBEATS; + } + + @Override + public void onSystemServicesReady() { + mQcConstants.start(mContext.getContentResolver()); } @Override @@ -581,89 +594,9 @@ public final class QuotaController extends StateController { @Override public void onConstantsUpdatedLocked() { - boolean changed = false; if (mShouldThrottle == mConstants.USE_HEARTBEATS) { mShouldThrottle = !mConstants.USE_HEARTBEATS; - changed = true; - } - long newAllowedTimeMs = Math.min(MAX_PERIOD_MS, - Math.max(MINUTE_IN_MILLIS, mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS)); - if (mAllowedTimePerPeriodMs != newAllowedTimeMs) { - mAllowedTimePerPeriodMs = newAllowedTimeMs; - mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs; - changed = true; - } - long newQuotaBufferMs = Math.max(0, - Math.min(5 * MINUTE_IN_MILLIS, mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS)); - if (mQuotaBufferMs != newQuotaBufferMs) { - mQuotaBufferMs = newQuotaBufferMs; - mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs; - mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs; - changed = true; - } - long newActivePeriodMs = Math.max(mAllowedTimePerPeriodMs, - Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS)); - if (mBucketPeriodsMs[ACTIVE_INDEX] != newActivePeriodMs) { - mBucketPeriodsMs[ACTIVE_INDEX] = newActivePeriodMs; - changed = true; - } - long newWorkingPeriodMs = Math.max(mAllowedTimePerPeriodMs, - Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS)); - if (mBucketPeriodsMs[WORKING_INDEX] != newWorkingPeriodMs) { - mBucketPeriodsMs[WORKING_INDEX] = newWorkingPeriodMs; - changed = true; - } - long newFrequentPeriodMs = Math.max(mAllowedTimePerPeriodMs, - Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS)); - if (mBucketPeriodsMs[FREQUENT_INDEX] != newFrequentPeriodMs) { - mBucketPeriodsMs[FREQUENT_INDEX] = newFrequentPeriodMs; - changed = true; - } - long newRarePeriodMs = Math.max(mAllowedTimePerPeriodMs, - Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS)); - if (mBucketPeriodsMs[RARE_INDEX] != newRarePeriodMs) { - mBucketPeriodsMs[RARE_INDEX] = newRarePeriodMs; - changed = true; - } - long newMaxExecutionTimeMs = Math.max(60 * MINUTE_IN_MILLIS, - Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS)); - if (mMaxExecutionTimeMs != newMaxExecutionTimeMs) { - mMaxExecutionTimeMs = newMaxExecutionTimeMs; - mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs; - changed = true; - } - int newMaxCountPerAllowedPeriod = Math.max(10, - mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME); - if (mMaxJobCountPerAllowedTime != newMaxCountPerAllowedPeriod) { - mMaxJobCountPerAllowedTime = newMaxCountPerAllowedPeriod; - changed = true; - } - int newActiveMaxJobCount = Math.max(mMaxJobCountPerAllowedTime, - Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE)); - if (mMaxBucketJobCounts[ACTIVE_INDEX] != newActiveMaxJobCount) { - mMaxBucketJobCounts[ACTIVE_INDEX] = newActiveMaxJobCount; - changed = true; - } - int newWorkingMaxJobCount = Math.max(mMaxJobCountPerAllowedTime, - Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING)); - if (mMaxBucketJobCounts[WORKING_INDEX] != newWorkingMaxJobCount) { - mMaxBucketJobCounts[WORKING_INDEX] = newWorkingMaxJobCount; - changed = true; - } - int newFrequentMaxJobCount = Math.max(mMaxJobCountPerAllowedTime, - Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT)); - if (mMaxBucketJobCounts[FREQUENT_INDEX] != newFrequentMaxJobCount) { - mMaxBucketJobCounts[FREQUENT_INDEX] = newFrequentMaxJobCount; - changed = true; - } - int newRareMaxJobCount = Math.max(mMaxJobCountPerAllowedTime, - Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE)); - if (mMaxBucketJobCounts[RARE_INDEX] != newRareMaxJobCount) { - mMaxBucketJobCounts[RARE_INDEX] = newRareMaxJobCount; - changed = true; - } - if (changed) { // Update job bookkeeping out of band. BackgroundThread.getHandler().post(() -> { synchronized (mLock) { @@ -1891,6 +1824,311 @@ public final class QuotaController extends StateController { } } + @VisibleForTesting + class QcConstants extends ContentObserver { + private ContentResolver mResolver; + private final KeyValueListParser mParser = new KeyValueListParser(','); + + private static final String KEY_ALLOWED_TIME_PER_PERIOD_MS = "allowed_time_per_period_ms"; + private static final String KEY_IN_QUOTA_BUFFER_MS = "in_quota_buffer_ms"; + private static final String KEY_WINDOW_SIZE_ACTIVE_MS = "window_size_active_ms"; + private static final String KEY_WINDOW_SIZE_WORKING_MS = "window_size_working_ms"; + private static final String KEY_WINDOW_SIZE_FREQUENT_MS = "window_size_frequent_ms"; + private static final String KEY_WINDOW_SIZE_RARE_MS = "window_size_rare_ms"; + private static final String KEY_MAX_EXECUTION_TIME_MS = "max_execution_time_ms"; + private static final String KEY_MAX_JOB_COUNT_ACTIVE = "max_job_count_active"; + private static final String KEY_MAX_JOB_COUNT_WORKING = "max_job_count_working"; + private static final String KEY_MAX_JOB_COUNT_FREQUENT = "max_job_count_frequent"; + private static final String KEY_MAX_JOB_COUNT_RARE = "max_job_count_rare"; + private static final String KEY_MAX_JOB_COUNT_PER_ALLOWED_TIME = + "max_count_per_allowed_time"; + + private static final long DEFAULT_ALLOWED_TIME_PER_PERIOD_MS = + 10 * 60 * 1000L; // 10 minutes + private static final long DEFAULT_IN_QUOTA_BUFFER_MS = + 30 * 1000L; // 30 seconds + private static final long DEFAULT_WINDOW_SIZE_ACTIVE_MS = + 10 * 60 * 1000L; // 10 minutes for ACTIVE -- ACTIVE apps can run jobs at any time + private static final long DEFAULT_WINDOW_SIZE_WORKING_MS = + 2 * 60 * 60 * 1000L; // 2 hours + private static final long DEFAULT_WINDOW_SIZE_FREQUENT_MS = + 8 * 60 * 60 * 1000L; // 8 hours + private static final long DEFAULT_WINDOW_SIZE_RARE_MS = + 24 * 60 * 60 * 1000L; // 24 hours + private static final long DEFAULT_MAX_EXECUTION_TIME_MS = + 4 * 60 * 60 * 1000L; // 4 hours + private static final int DEFAULT_MAX_JOB_COUNT_ACTIVE = + 200; // 1200/hr + private static final int DEFAULT_MAX_JOB_COUNT_WORKING = + 1200; // 600/hr + private static final int DEFAULT_MAX_JOB_COUNT_FREQUENT = + 1800; // 225/hr + private static final int DEFAULT_MAX_JOB_COUNT_RARE = + 2400; // 100/hr + private static final int DEFAULT_MAX_JOB_COUNT_PER_ALLOWED_TIME = 20; + + /** How much time each app will have to run jobs within their standby bucket window. */ + public long ALLOWED_TIME_PER_PERIOD_MS = DEFAULT_ALLOWED_TIME_PER_PERIOD_MS; + + /** + * How much time the package should have before transitioning from out-of-quota to in-quota. + * This should not affect processing if the package is already in-quota. + */ + public long IN_QUOTA_BUFFER_MS = DEFAULT_IN_QUOTA_BUFFER_MS; + + /** + * The quota window size of the particular standby bucket. Apps in this standby bucket are + * expected to run only {@link #ALLOWED_TIME_PER_PERIOD_MS} within the past + * WINDOW_SIZE_MS. + */ + public long WINDOW_SIZE_ACTIVE_MS = DEFAULT_WINDOW_SIZE_ACTIVE_MS; + + /** + * The quota window size of the particular standby bucket. Apps in this standby bucket are + * expected to run only {@link #ALLOWED_TIME_PER_PERIOD_MS} within the past + * WINDOW_SIZE_MS. + */ + public long WINDOW_SIZE_WORKING_MS = DEFAULT_WINDOW_SIZE_WORKING_MS; + + /** + * The quota window size of the particular standby bucket. Apps in this standby bucket are + * expected to run only {@link #ALLOWED_TIME_PER_PERIOD_MS} within the past + * WINDOW_SIZE_MS. + */ + public long WINDOW_SIZE_FREQUENT_MS = DEFAULT_WINDOW_SIZE_FREQUENT_MS; + + /** + * The quota window size of the particular standby bucket. Apps in this standby bucket are + * expected to run only {@link #ALLOWED_TIME_PER_PERIOD_MS} within the past + * WINDOW_SIZE_MS. + */ + public long WINDOW_SIZE_RARE_MS = DEFAULT_WINDOW_SIZE_RARE_MS; + + /** + * The maximum amount of time an app can have its jobs running within a 24 hour window. + */ + public long MAX_EXECUTION_TIME_MS = DEFAULT_MAX_EXECUTION_TIME_MS; + + /** + * The maximum number of jobs an app can run within this particular standby bucket's + * window size. + */ + public int MAX_JOB_COUNT_ACTIVE = DEFAULT_MAX_JOB_COUNT_ACTIVE; + + /** + * The maximum number of jobs an app can run within this particular standby bucket's + * window size. + */ + public int MAX_JOB_COUNT_WORKING = DEFAULT_MAX_JOB_COUNT_WORKING; + + /** + * The maximum number of jobs an app can run within this particular standby bucket's + * window size. + */ + public int MAX_JOB_COUNT_FREQUENT = DEFAULT_MAX_JOB_COUNT_FREQUENT; + + /** + * The maximum number of jobs an app can run within this particular standby bucket's + * window size. + */ + public int MAX_JOB_COUNT_RARE = DEFAULT_MAX_JOB_COUNT_RARE; + + /** + * The maximum number of jobs that can run within the past + * {@link #ALLOWED_TIME_PER_PERIOD_MS}. + */ + public int MAX_JOB_COUNT_PER_ALLOWED_TIME = DEFAULT_MAX_JOB_COUNT_PER_ALLOWED_TIME; + + QcConstants(Handler handler) { + super(handler); + } + + private void start(ContentResolver resolver) { + mResolver = resolver; + mResolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS), false, this); + updateConstants(); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + final String constants = Settings.Global.getString( + mResolver, Settings.Global.JOB_SCHEDULER_QUOTA_CONTROLLER_CONSTANTS); + + try { + mParser.setString(constants); + } catch (Exception e) { + // Failed to parse the settings string, log this and move on with defaults. + Slog.e(TAG, "Bad jobscheduler quota controller settings", e); + } + + ALLOWED_TIME_PER_PERIOD_MS = mParser.getDurationMillis( + KEY_ALLOWED_TIME_PER_PERIOD_MS, DEFAULT_ALLOWED_TIME_PER_PERIOD_MS); + IN_QUOTA_BUFFER_MS = mParser.getDurationMillis( + KEY_IN_QUOTA_BUFFER_MS, DEFAULT_IN_QUOTA_BUFFER_MS); + WINDOW_SIZE_ACTIVE_MS = mParser.getDurationMillis( + KEY_WINDOW_SIZE_ACTIVE_MS, DEFAULT_WINDOW_SIZE_ACTIVE_MS); + WINDOW_SIZE_WORKING_MS = mParser.getDurationMillis( + KEY_WINDOW_SIZE_WORKING_MS, DEFAULT_WINDOW_SIZE_WORKING_MS); + WINDOW_SIZE_FREQUENT_MS = mParser.getDurationMillis( + KEY_WINDOW_SIZE_FREQUENT_MS, DEFAULT_WINDOW_SIZE_FREQUENT_MS); + WINDOW_SIZE_RARE_MS = mParser.getDurationMillis( + KEY_WINDOW_SIZE_RARE_MS, DEFAULT_WINDOW_SIZE_RARE_MS); + MAX_EXECUTION_TIME_MS = mParser.getDurationMillis( + KEY_MAX_EXECUTION_TIME_MS, DEFAULT_MAX_EXECUTION_TIME_MS); + MAX_JOB_COUNT_ACTIVE = mParser.getInt( + KEY_MAX_JOB_COUNT_ACTIVE, DEFAULT_MAX_JOB_COUNT_ACTIVE); + MAX_JOB_COUNT_WORKING = mParser.getInt( + KEY_MAX_JOB_COUNT_WORKING, DEFAULT_MAX_JOB_COUNT_WORKING); + MAX_JOB_COUNT_FREQUENT = mParser.getInt( + KEY_MAX_JOB_COUNT_FREQUENT, DEFAULT_MAX_JOB_COUNT_FREQUENT); + MAX_JOB_COUNT_RARE = mParser.getInt( + KEY_MAX_JOB_COUNT_RARE, DEFAULT_MAX_JOB_COUNT_RARE); + MAX_JOB_COUNT_PER_ALLOWED_TIME = mParser.getInt( + KEY_MAX_JOB_COUNT_PER_ALLOWED_TIME, DEFAULT_MAX_JOB_COUNT_PER_ALLOWED_TIME); + + updateConstants(); + } + + @VisibleForTesting + void updateConstants() { + synchronized (mLock) { + boolean changed = false; + + long newAllowedTimeMs = Math.min(MAX_PERIOD_MS, + Math.max(MINUTE_IN_MILLIS, ALLOWED_TIME_PER_PERIOD_MS)); + if (mAllowedTimePerPeriodMs != newAllowedTimeMs) { + mAllowedTimePerPeriodMs = newAllowedTimeMs; + mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs; + changed = true; + } + long newQuotaBufferMs = Math.max(0, + Math.min(5 * MINUTE_IN_MILLIS, IN_QUOTA_BUFFER_MS)); + if (mQuotaBufferMs != newQuotaBufferMs) { + mQuotaBufferMs = newQuotaBufferMs; + mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs; + mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs; + changed = true; + } + long newActivePeriodMs = Math.max(mAllowedTimePerPeriodMs, + Math.min(MAX_PERIOD_MS, WINDOW_SIZE_ACTIVE_MS)); + if (mBucketPeriodsMs[ACTIVE_INDEX] != newActivePeriodMs) { + mBucketPeriodsMs[ACTIVE_INDEX] = newActivePeriodMs; + changed = true; + } + long newWorkingPeriodMs = Math.max(mAllowedTimePerPeriodMs, + Math.min(MAX_PERIOD_MS, WINDOW_SIZE_WORKING_MS)); + if (mBucketPeriodsMs[WORKING_INDEX] != newWorkingPeriodMs) { + mBucketPeriodsMs[WORKING_INDEX] = newWorkingPeriodMs; + changed = true; + } + long newFrequentPeriodMs = Math.max(mAllowedTimePerPeriodMs, + Math.min(MAX_PERIOD_MS, WINDOW_SIZE_FREQUENT_MS)); + if (mBucketPeriodsMs[FREQUENT_INDEX] != newFrequentPeriodMs) { + mBucketPeriodsMs[FREQUENT_INDEX] = newFrequentPeriodMs; + changed = true; + } + long newRarePeriodMs = Math.max(mAllowedTimePerPeriodMs, + Math.min(MAX_PERIOD_MS, WINDOW_SIZE_RARE_MS)); + if (mBucketPeriodsMs[RARE_INDEX] != newRarePeriodMs) { + mBucketPeriodsMs[RARE_INDEX] = newRarePeriodMs; + changed = true; + } + long newMaxExecutionTimeMs = Math.max(60 * MINUTE_IN_MILLIS, + Math.min(MAX_PERIOD_MS, MAX_EXECUTION_TIME_MS)); + if (mMaxExecutionTimeMs != newMaxExecutionTimeMs) { + mMaxExecutionTimeMs = newMaxExecutionTimeMs; + mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs; + changed = true; + } + int newMaxCountPerAllowedPeriod = Math.max(10, + MAX_JOB_COUNT_PER_ALLOWED_TIME); + if (mMaxJobCountPerAllowedTime != newMaxCountPerAllowedPeriod) { + mMaxJobCountPerAllowedTime = newMaxCountPerAllowedPeriod; + changed = true; + } + int newActiveMaxJobCount = Math.max(mMaxJobCountPerAllowedTime, + Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_ACTIVE)); + if (mMaxBucketJobCounts[ACTIVE_INDEX] != newActiveMaxJobCount) { + mMaxBucketJobCounts[ACTIVE_INDEX] = newActiveMaxJobCount; + changed = true; + } + int newWorkingMaxJobCount = Math.max(mMaxJobCountPerAllowedTime, + Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_WORKING)); + if (mMaxBucketJobCounts[WORKING_INDEX] != newWorkingMaxJobCount) { + mMaxBucketJobCounts[WORKING_INDEX] = newWorkingMaxJobCount; + changed = true; + } + int newFrequentMaxJobCount = Math.max(mMaxJobCountPerAllowedTime, + Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_FREQUENT)); + if (mMaxBucketJobCounts[FREQUENT_INDEX] != newFrequentMaxJobCount) { + mMaxBucketJobCounts[FREQUENT_INDEX] = newFrequentMaxJobCount; + changed = true; + } + int newRareMaxJobCount = Math.max(mMaxJobCountPerAllowedTime, + Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_RARE)); + if (mMaxBucketJobCounts[RARE_INDEX] != newRareMaxJobCount) { + mMaxBucketJobCounts[RARE_INDEX] = newRareMaxJobCount; + changed = true; + } + + if (changed && mShouldThrottle) { + // Update job bookkeeping out of band. + BackgroundThread.getHandler().post(() -> { + synchronized (mLock) { + maybeUpdateAllConstraintsLocked(); + } + }); + } + } + } + + private void dump(IndentingPrintWriter pw) { + pw.println(); + pw.println("QuotaController:"); + pw.increaseIndent(); + pw.printPair(KEY_ALLOWED_TIME_PER_PERIOD_MS, ALLOWED_TIME_PER_PERIOD_MS).println(); + pw.printPair(KEY_IN_QUOTA_BUFFER_MS, IN_QUOTA_BUFFER_MS).println(); + pw.printPair(KEY_WINDOW_SIZE_ACTIVE_MS, WINDOW_SIZE_ACTIVE_MS).println(); + pw.printPair(KEY_WINDOW_SIZE_WORKING_MS, WINDOW_SIZE_WORKING_MS).println(); + pw.printPair(KEY_WINDOW_SIZE_FREQUENT_MS, WINDOW_SIZE_FREQUENT_MS).println(); + pw.printPair(KEY_WINDOW_SIZE_RARE_MS, WINDOW_SIZE_RARE_MS).println(); + pw.printPair(KEY_MAX_EXECUTION_TIME_MS, MAX_EXECUTION_TIME_MS).println(); + pw.printPair(KEY_MAX_JOB_COUNT_ACTIVE, MAX_JOB_COUNT_ACTIVE).println(); + pw.printPair(KEY_MAX_JOB_COUNT_WORKING, MAX_JOB_COUNT_WORKING).println(); + pw.printPair(KEY_MAX_JOB_COUNT_FREQUENT, MAX_JOB_COUNT_FREQUENT).println(); + pw.printPair(KEY_MAX_JOB_COUNT_RARE, MAX_JOB_COUNT_RARE).println(); + pw.printPair(KEY_MAX_JOB_COUNT_PER_ALLOWED_TIME, MAX_JOB_COUNT_PER_ALLOWED_TIME) + .println(); + pw.decreaseIndent(); + } + + private void dump(ProtoOutputStream proto) { + final long qcToken = proto.start(ConstantsProto.QUOTA_CONTROLLER); + proto.write(ConstantsProto.QuotaController.ALLOWED_TIME_PER_PERIOD_MS, + ALLOWED_TIME_PER_PERIOD_MS); + proto.write(ConstantsProto.QuotaController.IN_QUOTA_BUFFER_MS, IN_QUOTA_BUFFER_MS); + proto.write(ConstantsProto.QuotaController.ACTIVE_WINDOW_SIZE_MS, + WINDOW_SIZE_ACTIVE_MS); + proto.write(ConstantsProto.QuotaController.WORKING_WINDOW_SIZE_MS, + WINDOW_SIZE_WORKING_MS); + proto.write(ConstantsProto.QuotaController.FREQUENT_WINDOW_SIZE_MS, + WINDOW_SIZE_FREQUENT_MS); + proto.write(ConstantsProto.QuotaController.RARE_WINDOW_SIZE_MS, WINDOW_SIZE_RARE_MS); + proto.write(ConstantsProto.QuotaController.MAX_EXECUTION_TIME_MS, + MAX_EXECUTION_TIME_MS); + proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_ACTIVE, MAX_JOB_COUNT_ACTIVE); + proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_WORKING, + MAX_JOB_COUNT_WORKING); + proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_FREQUENT, + MAX_JOB_COUNT_FREQUENT); + proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_RARE, MAX_JOB_COUNT_RARE); + proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_PER_ALLOWED_TIME, + MAX_JOB_COUNT_PER_ALLOWED_TIME); + proto.end(qcToken); + } + } + //////////////////////// TESTING HELPERS ///////////////////////////// @VisibleForTesting @@ -1943,6 +2181,12 @@ public final class QuotaController extends StateController { return mTimingSessions.get(userId, packageName); } + @VisibleForTesting + @NonNull + QcConstants getQcConstants() { + return mQcConstants; + } + //////////////////////////// DATA DUMP ////////////////////////////// @Override @@ -2188,4 +2432,14 @@ public final class QuotaController extends StateController { proto.end(mToken); proto.end(token); } + + @Override + public void dumpConstants(IndentingPrintWriter pw) { + mQcConstants.dump(pw); + } + + @Override + public void dumpConstants(ProtoOutputStream proto) { + mQcConstants.dump(proto); + } } diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java index 74628fb9b502..51be38be990d 100644 --- a/services/core/java/com/android/server/job/controllers/StateController.java +++ b/services/core/java/com/android/server/job/controllers/StateController.java @@ -52,6 +52,13 @@ public abstract class StateController { } /** + * Called when the system boot phase has reached + * {@link com.android.server.SystemService#PHASE_SYSTEM_SERVICES_READY}. + */ + public void onSystemServicesReady() { + } + + /** * Implement the logic here to decide whether a job should be tracked by this controller. * This logic is put here so the JobManager can be completely agnostic of Controller logic. * Also called when updating a task, so implementing controllers have to be aware of @@ -127,4 +134,12 @@ public abstract class StateController { Predicate<JobStatus> predicate); public abstract void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, Predicate<JobStatus> predicate); + + /** Dump any internal constants the Controller may have. */ + public void dumpConstants(IndentingPrintWriter pw) { + } + + /** Dump any internal constants the Controller may have. */ + public void dumpConstants(ProtoOutputStream proto) { + } } diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java index 70deb38080b4..ababad961c2d 100644 --- a/services/core/java/com/android/server/job/controllers/TimeController.java +++ b/services/core/java/com/android/server/job/controllers/TimeController.java @@ -18,13 +18,20 @@ package com.android.server.job.controllers; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlarmManager; import android.app.AlarmManager.OnAlarmListener; +import android.content.ContentResolver; import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; import android.os.Process; import android.os.UserHandle; import android.os.WorkSource; +import android.provider.Settings; +import android.util.KeyValueListParser; import android.util.Log; import android.util.Slog; import android.util.TimeUtils; @@ -32,6 +39,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.job.ConstantsProto; import com.android.server.job.JobSchedulerService; import com.android.server.job.StateControllerProto; @@ -55,6 +63,9 @@ public final class TimeController extends StateController { /** Delay alarm tag for logging purposes */ private final String DELAY_TAG = "*job.delay*"; + private final Handler mHandler; + private final TcConstants mTcConstants; + private long mNextJobExpiredElapsedMillis; private long mNextDelayExpiredElapsedMillis; @@ -70,6 +81,14 @@ public final class TimeController extends StateController { mNextJobExpiredElapsedMillis = Long.MAX_VALUE; mNextDelayExpiredElapsedMillis = Long.MAX_VALUE; mChainedAttributionEnabled = mService.isChainedAttributionEnabled(); + + mHandler = new Handler(mContext.getMainLooper()); + mTcConstants = new TcConstants(mHandler); + } + + @Override + public void onSystemServicesReady() { + mTcConstants.start(mContext.getContentResolver()); } /** @@ -118,7 +137,7 @@ public final class TimeController extends StateController { job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE; final long delayExpiredElapsed = job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE; - if (mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS) { + if (mTcConstants.SKIP_NOT_READY_JOBS) { if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) { maybeUpdateDelayAlarmLocked(delayExpiredElapsed, ws); } @@ -148,14 +167,8 @@ public final class TimeController extends StateController { } @Override - public void onConstantsUpdatedLocked() { - checkExpiredDeadlinesAndResetAlarm(); - checkExpiredDelaysAndResetAlarm(); - } - - @Override public void evaluateStateLocked(JobStatus job) { - if (!mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS) { + if (!mTcConstants.SKIP_NOT_READY_JOBS) { return; } @@ -248,7 +261,7 @@ public final class TimeController extends StateController { } it.remove(); } else { // Sorted by expiry time, so take the next one and stop. - if (mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS + if (mTcConstants.SKIP_NOT_READY_JOBS && !wouldBeReadyWithConstraintLocked( job, JobStatus.CONSTRAINT_DEADLINE)) { if (DEBUG) { @@ -308,7 +321,7 @@ public final class TimeController extends StateController { ready = true; } } else { - if (mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS + if (mTcConstants.SKIP_NOT_READY_JOBS && !wouldBeReadyWithConstraintLocked( job, JobStatus.CONSTRAINT_TIMING_DELAY)) { if (DEBUG) { @@ -439,6 +452,87 @@ public final class TimeController extends StateController { } }; + @VisibleForTesting + void recheckAlarmsLocked() { + checkExpiredDeadlinesAndResetAlarm(); + checkExpiredDelaysAndResetAlarm(); + } + + @VisibleForTesting + class TcConstants extends ContentObserver { + private ContentResolver mResolver; + private final KeyValueListParser mParser = new KeyValueListParser(','); + + private static final String KEY_SKIP_NOT_READY_JOBS = "skip_not_ready_jobs"; + + private static final boolean DEFAULT_SKIP_NOT_READY_JOBS = true; + + /** + * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't + * ready now. + */ + public boolean SKIP_NOT_READY_JOBS = DEFAULT_SKIP_NOT_READY_JOBS; + + /** + * Creates a content observer. + * + * @param handler The handler to run {@link #onChange} on, or null if none. + */ + TcConstants(Handler handler) { + super(handler); + } + + private void start(ContentResolver resolver) { + mResolver = resolver; + mResolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS), false, this); + onChange(true, null); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + final String constants = Settings.Global.getString( + mResolver, Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS); + + try { + mParser.setString(constants); + } catch (Exception e) { + // Failed to parse the settings string, log this and move on with defaults. + Slog.e(TAG, "Bad jobscheduler time controller settings", e); + } + + final boolean oldVal = SKIP_NOT_READY_JOBS; + SKIP_NOT_READY_JOBS = mParser.getBoolean( + KEY_SKIP_NOT_READY_JOBS, DEFAULT_SKIP_NOT_READY_JOBS); + + if (oldVal != SKIP_NOT_READY_JOBS) { + synchronized (mLock) { + recheckAlarmsLocked(); + } + } + } + + private void dump(IndentingPrintWriter pw) { + pw.println(); + pw.println("TimeController:"); + pw.increaseIndent(); + pw.printPair(KEY_SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS).println(); + pw.decreaseIndent(); + } + + private void dump(ProtoOutputStream proto) { + final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER); + proto.write(ConstantsProto.TimeController.SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS); + proto.end(tcToken); + } + } + + @VisibleForTesting + @NonNull + TcConstants getTcConstants() { + return mTcConstants; + } + @Override public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) { @@ -513,4 +607,14 @@ public final class TimeController extends StateController { proto.end(mToken); proto.end(token); } + + @Override + public void dumpConstants(IndentingPrintWriter pw) { + mTcConstants.dump(pw); + } + + @Override + public void dumpConstants(ProtoOutputStream proto) { + mTcConstants.dump(proto); + } } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java index c73965024c55..1dffcf9c89a6 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java @@ -333,6 +333,7 @@ public class RecoverableKeyStoreDb { String[] selectionArguments = new String[] {String.valueOf(userId)}; ensureUserMetadataEntryExists(userId); + invalidateKeysForUser(userId); return db.update(UserMetadataEntry.TABLE_NAME, values, selection, selectionArguments); } @@ -394,16 +395,13 @@ public class RecoverableKeyStoreDb { /** * Updates status of old keys to {@code RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE}. */ - public void invalidateKeysWithOldGenerationId(int userId, int newGenerationId) { + public void invalidateKeysForUser(int userId) { SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS, RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE); - String selection = - KeysEntry.COLUMN_NAME_USER_ID + " = ? AND " - + KeysEntry.COLUMN_NAME_GENERATION_ID + " < ?"; - db.update(KeysEntry.TABLE_NAME, values, selection, - new String[] {String.valueOf(userId), String.valueOf(newGenerationId)}); + String selection = KeysEntry.COLUMN_NAME_USER_ID + " = ?"; + db.update(KeysEntry.TABLE_NAME, values, selection, new String[] {String.valueOf(userId)}); } /** diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index c6f6c50a308d..19ff2c11d14c 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -1164,6 +1164,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Carrier might want to manage notifications themselves final PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId); + if (!CarrierConfigManager.isConfigForIdentifiedCarrier(config)) { + if (LOGV) Slog.v(TAG, "isConfigForIdentifiedCarrier returned false"); + // Don't show notifications until we confirm that the loaded config is from an + // identified carrier, which may want to manage their own notifications. This method + // should be called every time the carrier config changes anyways, and there's no + // reason to alert if there isn't a carrier. + return; + } + final boolean notifyWarning = getBooleanDefeatingNullable(config, KEY_DATA_WARNING_NOTIFICATION_BOOL, true); final boolean notifyLimit = getBooleanDefeatingNullable(config, diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 21a862a5ec6c..55191dbbbf40 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1811,14 +1811,15 @@ public class NotificationManagerService extends SystemService { } private void registerDeviceConfigChange() { - DeviceConfig.addOnPropertyChangedListener( + DeviceConfig.addOnPropertiesChangedListener( DeviceConfig.NAMESPACE_SYSTEMUI, getContext().getMainExecutor(), - (namespace, name, value) -> { - if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) { + (properties) -> { + if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) { return; } - if (SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE.equals(name)) { + if (properties.getKeyset() + .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) { mAssistants.resetDefaultAssistantsIfNecessary(); } }); diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index ee07c7de9dbc..209ccdae75d0 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -720,6 +720,26 @@ public final class OverlayManagerService extends SystemService { } @Override + public String[] getDefaultOverlayPackages() throws RemoteException { + try { + traceBegin(TRACE_TAG_RRO, "OMS#getDefaultOverlayPackages"); + getContext().enforceCallingOrSelfPermission( + android.Manifest.permission.MODIFY_THEME_OVERLAY, null); + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + return mImpl.getDefaultOverlayPackages(); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } finally { + traceEnd(TRACE_TAG_RRO); + } + } + + @Override public void onShellCommand(@NonNull final FileDescriptor in, @NonNull final FileDescriptor out, @NonNull final FileDescriptor err, @NonNull final String[] args, @NonNull final ShellCallback callback, diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index 3a84b1e18e36..092dbc817e32 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -641,6 +641,10 @@ final class OverlayManagerServiceImpl { pw.println("Default overlays: " + TextUtils.join(";", mDefaultOverlays)); } + @NonNull String[] getDefaultOverlayPackages() { + return mDefaultOverlays; + } + List<String> getEnabledOverlayPackageNames(@NonNull final String targetPackageName, final int userId) { final List<OverlayInfo> overlays = mSettings.getOverlaysForTarget(targetPackageName, diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index 5430f4c8daa0..497385fef39c 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -22,22 +22,21 @@ import android.apex.ApexInfo; import android.apex.ApexInfoList; import android.apex.ApexSessionInfo; import android.apex.IApexService; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; +import android.os.HandlerThread; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; +import android.os.SystemClock; import android.sysprop.ApexProperties; import android.util.Slog; -import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; +import com.android.server.SystemService; import java.io.File; import java.io.PrintWriter; @@ -46,75 +45,108 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.CountDownLatch; import java.util.function.Function; import java.util.stream.Collectors; /** * ApexManager class handles communications with the apex service to perform operation and queries, * as well as providing caching to avoid unnecessary calls to the service. + * + * @hide */ -class ApexManager { - static final String TAG = "ApexManager"; - private final IApexService mApexService; - private final Context mContext; - private final Object mLock = new Object(); - @GuardedBy("mLock") +public final class ApexManager extends SystemService { + private static final String TAG = "ApexManager"; + private IApexService mApexService; + + private final CountDownLatch mActivePackagesCacheLatch = new CountDownLatch(1); private Map<String, PackageInfo> mActivePackagesCache; - ApexManager(Context context) { + private final CountDownLatch mApexFilesCacheLatch = new CountDownLatch(1); + private ApexInfo[] mApexFiles; + + public ApexManager(Context context) { + super(context); + } + + @Override + public void onStart() { try { mApexService = IApexService.Stub.asInterface( - ServiceManager.getServiceOrThrow("apexservice")); + ServiceManager.getServiceOrThrow("apexservice")); } catch (ServiceNotFoundException e) { throw new IllegalStateException("Required service apexservice not available"); } - mContext = context; + publishLocalService(ApexManager.class, this); + HandlerThread oneShotThread = new HandlerThread("ApexManagerOneShotHandler"); + oneShotThread.start(); + oneShotThread.getThreadHandler().post(this::initSequence); + oneShotThread.quitSafely(); } - void systemReady() { - mContext.registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - onBootCompleted(); - mContext.unregisterReceiver(this); - } - }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); + private void initSequence() { + populateApexFilesCache(); + parseApexFiles(); } - private void populateActivePackagesCacheIfNeeded() { - synchronized (mLock) { - if (mActivePackagesCache != null) { - return; - } + private void populateApexFilesCache() { + if (mApexFiles != null) { + return; + } + long startTimeMicros = SystemClock.currentTimeMicro(); + Slog.i(TAG, "Starting to populate apex files cache"); + try { + mApexFiles = mApexService.getActivePackages(); + Slog.i(TAG, "IPC to apexd finished in " + (SystemClock.currentTimeMicro() + - startTimeMicros) + " μs"); + } catch (RemoteException re) { + // TODO: make sure this error is propagated to system server. + Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); + re.rethrowAsRuntimeException(); + } + mApexFilesCacheLatch.countDown(); + Slog.i(TAG, "Finished populating apex files cache in " + (SystemClock.currentTimeMicro() + - startTimeMicros) + " μs"); + } + + private void parseApexFiles() { + waitForLatch(mApexFilesCacheLatch); + if (mApexFiles == null) { + throw new IllegalStateException("mApexFiles must be populated"); + } + long startTimeMicros = SystemClock.currentTimeMicro(); + Slog.i(TAG, "Starting to parse apex files"); + List<PackageInfo> list = new ArrayList<>(); + // TODO: this can be parallelized. + for (ApexInfo ai : mApexFiles) { try { - List<PackageInfo> list = new ArrayList<>(); - final ApexInfo[] activePkgs = mApexService.getActivePackages(); - for (ApexInfo ai : activePkgs) { - // If the device is using flattened APEX, don't report any APEX - // packages since they won't be managed or updated by PackageManager. - if ((new File(ai.packagePath)).isDirectory()) { - break; - } - try { - list.add(PackageParser.generatePackageInfoFromApex( - new File(ai.packagePath), PackageManager.GET_META_DATA - | PackageManager.GET_SIGNING_CERTIFICATES)); - } catch (PackageParserException pe) { - throw new IllegalStateException("Unable to parse: " + ai, pe); - } + // If the device is using flattened APEX, don't report any APEX + // packages since they won't be managed or updated by PackageManager. + if ((new File(ai.packagePath)).isDirectory()) { + break; } - mActivePackagesCache = list.stream().collect( - Collectors.toMap(p -> p.packageName, Function.identity())); - } catch (RemoteException re) { - Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); - throw new RuntimeException(re); + list.add(PackageParser.generatePackageInfoFromApex( + new File(ai.packagePath), PackageManager.GET_META_DATA + | PackageManager.GET_SIGNING_CERTIFICATES)); + } catch (PackageParserException pe) { + // TODO: make sure this error is propagated to system server. + throw new IllegalStateException("Unable to parse: " + ai, pe); } } + mActivePackagesCache = list.stream().collect( + Collectors.toMap(p -> p.packageName, Function.identity())); + mActivePackagesCacheLatch.countDown(); + Slog.i(TAG, "Finished parsing apex files in " + (SystemClock.currentTimeMicro() + - startTimeMicros) + " μs"); } /** * Retrieves information about an active APEX package. * + * <p>This method blocks caller thread until {@link #parseApexFiles()} succeeds. Note that in + * case {@link #parseApexFiles()}} throws an exception this method will never finish + * essentially putting device into a boot loop. + * * @param packageName the package name to look for. Note that this is the package name reported * in the APK container manifest (i.e. AndroidManifest.xml), which might * differ from the one reported in the APEX manifest (i.e. @@ -123,30 +155,43 @@ class ApexManager { * is not found. */ @Nullable PackageInfo getActivePackage(String packageName) { - populateActivePackagesCacheIfNeeded(); + waitForLatch(mActivePackagesCacheLatch); return mActivePackagesCache.get(packageName); } /** * Retrieves information about all active APEX packages. * + * <p>This method blocks caller thread until {@link #parseApexFiles()} succeeds. Note that in + * case {@link #parseApexFiles()}} throws an exception this method will never finish + * essentially putting device into a boot loop. + * * @return a Collection of PackageInfo object, each one containing information about a different * active package. */ Collection<PackageInfo> getActivePackages() { - populateActivePackagesCacheIfNeeded(); + waitForLatch(mActivePackagesCacheLatch); return mActivePackagesCache.values(); } /** * Checks if {@code packageName} is an apex package. * + * <p>This method blocks caller thread until {@link #populateApexFilesCache()} succeeds. Note + * that in case {@link #populateApexFilesCache()} throws an exception this method will never + * finish essentially putting device into a boot loop. + * * @param packageName package to check. * @return {@code true} if {@code packageName} is an apex package. */ boolean isApexPackage(String packageName) { - populateActivePackagesCacheIfNeeded(); - return mActivePackagesCache.containsKey(packageName); + waitForLatch(mApexFilesCacheLatch); + for (ApexInfo ai : mApexFiles) { + if (ai.packageName.equals(packageName)) { + return true; + } + } + return false; } /** @@ -274,6 +319,19 @@ class ApexManager { } /** + * Blocks current thread until {@code latch} has counted down to zero. + * + * @throws RuntimeException if thread was interrupted while waiting. + */ + private void waitForLatch(CountDownLatch latch) { + try { + latch.await(); + } catch (InterruptedException e) { + throw new RuntimeException("Interrupted waiting for cache to be populated", e); + } + } + + /** * Dumps various state information to the provided {@link PrintWriter} object. * * @param pw the {@link PrintWriter} object to send information to. @@ -286,7 +344,7 @@ class ApexManager { ipw.println("Active APEX packages:"); ipw.increaseIndent(); try { - populateActivePackagesCacheIfNeeded(); + waitForLatch(mActivePackagesCacheLatch); for (PackageInfo pi : mActivePackagesCache.values()) { if (packageName != null && !packageName.equals(pi.packageName)) { continue; @@ -331,8 +389,4 @@ class ApexManager { ipw.println("Couldn't communicate with apexd."); } } - - public void onBootCompleted() { - populateActivePackagesCacheIfNeeded(); - } } diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java index 3a7919a0d9ba..d6108b7cc390 100644 --- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java @@ -24,6 +24,7 @@ import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.AppOpsManager; import android.app.IApplicationThread; +import android.app.admin.DevicePolicyEventLogger; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -37,6 +38,7 @@ import android.os.Binder; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.stats.devicepolicy.DevicePolicyEnums; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; @@ -69,6 +71,11 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { verifyCallingPackage(callingPackage); + DevicePolicyEventLogger + .createEvent(DevicePolicyEnums.CROSS_PROFILE_APPS_GET_TARGET_USER_PROFILES) + .setStrings(new String[] {callingPackage}) + .write(); + return getTargetUserProfilesUnchecked( callingPackage, mInjector.getCallingUserId()); } @@ -85,6 +92,11 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { verifyCallingPackage(callingPackage); + DevicePolicyEventLogger + .createEvent(DevicePolicyEnums.CROSS_PROFILE_APPS_START_ACTIVITY_AS_USER) + .setStrings(new String[] {callingPackage}) + .write(); + final int callerUserId = mInjector.getCallingUserId(); final int callingUid = mInjector.getCallingUid(); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 74fb4b27100e..5f6e7399f3a7 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -2050,6 +2050,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { synchronized (mLock) { assertCallerIsOwnerOrRootLocked(); + if (isStagedAndInTerminalState()) { + // We keep the session in the database if it's in a finalized state. It will be + // removed by PackageInstallerService when the last update time is old enough. + // Also, in such cases cleanStageDir() has already been executed so no need to + // do it now. + return; + } if (mCommitted && params.isStaged) { synchronized (mLock) { mDestroyed = true; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e08af6f3521f..c0f09d205efe 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -939,6 +939,7 @@ public class PackageManagerService extends IPackageManager.Stub ComponentName mCustomResolverComponentName; boolean mResolverReplaced = false; + boolean mOkToReplacePersistentPackages = false; private final @Nullable ComponentName mIntentFilterVerifierComponent; private final @Nullable IntentFilterVerifier<ActivityIntentInfo> mIntentFilterVerifier; @@ -2374,6 +2375,8 @@ public class PackageManagerService extends IPackageManager.Stub public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { + mApexManager = LocalServices.getService(ApexManager.class); + LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager"); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START, @@ -2470,7 +2473,6 @@ public class PackageManagerService extends IPackageManager.Stub mProtectedPackages = new ProtectedPackages(mContext); - mApexManager = new ApexManager(context); synchronized (mInstallLock) { // writer synchronized (mPackages) { @@ -17324,7 +17326,8 @@ public class PackageManagerService extends IPackageManager.Stub + " target SDK " + oldTargetSdk + " does."); } // Prevent persistent apps from being updated - if ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0) { + if (((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0) + && !mOkToReplacePersistentPackages) { throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK, "Package " + oldPackage.packageName + " is a persistent app. " + "Persistent apps are not updateable."); @@ -18759,6 +18762,7 @@ public class PackageManagerService extends IPackageManager.Stub boolean installedStateChanged = false; if (deletedPs != null) { if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) { + final SparseBooleanArray changedUsers = new SparseBooleanArray(); synchronized (mPackages) { clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL); clearDefaultBrowserIfNeeded(packageName); @@ -18790,10 +18794,9 @@ public class PackageManagerService extends IPackageManager.Stub } } } + clearPackagePreferredActivitiesLPw( + deletedPs.name, changedUsers, UserHandle.USER_ALL); } - final SparseBooleanArray changedUsers = new SparseBooleanArray(); - clearPackagePreferredActivitiesLPw( - deletedPs.name, changedUsers, UserHandle.USER_ALL); if (changedUsers.size() > 0) { updateDefaultHomeNotLocked(changedUsers); postPreferredActivityChangedBroadcast(UserHandle.USER_ALL); @@ -21462,7 +21465,6 @@ public class PackageManagerService extends IPackageManager.Stub storage.registerListener(mStorageListener); mInstallerService.systemReady(); - mApexManager.systemReady(); mPackageDexOptimizer.systemReady(); getStorageManagerInternal().addExternalStoragePolicy( @@ -21505,10 +21507,12 @@ public class PackageManagerService extends IPackageManager.Stub mModuleInfoProvider.systemReady(); + mOkToReplacePersistentPackages = true; // Installer service might attempt to install some packages that have been staged for // installation on reboot. Make sure this is the last component to be call since the // installation might require other components to be ready. mInstallerService.restoreAndApplyStagedSessionIfNeeded(); + mOkToReplacePersistentPackages = false; } public void waitForAppDataPrepared() { diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java index d8f07feb1ddb..748a6613091e 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -16,6 +16,7 @@ package com.android.server.rollback; +import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -32,7 +33,6 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.PowerManager; import android.text.TextUtils; -import android.util.Pair; import android.util.Slog; import android.util.StatsLog; @@ -77,74 +77,50 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve @Override public int onHealthCheckFailed(VersionedPackage failedPackage) { VersionedPackage moduleMetadataPackage = getModuleMetadataPackage(); - if (moduleMetadataPackage == null) { - // Ignore failure, no mainline update available - return PackageHealthObserverImpact.USER_IMPACT_NONE; - } - if (getAvailableRollback(mContext.getSystemService(RollbackManager.class), - failedPackage, moduleMetadataPackage) == null) { + if (getAvailableRollback(mContext.getSystemService(RollbackManager.class), failedPackage) + == null) { // Don't handle the notification, no rollbacks available for the package return PackageHealthObserverImpact.USER_IMPACT_NONE; + } else { + // Rollback is available, we may get a callback into #execute + return PackageHealthObserverImpact.USER_IMPACT_MEDIUM; } - // Rollback is available, we may get a callback into #execute - return PackageHealthObserverImpact.USER_IMPACT_MEDIUM; } @Override public boolean execute(VersionedPackage failedPackage) { + RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); VersionedPackage moduleMetadataPackage = getModuleMetadataPackage(); - if (moduleMetadataPackage == null) { - // Ignore failure, no mainline update available - return false; - } + RollbackInfo rollback = getAvailableRollback(rollbackManager, failedPackage); - RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); - Pair<RollbackInfo, Boolean> rollbackPair = getAvailableRollback(rollbackManager, - failedPackage, moduleMetadataPackage); - if (rollbackPair == null) { + if (rollback == null) { Slog.w(TAG, "Expected rollback but no valid rollback found for package: [ " + failedPackage.getPackageName() + "] with versionCode: [" + failedPackage.getVersionCode() + "]"); return false; } - RollbackInfo rollback = rollbackPair.first; - // We only log mainline package rollbacks, so check if rollback contains the - // module metadata provider, if it does, the rollback is a mainline rollback - boolean hasModuleMetadataPackage = rollbackPair.second; - - if (hasModuleMetadataPackage) { - StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE, - moduleMetadataPackage.getPackageName(), - moduleMetadataPackage.getVersionCode()); - } + logEvent(moduleMetadataPackage, + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE); LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> { - if (hasModuleMetadataPackage) { - int status = result.getIntExtra(RollbackManager.EXTRA_STATUS, - RollbackManager.STATUS_FAILURE); - if (status == RollbackManager.STATUS_SUCCESS) { - if (rollback.isStaged()) { - int rollbackId = rollback.getRollbackId(); - BroadcastReceiver listener = - listenForStagedSessionReady(rollbackManager, rollbackId, - moduleMetadataPackage); - handleStagedSessionChange(rollbackManager, rollbackId, listener, - moduleMetadataPackage); - } else { - StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, - StatsLog - .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, - moduleMetadataPackage.getPackageName(), - moduleMetadataPackage.getVersionCode()); - } + int status = result.getIntExtra(RollbackManager.EXTRA_STATUS, + RollbackManager.STATUS_FAILURE); + if (status == RollbackManager.STATUS_SUCCESS) { + if (rollback.isStaged()) { + int rollbackId = rollback.getRollbackId(); + BroadcastReceiver listener = + listenForStagedSessionReady(rollbackManager, rollbackId, + moduleMetadataPackage); + handleStagedSessionChange(rollbackManager, rollbackId, listener, + moduleMetadataPackage); } else { - StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, - moduleMetadataPackage.getPackageName(), - moduleMetadataPackage.getVersionCode()); + logEvent(moduleMetadataPackage, + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS); } + } else { + logEvent(moduleMetadataPackage, + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE); } }); @@ -193,26 +169,17 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } String moduleMetadataPackageName = getModuleMetadataPackageName(); - if (moduleMetadataPackageName == null) { - // Only log mainline staged rollbacks - return; - } // Use the version of the metadata package that was installed before // we rolled back for logging purposes. VersionedPackage moduleMetadataPackage = null; for (PackageRollbackInfo packageRollback : rollback.getPackages()) { - if (moduleMetadataPackageName.equals(packageRollback.getPackageName())) { + if (packageRollback.getPackageName().equals(moduleMetadataPackageName)) { moduleMetadataPackage = packageRollback.getVersionRolledBackFrom(); break; } } - if (moduleMetadataPackage == null) { - // Only log mainline staged rollbacks - return; - } - int sessionId = rollback.getCommittedSessionId(); PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId); if (sessionInfo == null) { @@ -220,42 +187,33 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve return; } if (sessionInfo.isStagedSessionApplied()) { - StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, - moduleMetadataPackage.getPackageName(), - moduleMetadataPackage.getVersionCode()); + logEvent(moduleMetadataPackage, + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS); } else if (sessionInfo.isStagedSessionReady()) { // TODO: What do for staged session ready but not applied } else { - StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, - moduleMetadataPackage.getPackageName(), - moduleMetadataPackage.getVersionCode()); + logEvent(moduleMetadataPackage, + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE); } } - private Pair<RollbackInfo, Boolean> getAvailableRollback(RollbackManager rollbackManager, - VersionedPackage failedPackage, VersionedPackage moduleMetadataPackage) { + private RollbackInfo getAvailableRollback(RollbackManager rollbackManager, + VersionedPackage failedPackage) { for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) { - // We only rollback mainline packages, so check if rollback contains the - // module metadata provider, if it does, the rollback is a mainline rollback - boolean hasModuleMetadataPackage = false; - boolean hasFailedPackage = false; for (PackageRollbackInfo packageRollback : rollback.getPackages()) { - hasModuleMetadataPackage |= packageRollback.getPackageName().equals( - moduleMetadataPackage.getPackageName()); - hasFailedPackage |= packageRollback.getPackageName().equals( + boolean hasFailedPackage = packageRollback.getPackageName().equals( failedPackage.getPackageName()) && packageRollback.getVersionRolledBackFrom().getVersionCode() == failedPackage.getVersionCode(); - } - if (hasFailedPackage) { - return new Pair<RollbackInfo, Boolean>(rollback, hasModuleMetadataPackage); + if (hasFailedPackage) { + return rollback; + } } } return null; } + @Nullable private String getModuleMetadataPackageName() { String packageName = mContext.getResources().getString( R.string.config_defaultModuleMetadataProvider); @@ -265,6 +223,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve return packageName; } + @Nullable private VersionedPackage getModuleMetadataPackage() { String packageName = getModuleMetadataPackageName(); if (packageName == null) { @@ -311,18 +270,13 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve if (sessionInfo.isStagedSessionReady()) { mContext.unregisterReceiver(listener); saveLastStagedRollbackId(rollbackId); - StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, + logEvent(moduleMetadataPackage, StatsLog - .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED, - moduleMetadataPackage.getPackageName(), - moduleMetadataPackage.getVersionCode()); + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED); mContext.getSystemService(PowerManager.class).reboot("Rollback staged install"); } else if (sessionInfo.isStagedSessionFailed()) { - StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, - StatsLog - .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, - moduleMetadataPackage.getPackageName(), - moduleMetadataPackage.getVersionCode()); + logEvent(moduleMetadataPackage, + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE); mContext.unregisterReceiver(listener); } } @@ -358,4 +312,12 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve mLastStagedRollbackIdFile.delete(); return rollbackId; } + + private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type) { + Slog.i(TAG, "Watchdog event occurred of type: " + type); + if (moduleMetadataPackage != null) { + StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED, type, + moduleMetadataPackage.getPackageName(), moduleMetadataPackage.getVersionCode()); + } + } } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index b9b5aae03587..7734d6bd30a7 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -77,7 +77,8 @@ public interface StatusBarManagerInternal { void onCameraLaunchGestureDetected(int source); void topAppWindowChanged(int displayId, boolean menuVisible); void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis, - int mask, Rect fullscreenBounds, Rect dockedBounds, String cause); + int mask, Rect fullscreenBounds, Rect dockedBounds, boolean isNavbarColorManagedByIme, + String cause); void toggleSplitScreen(); void appTransitionFinished(int displayId); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index a5656c3e40f0..b2d7084fcd05 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -262,9 +262,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds, - String cause) { + boolean isNavbarColorManagedByIme, String cause) { StatusBarManagerService.this.setSystemUiVisibility(displayId, vis, fullscreenStackVis, - dockedStackVis, mask, fullscreenBounds, dockedBounds, cause); + dockedStackVis, mask, fullscreenBounds, dockedBounds, isNavbarColorManagedByIme, + cause); } @Override @@ -872,11 +873,13 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D public void setSystemUiVisibility(int displayId, int vis, int mask, String cause) { final UiState state = getUiState(displayId); setSystemUiVisibility(displayId, vis, 0, 0, mask, - state.mFullscreenStackBounds, state.mDockedStackBounds, cause); + state.mFullscreenStackBounds, state.mDockedStackBounds, + state.mNavbarColorManagedByIme, cause); } private void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, - int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds, String cause) { + int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds, + boolean isNavbarColorManagedByIme, String cause) { // also allows calls from window manager which is in this process. enforceStatusBarService(); @@ -884,7 +887,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D synchronized (mLock) { updateUiVisibilityLocked(displayId, vis, fullscreenStackVis, dockedStackVis, mask, - fullscreenBounds, dockedBounds); + fullscreenBounds, dockedBounds, isNavbarColorManagedByIme); disableLocked( displayId, mCurrentUserId, @@ -896,17 +899,19 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D private void updateUiVisibilityLocked(final int displayId, final int vis, final int fullscreenStackVis, final int dockedStackVis, final int mask, - final Rect fullscreenBounds, final Rect dockedBounds) { + final Rect fullscreenBounds, final Rect dockedBounds, + final boolean isNavbarColorManagedByIme) { final UiState state = getUiState(displayId); if (!state.systemUiStateEquals(vis, fullscreenStackVis, dockedStackVis, - fullscreenBounds, dockedBounds)) { + fullscreenBounds, dockedBounds, isNavbarColorManagedByIme)) { state.setSystemUiState(vis, fullscreenStackVis, dockedStackVis, fullscreenBounds, - dockedBounds); + dockedBounds, isNavbarColorManagedByIme); mHandler.post(() -> { if (mBar != null) { try { mBar.setSystemUiVisibility(displayId, vis, fullscreenStackVis, - dockedStackVis, mask, fullscreenBounds, dockedBounds); + dockedStackVis, mask, fullscreenBounds, dockedBounds, + isNavbarColorManagedByIme); } catch (RemoteException ex) { Log.w(TAG, "Can not get StatusBar!"); } @@ -945,6 +950,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D private int mImeBackDisposition = 0; private boolean mShowImeSwitcher = false; private IBinder mImeToken = null; + private boolean mNavbarColorManagedByIme = false; private int getDisabled1() { return mDisabled1; @@ -972,21 +978,25 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } private void setSystemUiState(final int vis, final int fullscreenStackVis, - final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds) { + final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds, + final boolean navbarColorManagedByIme) { mSystemUiVisibility = vis; mFullscreenStackSysUiVisibility = fullscreenStackVis; mDockedStackSysUiVisibility = dockedStackVis; mFullscreenStackBounds.set(fullscreenBounds); mDockedStackBounds.set(dockedBounds); + mNavbarColorManagedByIme = navbarColorManagedByIme; } private boolean systemUiStateEquals(final int vis, final int fullscreenStackVis, - final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds) { + final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds, + final boolean navbarColorManagedByIme) { return mSystemUiVisibility == vis && mFullscreenStackSysUiVisibility == fullscreenStackVis && mDockedStackSysUiVisibility == dockedStackVis && mFullscreenStackBounds.equals(fullscreenBounds) - && mDockedStackBounds.equals(dockedBounds); + && mDockedStackBounds.equals(dockedBounds) + && mNavbarColorManagedByIme == navbarColorManagedByIme; } private void setImeWindowState(final int vis, final int backDisposition, @@ -1051,7 +1061,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D state.mImeBackDisposition, state.mShowImeSwitcher, gatherDisableActionsLocked(mCurrentUserId, 2), state.mFullscreenStackSysUiVisibility, state.mDockedStackSysUiVisibility, - state.mImeToken, state.mFullscreenStackBounds, state.mDockedStackBounds); + state.mImeToken, state.mFullscreenStackBounds, state.mDockedStackBounds, + state.mNavbarColorManagedByIme); } } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 2321898b91cc..a3cef7f7219d 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -2432,14 +2432,19 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } } - private boolean shouldAnimate(int transit) { + + @VisibleForTesting + boolean shouldAnimate(int transit) { final boolean isSplitScreenPrimary = getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN; - // Don't animate when the task runs recents animation. + // Don't animate while the task runs recents animation but only if we are in the mode + // where we cancel with deferred screenshot, which means that the controller has + // transformed the task. final RecentsAnimationController controller = mWmService.getRecentsAnimationController(); - if (controller != null && controller.isAnimatingTask(getTask())) { + if (controller != null && controller.isAnimatingTask(getTask()) + && controller.shouldCancelWithDeferredScreenshot()) { return false; } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 3bb365338749..32d0b32956cf 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -112,7 +112,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Px; import android.app.ActivityManager; -import android.app.ActivityManagerInternal; import android.app.ActivityThread; import android.app.LoadedApk; import android.app.ResourcesManager; @@ -133,6 +132,7 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.util.ArraySet; +import android.util.Pair; import android.util.PrintWriterPrinter; import android.util.Slog; import android.view.DisplayCutout; @@ -3113,7 +3113,9 @@ public class DisplayPolicy { WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mNonDockedStackBounds); mService.getStackBounds( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds); - final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility); + final Pair<Integer, Boolean> result = + updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility); + final int visibility = result.first; final int diff = visibility ^ mLastSystemUiFlags; final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags; final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags; @@ -3133,13 +3135,14 @@ public class DisplayPolicy { mLastDockedStackBounds.set(mDockedStackBounds); final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds); final Rect dockedStackBounds = new Rect(mDockedStackBounds); + final boolean isNavbarColorManagedByIme = result.second; mHandler.post(() -> { StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); if (statusBar != null) { final int displayId = getDisplayId(); statusBar.setSystemUiVisibility(displayId, visibility, fullscreenVisibility, dockedVisibility, 0xffffffff, fullscreenStackBounds, - dockedStackBounds, win.toString()); + dockedStackBounds, isNavbarColorManagedByIme, win.toString()); statusBar.topAppWindowChanged(displayId, needsMenu); } }); @@ -3222,7 +3225,7 @@ public class DisplayPolicy { return vis; } - private int updateSystemBarsLw(WindowState win, int oldVis, int vis) { + private Pair<Integer, Boolean> updateSystemBarsLw(WindowState win, int oldVis, int vis) { final boolean dockedStackVisible = mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); final boolean freeformStackVisible = @@ -3355,8 +3358,11 @@ public class DisplayPolicy { vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState, mDisplayContent.mInputMethodWindow, navColorWin); + // Navbar color is controlled by the IME. + final boolean isManagedByIme = + navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow; - return vis; + return Pair.create(vis, isManagedByIme); } private boolean drawsBarBackground(int vis, WindowState win, BarController controller, diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 78c5dbddee41..75a8dd53d2e6 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -481,7 +481,15 @@ public abstract class WindowManagerInternal { public abstract int getTopFocusedDisplayId(); /** - * Checks whether this display should support showing system decorations. + * Checks if this display is configured and allowed to show system decorations. */ public abstract boolean shouldShowSystemDecorOnDisplay(int displayId); + + /** + * Indicates that the display should show IME. + * + * @param displayId The id of the display. + * @return {@code true} if the display should show IME when an input field become focused on it. + */ + public abstract boolean shouldShowIme(int displayId); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index dae29b2cf180..4eddb3016205 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -35,6 +35,7 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; +import static android.view.Display.TYPE_VIRTUAL; import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; @@ -163,6 +164,7 @@ import android.os.PowerManager; import android.os.PowerManager.ServiceType; import android.os.PowerManagerInternal; import android.os.PowerSaveState; +import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; @@ -6871,10 +6873,21 @@ public class WindowManagerService extends IWindowManager.Stub + "not exist: " + displayId); return false; } + final Display display = displayContent.getDisplay(); + if (isUntrustedVirtualDisplay(display)) { + return false; + } return displayContent.supportsSystemDecorations(); } } + /** + * @return {@code true} if the display is non-system created virtual display. + */ + private static boolean isUntrustedVirtualDisplay(Display display) { + return display.getType() == TYPE_VIRTUAL && display.getOwnerUid() != Process.SYSTEM_UID; + } + @Override public void setShouldShowSystemDecors(int displayId, boolean shouldShow) { if (!checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "setShouldShowSystemDecors()")) { @@ -6908,7 +6921,12 @@ public class WindowManagerService extends IWindowManager.Stub + displayId); return false; } - return mDisplayWindowSettings.shouldShowImeLocked(displayContent); + final Display display = displayContent.getDisplay(); + if (isUntrustedVirtualDisplay(display)) { + return false; + } + return mDisplayWindowSettings.shouldShowImeLocked(displayContent) + || mForceDesktopModeOnExternalDisplays; } } @@ -7352,6 +7370,14 @@ public class WindowManagerService extends IWindowManager.Stub return WindowManagerService.this.shouldShowSystemDecors(displayId); } } + + @Override + public boolean shouldShowIme(int displayId) { + synchronized (mGlobalLock) { + final DisplayContent displayContent = mRoot.getDisplayContent(displayId); + return mDisplayWindowSettings.shouldShowImeLocked(displayContent); + } + } } void registerAppFreezeListener(AppFreezeListener listener) { diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 7bc6776803a3..4d37f1ace9c0 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -1860,13 +1860,14 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject * Fail if the main interface fails to initialize */ if (gnssHal == nullptr) { - ALOGE("Unable to Initialize GNSS HAL\n"); + ALOGE("Unable to initialize GNSS HAL."); return JNI_FALSE; } - sp<IGnssCallback> gnssCbIface = new GnssCallback(); - Return<bool> result = false; + + // Set top level IGnss.hal callback. + sp<IGnssCallback> gnssCbIface = new GnssCallback(); if (gnssHal_V2_0 != nullptr) { result = gnssHal_V2_0->setCallback_2_0(gnssCbIface); } else if (gnssHal_V1_1 != nullptr) { @@ -1876,62 +1877,89 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject } if (!result.isOk() || !result) { - ALOGE("SetCallback for Gnss Interface fails\n"); + ALOGE("SetCallback for IGnss interface failed."); return JNI_FALSE; } - sp<IGnssXtraCallback> gnssXtraCbIface = new GnssXtraCallback(); + // Set IGnssXtra.hal callback. if (gnssXtraIface == nullptr) { - ALOGI("Unable to initialize GNSS Xtra interface\n"); + ALOGI("Unable to initialize IGnssXtra interface."); } else { + sp<IGnssXtraCallback> gnssXtraCbIface = new GnssXtraCallback(); result = gnssXtraIface->setCallback(gnssXtraCbIface); if (!result.isOk() || !result) { gnssXtraIface = nullptr; - ALOGI("SetCallback for Gnss Xtra Interface fails\n"); + ALOGI("SetCallback for IGnssXtra interface failed."); } } + // Set IAGnss.hal callback. + Return<void> agnssStatus; if (agnssIface_V2_0 != nullptr) { sp<IAGnssCallback_V2_0> aGnssCbIface = new AGnssCallback_V2_0(); - agnssIface_V2_0->setCallback(aGnssCbIface); + agnssStatus = agnssIface_V2_0->setCallback(aGnssCbIface); } else if (agnssIface != nullptr) { sp<IAGnssCallback_V1_0> aGnssCbIface = new AGnssCallback_V1_0(); - agnssIface->setCallback(aGnssCbIface); + agnssStatus = agnssIface->setCallback(aGnssCbIface); } else { - ALOGI("Unable to initialize AGnss interface\n"); + ALOGI("Unable to initialize IAGnss interface."); } + if (!agnssStatus.isOk()) { + ALOGI("SetCallback for IAGnss interface failed."); + } + + // Set IGnssGeofencing.hal callback. sp<IGnssGeofenceCallback> gnssGeofencingCbIface = new GnssGeofenceCallback(); if (gnssGeofencingIface != nullptr) { - gnssGeofencingIface->setCallback(gnssGeofencingCbIface); + auto status = gnssGeofencingIface->setCallback(gnssGeofencingCbIface); + if (!status.isOk()) { + ALOGI("SetCallback for IGnssGeofencing interface failed."); + } } else { - ALOGI("Unable to initialize GNSS Geofencing interface\n"); + ALOGI("Unable to initialize IGnssGeofencing interface."); } + // Set IGnssNi.hal callback. sp<IGnssNiCallback> gnssNiCbIface = new GnssNiCallback(); if (gnssNiIface != nullptr) { - gnssNiIface->setCallback(gnssNiCbIface); + auto status = gnssNiIface->setCallback(gnssNiCbIface); + if (!status.isOk()) { + ALOGI("SetCallback for IGnssNi interface failed."); + } } else { - ALOGI("Unable to initialize GNSS NI interface\n"); + ALOGI("Unable to initialize IGnssNi interface."); } + // Set IAGnssRil.hal callback. sp<IAGnssRilCallback> aGnssRilCbIface = new AGnssRilCallback(); if (agnssRilIface != nullptr) { - agnssRilIface->setCallback(aGnssRilCbIface); + auto status = agnssRilIface->setCallback(aGnssRilCbIface); + if (!status.isOk()) { + ALOGI("SetCallback for IAGnssRil interface failed."); + } } else { - ALOGI("Unable to initialize AGnss Ril interface\n"); + ALOGI("Unable to initialize IAGnssRil interface."); } + // Set IGnssVisibilityControl.hal callback. if (gnssVisibilityControlIface != nullptr) { sp<IGnssVisibilityControlCallback> gnssVisibilityControlCbIface = new GnssVisibilityControlCallback(); - gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface); + result = gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface); + if (!result.isOk() || !result) { + ALOGI("SetCallback for IGnssVisibilityControl interface failed."); + } } + // Set IMeasurementCorrections.hal callback. if (gnssCorrectionsIface != nullptr) { sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface = new MeasurementCorrectionsCallback(); - gnssCorrectionsIface->setCallback(gnssCorrectionsIfaceCbIface); + result = gnssCorrectionsIface->setCallback(gnssCorrectionsIfaceCbIface); + if (!result.isOk() || !result) { + ALOGI("SetCallback for IMeasurementCorrections interface failed."); + } } return JNI_TRUE; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index be7dd31380ba..4ac8342e6e60 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -115,6 +115,7 @@ import com.android.server.om.OverlayManagerService; import com.android.server.os.BugreportManagerService; import com.android.server.os.DeviceIdentifiersPolicyService; import com.android.server.os.SchedulingPolicyService; +import com.android.server.pm.ApexManager; import com.android.server.pm.BackgroundDexOptService; import com.android.server.pm.CrossProfileAppsService; import com.android.server.pm.DynamicCodeLoggingService; @@ -627,6 +628,12 @@ public final class SystemServer { watchdog.start(); traceEnd(); + // Start ApexManager as early as we can to give it enough time to call apexd and populate + // cache of known apex packages. Note that calling apexd will happen asynchronously. + traceBeginAndSlog("StartApexManager"); + mSystemServiceManager.startService(ApexManager.class); + traceEnd(); + Slog.i(TAG, "Reading configuration..."); final String TAG_SYSTEM_CONFIG = "ReadingSystemConfig"; traceBeginAndSlog(TAG_SYSTEM_CONFIG); diff --git a/services/net/Android.bp b/services/net/Android.bp index a44d8351939f..ab11fe4df283 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -56,6 +56,7 @@ aidl_interface { versions: [ "1", "2", + "3", ], } diff --git a/services/net/aidl/networkstack/3/android/net/DhcpResultsParcelable.aidl b/services/net/aidl/networkstack/3/android/net/DhcpResultsParcelable.aidl new file mode 100644 index 000000000000..31891de7230a --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/DhcpResultsParcelable.aidl @@ -0,0 +1,9 @@ +package android.net; +parcelable DhcpResultsParcelable { + android.net.StaticIpConfiguration baseConfiguration; + int leaseDuration; + int mtu; + String serverAddress; + String vendorInfo; + String serverHostName; +} diff --git a/services/net/aidl/networkstack/3/android/net/INetworkMonitor.aidl b/services/net/aidl/networkstack/3/android/net/INetworkMonitor.aidl new file mode 100644 index 000000000000..029968b6f324 --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/INetworkMonitor.aidl @@ -0,0 +1,24 @@ +package android.net; +interface INetworkMonitor { + oneway void start(); + oneway void launchCaptivePortalApp(); + oneway void notifyCaptivePortalAppFinished(int response); + oneway void setAcceptPartialConnectivity(); + oneway void forceReevaluation(int uid); + oneway void notifyPrivateDnsChanged(in android.net.PrivateDnsConfigParcel config); + oneway void notifyDnsResponse(int returnCode); + oneway void notifyNetworkConnected(in android.net.LinkProperties lp, in android.net.NetworkCapabilities nc); + oneway void notifyNetworkDisconnected(); + oneway void notifyLinkPropertiesChanged(in android.net.LinkProperties lp); + oneway void notifyNetworkCapabilitiesChanged(in android.net.NetworkCapabilities nc); + const int NETWORK_TEST_RESULT_VALID = 0; + const int NETWORK_TEST_RESULT_INVALID = 1; + const int NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY = 2; + const int NETWORK_VALIDATION_RESULT_VALID = 1; + const int NETWORK_VALIDATION_RESULT_PARTIAL = 2; + const int NETWORK_VALIDATION_PROBE_DNS = 4; + const int NETWORK_VALIDATION_PROBE_HTTP = 8; + const int NETWORK_VALIDATION_PROBE_HTTPS = 16; + const int NETWORK_VALIDATION_PROBE_FALLBACK = 32; + const int NETWORK_VALIDATION_PROBE_PRIVDNS = 64; +} diff --git a/services/net/aidl/networkstack/3/android/net/INetworkMonitorCallbacks.aidl b/services/net/aidl/networkstack/3/android/net/INetworkMonitorCallbacks.aidl new file mode 100644 index 000000000000..ee9871ddcd15 --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/INetworkMonitorCallbacks.aidl @@ -0,0 +1,8 @@ +package android.net; +interface INetworkMonitorCallbacks { + oneway void onNetworkMonitorCreated(in android.net.INetworkMonitor networkMonitor); + oneway void notifyNetworkTested(int testResult, @nullable String redirectUrl); + oneway void notifyPrivateDnsConfigResolved(in android.net.PrivateDnsConfigParcel config); + oneway void showProvisioningNotification(String action, String packageName); + oneway void hideProvisioningNotification(); +} diff --git a/services/net/aidl/networkstack/3/android/net/INetworkStackConnector.aidl b/services/net/aidl/networkstack/3/android/net/INetworkStackConnector.aidl new file mode 100644 index 000000000000..7da11e476c0e --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/INetworkStackConnector.aidl @@ -0,0 +1,7 @@ +package android.net; +interface INetworkStackConnector { + oneway void makeDhcpServer(in String ifName, in android.net.dhcp.DhcpServingParamsParcel params, in android.net.dhcp.IDhcpServerCallbacks cb); + oneway void makeNetworkMonitor(in android.net.Network network, String name, in android.net.INetworkMonitorCallbacks cb); + oneway void makeIpClient(in String ifName, in android.net.ip.IIpClientCallbacks callbacks); + oneway void fetchIpMemoryStore(in android.net.IIpMemoryStoreCallbacks cb); +} diff --git a/services/net/aidl/networkstack/3/android/net/INetworkStackStatusCallback.aidl b/services/net/aidl/networkstack/3/android/net/INetworkStackStatusCallback.aidl new file mode 100644 index 000000000000..f6ca6f7a78e2 --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/INetworkStackStatusCallback.aidl @@ -0,0 +1,4 @@ +package android.net; +interface INetworkStackStatusCallback { + oneway void onStatusAvailable(int statusCode); +} diff --git a/services/net/aidl/networkstack/3/android/net/InitialConfigurationParcelable.aidl b/services/net/aidl/networkstack/3/android/net/InitialConfigurationParcelable.aidl new file mode 100644 index 000000000000..c80a78785b3b --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/InitialConfigurationParcelable.aidl @@ -0,0 +1,7 @@ +package android.net; +parcelable InitialConfigurationParcelable { + android.net.LinkAddress[] ipAddresses; + android.net.IpPrefix[] directlyConnectedRoutes; + String[] dnsServers; + String gateway; +} diff --git a/services/net/aidl/networkstack/3/android/net/NattKeepalivePacketDataParcelable.aidl b/services/net/aidl/networkstack/3/android/net/NattKeepalivePacketDataParcelable.aidl new file mode 100644 index 000000000000..65de8833e6c5 --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/NattKeepalivePacketDataParcelable.aidl @@ -0,0 +1,7 @@ +package android.net; +parcelable NattKeepalivePacketDataParcelable { + byte[] srcAddress; + int srcPort; + byte[] dstAddress; + int dstPort; +} diff --git a/services/net/aidl/networkstack/3/android/net/PrivateDnsConfigParcel.aidl b/services/net/aidl/networkstack/3/android/net/PrivateDnsConfigParcel.aidl new file mode 100644 index 000000000000..2de790bb7754 --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/PrivateDnsConfigParcel.aidl @@ -0,0 +1,5 @@ +package android.net; +parcelable PrivateDnsConfigParcel { + String hostname; + String[] ips; +} diff --git a/services/net/aidl/networkstack/3/android/net/ProvisioningConfigurationParcelable.aidl b/services/net/aidl/networkstack/3/android/net/ProvisioningConfigurationParcelable.aidl new file mode 100644 index 000000000000..3a6c30496fd8 --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/ProvisioningConfigurationParcelable.aidl @@ -0,0 +1,15 @@ +package android.net; +parcelable ProvisioningConfigurationParcelable { + boolean enableIPv4; + boolean enableIPv6; + boolean usingMultinetworkPolicyTracker; + boolean usingIpReachabilityMonitor; + int requestedPreDhcpActionMs; + android.net.InitialConfigurationParcelable initialConfig; + android.net.StaticIpConfiguration staticIpConfig; + android.net.apf.ApfCapabilities apfCapabilities; + int provisioningTimeoutMs; + int ipv6AddrGenMode; + android.net.Network network; + String displayName; +} diff --git a/services/net/aidl/networkstack/3/android/net/TcpKeepalivePacketDataParcelable.aidl b/services/net/aidl/networkstack/3/android/net/TcpKeepalivePacketDataParcelable.aidl new file mode 100644 index 000000000000..e121c064f7ac --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/TcpKeepalivePacketDataParcelable.aidl @@ -0,0 +1,13 @@ +package android.net; +parcelable TcpKeepalivePacketDataParcelable { + byte[] srcAddress; + int srcPort; + byte[] dstAddress; + int dstPort; + int seq; + int ack; + int rcvWnd; + int rcvWndScale; + int tos; + int ttl; +} diff --git a/services/net/aidl/networkstack/3/android/net/dhcp/DhcpServingParamsParcel.aidl b/services/net/aidl/networkstack/3/android/net/dhcp/DhcpServingParamsParcel.aidl new file mode 100644 index 000000000000..67193ae904bc --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/dhcp/DhcpServingParamsParcel.aidl @@ -0,0 +1,11 @@ +package android.net.dhcp; +parcelable DhcpServingParamsParcel { + int serverAddr; + int serverAddrPrefixLength; + int[] defaultRouters; + int[] dnsServers; + int[] excludedAddrs; + long dhcpLeaseTimeSecs; + int linkMtu; + boolean metered; +} diff --git a/services/net/aidl/networkstack/3/android/net/dhcp/IDhcpServer.aidl b/services/net/aidl/networkstack/3/android/net/dhcp/IDhcpServer.aidl new file mode 100644 index 000000000000..914315855496 --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/dhcp/IDhcpServer.aidl @@ -0,0 +1,10 @@ +package android.net.dhcp; +interface IDhcpServer { + oneway void start(in android.net.INetworkStackStatusCallback cb); + oneway void updateParams(in android.net.dhcp.DhcpServingParamsParcel params, in android.net.INetworkStackStatusCallback cb); + oneway void stop(in android.net.INetworkStackStatusCallback cb); + const int STATUS_UNKNOWN = 0; + const int STATUS_SUCCESS = 1; + const int STATUS_INVALID_ARGUMENT = 2; + const int STATUS_UNKNOWN_ERROR = 3; +} diff --git a/services/net/aidl/networkstack/3/android/net/dhcp/IDhcpServerCallbacks.aidl b/services/net/aidl/networkstack/3/android/net/dhcp/IDhcpServerCallbacks.aidl new file mode 100644 index 000000000000..dcc4489d52a6 --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/dhcp/IDhcpServerCallbacks.aidl @@ -0,0 +1,4 @@ +package android.net.dhcp; +interface IDhcpServerCallbacks { + oneway void onDhcpServerCreated(int statusCode, in android.net.dhcp.IDhcpServer server); +} diff --git a/services/net/aidl/networkstack/3/android/net/ip/IIpClient.aidl b/services/net/aidl/networkstack/3/android/net/ip/IIpClient.aidl new file mode 100644 index 000000000000..176a5ce85373 --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/ip/IIpClient.aidl @@ -0,0 +1,16 @@ +package android.net.ip; +interface IIpClient { + oneway void completedPreDhcpAction(); + oneway void confirmConfiguration(); + oneway void readPacketFilterComplete(in byte[] data); + oneway void shutdown(); + oneway void startProvisioning(in android.net.ProvisioningConfigurationParcelable req); + oneway void stop(); + oneway void setTcpBufferSizes(in String tcpBufferSizes); + oneway void setHttpProxy(in android.net.ProxyInfo proxyInfo); + oneway void setMulticastFilter(boolean enabled); + oneway void addKeepalivePacketFilter(int slot, in android.net.TcpKeepalivePacketDataParcelable pkt); + oneway void removeKeepalivePacketFilter(int slot); + oneway void setL2KeyAndGroupHint(in String l2Key, in String groupHint); + oneway void addNattKeepalivePacketFilter(int slot, in android.net.NattKeepalivePacketDataParcelable pkt); +} diff --git a/services/net/aidl/networkstack/3/android/net/ip/IIpClientCallbacks.aidl b/services/net/aidl/networkstack/3/android/net/ip/IIpClientCallbacks.aidl new file mode 100644 index 000000000000..d6bc8089a0be --- /dev/null +++ b/services/net/aidl/networkstack/3/android/net/ip/IIpClientCallbacks.aidl @@ -0,0 +1,16 @@ +package android.net.ip; +interface IIpClientCallbacks { + oneway void onIpClientCreated(in android.net.ip.IIpClient ipClient); + oneway void onPreDhcpAction(); + oneway void onPostDhcpAction(); + oneway void onNewDhcpResults(in android.net.DhcpResultsParcelable dhcpResults); + oneway void onProvisioningSuccess(in android.net.LinkProperties newLp); + oneway void onProvisioningFailure(in android.net.LinkProperties newLp); + oneway void onLinkPropertiesChange(in android.net.LinkProperties newLp); + oneway void onReachabilityLost(in String logMsg); + oneway void onQuit(); + oneway void installPacketFilter(in byte[] filter); + oneway void startReadPacketFilter(); + oneway void setFallbackMulticastFilter(boolean enabled); + oneway void setNeighborDiscoveryOffload(boolean enable); +} diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java new file mode 100644 index 000000000000..f7edf65a499f --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java @@ -0,0 +1,437 @@ +/* + * 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.job; + +import static android.text.format.DateUtils.HOUR_IN_MILLIS; +import static android.text.format.DateUtils.MINUTE_IN_MILLIS; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.when; + +import android.app.ActivityManager; +import android.app.ActivityManagerInternal; +import android.app.IActivityManager; +import android.app.job.JobInfo; +import android.app.usage.UsageStatsManagerInternal; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; +import android.content.res.Resources; +import android.net.ConnectivityManager; +import android.net.NetworkPolicyManager; +import android.os.BatteryManagerInternal; +import android.os.Looper; +import android.os.RemoteException; +import android.os.SystemClock; + +import com.android.server.AppStateTracker; +import com.android.server.DeviceIdleController; +import com.android.server.LocalServices; +import com.android.server.job.controllers.JobStatus; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; + +import java.time.Clock; +import java.time.Duration; +import java.time.ZoneOffset; + +public class JobSchedulerServiceTest { + private JobSchedulerService mService; + + private MockitoSession mMockingSession; + @Mock + private ActivityManagerInternal mActivityMangerInternal; + @Mock + private Context mContext; + + private class TestJobSchedulerService extends JobSchedulerService { + TestJobSchedulerService(Context context) { + super(context); + } + + @Override + public boolean isChainedAttributionEnabled() { + return false; + } + } + + @Before + public void setUp() { + mMockingSession = mockitoSession() + .initMocks(this) + .strictness(Strictness.LENIENT) + .mockStatic(LocalServices.class) + .startMocking(); + + // Called in JobSchedulerService constructor. + when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper()); + doReturn(mActivityMangerInternal) + .when(() -> LocalServices.getService(ActivityManagerInternal.class)); + doReturn(mock(UsageStatsManagerInternal.class)) + .when(() -> LocalServices.getService(UsageStatsManagerInternal.class)); + // Called in BackgroundJobsController constructor. + doReturn(mock(AppStateTracker.class)) + .when(() -> LocalServices.getService(AppStateTracker.class)); + // Called in BatteryController constructor. + doReturn(mock(BatteryManagerInternal.class)) + .when(() -> LocalServices.getService(BatteryManagerInternal.class)); + // Called in ConnectivityController constructor. + when(mContext.getSystemService(ConnectivityManager.class)) + .thenReturn(mock(ConnectivityManager.class)); + when(mContext.getSystemService(NetworkPolicyManager.class)) + .thenReturn(mock(NetworkPolicyManager.class)); + // Called in DeviceIdleJobsController constructor. + doReturn(mock(DeviceIdleController.LocalService.class)) + .when(() -> LocalServices.getService(DeviceIdleController.LocalService.class)); + // Used in JobStatus. + doReturn(mock(PackageManagerInternal.class)) + .when(() -> LocalServices.getService(PackageManagerInternal.class)); + // Called via IdleController constructor. + when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class)); + when(mContext.getResources()).thenReturn(mock(Resources.class)); + // Called in QuotaController constructor. + IActivityManager activityManager = ActivityManager.getService(); + spyOn(activityManager); + try { + doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any()); + } catch (RemoteException e) { + fail("registerUidObserver threw exception: " + e.getMessage()); + } + + JobSchedulerService.sSystemClock = Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC); + JobSchedulerService.sElapsedRealtimeClock = + Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC); + + mService = new TestJobSchedulerService(mContext); + } + + @After + public void tearDown() { + if (mMockingSession != null) { + mMockingSession.finishMocking(); + } + } + + private Clock getAdvancedClock(Clock clock, long incrementMs) { + return Clock.offset(clock, Duration.ofMillis(incrementMs)); + } + + private void advanceElapsedClock(long incrementMs) { + JobSchedulerService.sElapsedRealtimeClock = getAdvancedClock( + JobSchedulerService.sElapsedRealtimeClock, incrementMs); + } + + private static JobInfo.Builder createJobInfo() { + return new JobInfo.Builder(351, new ComponentName("foo", "bar")); + } + + private JobStatus createJobStatus(String testTag, JobInfo.Builder jobInfoBuilder) { + return JobStatus.createFromJobInfo( + jobInfoBuilder.build(), 1234, "com.android.test", 0, testTag); + } + + /** + * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job + * with the correct delay and deadline constraints if the periodic job is completed and + * rescheduled while run in its expected running window. + */ + @Test + public void testGetRescheduleJobForPeriodic_insideWindow() { + final long now = sElapsedRealtimeClock.millis(); + JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_insideWindow", + createJobInfo().setPeriodic(HOUR_IN_MILLIS)); + final long nextWindowStartTime = now + HOUR_IN_MILLIS; + final long nextWindowEndTime = now + 2 * HOUR_IN_MILLIS; + + JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + advanceElapsedClock(10 * MINUTE_IN_MILLIS); // now + 10 minutes + + rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + advanceElapsedClock(45 * MINUTE_IN_MILLIS); // now + 55 minutes + + rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + advanceElapsedClock(4 * MINUTE_IN_MILLIS); // now + 59 minutes + + rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + } + + /** + * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job + * with the correct delay and deadline constraints if the periodic job with a custom flex + * setting is completed and rescheduled while run in its expected running window. + */ + @Test + public void testGetRescheduleJobForPeriodic_insideWindow_flex() { + JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_insideWindow_flex", + createJobInfo().setPeriodic(HOUR_IN_MILLIS, 30 * MINUTE_IN_MILLIS)); + // First window starts 30 minutes from now. + advanceElapsedClock(30 * MINUTE_IN_MILLIS); + final long now = sElapsedRealtimeClock.millis(); + final long nextWindowStartTime = now + HOUR_IN_MILLIS; + final long nextWindowEndTime = now + 90 * MINUTE_IN_MILLIS; + + JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + advanceElapsedClock(10 * MINUTE_IN_MILLIS); // now + 10 minutes + + rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + advanceElapsedClock(15 * MINUTE_IN_MILLIS); // now + 25 minutes + + rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + advanceElapsedClock(4 * MINUTE_IN_MILLIS); // now + 29 minutes + + rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + } + + /** + * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job + * with the correct delay and deadline constraints if the periodic job failed but then ran + * successfully and was rescheduled while run in its expected running window. + */ + @Test + public void testGetRescheduleJobForPeriodic_insideWindow_failedJob() { + final long now = sElapsedRealtimeClock.millis(); + final long nextWindowStartTime = now + HOUR_IN_MILLIS; + final long nextWindowEndTime = now + 2 * HOUR_IN_MILLIS; + JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_insideWindow_failedJob", + createJobInfo().setPeriodic(HOUR_IN_MILLIS)); + JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job); + + JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + advanceElapsedClock(5 * MINUTE_IN_MILLIS); // now + 5 minutes + failedJob = mService.getRescheduleJobForFailureLocked(job); + advanceElapsedClock(5 * MINUTE_IN_MILLIS); // now + 10 minutes + + rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + advanceElapsedClock(35 * MINUTE_IN_MILLIS); // now + 45 minutes + failedJob = mService.getRescheduleJobForFailureLocked(job); + advanceElapsedClock(10 * MINUTE_IN_MILLIS); // now + 55 minutes + + rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + advanceElapsedClock(2 * MINUTE_IN_MILLIS); // now + 57 minutes + failedJob = mService.getRescheduleJobForFailureLocked(job); + advanceElapsedClock(2 * MINUTE_IN_MILLIS); // now + 59 minutes + + rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + } + + /** + * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job + * with the correct delay and deadline constraints if the periodic job is completed and + * rescheduled when run after its expected running window. + */ + @Test + public void testGetRescheduleJobForPeriodic_outsideWindow() { + JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_outsideWindow", + createJobInfo().setPeriodic(HOUR_IN_MILLIS)); + long now = sElapsedRealtimeClock.millis(); + long nextWindowStartTime = now + HOUR_IN_MILLIS; + long nextWindowEndTime = now + 2 * HOUR_IN_MILLIS; + + advanceElapsedClock(HOUR_IN_MILLIS + MINUTE_IN_MILLIS); + // Say the job ran at the very end of its previous window. The intended JSS behavior is to + // have consistent windows, so the new window should start as soon as the previous window + // ended and end PERIOD time after the previous window ended. + JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + advanceElapsedClock(2 * HOUR_IN_MILLIS); + // Say that the job ran at this point, possibly due to device idle. + // The next window should be consistent (start and end at the time it would have had the job + // run normally in previous windows). + nextWindowStartTime += 2 * HOUR_IN_MILLIS; + nextWindowEndTime += 2 * HOUR_IN_MILLIS; + + rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + } + + /** + * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job + * with the correct delay and deadline constraints if the periodic job with a custom flex + * setting is completed and rescheduled when run after its expected running window. + */ + @Test + public void testGetRescheduleJobForPeriodic_outsideWindow_flex() { + JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_outsideWindow_flex", + createJobInfo().setPeriodic(HOUR_IN_MILLIS, 30 * MINUTE_IN_MILLIS)); + // First window starts 30 minutes from now. + advanceElapsedClock(30 * MINUTE_IN_MILLIS); + long now = sElapsedRealtimeClock.millis(); + long nextWindowStartTime = now + HOUR_IN_MILLIS; + long nextWindowEndTime = now + 90 * MINUTE_IN_MILLIS; + + advanceElapsedClock(31 * MINUTE_IN_MILLIS); + // Say the job ran at the very end of its previous window. The intended JSS behavior is to + // have consistent windows, so the new window should start as soon as the previous window + // ended and end PERIOD time after the previous window ended. + JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + // 5 minutes before the start of the next window. It's too close to the next window, so the + // returned job should be for the window after. + advanceElapsedClock(24 * MINUTE_IN_MILLIS); + nextWindowStartTime += HOUR_IN_MILLIS; + nextWindowEndTime += HOUR_IN_MILLIS; + rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + advanceElapsedClock(2 * HOUR_IN_MILLIS + 10 * MINUTE_IN_MILLIS); + // Say that the job ran at this point, possibly due to device idle. + // The next window should be consistent (start and end at the time it would have had the job + // run normally in previous windows). + nextWindowStartTime += 2 * HOUR_IN_MILLIS; + nextWindowEndTime += 2 * HOUR_IN_MILLIS; + + rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + } + + /** + * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job + * with the correct delay and deadline constraints if the periodic job failed but then ran + * successfully and was rescheduled when run after its expected running window. + */ + @Test + public void testGetRescheduleJobForPeriodic_outsideWindow_failedJob() { + JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_outsideWindow_failedJob", + createJobInfo().setPeriodic(HOUR_IN_MILLIS)); + JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job); + long now = sElapsedRealtimeClock.millis(); + long nextWindowStartTime = now + HOUR_IN_MILLIS; + long nextWindowEndTime = now + 2 * HOUR_IN_MILLIS; + + advanceElapsedClock(HOUR_IN_MILLIS + MINUTE_IN_MILLIS); + // Say the job ran at the very end of its previous window. The intended JSS behavior is to + // have consistent windows, so the new window should start as soon as the previous window + // ended and end PERIOD time after the previous window ended. + JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + advanceElapsedClock(2 * HOUR_IN_MILLIS); + // Say that the job ran at this point, possibly due to device idle. + // The next window should be consistent (start and end at the time it would have had the job + // run normally in previous windows). + nextWindowStartTime += 2 * HOUR_IN_MILLIS; + nextWindowEndTime += 2 * HOUR_IN_MILLIS; + + rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + } + + /** + * Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job + * with the correct delay and deadline constraints if the periodic job with a custom flex + * setting failed but then ran successfully and was rescheduled when run after its expected + * running window. + */ + @Test + public void testGetRescheduleJobForPeriodic_outsideWindow_flex_failedJob() { + JobStatus job = createJobStatus( + "testGetRescheduleJobForPeriodic_outsideWindow_flex_failedJob", + createJobInfo().setPeriodic(HOUR_IN_MILLIS, 30 * MINUTE_IN_MILLIS)); + JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job); + // First window starts 30 minutes from now. + advanceElapsedClock(30 * MINUTE_IN_MILLIS); + long now = sElapsedRealtimeClock.millis(); + long nextWindowStartTime = now + HOUR_IN_MILLIS; + long nextWindowEndTime = now + 90 * MINUTE_IN_MILLIS; + + advanceElapsedClock(31 * MINUTE_IN_MILLIS); + // Say the job ran at the very end of its previous window. The intended JSS behavior is to + // have consistent windows, so the new window should start as soon as the previous window + // ended and end PERIOD time after the previous window ended. + JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + // 5 minutes before the start of the next window. It's too close to the next window, so the + // returned job should be for the window after. + advanceElapsedClock(24 * MINUTE_IN_MILLIS); + nextWindowStartTime += HOUR_IN_MILLIS; + nextWindowEndTime += HOUR_IN_MILLIS; + rescheduledJob = mService.getRescheduleJobForPeriodic(job); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + + advanceElapsedClock(2 * HOUR_IN_MILLIS); + // Say that the job ran at this point, possibly due to device idle. + // The next window should be consistent (start and end at the time it would have had the job + // run normally in previous windows). + nextWindowStartTime += 2 * HOUR_IN_MILLIS; + nextWindowEndTime += 2 * HOUR_IN_MILLIS; + + rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob); + assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime()); + assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed()); + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java index 7c30f25c6281..2e7283c287bf 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java @@ -105,8 +105,9 @@ public class QuotaControllerTest { private static final int SOURCE_USER_ID = 0; private BroadcastReceiver mChargingReceiver; - private Constants mConstants; + private Constants mJsConstants; private QuotaController mQuotaController; + private QuotaController.QcConstants mQcConstants; private int mSourceUid; private IUidObserver mUidObserver; @@ -132,13 +133,13 @@ public class QuotaControllerTest { .mockStatic(LocalServices.class) .startMocking(); // Make sure constants turn on QuotaController. - mConstants = new Constants(); - mConstants.USE_HEARTBEATS = false; + mJsConstants = new Constants(); + mJsConstants.USE_HEARTBEATS = false; // Called in StateController constructor. when(mJobSchedulerService.getTestableContext()).thenReturn(mContext); when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService); - when(mJobSchedulerService.getConstants()).thenReturn(mConstants); + when(mJobSchedulerService.getConstants()).thenReturn(mJsConstants); // Called in QuotaController constructor. IActivityManager activityManager = ActivityManager.getService(); spyOn(activityManager); @@ -196,6 +197,7 @@ public class QuotaControllerTest { } catch (RemoteException e) { fail(e.getMessage()); } + mQcConstants = mQuotaController.getQcConstants(); } @After @@ -531,7 +533,7 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 15; expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS) - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); assertEquals(expectedStats, inputStats); @@ -544,7 +546,7 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 15; expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS) - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); assertEquals(expectedStats, inputStats); @@ -557,7 +559,7 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 15; expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS) - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); assertEquals(expectedStats, inputStats); @@ -574,7 +576,7 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 23 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 18; expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS) - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); assertEquals(expectedStats, inputStats); @@ -590,7 +592,7 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 24 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 20; expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS) - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats); assertEquals(expectedStats, inputStats); } @@ -630,7 +632,7 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 20; expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS) - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + + mQcConstants.IN_QUOTA_BUFFER_MS; assertEquals(expectedStats, mQuotaController.getExecutionStatsLocked(0, "com.android.test", WORKING_INDEX)); @@ -642,7 +644,7 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 20; expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS) - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + + mQcConstants.IN_QUOTA_BUFFER_MS; assertEquals(expectedStats, mQuotaController.getExecutionStatsLocked(0, "com.android.test", FREQUENT_INDEX)); @@ -654,7 +656,7 @@ public class QuotaControllerTest { expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS; expectedStats.bgJobCountInMaxPeriod = 20; expectedStats.quotaCutoffTimeElapsed = now - (2 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS) - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + + mQcConstants.IN_QUOTA_BUFFER_MS; assertEquals(expectedStats, mQuotaController.getExecutionStatsLocked(0, "com.android.test", RARE_INDEX)); } @@ -685,8 +687,8 @@ public class QuotaControllerTest { // Advance clock so that the working stats shouldn't be the same. advanceElapsedClock(MINUTE_IN_MILLIS); // Change frequent bucket size so that the stats need to be recalculated. - mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = 6 * HOUR_IN_MILLIS; - mQuotaController.onConstantsUpdatedLocked(); + mQcConstants.WINDOW_SIZE_FREQUENT_MS = 6 * HOUR_IN_MILLIS; + mQcConstants.updateConstants(); ExecutionStats expectedStats = new ExecutionStats(); expectedStats.windowSizeMs = originalStatsActive.windowSizeMs; @@ -778,7 +780,7 @@ public class QuotaControllerTest { setStandbyBucket(ACTIVE_INDEX); assertEquals(7 * MINUTE_IN_MILLIS, mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); - assertEquals(mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS - 9 * MINUTE_IN_MILLIS, + assertEquals(mQcConstants.MAX_EXECUTION_TIME_MS - 9 * MINUTE_IN_MILLIS, mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE)); } @@ -901,7 +903,7 @@ public class QuotaControllerTest { public void testIsWithinQuotaLocked_UnderDuration_OverJobCount() { setDischarging(); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); - final int jobCount = mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME; + final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME; mQuotaController.saveTimingSession(0, "com.android.test.spam", createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25)); mQuotaController.saveTimingSession(0, "com.android.test.spam", @@ -936,7 +938,7 @@ public class QuotaControllerTest { public void testIsWithinQuotaLocked_OverDuration_OverJobCount() { setDischarging(); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); - final int jobCount = mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME; + final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME; mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25)); mQuotaController.saveTimingSession(0, "com.android.test", @@ -1098,8 +1100,7 @@ public class QuotaControllerTest { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); // Test with timing sessions out of window but still under max execution limit. final long expectedAlarmTime = - (now - 18 * HOUR_IN_MILLIS) + 24 * HOUR_IN_MILLIS - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + (now - 18 * HOUR_IN_MILLIS) + 24 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, createTimingSession(now - 18 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, 1)); mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, @@ -1156,8 +1157,7 @@ public class QuotaControllerTest { final long end = now - (2 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS); // Counting backwards, the quota will come back one minute before the end. final long expectedAlarmTime = - end - MINUTE_IN_MILLIS + 2 * HOUR_IN_MILLIS - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + end - MINUTE_IN_MILLIS + 2 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.saveTimingSession(0, "com.android.test", new TimingSession(now - 2 * HOUR_IN_MILLIS, end, 1)); mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); @@ -1207,8 +1207,7 @@ public class QuotaControllerTest { // Test with timing sessions in window but still in quota. final long start = now - (6 * HOUR_IN_MILLIS); - final long expectedAlarmTime = - start + 8 * HOUR_IN_MILLIS + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + final long expectedAlarmTime = start + 8 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1)); mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); @@ -1262,7 +1261,7 @@ public class QuotaControllerTest { // needs to be excluded. final long expectedAlarmTime = start + MINUTE_IN_MILLIS + 24 * HOUR_IN_MILLIS - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.saveTimingSession(0, "com.android.test", createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1)); mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket); @@ -1324,21 +1323,21 @@ public class QuotaControllerTest { // And down from there. final long expectedWorkingAlarmTime = outOfQuotaTime + (2 * HOUR_IN_MILLIS) - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", WORKING_INDEX); inOrder.verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); final long expectedFrequentAlarmTime = outOfQuotaTime + (8 * HOUR_IN_MILLIS) - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", FREQUENT_INDEX); inOrder.verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedFrequentAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); final long expectedRareAlarmTime = outOfQuotaTime + (24 * HOUR_IN_MILLIS) - + mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS; + + mQcConstants.IN_QUOTA_BUFFER_MS; mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", RARE_INDEX); inOrder.verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedRareAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); @@ -1365,7 +1364,7 @@ public class QuotaControllerTest { ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); stats.jobCountInAllowedTime = - mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME + 2; + mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME + 2; // Invalid time in the past, so the count shouldn't be used. stats.jobCountExpirationTimeElapsed = @@ -1400,8 +1399,8 @@ public class QuotaControllerTest { @Test public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedBufferSize() { // Make sure any new value is used correctly. - mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS *= 2; - mQuotaController.onConstantsUpdatedLocked(); + mQcConstants.IN_QUOTA_BUFFER_MS *= 2; + mQcConstants.updateConstants(); runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck(); mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck(); @@ -1410,8 +1409,8 @@ public class QuotaControllerTest { @Test public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedAllowedTime() { // Make sure any new value is used correctly. - mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS /= 2; - mQuotaController.onConstantsUpdatedLocked(); + mQcConstants.ALLOWED_TIME_PER_PERIOD_MS /= 2; + mQcConstants.updateConstants(); runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck(); mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck(); @@ -1420,8 +1419,8 @@ public class QuotaControllerTest { @Test public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedMaxTime() { // Make sure any new value is used correctly. - mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS /= 2; - mQuotaController.onConstantsUpdatedLocked(); + mQcConstants.MAX_EXECUTION_TIME_MS /= 2; + mQcConstants.updateConstants(); runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck(); mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck(); @@ -1430,10 +1429,10 @@ public class QuotaControllerTest { @Test public void testMaybeScheduleStartAlarmLocked_SmallRollingQuota_UpdatedEverything() { // Make sure any new value is used correctly. - mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS *= 2; - mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS /= 2; - mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS /= 2; - mQuotaController.onConstantsUpdatedLocked(); + mQcConstants.IN_QUOTA_BUFFER_MS *= 2; + mQcConstants.ALLOWED_TIME_PER_PERIOD_MS /= 2; + mQcConstants.MAX_EXECUTION_TIME_MS /= 2; + mQcConstants.updateConstants(); runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_AllowedTimeCheck(); mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear(); runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck(); @@ -1448,9 +1447,8 @@ public class QuotaControllerTest { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); // Working set window size is 2 hours. final int standbyBucket = WORKING_INDEX; - final long contributionMs = mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS / 2; - final long remainingTimeMs = - mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS - contributionMs; + final long contributionMs = mQcConstants.IN_QUOTA_BUFFER_MS / 2; + final long remainingTimeMs = mQcConstants.ALLOWED_TIME_PER_PERIOD_MS - contributionMs; // Session straddles edge of bucket window. Only the contribution should be counted towards // the quota. @@ -1462,7 +1460,7 @@ public class QuotaControllerTest { // Expected alarm time should be when the app will have QUOTA_BUFFER_MS time of quota, which // is 2 hours + (QUOTA_BUFFER_MS - contributionMs) after the start of the second session. final long expectedAlarmTime = now - HOUR_IN_MILLIS + 2 * HOUR_IN_MILLIS - + (mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS - contributionMs); + + (mQcConstants.IN_QUOTA_BUFFER_MS - contributionMs); mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); verify(mAlarmManager, times(1)) @@ -1479,9 +1477,8 @@ public class QuotaControllerTest { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); // Working set window size is 2 hours. final int standbyBucket = WORKING_INDEX; - final long contributionMs = mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS / 2; - final long remainingTimeMs = - mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS - contributionMs; + final long contributionMs = mQcConstants.IN_QUOTA_BUFFER_MS / 2; + final long remainingTimeMs = mQcConstants.MAX_EXECUTION_TIME_MS - contributionMs; // Session straddles edge of 24 hour window. Only the contribution should be counted towards // the quota. @@ -1493,9 +1490,8 @@ public class QuotaControllerTest { // Expected alarm time should be when the app will have QUOTA_BUFFER_MS time of quota, which // is 24 hours + (QUOTA_BUFFER_MS - contributionMs) after the start of the second session. final long expectedAlarmTime = now - 20 * HOUR_IN_MILLIS - //+ mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS + 24 * HOUR_IN_MILLIS - + (mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS - contributionMs); + + (mQcConstants.IN_QUOTA_BUFFER_MS - contributionMs); mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); verify(mAlarmManager, times(1)) @@ -1515,12 +1511,12 @@ public class QuotaControllerTest { mQuotaController.maybeStartTrackingJobLocked(jobStatus, null); assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - mConstants.USE_HEARTBEATS = true; + mJsConstants.USE_HEARTBEATS = true; mQuotaController.onConstantsUpdatedLocked(); Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background. assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); - mConstants.USE_HEARTBEATS = false; + mJsConstants.USE_HEARTBEATS = false; mQuotaController.onConstantsUpdatedLocked(); Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background. assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); @@ -1528,20 +1524,20 @@ public class QuotaControllerTest { @Test public void testConstantsUpdating_ValidValues() { - mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = 5 * MINUTE_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = 2 * MINUTE_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = 15 * MINUTE_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = 30 * MINUTE_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = 45 * MINUTE_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = 60 * MINUTE_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = 3 * HOUR_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = 5000; - mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = 4000; - mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = 3000; - mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = 2000; - mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = 500; - - mQuotaController.onConstantsUpdatedLocked(); + mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 5 * MINUTE_IN_MILLIS; + mQcConstants.IN_QUOTA_BUFFER_MS = 2 * MINUTE_IN_MILLIS; + mQcConstants.WINDOW_SIZE_ACTIVE_MS = 15 * MINUTE_IN_MILLIS; + mQcConstants.WINDOW_SIZE_WORKING_MS = 30 * MINUTE_IN_MILLIS; + mQcConstants.WINDOW_SIZE_FREQUENT_MS = 45 * MINUTE_IN_MILLIS; + mQcConstants.WINDOW_SIZE_RARE_MS = 60 * MINUTE_IN_MILLIS; + mQcConstants.MAX_EXECUTION_TIME_MS = 3 * HOUR_IN_MILLIS; + mQcConstants.MAX_JOB_COUNT_ACTIVE = 5000; + mQcConstants.MAX_JOB_COUNT_WORKING = 4000; + mQcConstants.MAX_JOB_COUNT_FREQUENT = 3000; + mQcConstants.MAX_JOB_COUNT_RARE = 2000; + mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME = 500; + + mQcConstants.updateConstants(); assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs()); assertEquals(2 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs()); @@ -1561,20 +1557,20 @@ public class QuotaControllerTest { @Test public void testConstantsUpdating_InvalidValues() { // Test negatives/too low. - mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = -MINUTE_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = -MINUTE_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = -MINUTE_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = -MINUTE_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = -MINUTE_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = -MINUTE_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = -MINUTE_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = -1; - mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = 1; - mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = 1; - mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = 1; - mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = 0; - - mQuotaController.onConstantsUpdatedLocked(); + mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = -MINUTE_IN_MILLIS; + mQcConstants.IN_QUOTA_BUFFER_MS = -MINUTE_IN_MILLIS; + mQcConstants.WINDOW_SIZE_ACTIVE_MS = -MINUTE_IN_MILLIS; + mQcConstants.WINDOW_SIZE_WORKING_MS = -MINUTE_IN_MILLIS; + mQcConstants.WINDOW_SIZE_FREQUENT_MS = -MINUTE_IN_MILLIS; + mQcConstants.WINDOW_SIZE_RARE_MS = -MINUTE_IN_MILLIS; + mQcConstants.MAX_EXECUTION_TIME_MS = -MINUTE_IN_MILLIS; + mQcConstants.MAX_JOB_COUNT_ACTIVE = -1; + mQcConstants.MAX_JOB_COUNT_WORKING = 1; + mQcConstants.MAX_JOB_COUNT_FREQUENT = 1; + mQcConstants.MAX_JOB_COUNT_RARE = 1; + mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME = 0; + + mQcConstants.updateConstants(); assertEquals(MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs()); assertEquals(0, mQuotaController.getInQuotaBufferMs()); @@ -1590,15 +1586,15 @@ public class QuotaControllerTest { assertEquals(100, mQuotaController.getBucketMaxJobCounts()[RARE_INDEX]); // Test larger than a day. Controller should cap at one day. - mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = 25 * HOUR_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = 25 * HOUR_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = 25 * HOUR_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = 25 * HOUR_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = 25 * HOUR_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = 25 * HOUR_IN_MILLIS; - mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = 25 * HOUR_IN_MILLIS; + mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 25 * HOUR_IN_MILLIS; + mQcConstants.IN_QUOTA_BUFFER_MS = 25 * HOUR_IN_MILLIS; + mQcConstants.WINDOW_SIZE_ACTIVE_MS = 25 * HOUR_IN_MILLIS; + mQcConstants.WINDOW_SIZE_WORKING_MS = 25 * HOUR_IN_MILLIS; + mQcConstants.WINDOW_SIZE_FREQUENT_MS = 25 * HOUR_IN_MILLIS; + mQcConstants.WINDOW_SIZE_RARE_MS = 25 * HOUR_IN_MILLIS; + mQcConstants.MAX_EXECUTION_TIME_MS = 25 * HOUR_IN_MILLIS; - mQuotaController.onConstantsUpdatedLocked(); + mQcConstants.updateConstants(); assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs()); assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs()); @@ -2219,7 +2215,7 @@ public class QuotaControllerTest { verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any()); // Ran jobs up to the job limit. All of them should be allowed to run. - for (int i = 0; i < mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME; ++i) { + for (int i = 0; i < mQcConstants.MAX_JOB_COUNT_PER_ALLOWED_TIME; ++i) { JobStatus job = createJobStatus("testStartAlarmScheduled_JobCount_AllowedTime", i); mQuotaController.maybeStartTrackingJobLocked(job, null); assertTrue(job.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); @@ -2240,7 +2236,7 @@ public class QuotaControllerTest { ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket); final long expectedWorkingAlarmTime = - stats.jobCountExpirationTimeElapsed + mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS; + stats.jobCountExpirationTimeElapsed + mQcConstants.ALLOWED_TIME_PER_PERIOD_MS; verify(mAlarmManager, times(1)) .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any()); } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java index 494677d38c0e..19369dbe5f44 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java @@ -39,6 +39,7 @@ import android.app.job.JobInfo; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManagerInternal; +import android.os.Looper; import android.os.SystemClock; import androidx.test.runner.AndroidJUnit4; @@ -70,7 +71,7 @@ public class TimeControllerTest { private static final String SOURCE_PACKAGE = "com.android.frameworks.mockingservicestests"; private static final int SOURCE_USER_ID = 0; - private Constants mConstants; + private TimeController.TcConstants mConstants; private TimeController mTimeController; private MockitoSession mMockingSession; @@ -88,14 +89,13 @@ public class TimeControllerTest { .strictness(Strictness.LENIENT) .mockStatic(LocalServices.class) .startMocking(); - // Use default constants for now. - mConstants = new Constants(); // Called in StateController constructor. when(mJobSchedulerService.getTestableContext()).thenReturn(mContext); when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService); - when(mJobSchedulerService.getConstants()).thenReturn(mConstants); + when(mJobSchedulerService.getConstants()).thenReturn(mock(Constants.class)); // Called in TimeController constructor. + when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper()); when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager); // Used in JobStatus. doReturn(mock(PackageManagerInternal.class)) @@ -111,6 +111,7 @@ public class TimeControllerTest { // Initialize real objects. mTimeController = new TimeController(mJobSchedulerService); + mConstants = mTimeController.getTcConstants(); spyOn(mTimeController); } @@ -159,7 +160,7 @@ public class TimeControllerTest { @Test public void testMaybeStartTrackingJobLocked_DelayInOrder_NoSkipping() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false; + mConstants.SKIP_NOT_READY_JOBS = false; mTimeController.onConstantsUpdatedLocked(); runTestMaybeStartTrackingJobLocked_DelayInOrder(); @@ -167,7 +168,7 @@ public class TimeControllerTest { @Test public void testMaybeStartTrackingJobLocked_DelayInOrder_WithSkipping_AllReady() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; + mConstants.SKIP_NOT_READY_JOBS = true; mTimeController.onConstantsUpdatedLocked(); doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); @@ -201,7 +202,7 @@ public class TimeControllerTest { @Test public void testMaybeStartTrackingJobLocked_DelayInOrder_WithSkipping_SomeNotReady() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; + mConstants.SKIP_NOT_READY_JOBS = true; mTimeController.onConstantsUpdatedLocked(); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); @@ -235,7 +236,7 @@ public class TimeControllerTest { @Test public void testMaybeStartTrackingJobLocked_DelayReverseOrder_NoSkipping() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false; + mConstants.SKIP_NOT_READY_JOBS = false; mTimeController.onConstantsUpdatedLocked(); runTestMaybeStartTrackingJobLocked_DelayReverseOrder(); @@ -243,7 +244,7 @@ public class TimeControllerTest { @Test public void testMaybeStartTrackingJobLocked_DelayReverseOrder_WithSkipping_AllReady() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; + mConstants.SKIP_NOT_READY_JOBS = true; mTimeController.onConstantsUpdatedLocked(); doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); @@ -279,7 +280,7 @@ public class TimeControllerTest { @Test public void testMaybeStartTrackingJobLocked_DelayReverseOrder_WithSkipping_SomeNotReady() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; + mConstants.SKIP_NOT_READY_JOBS = true; mTimeController.onConstantsUpdatedLocked(); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); @@ -315,7 +316,7 @@ public class TimeControllerTest { @Test public void testMaybeStartTrackingJobLocked_DeadlineInOrder_NoSkipping() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false; + mConstants.SKIP_NOT_READY_JOBS = false; mTimeController.onConstantsUpdatedLocked(); runTestMaybeStartTrackingJobLocked_DeadlineInOrder(); @@ -323,7 +324,7 @@ public class TimeControllerTest { @Test public void testMaybeStartTrackingJobLocked_DeadlineInOrder_WithSkipping_AllReady() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; + mConstants.SKIP_NOT_READY_JOBS = true; mTimeController.onConstantsUpdatedLocked(); doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); @@ -357,7 +358,7 @@ public class TimeControllerTest { @Test public void testMaybeStartTrackingJobLocked_DeadlineInOrder_WithSkipping_SomeNotReady() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; + mConstants.SKIP_NOT_READY_JOBS = true; mTimeController.onConstantsUpdatedLocked(); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); @@ -391,7 +392,7 @@ public class TimeControllerTest { @Test public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_NoSkipping() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false; + mConstants.SKIP_NOT_READY_JOBS = false; mTimeController.onConstantsUpdatedLocked(); runTestMaybeStartTrackingJobLocked_DeadlineReverseOrder(); @@ -399,7 +400,7 @@ public class TimeControllerTest { @Test public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_WithSkipping_AllReady() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; + mConstants.SKIP_NOT_READY_JOBS = true; mTimeController.onConstantsUpdatedLocked(); doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); @@ -438,7 +439,7 @@ public class TimeControllerTest { @Test public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_WithSkipping_SomeNotReady() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; + mConstants.SKIP_NOT_READY_JOBS = true; mTimeController.onConstantsUpdatedLocked(); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); @@ -493,8 +494,8 @@ public class TimeControllerTest { .wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt()); // Starting off with the skipping off, we should still set an alarm for the earlier job. - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false; - mTimeController.onConstantsUpdatedLocked(); + mConstants.SKIP_NOT_READY_JOBS = false; + mTimeController.recheckAlarmsLocked(); InOrder inOrder = inOrder(mAlarmManager); mTimeController.maybeStartTrackingJobLocked(jobEarliest, null); @@ -504,16 +505,16 @@ public class TimeControllerTest { eq(TAG_DEADLINE), any(), any(), any()); // Turn it on, use alarm for later job. - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); + mConstants.SKIP_NOT_READY_JOBS = true; + mTimeController.recheckAlarmsLocked(); inOrder.verify(mAlarmManager, times(1)) .set(anyInt(), eq(now + HOUR_IN_MILLIS), anyLong(), anyLong(), eq(TAG_DEADLINE), any(), any(), any()); // Back off, use alarm for earlier job. - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false; - mTimeController.onConstantsUpdatedLocked(); + mConstants.SKIP_NOT_READY_JOBS = false; + mTimeController.recheckAlarmsLocked(); inOrder.verify(mAlarmManager, times(1)) .set(anyInt(), eq(now + 5 * MINUTE_IN_MILLIS), anyLong(), anyLong(), @@ -522,16 +523,16 @@ public class TimeControllerTest { @Test public void testCheckExpiredDelaysAndResetAlarm_NoSkipping() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false; - mTimeController.onConstantsUpdatedLocked(); + mConstants.SKIP_NOT_READY_JOBS = false; + mTimeController.recheckAlarmsLocked(); runTestCheckExpiredDelaysAndResetAlarm(); } @Test public void testCheckExpiredDelaysAndResetAlarm_WithSkipping_AllReady() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); + mConstants.SKIP_NOT_READY_JOBS = true; + mTimeController.recheckAlarmsLocked(); doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); @@ -589,8 +590,8 @@ public class TimeControllerTest { @Test public void testCheckExpiredDelaysAndResetAlarm_WithSkipping_SomeNotReady() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); + mConstants.SKIP_NOT_READY_JOBS = true; + mTimeController.recheckAlarmsLocked(); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); JobStatus jobLatest = createJobStatus("testCheckExpiredDelaysAndResetAlarm", @@ -639,16 +640,16 @@ public class TimeControllerTest { @Test public void testCheckExpiredDeadlinesAndResetAlarm_NoSkipping() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false; - mTimeController.onConstantsUpdatedLocked(); + mConstants.SKIP_NOT_READY_JOBS = false; + mTimeController.recheckAlarmsLocked(); runTestCheckExpiredDeadlinesAndResetAlarm(); } @Test public void testCheckExpiredDeadlinesAndResetAlarm_WithSkipping_AllReady() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); + mConstants.SKIP_NOT_READY_JOBS = true; + mTimeController.recheckAlarmsLocked(); doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt()); @@ -706,8 +707,8 @@ public class TimeControllerTest { @Test public void testCheckExpiredDeadlinesAndResetAlarm_WithSkipping_SomeNotReady() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); + mConstants.SKIP_NOT_READY_JOBS = true; + mTimeController.recheckAlarmsLocked(); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); JobStatus jobLatest = createJobStatus("testCheckExpiredDeadlinesAndResetAlarm", @@ -756,8 +757,8 @@ public class TimeControllerTest { @Test public void testEvaluateStateLocked_SkippingOff() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false; - mTimeController.onConstantsUpdatedLocked(); + mConstants.SKIP_NOT_READY_JOBS = false; + mTimeController.recheckAlarmsLocked(); JobStatus job = createJobStatus("testEvaluateStateLocked_SkippingOff", createJob().setOverrideDeadline(HOUR_IN_MILLIS)); @@ -768,8 +769,8 @@ public class TimeControllerTest { @Test public void testEvaluateStateLocked_SkippingOn_Delay() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); + mConstants.SKIP_NOT_READY_JOBS = true; + mTimeController.recheckAlarmsLocked(); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_SkippingOn_Delay", @@ -827,8 +828,8 @@ public class TimeControllerTest { @Test public void testEvaluateStateLocked_SkippingOn_Deadline() { - mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true; - mTimeController.onConstantsUpdatedLocked(); + mConstants.SKIP_NOT_READY_JOBS = true; + mTimeController.recheckAlarmsLocked(); final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_SkippingOn_Deadline", diff --git a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java index eb90295ed8c9..dae3d30c4fd1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java +++ b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java @@ -137,7 +137,6 @@ public final class TestableDeviceConfig implements TestRule { return mKeyValueMap.get(getKey(namespace, name)); }).when(() -> DeviceConfig.getProperty(anyString(), anyString())); - return new TestWatcher() { @Override protected void succeeded(Description description) { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java index bac8414ef205..7a20af45b999 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java @@ -329,6 +329,31 @@ public class RecoverableKeyStoreDbTest { assertEquals(serialNumber, mRecoverableKeyStoreDb.getUserSerialNumbers().get(userId)); } + @Test + public void setPlatformKeyGenerationId_invalidatesExistingKeysForUser() { + int userId = 42; + int generationId = 110; + int uid = 1009; + int status = 120; + String alias = "test"; + byte[] nonce = getUtf8Bytes("nonce"); + byte[] keyMaterial = getUtf8Bytes("keymaterial"); + byte[] keyMetadata = null; + + WrappedKey wrappedKey = + new WrappedKey(nonce, keyMaterial, keyMetadata, generationId, status); + mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey); + + WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias); + assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status); + + mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId + 1); + + retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias); + assertThat(retrievedKey.getRecoveryStatus()) + .isEqualTo(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE); + } + @Test public void removeUserFromAllTables_removesData() throws Exception { @@ -439,7 +464,7 @@ public class RecoverableKeyStoreDbTest { } @Test - public void testInvalidateKeysWithOldGenerationId_withSingleKey() { + public void testInvalidateKeysForUser_withSingleKey() { int userId = 12; int uid = 1009; int generationId = 6; @@ -458,7 +483,7 @@ public class RecoverableKeyStoreDbTest { assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status); mRecoverableKeyStoreDb.setRecoveryStatus(uid, alias, status2); - mRecoverableKeyStoreDb.invalidateKeysWithOldGenerationId(userId, generationId + 1); + mRecoverableKeyStoreDb.invalidateKeysForUser(userId); retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias); assertThat(retrievedKey.getRecoveryStatus()) diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 99b827c11853..bdc46ec808c1 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -263,6 +263,7 @@ public class NetworkPolicyManagerServiceTest { private static final int INVALID_CARRIER_CONFIG_VALUE = -9999; private long mDefaultWarningBytes; // filled in with the actual default before tests are run private long mDefaultLimitBytes; // filled in with the actual default before tests are run + private PersistableBundle mCarrierConfig = CarrierConfigManager.getDefaultConfig(); private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 4; private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 8; @@ -409,6 +410,9 @@ public class NetworkPolicyManagerServiceTest { doNothing().when(mConnectivityManager) .registerNetworkCallback(any(), mNetworkCallbackCaptor.capture()); + // Create the expected carrier config + mCarrierConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); + // Prepare NPMS. mService.systemReady(mService.networkScoreAndNetworkManagementServiceReady()); @@ -1086,6 +1090,25 @@ public class NetworkPolicyManagerServiceTest { isA(Notification.class), eq(UserHandle.ALL)); } + // Push over warning, but with a config that isn't from an identified carrier + { + history.clear(); + history.recordData(start, end, + new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1799), 0L, 0L, 0L, 0)); + + reset(mTelephonyManager, mNetworkManager, mNotifManager); + expectMobileDefaults(); + expectDefaultCarrierConfig(); + + mService.updateNetworks(); + + verify(mTelephonyManager, atLeastOnce()).setPolicyDataEnabled(true, TEST_SUB_ID); + verify(mNetworkManager, atLeastOnce()).setInterfaceQuota(TEST_IFACE, + DataUnit.MEGABYTES.toBytes(1800 - 1799)); + // Since this isn't from the identified carrier, there should be no notifications + verify(mNotifManager, never()).notifyAsUser(any(), anyInt(), any(), any()); + } + // Push over limit { history.clear(); @@ -1812,7 +1835,7 @@ public class NetworkPolicyManagerServiceTest { private void expectNetworkState(boolean roaming) throws Exception { when(mCarrierConfigManager.getConfigForSubId(eq(TEST_SUB_ID))) - .thenReturn(CarrierConfigManager.getDefaultConfig()); + .thenReturn(mCarrierConfig); when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[] { new NetworkState(buildNetworkInfo(), buildLinkProperties(TEST_IFACE), @@ -1821,10 +1844,16 @@ public class NetworkPolicyManagerServiceTest { }); } + private void expectDefaultCarrierConfig() throws Exception { + when(mCarrierConfigManager.getConfigForSubId(eq(TEST_SUB_ID))) + .thenReturn(CarrierConfigManager.getDefaultConfig()); + } + private void expectMobileDefaults() throws Exception { when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn( new int[] { TEST_SUB_ID }); when(mTelephonyManager.getSubscriberId(TEST_SUB_ID)).thenReturn(TEST_IMSI); + doNothing().when(mTelephonyManager).setPolicyDataEnabled(anyBoolean(), anyInt()); expectNetworkState(false /* roaming */); } diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java index 380f7c67402e..5cd649fc968f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java @@ -27,6 +27,7 @@ import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Before; @@ -80,6 +81,7 @@ public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testContainerRemoved() { final AppWindowToken window1 = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 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 83c0af92a6ee..777e4f4915b8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java @@ -38,6 +38,7 @@ import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationDefinition; import android.view.RemoteAnimationTarget; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Test; @@ -96,6 +97,7 @@ public class AppChangeTransitionTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testModeChangeRemoteAnimatorNoSnapshot() { // setup currently defaults to no snapshot. setUpOnDisplay(mDisplayContent); @@ -113,6 +115,7 @@ public class AppChangeTransitionTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testCancelPendingChangeOnRemove() { // setup currently defaults to no snapshot. setUpOnDisplay(mDisplayContent); @@ -132,6 +135,7 @@ public class AppChangeTransitionTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testNoChangeWhenMoveDisplay() { mDisplayContent.setWindowingMode(WINDOWING_MODE_FULLSCREEN); final DisplayContent dc1 = createNewDisplay(Display.STATE_ON); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index b1ffbbd4ffba..2d1dd39db83e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -31,6 +31,7 @@ import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; import android.view.WindowManager; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Before; @@ -52,6 +53,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testTranslucentOpen() { synchronized (mWm.mGlobalLock) { final AppWindowToken behind = createAppWindowToken(mDisplayContent, @@ -69,6 +71,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testTranslucentClose() { synchronized (mWm.mGlobalLock) { final AppWindowToken behind = createAppWindowToken(mDisplayContent, @@ -84,6 +87,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testChangeIsNotOverwritten() { synchronized (mWm.mGlobalLock) { final AppWindowToken behind = createAppWindowToken(mDisplayContent, diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index 6e09167f7cba..9cdea9a3eab4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -39,6 +39,7 @@ import android.view.Display; import org.junit.Before; import org.junit.Test; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; /** @@ -78,6 +79,7 @@ public class AppTransitionTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testForceOverride() { mWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */); mDc.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, @@ -93,6 +95,7 @@ public class AppTransitionTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testKeepKeyguard_withCrashing() { mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */); mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */); @@ -100,6 +103,7 @@ public class AppTransitionTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testAppTransitionStateForMultiDisplay() { // Create 2 displays & presume both display the state is ON for ready to display & animate. final DisplayContent dc1 = createNewDisplay(Display.STATE_ON); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowThumbnailTest.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowThumbnailTest.java index fa0c384ca89d..b8f8e21d64ac 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowThumbnailTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowThumbnailTest.java @@ -28,6 +28,7 @@ import android.platform.test.annotations.Presubmit; import android.view.Surface; import android.view.SurfaceControl; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Test; @@ -53,6 +54,7 @@ public class AppWindowThumbnailTest extends WindowTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testDestroy_nullsSurface() { final AppWindowThumbnail t = buildThumbnail(); assertNotNull(t.getSurfaceControl()); diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java index 196cc211692c..0110e94eb1cd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java @@ -39,6 +39,7 @@ import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.View; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.LocalServices; @@ -146,16 +147,19 @@ public class DragDropControllerTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testDragFlow() { dragFlow(0, ClipData.newPlainText("label", "Test"), 0, 0); } @Test + @FlakyTest(bugId = 131005232) public void testPerformDrag_NullDataWithGrantUri() { dragFlow(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0); } @Test + @FlakyTest(bugId = 131005232) public void testPerformDrag_NullDataToOtherUser() { final WindowState otherUsersWindow = createDropTargetWindow("Other user's window", 1 * UserHandle.PER_USER_RANGE); diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java index a0546d7623e7..86ee75ebf3df 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -31,6 +31,7 @@ import android.platform.test.annotations.Presubmit; import android.view.InsetsSource; import android.view.InsetsState; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Before; diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index 2d906d1683d5..9fce78b292f5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -58,6 +58,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testStripForDispatch_notOwn() { final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); final WindowState app = createWindow(null, TYPE_APPLICATION, "parentWindow"); diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java index b769fcecc469..103c3ab7e541 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java @@ -24,6 +24,7 @@ import android.app.ActivityOptions; import android.platform.test.annotations.Presubmit; import android.view.RemoteAnimationAdapter; +import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.server.testutils.OffsettableClock; @@ -73,6 +74,7 @@ public class PendingRemoteAnimationRegistryTest extends ActivityTestsBase { } @Test + @FlakyTest(bugId = 131005232) public void testTimeout() { mRegistry.addPendingAnimation("com.android.test", mAdapter); mClock.fastForward(5000); diff --git a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java index 4673992f64ef..027f90333561 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java @@ -110,6 +110,7 @@ public class PersisterQueueTests { } @Test + @FlakyTest(bugId = 131005232) public void testProcessOneItem_Flush() throws Exception { mFactory.setExpectedProcessedItemNumber(1); mListener.setExpectedOnPreProcessItemCallbackTimes(1); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index 0c2ce614b772..385748c21ff8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE; import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; @@ -166,6 +167,25 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false); } + @Test + public void testShouldAnimateWhenNoCancelWithDeferredScreenshot() { + mWm.setRecentsAnimationController(mController); + final AppWindowToken appWindow = createAppWindowToken(mDisplayContent, + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); + final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1"); + appWindow.addWindow(win1); + assertEquals(appWindow.getTask().getTopVisibleAppToken(), appWindow); + assertEquals(appWindow.findMainWindow(), win1); + + mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */); + assertTrue(mController.isAnimatingTask(appWindow.getTask())); + + // Assume appWindow transition should animate when no + // IRecentsAnimationController#setCancelWithDeferredScreenshot called. + assertFalse(mController.shouldCancelWithDeferredScreenshot()); + assertTrue(appWindow.shouldAnimate(TRANSIT_ACTIVITY_CLOSE)); + } + private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) { verify(binder, atLeast(0)).asBinder(); verifyNoMoreInteractions(binder); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java index 9dfeadf878e0..9fc160229d45 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java @@ -29,6 +29,8 @@ import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.util.SparseBooleanArray; +import androidx.test.filters.FlakyTest; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -72,6 +74,7 @@ public class TaskPersisterTest { } @Test + @FlakyTest(bugId = 131005232) public void testTaskIdsPersistence() { SparseBooleanArray taskIdsOnFile = new SparseBooleanArray(); for (int i = 0; i < 100; i++) { diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 373c5d27eec8..3ce28a46a029 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -38,6 +38,8 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Executor; +import dalvik.system.VMRuntime; + /** * A listener class for monitoring changes in specific telephony states * on the device, including service state, signal strength, message @@ -400,8 +402,12 @@ public class PhoneStateListener { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public PhoneStateListener(Integer subId) { this(subId, Looper.myLooper()); + if (subId != null && VMRuntime.getRuntime().getTargetSdkVersion() + >= Build.VERSION_CODES.Q) { + throw new IllegalArgumentException("PhoneStateListener with subId: " + + subId + " is not supported, use default constructor"); + } } - /** * Create a PhoneStateListener for the Phone using the specified subscription * and non-null Looper. @@ -410,6 +416,11 @@ public class PhoneStateListener { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public PhoneStateListener(Integer subId, Looper looper) { this(subId, new HandlerExecutor(new Handler(looper))); + if (subId != null && VMRuntime.getRuntime().getTargetSdkVersion() + >= Build.VERSION_CODES.Q) { + throw new IllegalArgumentException("PhoneStateListener with subId: " + + subId + " is not supported, use default constructor"); + } } /** diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index f0cad6a35b16..903e53394c03 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -108,6 +108,8 @@ import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; +import dalvik.system.VMRuntime; + /** * Provides access to information about the telephony services on * the device. Applications can use the methods in this class to @@ -4863,18 +4865,22 @@ public class TelephonyManager { * Registers a listener object to receive notification of changes * in specified telephony states. * <p> - * To register a listener, pass a {@link PhoneStateListener} - * and specify at least one telephony state of interest in - * the events argument. - * - * At registration, and when a specified telephony state - * changes, the telephony manager invokes the appropriate - * callback method on the listener object and passes the - * current (updated) values. + * To register a listener, pass a {@link PhoneStateListener} and specify at least one telephony + * state of interest in the events argument. + * + * At registration, and when a specified telephony state changes, the telephony manager invokes + * the appropriate callback method on the listener object and passes the current (updated) + * values. * <p> - * To unregister a listener, pass the listener object and set the - * events argument to + * To un-register a listener, pass the listener object and set the events argument to * {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0). + * + * If this TelephonyManager object has been created with {@link #createForSubscriptionId}, + * applies to the given subId. Otherwise, applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds, + * pass a separate listener object to each TelephonyManager object created with + * {@link #createForSubscriptionId}. + * * Note: if you call this method while in the middle of a binder transaction, you <b>must</b> * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A * {@link SecurityException} will be thrown otherwise. @@ -4889,17 +4895,26 @@ public class TelephonyManager { if (mContext == null) return; try { boolean notifyNow = (getITelephony() != null); - // If the listener has not explicitly set the subId (for example, created with the - // default constructor), replace the subId so it will listen to the account the - // telephony manager is created with. - if (listener.mSubId == null) { - listener.mSubId = mSubId; - } - ITelephonyRegistry registry = getTelephonyRegistry(); if (registry != null) { - registry.listenForSubscriber(listener.mSubId, getOpPackageName(), + int subId; + // subId from phonestatelistner is deprecated Q on forward, use the subId from + // TelephonyManager instance. + if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q + || listener.mSubId == null) { + subId = mSubId; + } else { + subId = listener.mSubId; + } + + registry.listenForSubscriber(subId, getOpPackageName(), listener.callback, events, notifyNow); + // TODO: remove this once we remove PhoneStateListener constructor with subId. + if (events == PhoneStateListener.LISTEN_NONE) { + listener.mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } else { + listener.mSubId = subId; + } } else { Rlog.w(TAG, "telephony registry not ready."); } diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java index 12b20efcb0b3..64c1830c5e5c 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java @@ -419,7 +419,8 @@ public final class TelephonyPermissions { // settings to individually disable the new restrictions for privileged, preloaded // non-privileged, and non-preinstalled apps. if (!isIdentifierCheckDisabled() && ( - (!isPreinstalled && !relax3PDeviceIdentifierCheck) + (isPrivApp && !relaxPrivDeviceIdentifierCheck) + || (!isPreinstalled && !relax3PDeviceIdentifierCheck) || (isPreinstalled && !isPrivApp && !relaxNonPrivDeviceIdentifierCheck))) { // The current package should only be reported in StatsLog if it has not previously been // reported for the currently invoked device identifier method. diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index 13e737e9fed3..eb19361d86a3 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -18,25 +18,27 @@ package com.android.server; import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig; -import static com.android.server.PackageWatchdog.MonitoredPackage; -import static com.android.server.PackageWatchdog.TRIGGER_FAILURE_COUNT; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import android.Manifest; import android.content.Context; import android.content.pm.VersionedPackage; import android.os.Handler; import android.os.test.TestLooper; +import android.provider.DeviceConfig; import android.util.AtomicFile; import androidx.test.InstrumentationRegistry; +import com.android.server.PackageWatchdog.MonitoredPackage; import com.android.server.PackageWatchdog.PackageHealthObserver; import com.android.server.PackageWatchdog.PackageHealthObserverImpact; +import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -73,8 +75,13 @@ public class PackageWatchdogTest { public void setUp() throws Exception { new File(InstrumentationRegistry.getContext().getFilesDir(), "package-watchdog.xml").delete(); + adoptShellPermissions(Manifest.permission.READ_DEVICE_CONFIG); mTestLooper = new TestLooper(); - mTestLooper.startAutoDispatch(); + } + + @After + public void tearDown() throws Exception { + dropShellPermissions(); } /** @@ -204,7 +211,7 @@ public class PackageWatchdogTest { // Verify random observer not saved returns null assertNull(watchdog2.getPackages(new TestObserver(OBSERVER_NAME_3))); - // Then regiser observer1 + // Then register observer1 watchdog2.registerHealthObserver(observer1); watchdog2.registerHealthObserver(observer2); @@ -231,7 +238,7 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION); // Then fail APP_A below the threshold - for (int i = 0; i < TRIGGER_FAILURE_COUNT - 1; i++) { + for (int i = 0; i < watchdog.getTriggerFailureCount() - 1; i++) { watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); } @@ -258,7 +265,7 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer1, Arrays.asList(APP_B), SHORT_DURATION); // Then fail APP_C (not observed) above the threshold - for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) { + for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_C, VERSION_CODE))); } @@ -292,7 +299,7 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION); // Then fail APP_A (different version) above the threshold - for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) { + for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { watchdog.onPackageFailure(Arrays.asList( new VersionedPackage(APP_A, differentVersionCode))); } @@ -331,7 +338,7 @@ public class PackageWatchdogTest { SHORT_DURATION); // Then fail all apps above the threshold - for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) { + for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE), new VersionedPackage(APP_B, VERSION_CODE), new VersionedPackage(APP_C, VERSION_CODE), @@ -384,7 +391,7 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observerSecond, Arrays.asList(APP_A), LONG_DURATION); // Then fail APP_A above the threshold - for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) { + for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); } // Run handler so package failures are dispatched to observers @@ -401,7 +408,7 @@ public class PackageWatchdogTest { observerSecond.mFailedPackages.clear(); // Then fail APP_A again above the threshold - for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) { + for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); } // Run handler so package failures are dispatched to observers @@ -418,7 +425,7 @@ public class PackageWatchdogTest { observerSecond.mFailedPackages.clear(); // Then fail APP_A again above the threshold - for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) { + for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); } // Run handler so package failures are dispatched to observers @@ -435,7 +442,7 @@ public class PackageWatchdogTest { observerSecond.mFailedPackages.clear(); // Then fail APP_A again above the threshold - for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) { + for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); } // Run handler so package failures are dispatched to observers @@ -462,7 +469,7 @@ public class PackageWatchdogTest { watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION); // Then fail APP_A above the threshold - for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) { + for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); } @@ -539,6 +546,10 @@ public class PackageWatchdogTest { */ @Test public void testExplicitHealthCheckStateChanges() throws Exception { + adoptShellPermissions( + Manifest.permission.WRITE_DEVICE_CONFIG, + Manifest.permission.READ_DEVICE_CONFIG); + TestController controller = new TestController(); PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */); TestObserver observer = new TestObserver(OBSERVER_NAME_1, @@ -559,7 +570,7 @@ public class PackageWatchdogTest { assertEquals(APP_B, requestedPackages.get(1)); // Disable explicit health checks (marks APP_A and APP_B as passed) - watchdog.setExplicitHealthCheckEnabled(false); + setExplicitHealthCheckEnabled(false); // Run handler so requests/cancellations are dispatched to the controller mTestLooper.dispatchAll(); @@ -575,7 +586,7 @@ public class PackageWatchdogTest { assertEquals(0, observer.mFailedPackages.size()); // Re-enable explicit health checks - watchdog.setExplicitHealthCheckEnabled(true); + setExplicitHealthCheckEnabled(true); // Run handler so requests/cancellations are dispatched to the controller mTestLooper.dispatchAll(); @@ -643,11 +654,13 @@ public class PackageWatchdogTest { /** Tests {@link MonitoredPackage} health check state transitions. */ @Test public void testPackageHealthCheckStateTransitions() { - MonitoredPackage m1 = new MonitoredPackage(APP_A, LONG_DURATION, + TestController controller = new TestController(); + PackageWatchdog wd = createWatchdog(controller, true /* withPackagesReady */); + MonitoredPackage m1 = wd.new MonitoredPackage(APP_A, LONG_DURATION, false /* hasPassedHealthCheck */); - MonitoredPackage m2 = new MonitoredPackage(APP_B, LONG_DURATION, false); - MonitoredPackage m3 = new MonitoredPackage(APP_C, LONG_DURATION, false); - MonitoredPackage m4 = new MonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true); + MonitoredPackage m2 = wd.new MonitoredPackage(APP_B, LONG_DURATION, false); + MonitoredPackage m3 = wd.new MonitoredPackage(APP_C, LONG_DURATION, false); + MonitoredPackage m4 = wd.new MonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true); // Verify transition: inactive -> active -> passed // Verify initially inactive @@ -683,6 +696,32 @@ public class PackageWatchdogTest { assertEquals(MonitoredPackage.STATE_PASSED, m4.handleElapsedTimeLocked(LONG_DURATION)); } + private void adoptShellPermissions(String... permissions) { + InstrumentationRegistry + .getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(permissions); + } + + private void dropShellPermissions() { + InstrumentationRegistry + .getInstrumentation() + .getUiAutomation() + .dropShellPermissionIdentity(); + } + + private void setExplicitHealthCheckEnabled(boolean enabled) { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK, + PackageWatchdog.PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED, + Boolean.toString(enabled), /*makeDefault*/false); + //give time for DeviceConfig to broadcast the property value change + try { + Thread.sleep(SHORT_DURATION); + } catch (InterruptedException e) { + fail("Thread.sleep unexpectedly failed!"); + } + } + private PackageWatchdog createWatchdog() { return createWatchdog(new TestController(), true /* withPackagesReady */); } |