diff options
96 files changed, 2692 insertions, 1006 deletions
diff --git a/Android.mk b/Android.mk index b3db4097f240..b1bb1bbe175e 100644 --- a/Android.mk +++ b/Android.mk @@ -694,6 +694,7 @@ aidl_files := \ frameworks/base/telephony/java/android/telephony/NeighboringCellInfo.aidl \ frameworks/base/telephony/java/android/telephony/ModemActivityInfo.aidl \ frameworks/base/telephony/java/android/telephony/UiccAccessRule.aidl \ + frameworks/base/telephony/java/android/telephony/data/DataProfile.aidl \ frameworks/base/telephony/java/android/telephony/euicc/DownloadableSubscription.aidl \ frameworks/base/telephony/java/android/telephony/euicc/EuiccInfo.aidl \ frameworks/base/location/java/android/location/Location.aidl \ @@ -1029,6 +1030,7 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS := \ -manifest ./frameworks/base/core/res/AndroidManifest.xml \ -hidePackage com.android.okhttp \ -hidePackage com.android.org.conscrypt \ + -hidePackage com.android.server \ -since $(SRC_API_DIR)/1.xml 1 \ -since $(SRC_API_DIR)/2.xml 2 \ -since $(SRC_API_DIR)/3.xml 3 \ @@ -1562,7 +1564,8 @@ LOCAL_SRC_FILES := \ tools/streaming_proto/stream.proto \ cmds/am/proto/instrumentation_data.proto \ $(call all-proto-files-under, core/proto) \ - $(call all-proto-files-under, libs/incident/proto) + $(call all-proto-files-under, libs/incident/proto) \ + $(call all-proto-files-under, cmds/statsd/src) include $(BUILD_HOST_JAVA_LIBRARY) # ==== java proto device library (for test only) ============================== diff --git a/api/current.txt b/api/current.txt index c1188dcd330b..93b6b424458f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -37499,6 +37499,7 @@ package android.service.autofill { public final class SaveCallback { method public void onFailure(java.lang.CharSequence); method public void onSuccess(); + method public void onSuccess(android.content.IntentSender); } public final class SaveInfo implements android.os.Parcelable { diff --git a/api/system-current.txt b/api/system-current.txt index 9dca6f782385..990df9be9b29 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4131,6 +4131,39 @@ package android.telephony { } +package android.telephony.data { + + public final class DataProfile implements android.os.Parcelable { + ctor public DataProfile(int, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, int, int, int, int, boolean, int, java.lang.String, int, int, java.lang.String, java.lang.String, boolean); + ctor public DataProfile(android.os.Parcel); + method public int describeContents(); + method public java.lang.String getApn(); + method public int getAuthType(); + method public int getBearerBitmap(); + method public int getMaxConns(); + method public int getMaxConnsTime(); + method public int getMtu(); + method public java.lang.String getMvnoMatchData(); + method public java.lang.String getMvnoType(); + method public java.lang.String getPassword(); + method public int getProfileId(); + method public java.lang.String getProtocol(); + method public java.lang.String getRoamingProtocol(); + method public int getSupportedApnTypesBitmap(); + method public int getType(); + method public java.lang.String getUserName(); + method public int getWaitTime(); + method public boolean isEnabled(); + method public boolean isModemCognitive(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.data.DataProfile> CREATOR; + field public static final int TYPE_3GPP = 1; // 0x1 + field public static final int TYPE_3GPP2 = 2; // 0x2 + field public static final int TYPE_COMMON = 0; // 0x0 + } + +} + package android.telephony.ims { public class ImsService extends android.app.Service { diff --git a/api/test-current.txt b/api/test-current.txt index 2e6c40ac34aa..8647ed397c49 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -75,9 +75,11 @@ package android.app { method public int describeContents(); method public int getActivityType(); method public android.graphics.Rect getAppBounds(); + method public android.graphics.Rect getBounds(); method public int getWindowingMode(); method public void setActivityType(int); method public void setAppBounds(android.graphics.Rect); + method public void setBounds(android.graphics.Rect); method public void setTo(android.app.WindowConfiguration); method public void setWindowingMode(int); method public void writeToParcel(android.os.Parcel, int); diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index 4d975fcf9c64..1f15c5e97e0d 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -57,7 +57,8 @@ statsd_common_src := \ src/StatsLogProcessor.cpp \ src/StatsService.cpp \ src/stats_util.cpp \ - src/guardrail/MemoryLeakTrackUtil.cpp + src/guardrail/MemoryLeakTrackUtil.cpp \ + src/guardrail/StatsdStats.cpp statsd_common_c_includes := \ $(LOCAL_PATH)/src \ @@ -167,7 +168,8 @@ LOCAL_SRC_FILES := \ tests/metrics/MaxDurationTracker_test.cpp \ tests/metrics/CountMetricProducer_test.cpp \ tests/metrics/EventMetricProducer_test.cpp \ - tests/metrics/ValueMetricProducer_test.cpp + tests/metrics/ValueMetricProducer_test.cpp \ + tests/guardrail/StatsdStats_test.cpp LOCAL_STATIC_LIBRARIES := \ libgmock diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index b5cb20c274ea..2690c7e43d79 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define DEBUG true // STOPSHIP if true #include "Log.h" #include "statslog.h" @@ -21,6 +22,7 @@ #include <dirent.h> #include "StatsLogProcessor.h" #include "android-base/stringprintf.h" +#include "guardrail/StatsdStats.h" #include "metrics/CountMetricProducer.h" #include "stats_util.h" #include "storage/StorageManager.h" @@ -82,6 +84,7 @@ void StatsLogProcessor::onAnomalyAlarmFired( // TODO: what if statsd service restarts? How do we know what logs are already processed before? void StatsLogProcessor::OnLogEvent(const LogEvent& msg) { + StatsdStats::getInstance().noteAtomLogged(msg.GetTagId(), msg.GetTimestampNs() / NS_PER_SEC); // pass the event to metrics managers. for (auto& pair : mMetricsManagers) { pair.second->onLogEvent(msg); @@ -106,23 +109,26 @@ void StatsLogProcessor::OnLogEvent(const LogEvent& msg) { } void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) { + ALOGD("Updated configuration for key %s", key.ToString().c_str()); + unique_ptr<MetricsManager> newMetricsManager = std::make_unique<MetricsManager>(key, config); + auto it = mMetricsManagers.find(key); if (it != mMetricsManagers.end()) { it->second->finish(); + } else if (mMetricsManagers.size() > StatsdStats::kMaxConfigCount) { + ALOGE("Can't accept more configs!"); + return; } - ALOGD("Updated configuration for key %s", key.ToString().c_str()); - - unique_ptr<MetricsManager> newMetricsManager = std::make_unique<MetricsManager>(config); if (newMetricsManager->isConfigValid()) { mUidMap->OnConfigUpdated(key); newMetricsManager->setAnomalyMonitor(mAnomalyMonitor); mMetricsManagers[key] = std::move(newMetricsManager); // Why doesn't this work? mMetricsManagers.insert({key, std::move(newMetricsManager)}); - ALOGD("StatsdConfig valid"); + VLOG("StatsdConfig valid"); } else { // If there is any error in the config, don't use it. - ALOGD("StatsdConfig NOT valid"); + ALOGE("StatsdConfig NOT valid"); } } @@ -204,6 +210,7 @@ void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) { mMetricsManagers.erase(it); mUidMap->OnConfigRemoved(key); } + StatsdStats::getInstance().noteConfigRemoved(key); std::lock_guard<std::mutex> lock(mBroadcastTimesMutex); mLastBroadcastTimes.erase(key); @@ -223,12 +230,14 @@ void StatsLogProcessor::flushIfNecessary(uint64_t timestampNs, } } mLastBroadcastTimes[key] = timestampNs; - ALOGD("StatsD requesting broadcast for %s", key.ToString().c_str()); + VLOG("StatsD requesting broadcast for %s", key.ToString().c_str()); mSendBroadcast(key); + StatsdStats::getInstance().noteBroadcastSent(key); } else if (totalBytes > kMaxSerializedBytes) { // Too late. We need to start clearing data. // We ignore the return value so we force each metric producer to clear its contents. metricsManager->onDumpReport(); - ALOGD("StatsD had to toss out metrics for %s", key.ToString().c_str()); + StatsdStats::getInstance().noteDataDrop(key); + VLOG("StatsD had to toss out metrics for %s", key.ToString().c_str()); } } diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index ec2650e72c08..8b64f0db5728 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -22,6 +22,7 @@ #include "config/ConfigKey.h" #include "config/ConfigManager.h" #include "guardrail/MemoryLeakTrackUtil.h" +#include "guardrail/StatsdStats.h" #include "storage/DropboxReader.h" #include "storage/StorageManager.h" @@ -222,7 +223,7 @@ status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& } if (!args[0].compare(String8("print-stats"))) { - return cmd_print_stats(out); + return cmd_print_stats(out, args); } if (!args[0].compare(String8("clear-config"))) { @@ -305,8 +306,9 @@ void StatsService::print_cmd_help(FILE* out) { fprintf(out, " NAME The name of the configuration\n"); fprintf(out, "\n"); fprintf(out, "\n"); - fprintf(out, "usage: adb shell cmd stats print-stats\n"); + fprintf(out, "usage: adb shell cmd stats print-stats [reset]\n"); fprintf(out, " Prints some basic stats.\n"); + fprintf(out, " reset: 1 to reset the statsd stats. default=0.\n"); } status_t StatsService::cmd_trigger_broadcast(FILE* out, Vector<String8>& args) { @@ -474,12 +476,20 @@ status_t StatsService::cmd_dump_report(FILE* out, FILE* err, const Vector<String } } -status_t StatsService::cmd_print_stats(FILE* out) { +status_t StatsService::cmd_print_stats(FILE* out, const Vector<String8>& args) { vector<ConfigKey> configs = mConfigManager->GetAllConfigKeys(); for (const ConfigKey& key : configs) { fprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(), mProcessor->GetMetricsSize(key)); } + fprintf(out, "Detailed statsd stats in logcat..."); + StatsdStats& statsdStats = StatsdStats::getInstance(); + bool reset = false; + if (args.size() > 1) { + reset = strtol(args[1].string(), NULL, 10); + } + vector<int8_t> output; + statsdStats.dumpStats(&output, reset); return NO_ERROR; } diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 6b5c156969e2..a32595a4a7f4 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -134,7 +134,7 @@ private: /** * Prints some basic stats to std out. */ - status_t cmd_print_stats(FILE* out); + status_t cmd_print_stats(FILE* out, const Vector<String8>& args); /** * Print the event log. diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp index d8099b34f39a..50cd130e9f39 100644 --- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp +++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp @@ -18,6 +18,7 @@ #include "Log.h" #include "SimpleConditionTracker.h" +#include "guardrail/StatsdStats.h" #include <log/logprint.h> @@ -32,9 +33,10 @@ using std::unordered_map; using std::vector; SimpleConditionTracker::SimpleConditionTracker( - const string& name, const int index, const SimpleCondition& simpleCondition, + const ConfigKey& key, const string& name, const int index, + const SimpleCondition& simpleCondition, const unordered_map<string, int>& trackerNameIndexMap) - : ConditionTracker(name, index) { + : ConditionTracker(name, index), mConfigKey(key) { VLOG("creating SimpleConditionTracker %s", mName.c_str()); mCountNesting = simpleCondition.count_nesting(); @@ -126,6 +128,24 @@ void SimpleConditionTracker::handleStopAll(std::vector<ConditionState>& conditio conditionCache[mIndex] = ConditionState::kFalse; } +bool SimpleConditionTracker::hitGuardRail(const HashableDimensionKey& newKey) { + if (!mSliced || mSlicedConditionState.find(newKey) != mSlicedConditionState.end()) { + // if the condition is not sliced or the key is not new, we are good! + return false; + } + // 1. Report the tuple count if the tuple count > soft limit + if (mSlicedConditionState.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) { + size_t newTupleCount = mSlicedConditionState.size() + 1; + StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mName, newTupleCount); + // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. + if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) { + ALOGE("Condition %s dropping data for dimension key %s", mName.c_str(), newKey.c_str()); + return true; + } + } + return false; +} + void SimpleConditionTracker::handleConditionEvent(const HashableDimensionKey& outputKey, bool matchStart, std::vector<ConditionState>& conditionCache, @@ -133,6 +153,12 @@ void SimpleConditionTracker::handleConditionEvent(const HashableDimensionKey& ou bool changed = false; auto outputIt = mSlicedConditionState.find(outputKey); ConditionState newCondition; + if (hitGuardRail(outputKey)) { + conditionChangedCache[mIndex] = false; + // Tells the caller it's evaluated. + conditionCache[mIndex] = ConditionState::kUnknown; + return; + } if (outputIt == mSlicedConditionState.end()) { // We get a new output key. newCondition = matchStart ? ConditionState::kTrue : ConditionState::kFalse; diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h index c287d8f34e8f..d21afd1d8083 100644 --- a/cmds/statsd/src/condition/SimpleConditionTracker.h +++ b/cmds/statsd/src/condition/SimpleConditionTracker.h @@ -19,6 +19,7 @@ #include <gtest/gtest_prod.h> #include "ConditionTracker.h" +#include "config/ConfigKey.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "stats_util.h" @@ -28,7 +29,7 @@ namespace statsd { class SimpleConditionTracker : public virtual ConditionTracker { public: - SimpleConditionTracker(const std::string& name, const int index, + SimpleConditionTracker(const ConfigKey& key, const std::string& name, const int index, const SimpleCondition& simpleCondition, const std::unordered_map<std::string, int>& trackerNameIndexMap); @@ -50,6 +51,7 @@ public: std::vector<ConditionState>& conditionCache) const override; private: + const ConfigKey mConfigKey; // The index of the LogEventMatcher which defines the start. int mStartLogMatcherIndex; @@ -75,6 +77,8 @@ private: std::vector<ConditionState>& conditionCache, std::vector<bool>& changedCache); + bool hitGuardRail(const HashableDimensionKey& newKey); + FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedCondition); FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim); FRIEND_TEST(SimpleConditionTrackerTest, TestStopAll); diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp new file mode 100644 index 000000000000..815e03f6d3f1 --- /dev/null +++ b/cmds/statsd/src/guardrail/StatsdStats.cpp @@ -0,0 +1,342 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define DEBUG true // STOPSHIP if true +#include "Log.h" + +#include "StatsdStats.h" + +#include <android/util/ProtoOutputStream.h> +#include "statslog.h" + +namespace android { +namespace os { +namespace statsd { + +using android::util::FIELD_COUNT_REPEATED; +using android::util::FIELD_TYPE_BOOL; +using android::util::FIELD_TYPE_FLOAT; +using android::util::FIELD_TYPE_INT32; +using android::util::FIELD_TYPE_INT64; +using android::util::FIELD_TYPE_MESSAGE; +using android::util::FIELD_TYPE_STRING; +using android::util::ProtoOutputStream; +using std::lock_guard; +using std::map; +using std::string; +using std::vector; + +const int FIELD_ID_BEGIN_TIME = 1; +const int FIELD_ID_END_TIME = 2; +const int FIELD_ID_CONFIG_STATS = 3; +const int FIELD_ID_MATCHER_STATS = 4; +const int FIELD_ID_CONDITION_STATS = 5; +const int FIELD_ID_METRIC_STATS = 6; +const int FIELD_ID_ATOM_STATS = 7; + +const int FIELD_ID_MATCHER_STATS_NAME = 1; +const int FIELD_ID_MATCHER_STATS_COUNT = 2; + +const int FIELD_ID_CONDITION_STATS_NAME = 1; +const int FIELD_ID_CONDITION_STATS_COUNT = 2; + +const int FIELD_ID_METRIC_STATS_NAME = 1; +const int FIELD_ID_METRIC_STATS_COUNT = 2; + +const int FIELD_ID_ATOM_STATS_TAG = 1; +const int FIELD_ID_ATOM_STATS_COUNT = 2; + +// TODO: add stats for pulled atoms. +StatsdStats::StatsdStats() { + mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1); + mStartTime = time(nullptr); +} + +StatsdStats& StatsdStats::getInstance() { + static StatsdStats statsInstance; + return statsInstance; +} + +void StatsdStats::noteConfigReceived(const ConfigKey& key, int metricsCount, int conditionsCount, + int matchersCount, int alertsCount, bool isValid) { + lock_guard<std::mutex> lock(mLock); + int32_t nowTimeSec = time(nullptr); + + // If there is an existing config for the same key, icebox the old config. + noteConfigRemovedInternalLocked(key); + + StatsdStatsReport_ConfigStats configStats; + configStats.set_uid(key.GetUid()); + configStats.set_name(key.GetName()); + configStats.set_creation_time_sec(nowTimeSec); + configStats.set_metric_count(metricsCount); + configStats.set_condition_count(conditionsCount); + configStats.set_matcher_count(matchersCount); + configStats.set_alert_count(alertsCount); + configStats.set_is_valid(isValid); + + if (isValid) { + mConfigStats[key] = configStats; + } else { + configStats.set_deletion_time_sec(nowTimeSec); + mIceBox.push_back(configStats); + } +} + +void StatsdStats::noteConfigRemovedInternalLocked(const ConfigKey& key) { + auto it = mConfigStats.find(key); + if (it != mConfigStats.end()) { + int32_t nowTimeSec = time(nullptr); + it->second.set_deletion_time_sec(nowTimeSec); + // Add condition stats, metrics stats, matcher stats + addSubStatsToConfig(key, it->second); + // Remove them after they are added to the config stats. + mMatcherStats.erase(key); + mMetricsStats.erase(key); + mConditionStats.erase(key); + mIceBox.push_back(it->second); + } +} + +void StatsdStats::noteConfigRemoved(const ConfigKey& key) { + lock_guard<std::mutex> lock(mLock); + noteConfigRemovedInternalLocked(key); +} + +void StatsdStats::noteBroadcastSent(const ConfigKey& key) { + lock_guard<std::mutex> lock(mLock); + auto it = mConfigStats.find(key); + if (it == mConfigStats.end()) { + ALOGE("Config key %s not found!", key.ToString().c_str()); + return; + } + + it->second.add_broadcast_sent_time_sec(time(nullptr)); +} + +void StatsdStats::noteDataDrop(const ConfigKey& key) { + lock_guard<std::mutex> lock(mLock); + auto it = mConfigStats.find(key); + if (it == mConfigStats.end()) { + ALOGE("Config key %s not found!", key.ToString().c_str()); + return; + } + + it->second.add_data_drop_time_sec(time(nullptr)); +} + +void StatsdStats::noteConditionDimensionSize(const ConfigKey& key, const string& name, int size) { + lock_guard<std::mutex> lock(mLock); + // if name doesn't exist before, it will create the key with count 0. + auto& conditionSizeMap = mConditionStats[key]; + if (size > conditionSizeMap[name]) { + conditionSizeMap[name] = size; + } +} + +void StatsdStats::noteMetricDimensionSize(const ConfigKey& key, const string& name, int size) { + lock_guard<std::mutex> lock(mLock); + // if name doesn't exist before, it will create the key with count 0. + auto& metricsDimensionMap = mMetricsStats[key]; + if (size > metricsDimensionMap[name]) { + metricsDimensionMap[name] = size; + } +} + +void StatsdStats::noteMatcherMatched(const ConfigKey& key, const string& name) { + lock_guard<std::mutex> lock(mLock); + auto& matcherStats = mMatcherStats[key]; + matcherStats[name]++; +} + +void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) { + lock_guard<std::mutex> lock(mLock); + + if (timeSec < mStartTime) { + return; + } + + if (atomId > android::util::kMaxPushedAtomId) { + ALOGW("not interested in atom %d", atomId); + return; + } + + mPushedAtomStats[atomId]++; +} + +void StatsdStats::reset() { + lock_guard<std::mutex> lock(mLock); + resetInternalLocked(); +} + +void StatsdStats::resetInternalLocked() { + // Reset the historical data, but keep the active ConfigStats + mStartTime = time(nullptr); + mIceBox.clear(); + mConditionStats.clear(); + mMetricsStats.clear(); + std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0); + mMatcherStats.clear(); +} + +void StatsdStats::addSubStatsToConfig(const ConfigKey& key, + StatsdStatsReport_ConfigStats& configStats) { + // Add matcher stats + if (mMatcherStats.find(key) != mMatcherStats.end()) { + const auto& matcherStats = mMatcherStats[key]; + for (const auto& stats : matcherStats) { + auto output = configStats.add_matcher_stats(); + output->set_name(stats.first); + output->set_matched_times(stats.second); + VLOG("matcher %s matched %d times", stats.first.c_str(), stats.second); + } + } + // Add condition stats + if (mConditionStats.find(key) != mConditionStats.end()) { + const auto& conditionStats = mConditionStats[key]; + for (const auto& stats : conditionStats) { + auto output = configStats.add_condition_stats(); + output->set_name(stats.first); + output->set_max_tuple_counts(stats.second); + VLOG("condition %s max output tuple size %d", stats.first.c_str(), stats.second); + } + } + // Add metrics stats + if (mMetricsStats.find(key) != mMetricsStats.end()) { + const auto& conditionStats = mMetricsStats[key]; + for (const auto& stats : conditionStats) { + auto output = configStats.add_metric_stats(); + output->set_name(stats.first); + output->set_max_tuple_counts(stats.second); + VLOG("metrics %s max output tuple size %d", stats.first.c_str(), stats.second); + } + } +} + +void StatsdStats::dumpStats(std::vector<int8_t>* output, bool reset) { + lock_guard<std::mutex> lock(mLock); + + if (DEBUG) { + time_t t = time(nullptr); + struct tm* tm = localtime(&t); + char timeBuffer[80]; + strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %I:%M%p", tm); + VLOG("=================StatsdStats dump begins===================="); + VLOG("Stats collection start second: %s", timeBuffer); + } + ProtoOutputStream proto; + proto.write(FIELD_TYPE_INT32 | FIELD_ID_BEGIN_TIME, mStartTime); + proto.write(FIELD_TYPE_INT32 | FIELD_ID_END_TIME, (int32_t)time(nullptr)); + + VLOG("%lu Config in icebox: ", (unsigned long)mIceBox.size()); + for (const auto& configStats : mIceBox) { + const int numBytes = configStats.ByteSize(); + vector<char> buffer(numBytes); + configStats.SerializeToArray(&buffer[0], numBytes); + proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CONFIG_STATS, &buffer[0], + buffer.size()); + + // surround the whole block with DEBUG, so that compiler can strip out the code + // in production. + if (DEBUG) { + VLOG("*****ICEBOX*****"); + VLOG("Config {%d-%s}: creation=%d, deletion=%d, #metric=%d, #condition=%d, " + "#matcher=%d, #alert=%d, #valid=%d", + configStats.uid(), configStats.name().c_str(), configStats.creation_time_sec(), + configStats.deletion_time_sec(), configStats.metric_count(), + configStats.condition_count(), configStats.matcher_count(), + configStats.alert_count(), configStats.is_valid()); + + for (const auto& broadcastTime : configStats.broadcast_sent_time_sec()) { + VLOG("\tbroadcast time: %d", broadcastTime); + } + + for (const auto& dataDropTime : configStats.data_drop_time_sec()) { + VLOG("\tdata drop time: %d", dataDropTime); + } + } + } + + for (auto& pair : mConfigStats) { + auto& configStats = pair.second; + if (DEBUG) { + VLOG("********Active Configs***********"); + VLOG("Config {%d-%s}: creation=%d, deletion=%d, #metric=%d, #condition=%d, " + "#matcher=%d, #alert=%d, #valid=%d", + configStats.uid(), configStats.name().c_str(), configStats.creation_time_sec(), + configStats.deletion_time_sec(), configStats.metric_count(), + configStats.condition_count(), configStats.matcher_count(), + configStats.alert_count(), configStats.is_valid()); + for (const auto& broadcastTime : configStats.broadcast_sent_time_sec()) { + VLOG("\tbroadcast time: %d", broadcastTime); + } + + for (const auto& dataDropTime : configStats.data_drop_time_sec()) { + VLOG("\tdata drop time: %d", dataDropTime); + } + } + + addSubStatsToConfig(pair.first, configStats); + + const int numBytes = configStats.ByteSize(); + vector<char> buffer(numBytes); + configStats.SerializeToArray(&buffer[0], numBytes); + proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CONFIG_STATS, &buffer[0], + buffer.size()); + // reset the sub stats, the source of truth is in the individual map + // they will be repopulated when dumpStats() is called again. + configStats.clear_matcher_stats(); + configStats.clear_condition_stats(); + configStats.clear_metric_stats(); + } + + VLOG("********Atom stats***********"); + const size_t atomCounts = mPushedAtomStats.size(); + for (size_t i = 2; i < atomCounts; i++) { + if (mPushedAtomStats[i] > 0) { + long long token = + proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM_STATS | FIELD_COUNT_REPEATED); + proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_TAG, (int32_t)i); + proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_COUNT, mPushedAtomStats[i]); + proto.end(token); + + VLOG("Atom %lu->%d\n", (unsigned long)i, mPushedAtomStats[i]); + } + } + + output->clear(); + size_t bufferSize = proto.size(); + output->resize(bufferSize); + + size_t pos = 0; + auto it = proto.data(); + while (it.readBuffer() != NULL) { + size_t toRead = it.currentToRead(); + std::memcpy(&((*output)[pos]), it.readBuffer(), toRead); + pos += toRead; + it.rp()->move(toRead); + } + + if (reset) { + resetInternalLocked(); + } + + VLOG("reset=%d, returned proto size %lu", reset, (unsigned long)bufferSize); + VLOG("=================StatsdStats dump ends===================="); +} + +} // namespace statsd +} // namespace os +} // namespace android
\ No newline at end of file diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h new file mode 100644 index 000000000000..73ce2798cd6c --- /dev/null +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -0,0 +1,160 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include "config/ConfigKey.h" +#include "frameworks/base/cmds/statsd/src/stats_log.pb.h" + +#include <mutex> +#include <string> +#include <vector> + +namespace android { +namespace os { +namespace statsd { + +// Keeps track of stats of statsd. +// Single instance shared across the process. All methods are thread safe. +class StatsdStats { +public: + static StatsdStats& getInstance(); + ~StatsdStats(){}; + + // TODO: set different limit if the device is low ram. + const static int kDimensionKeySizeSoftLimit = 300; + const static int kDimensionKeySizeHardLimit = 500; + + const static int kMaxConfigCount = 10; + const static int kMaxConditionCountPerConfig = 200; + const static int kMaxMetricCountPerConfig = 300; + const static int kMaxMatcherCountPerConfig = 500; + + /** + * Report a new config has been received and report the static stats about the config. + * + * The static stats include: the count of metrics, conditions, matchers, and alerts. + * If the config is not valid, this config stats will be put into icebox immediately. + */ + void noteConfigReceived(const ConfigKey& key, int metricsCount, int conditionsCount, + int matchersCount, int alertCount, bool isValid); + /** + * Report a config has been removed. + */ + void noteConfigRemoved(const ConfigKey& key); + + /** + * Report a broadcast has been sent to a config owner to collect the data. + */ + void noteBroadcastSent(const ConfigKey& key); + + /** + * Report a config's metrics data has been dropped. + */ + void noteDataDrop(const ConfigKey& key); + + /** + * Report the size of output tuple of a condition. + * + * Note: only report when the condition has an output dimension, and the tuple + * count > kDimensionKeySizeSoftLimit. + * + * [key]: The config key that this condition belongs to. + * [name]: The name of the condition. + * [size]: The output tuple size. + */ + void noteConditionDimensionSize(const ConfigKey& key, const std::string& name, int size); + + /** + * Report the size of output tuple of a metric. + * + * Note: only report when the metric has an output dimension, and the tuple + * count > kDimensionKeySizeSoftLimit. + * + * [key]: The config key that this metric belongs to. + * [name]: The name of the metric. + * [size]: The output tuple size. + */ + void noteMetricDimensionSize(const ConfigKey& key, const std::string& name, int size); + + /** + * Report a matcher has been matched. + * + * [key]: The config key that this matcher belongs to. + * [name]: The name of the matcher. + */ + void noteMatcherMatched(const ConfigKey& key, const std::string& name); + + /** + * Report an atom event has been logged. + */ + void noteAtomLogged(int atomId, int32_t timeSec); + + /** + * Reset the historical stats. Including all stats in icebox, and the tracked stats about + * metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue + * to collect stats after reset() has been called. + */ + void reset(); + + /** + * Output the stats in protobuf binary format to [buffer]. + * + * [reset]: whether to clear the historical stats after the call. + */ + void dumpStats(std::vector<int8_t>* buffer, bool reset); + +private: + StatsdStats(); + + mutable std::mutex mLock; + + int32_t mStartTime; + + // The stats about the configs that are still in use. + std::map<const ConfigKey, StatsdStatsReport_ConfigStats> mConfigStats; + + // Stores the stats for the configs that are no longer in use. + std::vector<const StatsdStatsReport_ConfigStats> mIceBox; + + // Stores the number of output tuple of condition trackers when it's bigger than + // kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1, + // it means some data has been dropped. + std::map<const ConfigKey, std::map<const std::string, int>> mConditionStats; + + // Stores the number of output tuple of metric producers when it's bigger than + // kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1, + // it means some data has been dropped. + std::map<const ConfigKey, std::map<const std::string, int>> mMetricsStats; + + // Stores the number of times a pushed atom is logged. + // The size of the vector is the largest pushed atom id in atoms.proto + 1. Atoms + // out of that range will be dropped (it's either pulled atoms or test atoms). + // This is a vector, not a map because it will be accessed A LOT -- for each stats log. + std::vector<int> mPushedAtomStats; + + // Stores how many times a matcher have been matched. + std::map<const ConfigKey, std::map<const std::string, int>> mMatcherStats; + + void noteConfigRemovedInternalLocked(const ConfigKey& key); + + void resetInternalLocked(); + + void addSubStatsToConfig(const ConfigKey& key, StatsdStatsReport_ConfigStats& configStats); +}; + +} // namespace statsd +} // namespace os +} // namespace android
\ No newline at end of file diff --git a/cmds/statsd/src/matchers/LogMatchingTracker.h b/cmds/statsd/src/matchers/LogMatchingTracker.h index ffbf2488ad2c..fea3e9b367ef 100644 --- a/cmds/statsd/src/matchers/LogMatchingTracker.h +++ b/cmds/statsd/src/matchers/LogMatchingTracker.h @@ -69,6 +69,10 @@ public: return mTagIds; } + const std::string& getName() const { + return mName; + } + protected: // Name of this matching. We don't really need the name, but it makes log message easy to debug. const std::string mName; diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp index b2c88a0d3013..ad37b010d1fb 100644 --- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp +++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp @@ -19,8 +19,6 @@ #include "SimpleLogMatchingTracker.h" -#include <log/logprint.h> - namespace android { namespace os { namespace statsd { diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp index 149b9c16fd88..ce60eb965d62 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.cpp +++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp @@ -18,6 +18,7 @@ #include "Log.h" #include "CountMetricProducer.h" +#include "guardrail/StatsdStats.h" #include "stats_util.h" #include <limits.h> @@ -63,10 +64,11 @@ const int FIELD_ID_COUNT = 3; // TODO: add back AnomalyTracker. -CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex, +CountMetricProducer::CountMetricProducer(const ConfigKey& key, const CountMetric& metric, + const int conditionIndex, const sp<ConditionWizard>& wizard, const uint64_t startTimeNs) - : MetricProducer(startTimeNs, conditionIndex, wizard), mMetric(metric) { + : MetricProducer(key, startTimeNs, conditionIndex, wizard), mMetric(metric) { // TODO: evaluate initial conditions. and set mConditionMet. if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) { mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000; @@ -180,6 +182,26 @@ void CountMetricProducer::onConditionChanged(const bool conditionMet, const uint mCondition = conditionMet; } +bool CountMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) { + if (mCurrentSlicedCounter->find(newKey) != mCurrentSlicedCounter->end()) { + return false; + } + // ===========GuardRail============== + // 1. Report the tuple count if the tuple count > soft limit + if (mCurrentSlicedCounter->size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) { + size_t newTupleCount = mCurrentSlicedCounter->size() + 1; + StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetric.name(), + newTupleCount); + // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. + if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) { + ALOGE("CountMetric %s dropping data for dimension key %s", mMetric.name().c_str(), + newKey.c_str()); + return true; + } + } + + return false; +} void CountMetricProducer::onMatchedLogEventInternal( const size_t matcherIndex, const HashableDimensionKey& eventKey, const map<string, HashableDimensionKey>& conditionKey, bool condition, @@ -195,6 +217,11 @@ void CountMetricProducer::onMatchedLogEventInternal( auto it = mCurrentSlicedCounter->find(eventKey); if (it == mCurrentSlicedCounter->end()) { + // ===========GuardRail============== + if (hitGuardRail(eventKey)) { + return; + } + // create a counter for the new key (*mCurrentSlicedCounter)[eventKey] = 1; } else { diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h index 293e5b971fa5..f78a199de103 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.h +++ b/cmds/statsd/src/metrics/CountMetricProducer.h @@ -42,8 +42,9 @@ struct CountBucket { class CountMetricProducer : public MetricProducer { public: // TODO: Pass in the start time from MetricsManager, it should be consistent for all metrics. - CountMetricProducer(const CountMetric& countMetric, const int conditionIndex, - const sp<ConditionWizard>& wizard, const uint64_t startTimeNs); + CountMetricProducer(const ConfigKey& key, const CountMetric& countMetric, + const int conditionIndex, const sp<ConditionWizard>& wizard, + const uint64_t startTimeNs); virtual ~CountMetricProducer(); @@ -84,6 +85,8 @@ private: static const size_t kBucketSize = sizeof(CountBucket{}); + bool hitGuardRail(const HashableDimensionKey& newKey); + FRIEND_TEST(CountMetricProducerTest, TestNonDimensionalEvents); FRIEND_TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition); FRIEND_TEST(CountMetricProducerTest, TestEventsWithSlicedCondition); diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index c8e6ccec07cd..a0374c0ba67c 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -18,6 +18,7 @@ #include "Log.h" #include "DurationMetricProducer.h" +#include "guardrail/StatsdStats.h" #include "stats_util.h" #include <limits.h> @@ -60,14 +61,14 @@ const int FIELD_ID_START_BUCKET_NANOS = 1; const int FIELD_ID_END_BUCKET_NANOS = 2; const int FIELD_ID_DURATION = 3; -DurationMetricProducer::DurationMetricProducer(const DurationMetric& metric, +DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const DurationMetric& metric, const int conditionIndex, const size_t startIndex, const size_t stopIndex, const size_t stopAllIndex, const bool nesting, const sp<ConditionWizard>& wizard, const vector<KeyMatcher>& internalDimension, const uint64_t startTimeNs) - : MetricProducer(startTimeNs, conditionIndex, wizard), + : MetricProducer(key, startTimeNs, conditionIndex, wizard), mMetric(metric), mStartIndex(startIndex), mStopIndex(stopIndex), @@ -113,13 +114,13 @@ unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker( const HashableDimensionKey& eventKey, vector<DurationBucket>& bucket) { switch (mMetric.aggregation_type()) { case DurationMetric_AggregationType_SUM: - return make_unique<OringDurationTracker>(eventKey, mWizard, mConditionTrackerIndex, - mNested, mCurrentBucketStartTimeNs, - mBucketSizeNs, mAnomalyTrackers, bucket); + return make_unique<OringDurationTracker>( + mConfigKey, mMetric.name(), eventKey, mWizard, mConditionTrackerIndex, mNested, + mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers, bucket); case DurationMetric_AggregationType_MAX_SPARSE: - return make_unique<MaxDurationTracker>(eventKey, mWizard, mConditionTrackerIndex, - mNested, mCurrentBucketStartTimeNs, - mBucketSizeNs, mAnomalyTrackers, bucket); + return make_unique<MaxDurationTracker>( + mConfigKey, mMetric.name(), eventKey, mWizard, mConditionTrackerIndex, mNested, + mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers, bucket); } } @@ -238,6 +239,26 @@ void DurationMetricProducer::flushIfNeeded(uint64_t eventTime) { mCurrentBucketNum += numBucketsForward; } +bool DurationMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) { + // the key is not new, we are good. + if (mCurrentSlicedDuration.find(newKey) != mCurrentSlicedDuration.end()) { + return false; + } + // 1. Report the tuple count if the tuple count > soft limit + if (mCurrentSlicedDuration.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) { + size_t newTupleCount = mCurrentSlicedDuration.size() + 1; + StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetric.name(), + newTupleCount); + // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. + if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) { + ALOGE("DurationMetric %s dropping data for dimension key %s", mMetric.name().c_str(), + newKey.c_str()); + return true; + } + } + return false; +} + void DurationMetricProducer::onMatchedLogEventInternal( const size_t matcherIndex, const HashableDimensionKey& eventKey, const map<string, HashableDimensionKey>& conditionKeys, bool condition, @@ -254,6 +275,9 @@ void DurationMetricProducer::onMatchedLogEventInternal( HashableDimensionKey atomKey = getHashableKey(getDimensionKey(event, mInternalDimension)); if (mCurrentSlicedDuration.find(eventKey) == mCurrentSlicedDuration.end()) { + if (hitGuardRail(eventKey)) { + return; + } mCurrentSlicedDuration[eventKey] = createDurationTracker(eventKey, mPastBuckets[eventKey]); } diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h index ebd5e8d36412..5b5373ec9aeb 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.h +++ b/cmds/statsd/src/metrics/DurationMetricProducer.h @@ -37,9 +37,9 @@ namespace statsd { class DurationMetricProducer : public MetricProducer { public: - DurationMetricProducer(const DurationMetric& durationMetric, const int conditionIndex, - const size_t startIndex, const size_t stopIndex, - const size_t stopAllIndex, const bool nesting, + DurationMetricProducer(const ConfigKey& key, const DurationMetric& durationMetric, + const int conditionIndex, const size_t startIndex, + const size_t stopIndex, const size_t stopAllIndex, const bool nesting, const sp<ConditionWizard>& wizard, const vector<KeyMatcher>& internalDimension, const uint64_t startTimeNs); @@ -98,6 +98,7 @@ private: std::unique_ptr<DurationTracker> createDurationTracker(const HashableDimensionKey& eventKey, std::vector<DurationBucket>& bucket); + bool hitGuardRail(const HashableDimensionKey& newKey); static const size_t kBucketSize = sizeof(DurationBucket{}); }; diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp index 567b4c77bf7b..95a18f7241f0 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.cpp +++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp @@ -51,10 +51,11 @@ const int FIELD_ID_DATA = 1; const int FIELD_ID_TIMESTAMP_NANOS = 1; const int FIELD_ID_ATOMS = 2; -EventMetricProducer::EventMetricProducer(const EventMetric& metric, const int conditionIndex, +EventMetricProducer::EventMetricProducer(const ConfigKey& key, const EventMetric& metric, + const int conditionIndex, const sp<ConditionWizard>& wizard, const uint64_t startTimeNs) - : MetricProducer(startTimeNs, conditionIndex, wizard), mMetric(metric) { + : MetricProducer(key, startTimeNs, conditionIndex, wizard), mMetric(metric) { if (metric.links().size() > 0) { mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(), metric.links().end()); diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h index 5afcebd29e58..33a951035dca 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.h +++ b/cmds/statsd/src/metrics/EventMetricProducer.h @@ -34,8 +34,9 @@ namespace statsd { class EventMetricProducer : public MetricProducer { public: // TODO: Pass in the start time from MetricsManager, it should be consistent for all metrics. - EventMetricProducer(const EventMetric& eventMetric, const int conditionIndex, - const sp<ConditionWizard>& wizard, const uint64_t startTimeNs); + EventMetricProducer(const ConfigKey& key, const EventMetric& eventMetric, + const int conditionIndex, const sp<ConditionWizard>& wizard, + const uint64_t startTimeNs); virtual ~EventMetricProducer(); diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index be030d856aee..1791654ba7cc 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -18,6 +18,7 @@ #include "Log.h" #include "GaugeMetricProducer.h" +#include "guardrail/StatsdStats.h" #include "stats_util.h" #include <cutils/log.h> @@ -62,10 +63,11 @@ const int FIELD_ID_START_BUCKET_NANOS = 1; const int FIELD_ID_END_BUCKET_NANOS = 2; const int FIELD_ID_GAUGE = 3; -GaugeMetricProducer::GaugeMetricProducer(const GaugeMetric& metric, const int conditionIndex, +GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric, + const int conditionIndex, const sp<ConditionWizard>& wizard, const int pullTagId, const int64_t startTimeNs) - : MetricProducer(startTimeNs, conditionIndex, wizard), + : MetricProducer(key, startTimeNs, conditionIndex, wizard), mMetric(metric), mPullTagId(pullTagId) { if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) { @@ -225,6 +227,26 @@ void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven } } +bool GaugeMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) { + if (mCurrentSlicedBucket->find(newKey) != mCurrentSlicedBucket->end()) { + return false; + } + // 1. Report the tuple count if the tuple count > soft limit + if (mCurrentSlicedBucket->size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) { + size_t newTupleCount = mCurrentSlicedBucket->size() + 1; + StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetric.name(), + newTupleCount); + // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. + if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) { + ALOGE("GaugeMetric %s dropping data for dimension key %s", mMetric.name().c_str(), + newKey.c_str()); + return true; + } + } + + return false; +} + void GaugeMetricProducer::onMatchedLogEventInternal( const size_t matcherIndex, const HashableDimensionKey& eventKey, const map<string, HashableDimensionKey>& conditionKey, bool condition, @@ -244,12 +266,15 @@ void GaugeMetricProducer::onMatchedLogEventInternal( flushIfNeeded(eventTimeNs); } - // For gauge metric, we just simply use the first guage in the given bucket. + // For gauge metric, we just simply use the first gauge in the given bucket. if (!mCurrentSlicedBucket->empty()) { return; } const long gauge = getGauge(event); if (gauge >= 0) { + if (hitGuardRail(eventKey)) { + return; + } (*mCurrentSlicedBucket)[eventKey] = gauge; } for (auto& tracker : mAnomalyTrackers) { diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h index 4b7654b4ca6b..f344303179e8 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.h +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h @@ -47,9 +47,9 @@ class GaugeMetricProducer : public virtual MetricProducer, public virtual PullDa public: // TODO: Pass in the start time from MetricsManager, it should be consistent // for all metrics. - GaugeMetricProducer(const GaugeMetric& countMetric, const int conditionIndex, - const sp<ConditionWizard>& wizard, const int pullTagId, - const int64_t startTimeNs); + GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& countMetric, + const int conditionIndex, const sp<ConditionWizard>& wizard, + const int pullTagId, const int64_t startTimeNs); virtual ~GaugeMetricProducer(); @@ -100,6 +100,8 @@ private: int64_t getGauge(const LogEvent& event); + bool hitGuardRail(const HashableDimensionKey& newKey); + static const size_t kBucketSize = sizeof(GaugeBucket{}); FRIEND_TEST(GaugeMetricProducerTest, TestWithCondition); diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index ddccf9a1970b..b22ff6f3348c 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -19,6 +19,7 @@ #include "anomaly/AnomalyTracker.h" #include "condition/ConditionWizard.h" +#include "config/ConfigKey.h" #include "matchers/matcher_util.h" #include "packages/PackageInfoListener.h" @@ -35,9 +36,10 @@ namespace statsd { // be a no-op. class MetricProducer : public virtual PackageInfoListener { public: - MetricProducer(const int64_t startTimeNs, const int conditionIndex, + MetricProducer(const ConfigKey& key, const int64_t startTimeNs, const int conditionIndex, const sp<ConditionWizard>& wizard) - : mStartTimeNs(startTimeNs), + : mConfigKey(key), + mStartTimeNs(startTimeNs), mCurrentBucketStartTimeNs(startTimeNs), mCurrentBucketNum(0), mCondition(conditionIndex >= 0 ? false : true), @@ -83,6 +85,8 @@ public: } protected: + const ConfigKey mConfigKey; + const uint64_t mStartTimeNs; uint64_t mCurrentBucketStartTimeNs; diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index 5916b040889c..c8669519119a 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -20,6 +20,7 @@ #include "CountMetricProducer.h" #include "condition/CombinationConditionTracker.h" #include "condition/SimpleConditionTracker.h" +#include "guardrail/StatsdStats.h" #include "matchers/CombinationLogMatchingTracker.h" #include "matchers/SimpleLogMatchingTracker.h" #include "metrics_manager_util.h" @@ -36,10 +37,24 @@ namespace android { namespace os { namespace statsd { -MetricsManager::MetricsManager(const StatsdConfig& config) { - mConfigValid = initStatsdConfig(config, mTagIds, mAllLogEntryMatchers, mAllConditionTrackers, - mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap, - mTrackerToMetricMap, mTrackerToConditionMap); +MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config) : mConfigKey(key) { + mConfigValid = + initStatsdConfig(key, config, mTagIds, mAllLogEntryMatchers, mAllConditionTrackers, + mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap, + mTrackerToMetricMap, mTrackerToConditionMap); + + // TODO: add alert size. + // no matter whether this config is valid, log it in the stats. + StatsdStats::getInstance().noteConfigReceived(key, mAllMetricProducers.size(), + mAllConditionTrackers.size(), + mAllLogEntryMatchers.size(), 0, mConfigValid); + // Guardrail. Reject the config if it's too big. + if (mAllMetricProducers.size() > StatsdStats::kMaxMetricCountPerConfig || + mAllConditionTrackers.size() > StatsdStats::kMaxConditionCountPerConfig || + mAllLogEntryMatchers.size() > StatsdStats::kMaxMatcherCountPerConfig) { + ALOGE("This config is too big! Reject!"); + mConfigValid = false; + } } MetricsManager::~MetricsManager() { @@ -137,6 +152,8 @@ void MetricsManager::onLogEvent(const LogEvent& event) { // For matched LogEntryMatchers, tell relevant metrics that a matched event has come. for (size_t i = 0; i < mAllLogEntryMatchers.size(); i++) { if (matcherCache[i] == MatchingState::kMatched) { + StatsdStats::getInstance().noteMatcherMatched(mConfigKey, + mAllLogEntryMatchers[i]->getName()); auto pair = mTrackerToMetricMap.find(i); if (pair != mTrackerToMetricMap.end()) { auto& metricList = pair->second; diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index a6054e353aa2..517831d1b09d 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -19,6 +19,7 @@ #include "anomaly/AnomalyMonitor.h" #include "anomaly/AnomalyTracker.h" #include "condition/ConditionTracker.h" +#include "config/ConfigKey.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "logd/LogEvent.h" #include "matchers/LogMatchingTracker.h" @@ -33,7 +34,7 @@ namespace statsd { // A MetricsManager is responsible for managing metrics from one single config source. class MetricsManager { public: - MetricsManager(const StatsdConfig& config); + MetricsManager(const ConfigKey& configKey, const StatsdConfig& config); ~MetricsManager(); @@ -57,6 +58,8 @@ public: size_t byteSize(); private: + const ConfigKey mConfigKey; + // All event tags that are interesting to my metrics. std::set<int> mTagIds; diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index cc02c69d4405..66c8419de662 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -18,6 +18,7 @@ #include "Log.h" #include "ValueMetricProducer.h" +#include "guardrail/StatsdStats.h" #include <cutils/log.h> #include <limits.h> @@ -67,11 +68,12 @@ const int FIELD_ID_VALUE = 3; static const uint64_t kDefaultBucketSizeMillis = 60 * 60 * 1000L; // ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently -ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int conditionIndex, +ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric& metric, + const int conditionIndex, const sp<ConditionWizard>& wizard, const int pullTagId, const uint64_t startTimeNs, shared_ptr<StatsPullerManager> statsPullerManager) - : MetricProducer(startTimeNs, conditionIndex, wizard), + : MetricProducer(key, startTimeNs, conditionIndex, wizard), mMetric(metric), mStatsPullerManager(statsPullerManager), mPullTagId(pullTagId) { @@ -103,10 +105,11 @@ ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int co } // for testing -ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int conditionIndex, +ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric& metric, + const int conditionIndex, const sp<ConditionWizard>& wizard, const int pullTagId, const uint64_t startTimeNs) - : ValueMetricProducer(metric, conditionIndex, wizard, pullTagId, startTimeNs, + : ValueMetricProducer(key, metric, conditionIndex, wizard, pullTagId, startTimeNs, make_shared<StatsPullerManager>()) { } @@ -238,6 +241,27 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven } } +bool ValueMetricProducer::hitGuardRail(const HashableDimensionKey& newKey) { + // ===========GuardRail============== + // 1. Report the tuple count if the tuple count > soft limit + if (mCurrentSlicedBucket.find(newKey) != mCurrentSlicedBucket.end()) { + return false; + } + if (mCurrentSlicedBucket.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) { + size_t newTupleCount = mCurrentSlicedBucket.size() + 1; + StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetric.name(), + newTupleCount); + // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. + if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) { + ALOGE("ValueMetric %s dropping data for dimension key %s", mMetric.name().c_str(), + newKey.c_str()); + return true; + } + } + + return false; +} + void ValueMetricProducer::onMatchedLogEventInternal( const size_t matcherIndex, const HashableDimensionKey& eventKey, const map<string, HashableDimensionKey>& conditionKey, bool condition, @@ -249,6 +273,9 @@ void ValueMetricProducer::onMatchedLogEventInternal( return; } + if (hitGuardRail(eventKey)) { + return; + } Interval& interval = mCurrentSlicedBucket[eventKey]; long value = get_value(event); diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index 24c76f26dcaa..a024bd804d83 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -38,9 +38,9 @@ struct ValueBucket { class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver { public: - ValueMetricProducer(const ValueMetric& valueMetric, const int conditionIndex, - const sp<ConditionWizard>& wizard, const int pullTagId, - const uint64_t startTimeNs); + ValueMetricProducer(const ConfigKey& key, const ValueMetric& valueMetric, + const int conditionIndex, const sp<ConditionWizard>& wizard, + const int pullTagId, const uint64_t startTimeNs); virtual ~ValueMetricProducer(); @@ -77,9 +77,9 @@ private: std::shared_ptr<StatsPullerManager> mStatsPullerManager; // for testing - ValueMetricProducer(const ValueMetric& valueMetric, const int conditionIndex, - const sp<ConditionWizard>& wizard, const int pullTagId, - const uint64_t startTimeNs, + ValueMetricProducer(const ConfigKey& key, const ValueMetric& valueMetric, + const int conditionIndex, const sp<ConditionWizard>& wizard, + const int pullTagId, const uint64_t startTimeNs, std::shared_ptr<StatsPullerManager> statsPullerManager); Mutex mLock; @@ -104,6 +104,8 @@ private: long get_value(const LogEvent& event); + bool hitGuardRail(const HashableDimensionKey& newKey); + static const size_t kBucketSize = sizeof(ValueBucket{}); FRIEND_TEST(ValueMetricProducerTest, TestNonDimensionalEvents); diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h index 7ce7f02e06bb..834f7f5b0b86 100644 --- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h +++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h @@ -19,6 +19,7 @@ #include "anomaly/AnomalyTracker.h" #include "condition/ConditionWizard.h" +#include "config/ConfigKey.h" #include "stats_util.h" namespace android { @@ -59,11 +60,14 @@ struct DurationBucket { class DurationTracker { public: - DurationTracker(const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard, - int conditionIndex, bool nesting, uint64_t currentBucketStartNs, - uint64_t bucketSizeNs, const std::vector<sp<AnomalyTracker>>& anomalyTrackers, + DurationTracker(const ConfigKey& key, const string& name, const HashableDimensionKey& eventKey, + sp<ConditionWizard> wizard, int conditionIndex, bool nesting, + uint64_t currentBucketStartNs, uint64_t bucketSizeNs, + const std::vector<sp<AnomalyTracker>>& anomalyTrackers, std::vector<DurationBucket>& bucket) - : mEventKey(eventKey), + : mConfigKey(key), + mName(name), + mEventKey(eventKey), mWizard(wizard), mConditionTrackerIndex(conditionIndex), mBucketSizeNs(bucketSizeNs), @@ -138,6 +142,10 @@ protected: } } } + // A reference to the DurationMetricProducer's config key. + const ConfigKey& mConfigKey; + + const std::string mName; HashableDimensionKey mEventKey; diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp index e4b3693fb24d..4b346dd25050 100644 --- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp +++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp @@ -18,23 +18,50 @@ #include "Log.h" #include "MaxDurationTracker.h" +#include "guardrail/StatsdStats.h" namespace android { namespace os { namespace statsd { -MaxDurationTracker::MaxDurationTracker(const HashableDimensionKey& eventKey, +MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const string& name, + const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard, int conditionIndex, bool nesting, uint64_t currentBucketStartNs, uint64_t bucketSizeNs, const std::vector<sp<AnomalyTracker>>& anomalyTrackers, std::vector<DurationBucket>& bucket) - : DurationTracker(eventKey, wizard, conditionIndex, nesting, currentBucketStartNs, bucketSizeNs, - anomalyTrackers, bucket) { + : DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs, + bucketSizeNs, anomalyTrackers, bucket) { +} + +bool MaxDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) { + // ===========GuardRail============== + if (mInfos.find(newKey) != mInfos.end()) { + // if the key existed, we are good! + return false; + } + // 1. Report the tuple count if the tuple count > soft limit + if (mInfos.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) { + size_t newTupleCount = mInfos.size() + 1; + StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName + mEventKey, + newTupleCount); + // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. + if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) { + ALOGE("MaxDurTracker %s dropping data for dimension key %s", mName.c_str(), + newKey.c_str()); + return true; + } + } + return false; } void MaxDurationTracker::noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime, const ConditionKey& conditionKey) { // this will construct a new DurationInfo if this key didn't exist. + if (hitGuardRail(key)) { + return; + } + DurationInfo& duration = mInfos[key]; duration.conditionKeys = conditionKey; VLOG("MaxDuration: key %s start condition %d", key.c_str(), condition); diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h index 0f79ffed4ec2..e0d1466c6fc4 100644 --- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h +++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h @@ -28,7 +28,8 @@ namespace statsd { // they stop or bucket expires. class MaxDurationTracker : public DurationTracker { public: - MaxDurationTracker(const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard, + MaxDurationTracker(const ConfigKey& key, const string& name, + const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard, int conditionIndex, bool nesting, uint64_t currentBucketStartNs, uint64_t bucketSizeNs, const std::vector<sp<AnomalyTracker>>& anomalyTrackers, @@ -53,6 +54,9 @@ private: void noteConditionChanged(const HashableDimensionKey& key, bool conditionMet, const uint64_t timestamp); + // return true if we should not allow newKey to be tracked because we are above the threshold + bool hitGuardRail(const HashableDimensionKey& newKey); + FRIEND_TEST(MaxDurationTrackerTest, TestSimpleMaxDuration); FRIEND_TEST(MaxDurationTrackerTest, TestCrossBucketBoundary); FRIEND_TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition); diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp index 76f8514178f8..22c33d60169e 100644 --- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp +++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp @@ -16,6 +16,7 @@ #define DEBUG true #include "Log.h" #include "OringDurationTracker.h" +#include "guardrail/StatsdStats.h" namespace android { namespace os { @@ -23,21 +24,45 @@ namespace statsd { using std::pair; -OringDurationTracker::OringDurationTracker(const HashableDimensionKey& eventKey, +OringDurationTracker::OringDurationTracker(const ConfigKey& key, const string& name, + const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard, int conditionIndex, bool nesting, uint64_t currentBucketStartNs, uint64_t bucketSizeNs, const std::vector<sp<AnomalyTracker>>& anomalyTrackers, std::vector<DurationBucket>& bucket) - : DurationTracker(eventKey, wizard, conditionIndex, nesting, currentBucketStartNs, bucketSizeNs, - anomalyTrackers, bucket), + : DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs, + bucketSizeNs, anomalyTrackers, bucket), mStarted(), mPaused() { mLastStartTime = 0; } +bool OringDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) { + // ===========GuardRail============== + // 1. Report the tuple count if the tuple count > soft limit + if (mConditionKeyMap.find(newKey) != mConditionKeyMap.end()) { + return false; + } + if (mConditionKeyMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) { + size_t newTupleCount = mConditionKeyMap.size() + 1; + StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mName + mEventKey, + newTupleCount); + // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. + if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) { + ALOGE("OringDurTracker %s dropping data for dimension key %s", mName.c_str(), + newKey.c_str()); + return true; + } + } + return false; +} + void OringDurationTracker::noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime, const ConditionKey& conditionKey) { + if (hitGuardRail(key)) { + return; + } if (condition) { if (mStarted.size() == 0) { mLastStartTime = eventTime; diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h index ef32fdb510d1..a8404a961dd2 100644 --- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h +++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h @@ -27,7 +27,8 @@ namespace statsd { // Tracks the "Or'd" duration -- if 2 durations are overlapping, they won't be double counted. class OringDurationTracker : public DurationTracker { public: - OringDurationTracker(const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard, + OringDurationTracker(const ConfigKey& key, const string& name, + const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard, int conditionIndex, bool nesting, uint64_t currentBucketStartNs, uint64_t bucketSizeNs, const std::vector<sp<AnomalyTracker>>& anomalyTrackers, @@ -58,6 +59,9 @@ private: int64_t mLastStartTime; std::map<HashableDimensionKey, ConditionKey> mConditionKeyMap; + // return true if we should not allow newKey to be tracked because we are above the threshold + bool hitGuardRail(const HashableDimensionKey& newKey); + FRIEND_TEST(OringDurationTrackerTest, TestDurationOverlap); FRIEND_TEST(OringDurationTrackerTest, TestCrossBucketBoundary); FRIEND_TEST(OringDurationTrackerTest, TestDurationConditionChange); diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index 466026350ddd..1b9efc51c7b7 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -134,7 +134,8 @@ bool initLogTrackers(const StatsdConfig& config, unordered_map<string, int>& log return true; } -bool initConditions(const StatsdConfig& config, const unordered_map<string, int>& logTrackerMap, +bool initConditions(const ConfigKey& key, const StatsdConfig& config, + const unordered_map<string, int>& logTrackerMap, unordered_map<string, int>& conditionTrackerMap, vector<sp<ConditionTracker>>& allConditionTrackers, unordered_map<int, std::vector<int>>& trackerToConditionMap) { @@ -149,7 +150,7 @@ bool initConditions(const StatsdConfig& config, const unordered_map<string, int> switch (condition.contents_case()) { case Condition::ContentsCase::kSimpleCondition: { allConditionTrackers.push_back(new SimpleConditionTracker( - condition.name(), index, condition.simple_condition(), logTrackerMap)); + key, condition.name(), index, condition.simple_condition(), logTrackerMap)); break; } case Condition::ContentsCase::kCombination: { @@ -184,7 +185,8 @@ bool initConditions(const StatsdConfig& config, const unordered_map<string, int> return true; } -bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& logTrackerMap, +bool initMetrics(const ConfigKey& key, const StatsdConfig& config, + const unordered_map<string, int>& logTrackerMap, const unordered_map<string, int>& conditionTrackerMap, const vector<sp<LogMatchingTracker>>& allLogEntryMatchers, vector<sp<ConditionTracker>>& allConditionTrackers, @@ -230,7 +232,7 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l } sp<MetricProducer> countProducer = - new CountMetricProducer(metric, conditionIndex, wizard, startTimeNs); + new CountMetricProducer(key, metric, conditionIndex, wizard, startTimeNs); allMetricProducers.push_back(countProducer); } @@ -298,8 +300,8 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l } sp<MetricProducer> durationMetric = new DurationMetricProducer( - metric, conditionIndex, trackerIndices[0], trackerIndices[1], trackerIndices[2], - nesting, wizard, internalDimension, startTimeNs); + key, metric, conditionIndex, trackerIndices[0], trackerIndices[1], + trackerIndices[2], nesting, wizard, internalDimension, startTimeNs); allMetricProducers.push_back(durationMetric); } @@ -332,7 +334,7 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l } sp<MetricProducer> eventMetric = - new EventMetricProducer(metric, conditionIndex, wizard, startTimeNs); + new EventMetricProducer(key, metric, conditionIndex, wizard, startTimeNs); allMetricProducers.push_back(eventMetric); } @@ -378,8 +380,8 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l } } - sp<MetricProducer> valueProducer = - new ValueMetricProducer(metric, conditionIndex, wizard, pullTagId, startTimeNs); + sp<MetricProducer> valueProducer = new ValueMetricProducer(key, metric, conditionIndex, + wizard, pullTagId, startTimeNs); allMetricProducers.push_back(valueProducer); } @@ -424,8 +426,8 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l } } - sp<MetricProducer> gaugeProducer = - new GaugeMetricProducer(metric, conditionIndex, wizard, pullTagId, startTimeNs); + sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(key, metric, conditionIndex, + wizard, pullTagId, startTimeNs); allMetricProducers.push_back(gaugeProducer); } return true; @@ -451,7 +453,7 @@ bool initAlerts(const StatsdConfig& config, const unordered_map<string, int>& me return true; } -bool initStatsdConfig(const StatsdConfig& config, set<int>& allTagIds, +bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, set<int>& allTagIds, vector<sp<LogMatchingTracker>>& allLogEntryMatchers, vector<sp<ConditionTracker>>& allConditionTrackers, vector<sp<MetricProducer>>& allMetricProducers, @@ -469,13 +471,13 @@ bool initStatsdConfig(const StatsdConfig& config, set<int>& allTagIds, } ALOGD("initLogMatchingTrackers succeed..."); - if (!initConditions(config, logTrackerMap, conditionTrackerMap, allConditionTrackers, + if (!initConditions(key, config, logTrackerMap, conditionTrackerMap, allConditionTrackers, trackerToConditionMap)) { ALOGE("initConditionTrackers failed"); return false; } - if (!initMetrics(config, logTrackerMap, conditionTrackerMap, allLogEntryMatchers, + if (!initMetrics(key, config, logTrackerMap, conditionTrackerMap, allLogEntryMatchers, allConditionTrackers, allMetricProducers, conditionToMetricMap, trackerToMetricMap, metricProducerMap)) { ALOGE("initMetricProducers failed"); diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h index 7d7e0c36951f..e7cbd533b5b4 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.h +++ b/cmds/statsd/src/metrics/metrics_manager_util.h @@ -36,6 +36,7 @@ namespace statsd { // Initialize the LogMatchingTrackers. // input: +// [key]: the config key that this config belongs to // [config]: the input StatsdConfig // output: // [logTrackerMap]: this map should contain matcher name to index mapping @@ -48,6 +49,7 @@ bool initLogTrackers(const StatsdConfig& config, // Initialize ConditionTrackers // input: +// [key]: the config key that this config belongs to // [config]: the input config // [logTrackerMap]: LogMatchingTracker name to index mapping from previous step. // output: @@ -55,7 +57,7 @@ bool initLogTrackers(const StatsdConfig& config, // [allConditionTrackers]: stores the sp to all the ConditionTrackers // [trackerToConditionMap]: contain the mapping from index of // log tracker to condition trackers that use the log tracker -bool initConditions(const StatsdConfig& config, +bool initConditions(const ConfigKey& key, const StatsdConfig& config, const std::unordered_map<std::string, int>& logTrackerMap, std::unordered_map<std::string, int>& conditionTrackerMap, std::vector<sp<ConditionTracker>>& allConditionTrackers, @@ -64,6 +66,7 @@ bool initConditions(const StatsdConfig& config, // Initialize MetricProducers. // input: +// [key]: the config key that this config belongs to // [config]: the input config // [logTrackerMap]: LogMatchingTracker name to index mapping from previous step. // [conditionTrackerMap]: condition name to index mapping @@ -73,7 +76,8 @@ bool initConditions(const StatsdConfig& config, // the list of MetricProducer index // [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index. bool initMetrics( - const StatsdConfig& config, const std::unordered_map<std::string, int>& logTrackerMap, + const ConfigKey& key, const StatsdConfig& config, + const std::unordered_map<std::string, int>& logTrackerMap, const std::unordered_map<std::string, int>& conditionTrackerMap, const std::unordered_map<int, std::vector<EventConditionLink>>& eventConditionLinks, const vector<sp<LogMatchingTracker>>& allLogEntryMatchers, @@ -84,7 +88,7 @@ bool initMetrics( // Initialize MetricsManager from StatsdConfig. // Parameters are the members of MetricsManager. See MetricsManager for declaration. -bool initStatsdConfig(const StatsdConfig& config, std::set<int>& allTagIds, +bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, std::set<int>& allTagIds, std::vector<sp<LogMatchingTracker>>& allLogEntryMatchers, std::vector<sp<ConditionTracker>>& allConditionTrackers, std::vector<sp<MetricProducer>>& allMetricProducers, diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index 4783cd893ae5..81f8eb619d35 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -172,3 +172,51 @@ message ConfigMetricsReportList { repeated ConfigMetricsReport reports = 2; } + +message StatsdStatsReport { + optional int32 stats_begin_time_sec = 1; + + optional int32 stats_end_time_sec = 2; + + message MatcherStats { + optional string name = 1; + optional int32 matched_times = 2; + } + + message ConditionStats { + optional string name = 1; + optional int32 max_tuple_counts = 2; + } + + message MetricStats { + optional string name = 1; + optional int32 max_tuple_counts = 2; + } + + message ConfigStats { + optional int32 uid = 1; + optional string name = 2; + optional int32 creation_time_sec = 3; + optional int32 deletion_time_sec = 4; + optional int32 metric_count = 5; + optional int32 condition_count = 6; + optional int32 matcher_count = 7; + optional int32 alert_count = 8; + optional bool is_valid = 9; + + repeated int32 broadcast_sent_time_sec = 10; + repeated int32 data_drop_time_sec = 11; + repeated MatcherStats matcher_stats = 12; + repeated ConditionStats condition_stats = 13; + repeated MetricStats metric_stats = 14; + } + + repeated ConfigStats config_stats = 3; + + message AtomStats { + optional int32 tag = 1; + optional int32 count = 2; + } + + repeated AtomStats atom_stats = 7; +}
\ No newline at end of file diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp index 618aef6d0847..696fddf003e1 100644 --- a/cmds/statsd/tests/ConfigManager_test.cpp +++ b/cmds/statsd/tests/ConfigManager_test.cpp @@ -62,7 +62,8 @@ MATCHER_P(StatsdConfigEq, name, "") { } TEST(ConfigManagerTest, TestFakeConfig) { - auto metricsManager = std::make_unique<MetricsManager>(build_fake_config()); + auto metricsManager = + std::make_unique<MetricsManager>(ConfigKey(0, "test"), build_fake_config()); EXPECT_TRUE(metricsManager->isConfigValid()); } diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp index 3dd4e70ff49c..2adec945b85a 100644 --- a/cmds/statsd/tests/MetricsManager_test.cpp +++ b/cmds/statsd/tests/MetricsManager_test.cpp @@ -40,6 +40,8 @@ using android::os::statsd::Condition; // TODO: ADD MORE TEST CASES. +const ConfigKey kConfigKey(0, "test"); + StatsdConfig buildGoodConfig() { StatsdConfig config; config.set_name("12345"); @@ -254,9 +256,9 @@ TEST(MetricsManagerTest, TestGoodConfig) { unordered_map<int, std::vector<int>> trackerToMetricMap; unordered_map<int, std::vector<int>> trackerToConditionMap; - EXPECT_TRUE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers, - allMetricProducers, allAnomalyTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap)); + EXPECT_TRUE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap)); EXPECT_EQ(1u, allMetricProducers.size()); EXPECT_EQ(1u, allAnomalyTrackers.size()); } @@ -272,9 +274,9 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) { unordered_map<int, std::vector<int>> trackerToMetricMap; unordered_map<int, std::vector<int>> trackerToConditionMap; - EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers, - allMetricProducers, allAnomalyTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap)); + EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap)); } TEST(MetricsManagerTest, TestCircleLogMatcherDependency) { @@ -288,9 +290,9 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) { unordered_map<int, std::vector<int>> trackerToMetricMap; unordered_map<int, std::vector<int>> trackerToConditionMap; - EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers, - allMetricProducers, allAnomalyTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap)); + EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap)); } TEST(MetricsManagerTest, TestMissingMatchers) { @@ -303,9 +305,9 @@ TEST(MetricsManagerTest, TestMissingMatchers) { unordered_map<int, std::vector<int>> conditionToMetricMap; unordered_map<int, std::vector<int>> trackerToMetricMap; unordered_map<int, std::vector<int>> trackerToConditionMap; - EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers, - allMetricProducers, allAnomalyTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap)); + EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap)); } TEST(MetricsManagerTest, TestCircleConditionDependency) { @@ -319,9 +321,9 @@ TEST(MetricsManagerTest, TestCircleConditionDependency) { unordered_map<int, std::vector<int>> trackerToMetricMap; unordered_map<int, std::vector<int>> trackerToConditionMap; - EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers, - allMetricProducers, allAnomalyTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap)); + EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap)); } TEST(MetricsManagerTest, testAlertWithUnknownMetric) { @@ -335,9 +337,9 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) { unordered_map<int, std::vector<int>> trackerToMetricMap; unordered_map<int, std::vector<int>> trackerToConditionMap; - EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers, - allMetricProducers, allAnomalyTrackers, conditionToMetricMap, - trackerToMetricMap, trackerToConditionMap)); + EXPECT_FALSE(initStatsdConfig(kConfigKey, config, allTagIds, allLogEntryMatchers, + allConditionTrackers, allMetricProducers, allAnomalyTrackers, + conditionToMetricMap, trackerToMetricMap, trackerToConditionMap)); } #else diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp index 11fb011fd74e..92b4ffcdbc43 100644 --- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp +++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp @@ -28,6 +28,8 @@ namespace android { namespace os { namespace statsd { +const ConfigKey kConfigKey(0, "test"); + SimpleCondition getWakeLockHeldCondition(bool countNesting, bool defaultFalse, bool outputSlicedUid) { SimpleCondition simpleCondition; @@ -76,8 +78,8 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) { trackerNameIndexMap["SCREEN_TURNED_ON"] = 0; trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1; - SimpleConditionTracker conditionTracker("SCREEN_IS_ON", 0 /*tracker index*/, simpleCondition, - trackerNameIndexMap); + SimpleConditionTracker conditionTracker(kConfigKey, "SCREEN_IS_ON", 0 /*tracker index*/, + simpleCondition, trackerNameIndexMap); LogEvent event(1 /*tagId*/, 0 /*timestamp*/); @@ -158,8 +160,9 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) { trackerNameIndexMap["SCREEN_TURNED_ON"] = 0; trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1; - SimpleConditionTracker conditionTracker("SCREEN_IS_ON", 0 /*condition tracker index*/, - simpleCondition, trackerNameIndexMap); + SimpleConditionTracker conditionTracker(kConfigKey, "SCREEN_IS_ON", + 0 /*condition tracker index*/, simpleCondition, + trackerNameIndexMap); LogEvent event(1 /*tagId*/, 0 /*timestamp*/); @@ -227,8 +230,9 @@ TEST(SimpleConditionTrackerTest, TestSlicedCondition) { trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1; trackerNameIndexMap["RELEASE_ALL"] = 2; - SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/, - simpleCondition, trackerNameIndexMap); + SimpleConditionTracker conditionTracker(kConfigKey, conditionName, + 0 /*condition tracker index*/, simpleCondition, + trackerNameIndexMap); int uid = 111; LogEvent event(1 /*tagId*/, 0 /*timestamp*/); @@ -308,8 +312,9 @@ TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) { trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1; trackerNameIndexMap["RELEASE_ALL"] = 2; - SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/, - simpleCondition, trackerNameIndexMap); + SimpleConditionTracker conditionTracker(kConfigKey, conditionName, + 0 /*condition tracker index*/, simpleCondition, + trackerNameIndexMap); int uid1 = 111; string uid1_wl1 = "wl1_1"; int uid2 = 222; @@ -392,8 +397,9 @@ TEST(SimpleConditionTrackerTest, TestStopAll) { trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1; trackerNameIndexMap["RELEASE_ALL"] = 2; - SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/, - simpleCondition, trackerNameIndexMap); + SimpleConditionTracker conditionTracker(kConfigKey, conditionName, + 0 /*condition tracker index*/, simpleCondition, + trackerNameIndexMap); int uid1 = 111; int uid2 = 222; diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp new file mode 100644 index 000000000000..286f6bd75442 --- /dev/null +++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp @@ -0,0 +1,50 @@ +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/guardrail/StatsdStats.h" + +#include <gtest/gtest.h> + +#ifdef __ANDROID__ + +namespace android { +namespace os { +namespace statsd { + +TEST(StatsdStatsTest, TestConfigAdd) { + // TODO: implement +} + +TEST(StatsdStatsTest, TestConfigRemove) { + // TODO: implement +} + +TEST(StatsdStatsTest, TestMatcherReport) { + // TODO: implement +} + +TEST(StatsdStatsTest, TestConditionReport) { + // TODO: implement +} + +TEST(StatsdStatsTest, TestAtomLog) { + // TODO: implement +} + +} // namespace statsd +} // namespace os +} // namespace android +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp index 35e08af68739..df743644c3d5 100644 --- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp @@ -32,6 +32,8 @@ namespace android { namespace os { namespace statsd { +const ConfigKey kConfigKey(0, "test"); + TEST(CountMetricProducerTest, TestNonDimensionalEvents) { int64_t bucketStartTimeNs = 10000000000; int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; @@ -48,7 +50,7 @@ TEST(CountMetricProducerTest, TestNonDimensionalEvents) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - CountMetricProducer countProducer(metric, -1 /*-1 meaning no condition*/, wizard, + CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, bucketStartTimeNs); // 2 events in bucket 1. @@ -106,7 +108,7 @@ TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - CountMetricProducer countProducer(metric, 1, wizard, bucketStartTimeNs); + CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs); countProducer.onConditionChanged(true, bucketStartTimeNs); countProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/); @@ -161,7 +163,7 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) { EXPECT_CALL(*wizard, query(_, key2)).WillOnce(Return(ConditionState::kTrue)); - CountMetricProducer countProducer(metric, 1 /*condition tracker index*/, wizard, + CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard, bucketStartTimeNs); countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1, false); @@ -201,7 +203,7 @@ TEST(CountMetricProducerTest, TestAnomalyDetection) { metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - CountMetricProducer countProducer(metric, -1 /*-1 meaning no condition*/, wizard, + CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, bucketStartTimeNs); countProducer.addAnomalyTracker(anomalyTracker); diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp index 18d177cb9173..724ad59eeab6 100644 --- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp @@ -32,6 +32,8 @@ namespace android { namespace os { namespace statsd { +const ConfigKey kConfigKey(0, "test"); + TEST(EventMetricProducerTest, TestNoCondition) { uint64_t bucketStartTimeNs = 10000000000; uint64_t eventStartTimeNs = bucketStartTimeNs + 1; @@ -45,7 +47,7 @@ TEST(EventMetricProducerTest, TestNoCondition) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - EventMetricProducer eventProducer(metric, -1 /*-1 meaning no condition*/, wizard, + EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, bucketStartTimeNs); eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/); @@ -69,7 +71,7 @@ TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - EventMetricProducer eventProducer(metric, 1, wizard, bucketStartTimeNs); + EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs); eventProducer.onConditionChanged(true /*condition*/, bucketStartTimeNs); eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/); @@ -111,7 +113,7 @@ TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) { EXPECT_CALL(*wizard, query(_, key2)).WillOnce(Return(ConditionState::kTrue)); - EventMetricProducer eventProducer(metric, 1, wizard, bucketStartTimeNs); + EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs); eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/); eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/); diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp index d82ccfe6b43e..0763c944c556 100644 --- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp +++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp @@ -36,6 +36,8 @@ namespace android { namespace os { namespace statsd { +const ConfigKey kConfigKey(0, "test"); + TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); @@ -45,8 +47,8 @@ TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) { uint64_t bucketStartTimeNs = 10000000000; uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; - MaxDurationTracker tracker("event", wizard, -1, false, bucketStartTimeNs, bucketSizeNs, {}, - buckets); + MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, false, bucketStartTimeNs, + bucketSizeNs, {}, buckets); tracker.noteStart("1", true, bucketStartTimeNs, key1); // Event starts again. This would not change anything as it already starts. @@ -72,8 +74,8 @@ TEST(MaxDurationTrackerTest, TestStopAll) { uint64_t bucketStartTimeNs = 10000000000; uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; - MaxDurationTracker tracker("event", wizard, -1, false, bucketStartTimeNs, bucketSizeNs, {}, - buckets); + MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, false, bucketStartTimeNs, + bucketSizeNs, {}, buckets); tracker.noteStart("1", true, bucketStartTimeNs + 1, key1); @@ -100,8 +102,8 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) { uint64_t bucketStartTimeNs = 10000000000; uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; - MaxDurationTracker tracker("event", wizard, -1, false, bucketStartTimeNs, bucketSizeNs, {}, - buckets); + MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, false, bucketStartTimeNs, + bucketSizeNs, {}, buckets); // The event starts. tracker.noteStart("", true, bucketStartTimeNs + 1, key1); @@ -127,8 +129,8 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) { uint64_t bucketStartTimeNs = 10000000000; uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; - MaxDurationTracker tracker("event", wizard, -1, true, bucketStartTimeNs, bucketSizeNs, {}, - buckets); + MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, true, bucketStartTimeNs, + bucketSizeNs, {}, buckets); // 2 starts tracker.noteStart("", true, bucketStartTimeNs + 1, key1); @@ -168,8 +170,8 @@ TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) { uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; int64_t durationTimeNs = 2 * 1000; - MaxDurationTracker tracker("event", wizard, 1, false, bucketStartTimeNs, bucketSizeNs, {}, - buckets); + MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs, + bucketSizeNs, {}, buckets); EXPECT_TRUE(tracker.mAnomalyTrackers.empty()); tracker.noteStart("2:maps", true, eventStartTimeNs, key1); @@ -200,8 +202,8 @@ TEST(MaxDurationTrackerTest, TestAnomalyDetection) { uint64_t bucketSizeNs = 30 * NS_PER_SEC; sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, bucketSizeNs); - MaxDurationTracker tracker("event", wizard, -1, true, bucketStartTimeNs, bucketSizeNs, - {anomalyTracker}, buckets); + MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, true, bucketStartTimeNs, + bucketSizeNs, {anomalyTracker}, buckets); tracker.noteStart("1", true, eventStartTimeNs, key1); tracker.noteStop("1", eventStartTimeNs + 10, false); diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp index 54618b5fb588..63a0e2b3499f 100644 --- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp +++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp @@ -34,6 +34,8 @@ namespace android { namespace os { namespace statsd { +const ConfigKey kConfigKey(0, "test"); + TEST(OringDurationTrackerTest, TestDurationOverlap) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); @@ -47,8 +49,8 @@ TEST(OringDurationTrackerTest, TestDurationOverlap) { uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; uint64_t durationTimeNs = 2 * 1000; - OringDurationTracker tracker("event", wizard, 1, false, bucketStartTimeNs, bucketSizeNs, {}, - buckets); + OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs, + bucketSizeNs, {}, buckets); tracker.noteStart("2:maps", true, eventStartTimeNs, key1); EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime); @@ -73,8 +75,8 @@ TEST(OringDurationTrackerTest, TestDurationNested) { uint64_t eventStartTimeNs = bucketStartTimeNs + 1; uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; - OringDurationTracker tracker("event", wizard, 1, true, bucketStartTimeNs, bucketSizeNs, {}, - buckets); + OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs, + bucketSizeNs, {}, buckets); tracker.noteStart("2:maps", true, eventStartTimeNs, key1); tracker.noteStart("2:maps", true, eventStartTimeNs + 10, key1); // overlapping wl @@ -99,8 +101,8 @@ TEST(OringDurationTrackerTest, TestStopAll) { uint64_t eventStartTimeNs = bucketStartTimeNs + 1; uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; - OringDurationTracker tracker("event", wizard, 1, true, bucketStartTimeNs, bucketSizeNs, {}, - buckets); + OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs, + bucketSizeNs, {}, buckets); tracker.noteStart("2:maps", true, eventStartTimeNs, key1); tracker.noteStart("3:maps", true, eventStartTimeNs + 10, key1); // overlapping wl @@ -125,8 +127,8 @@ TEST(OringDurationTrackerTest, TestCrossBucketBoundary) { uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; uint64_t durationTimeNs = 2 * 1000; - OringDurationTracker tracker("event", wizard, 1, true, bucketStartTimeNs, bucketSizeNs, {}, - buckets); + OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs, + bucketSizeNs, {}, buckets); tracker.noteStart("2:maps", true, eventStartTimeNs, key1); EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime); @@ -162,8 +164,8 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange) { uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; uint64_t durationTimeNs = 2 * 1000; - OringDurationTracker tracker("event", wizard, 1, false, bucketStartTimeNs, bucketSizeNs, {}, - buckets); + OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs, + bucketSizeNs, {}, buckets); tracker.noteStart("2:maps", true, eventStartTimeNs, key1); @@ -194,8 +196,8 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange2) { uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; uint64_t durationTimeNs = 2 * 1000; - OringDurationTracker tracker("event", wizard, 1, false, bucketStartTimeNs, bucketSizeNs, {}, - buckets); + OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs, + bucketSizeNs, {}, buckets); tracker.noteStart("2:maps", true, eventStartTimeNs, key1); // condition to false; record duration 5n @@ -225,8 +227,8 @@ TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) { uint64_t eventStartTimeNs = bucketStartTimeNs + 1; uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; - OringDurationTracker tracker("event", wizard, 1, true, bucketStartTimeNs, bucketSizeNs, {}, - buckets); + OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs, + bucketSizeNs, {}, buckets); tracker.noteStart("2:maps", true, eventStartTimeNs, key1); tracker.noteStart("2:maps", true, eventStartTimeNs + 2, key1); @@ -259,8 +261,8 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) { uint64_t bucketSizeNs = 30 * NS_PER_SEC; sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, bucketSizeNs); - OringDurationTracker tracker("event", wizard, 1, true, bucketStartTimeNs, bucketSizeNs, - {anomalyTracker}, buckets); + OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs, + bucketSizeNs, {anomalyTracker}, buckets); // Nothing in the past bucket. tracker.noteStart("", true, eventStartTimeNs, key1); @@ -319,8 +321,8 @@ TEST(OringDurationTrackerTest, TestAnomalyDetection) { uint64_t bucketSizeNs = 30 * NS_PER_SEC; sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, bucketSizeNs); - OringDurationTracker tracker("event", wizard, 1, true /*nesting*/, bucketStartTimeNs, - bucketSizeNs, {anomalyTracker}, buckets); + OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true /*nesting*/, + bucketStartTimeNs, bucketSizeNs, {anomalyTracker}, buckets); tracker.noteStart("", true, eventStartTimeNs, key1); tracker.noteStop("", eventStartTimeNs + 10, false); diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index 1ed3636f4ec4..9d784663de03 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "metrics_test_helper.h" #include "src/metrics/ValueMetricProducer.h" +#include "metrics_test_helper.h" #include <gmock/gmock.h> #include <gtest/gtest.h> @@ -22,11 +22,11 @@ using namespace testing; using android::sp; +using std::make_shared; using std::set; +using std::shared_ptr; using std::unordered_map; using std::vector; -using std::shared_ptr; -using std::make_shared; #ifdef __ANDROID__ @@ -34,6 +34,7 @@ namespace android { namespace os { namespace statsd { +const ConfigKey kConfigKey(0, "test"); /* * Tests pulled atoms with no conditions */ @@ -42,7 +43,7 @@ TEST(ValueMetricProducerTest, TestNonDimensionalEvents) { int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL; int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs; - int64_t bucket3StartTimeNs = bucketStartTimeNs + 2*bucketSizeNs; + int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; ValueMetric metric; metric.set_name("1"); @@ -54,12 +55,13 @@ TEST(ValueMetricProducerTest, TestNonDimensionalEvents) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); // TODO: pending refactor of StatsPullerManager // For now we still need this so that it doesn't do real pulling. - shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>(); + shared_ptr<MockStatsPullerManager> pullerManager = + make_shared<StrictMock<MockStatsPullerManager>>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); - ValueMetricProducer valueProducer(metric, -1 /*-1 meaning no condition*/, wizard,tagId, - bucketStartTimeNs, pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, + tagId, bucketStartTimeNs, pullerManager); vector<shared_ptr<LogEvent>> allData; allData.clear(); @@ -144,41 +146,43 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { int tagId = 1; sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>(); + shared_ptr<MockStatsPullerManager> pullerManager = + make_shared<StrictMock<MockStatsPullerManager>>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Invoke([] (int tagId, vector<std::shared_ptr<LogEvent>>* data) { - int64_t bucketStartTimeNs = 10000000000; - int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL; - - int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs; - int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; - data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); - event->write(1); - event->write(100); - event->init(); - data->push_back(event); - return true; - })) - .WillOnce(Invoke([] (int tagId, vector<std::shared_ptr<LogEvent>>* data) { - int64_t bucketStartTimeNs = 10000000000; - int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL; - - int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs; - int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; - data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10); - event->write(1); - event->write(120); - event->init(); - data->push_back(event); - return true; - })); - - ValueMetricProducer valueProducer(metric, 1, wizard,tagId, - bucketStartTimeNs, pullerManager); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL; + + int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs; + int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; + data->clear(); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); + event->write(1); + event->write(100); + event->init(); + data->push_back(event); + return true; + })) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL; + + int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs; + int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; + data->clear(); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10); + event->write(1); + event->write(120); + event->init(); + data->push_back(event); + return true; + })); + + ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs, + pullerManager); valueProducer.onConditionChanged(true, bucketStartTimeNs + 10); @@ -241,10 +245,11 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) { int tagId = 1; sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>(); + shared_ptr<MockStatsPullerManager> pullerManager = + make_shared<StrictMock<MockStatsPullerManager>>(); - ValueMetricProducer valueProducer(metric, -1, wizard,-1, - bucketStartTimeNs, pullerManager); + ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs, + pullerManager); shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); event1->write(1); diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index 2c1fad1cf140..80399ae65c58 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -40,6 +40,13 @@ import android.view.DisplayInfo; */ @TestApi public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> { + /** + * bounds that can differ from app bounds, which may include things such as insets. + * + * TODO: Investigate combining with {@link mAppBounds}. Can the latter be a product of the + * former? + */ + private Rect mBounds = new Rect(); /** * {@link android.graphics.Rect} defining app bounds. The dimensions override usages of @@ -117,22 +124,26 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu }) public @interface ActivityType {} + /** Bit that indicates that the {@link #mBounds} changed. + * @hide */ + public static final int WINDOW_CONFIG_BOUNDS = 1 << 0; /** Bit that indicates that the {@link #mAppBounds} changed. * @hide */ - public static final int WINDOW_CONFIG_APP_BOUNDS = 1 << 0; + public static final int WINDOW_CONFIG_APP_BOUNDS = 1 << 1; /** Bit that indicates that the {@link #mWindowingMode} changed. * @hide */ - public static final int WINDOW_CONFIG_WINDOWING_MODE = 1 << 1; + public static final int WINDOW_CONFIG_WINDOWING_MODE = 1 << 2; /** Bit that indicates that the {@link #mActivityType} changed. * @hide */ - public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 2; + public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 3; /** @hide */ @IntDef(flag = true, value = { + WINDOW_CONFIG_BOUNDS, WINDOW_CONFIG_APP_BOUNDS, WINDOW_CONFIG_WINDOWING_MODE, - WINDOW_CONFIG_ACTIVITY_TYPE, + WINDOW_CONFIG_ACTIVITY_TYPE }) public @interface WindowConfig {} @@ -151,12 +162,14 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(mBounds, flags); dest.writeParcelable(mAppBounds, flags); dest.writeInt(mWindowingMode); dest.writeInt(mActivityType); } private void readFromParcel(Parcel source) { + mBounds = source.readParcelable(Rect.class.getClassLoader()); mAppBounds = source.readParcelable(Rect.class.getClassLoader()); mWindowingMode = source.readInt(); mActivityType = source.readInt(); @@ -181,6 +194,19 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu }; /** + * Sets the bounds to the provided {@link Rect}. + * @param rect the new bounds value. + */ + public void setBounds(Rect rect) { + if (rect == null) { + mBounds.setEmpty(); + return; + } + + mBounds.set(rect); + } + + /** * Set {@link #mAppBounds} to the input Rect. * @param rect The rect value to set {@link #mAppBounds} to. * @see #getAppBounds() @@ -212,6 +238,11 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu return mAppBounds; } + /** @see #setBounds(Rect) */ + public Rect getBounds() { + return mBounds; + } + public void setWindowingMode(@WindowingMode int windowingMode) { mWindowingMode = windowingMode; } @@ -244,6 +275,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu } public void setTo(WindowConfiguration other) { + setBounds(other.mBounds); setAppBounds(other.mAppBounds); setWindowingMode(other.mWindowingMode); setActivityType(other.mActivityType); @@ -258,6 +290,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu /** @hide */ public void setToDefaults() { setAppBounds(null); + setBounds(null); setWindowingMode(WINDOWING_MODE_UNDEFINED); setActivityType(ACTIVITY_TYPE_UNDEFINED); } @@ -272,6 +305,11 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu */ public @WindowConfig int updateFrom(@NonNull WindowConfiguration delta) { int changed = 0; + // Only allow override if bounds is not empty + if (!delta.mBounds.isEmpty() && !delta.mBounds.equals(mBounds)) { + changed |= WINDOW_CONFIG_BOUNDS; + setBounds(delta.mBounds); + } if (delta.mAppBounds != null && !delta.mAppBounds.equals(mAppBounds)) { changed |= WINDOW_CONFIG_APP_BOUNDS; setAppBounds(delta.mAppBounds); @@ -303,6 +341,10 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu public @WindowConfig long diff(WindowConfiguration other, boolean compareUndefined) { long changes = 0; + if (!mBounds.equals(other.mBounds)) { + changes |= WINDOW_CONFIG_BOUNDS; + } + // Make sure that one of the values is not null and that they are not equal. if ((compareUndefined || other.mAppBounds != null) && mAppBounds != other.mAppBounds @@ -340,6 +382,16 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu n = mAppBounds.bottom - that.mAppBounds.bottom; if (n != 0) return n; } + + n = mBounds.left - that.mBounds.left; + if (n != 0) return n; + n = mBounds.top - that.mBounds.top; + if (n != 0) return n; + n = mBounds.right - that.mBounds.right; + if (n != 0) return n; + n = mBounds.bottom - that.mBounds.bottom; + if (n != 0) return n; + n = mWindowingMode - that.mWindowingMode; if (n != 0) return n; n = mActivityType - that.mActivityType; @@ -367,6 +419,8 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu if (mAppBounds != null) { result = 31 * result + mAppBounds.hashCode(); } + result = 31 * result + mBounds.hashCode(); + result = 31 * result + mWindowingMode; result = 31 * result + mActivityType; return result; @@ -375,7 +429,8 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu /** @hide */ @Override public String toString() { - return "{mAppBounds=" + mAppBounds + return "{ mBounds=" + mBounds + + " mAppBounds=" + mAppBounds + " mWindowingMode=" + windowingModeToString(mWindowingMode) + " mActivityType=" + activityTypeToString(mActivityType) + "}"; } diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index ee75fd443052..f468e5d2f92b 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -31,16 +31,10 @@ import java.util.Objects; import java.util.StringJoiner; /** - * Representation of the capabilities of a network. This object serves two - * purposes: - * <ul> - * <li>An expression of the current capabilities of an active network, typically - * expressed through + * Representation of the capabilities of an active network. Instances are + * typically obtained through * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} * or {@link ConnectivityManager#getNetworkCapabilities(Network)}. - * <li>An expression of the future capabilities of a desired network, typically - * expressed through {@link NetworkRequest}. - * </ul> * <p> * This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of * network selection. Rather than indicate a need for Wi-Fi because an @@ -79,7 +73,7 @@ public final class NetworkCapabilities implements Parcelable { */ public void clearAll() { mNetworkCapabilities = mTransportTypes = 0; - mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = 0; + mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED; mNetworkSpecifier = null; mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED; } @@ -359,6 +353,7 @@ public final class NetworkCapabilities implements Parcelable { /** * Sets all the capabilities set on this {@code NetworkCapability} instance. + * This overwrites any existing capabilities. * * @hide */ @@ -582,6 +577,7 @@ public final class NetworkCapabilities implements Parcelable { /** * Sets all the transports set on this {@code NetworkCapability} instance. + * This overwrites any existing transports. * * @hide */ @@ -780,7 +776,7 @@ public final class NetworkCapabilities implements Parcelable { * Signal strength. This is a signed integer, and higher values indicate better signal. * The exact units are bearer-dependent. For example, Wi-Fi uses RSSI. */ - private int mSignalStrength; + private int mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED; /** * Sets the signal strength. This is a signed integer, with higher values indicating a stronger diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 25b1705262e8..97ded2d73b60 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -32,7 +33,7 @@ public class NetworkRequest implements Parcelable { * The {@link NetworkCapabilities} that define this request. * @hide */ - public final NetworkCapabilities networkCapabilities; + public final @NonNull NetworkCapabilities networkCapabilities; /** * Identifies the request. NetworkRequests should only be constructed by @@ -307,7 +308,7 @@ public class NetworkRequest implements Parcelable { return 0; } public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(networkCapabilities, flags); + networkCapabilities.writeToParcel(dest, flags); dest.writeInt(legacyType); dest.writeInt(requestId); dest.writeString(type.name()); @@ -315,7 +316,7 @@ public class NetworkRequest implements Parcelable { public static final Creator<NetworkRequest> CREATOR = new Creator<NetworkRequest>() { public NetworkRequest createFromParcel(Parcel in) { - NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null); + NetworkCapabilities nc = NetworkCapabilities.CREATOR.createFromParcel(in); int legacyType = in.readInt(); int requestId = in.readInt(); Type type = Type.valueOf(in.readString()); // IllegalArgumentException if invalid. diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java index 95e3802eeefa..b00cb482e73e 100644 --- a/core/java/android/net/NetworkState.java +++ b/core/java/android/net/NetworkState.java @@ -18,6 +18,7 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; +import android.util.Slog; /** * Snapshot of network state. @@ -43,6 +44,16 @@ public class NetworkState implements Parcelable { this.network = network; this.subscriberId = subscriberId; this.networkId = networkId; + + // This object is an atomic view of a network, so the various components + // should always agree on roaming state. + if (networkInfo != null && networkCapabilities != null) { + if (networkInfo.isRoaming() == networkCapabilities + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) { + Slog.wtf("NetworkState", "Roaming state disagreement between " + networkInfo + + " and " + networkCapabilities); + } + } } public NetworkState(Parcel in) { diff --git a/core/java/android/service/autofill/ISaveCallback.aidl b/core/java/android/service/autofill/ISaveCallback.aidl index e260c7375cc5..a9364fe5ccba 100644 --- a/core/java/android/service/autofill/ISaveCallback.aidl +++ b/core/java/android/service/autofill/ISaveCallback.aidl @@ -16,12 +16,14 @@ package android.service.autofill; +import android.content.IntentSender; + /** * Interface to receive the result of a save request. * * @hide */ interface ISaveCallback { - void onSuccess(); + void onSuccess(in IntentSender intentSender); void onFailure(CharSequence message); } diff --git a/core/java/android/service/autofill/SaveCallback.java b/core/java/android/service/autofill/SaveCallback.java index 7207f1df3ee5..855981a544fd 100644 --- a/core/java/android/service/autofill/SaveCallback.java +++ b/core/java/android/service/autofill/SaveCallback.java @@ -16,9 +16,14 @@ package android.service.autofill; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Activity; +import android.content.IntentSender; import android.os.RemoteException; +import com.android.internal.util.Preconditions; + /** * Handles save requests from the {@link AutofillService} into the {@link Activity} being * autofilled. @@ -36,18 +41,33 @@ public final class SaveCallback { * Notifies the Android System that an * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} was successfully handled * by the service. + */ + public void onSuccess() { + onSuccessInternal(null); + } + + /** + * Notifies the Android System that an + * {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} was successfully handled + * by the service. * - * <p>If the service could not handle the request right away—for example, because it must - * launch an activity asking the user to authenticate first or because the network is - * down—it should still call {@link #onSuccess()}. + * <p>This method is useful when the service requires extra work—for example, launching an + * activity asking the user to authenticate first —before it can process the request, + * as the intent will be launched from the context of the activity being autofilled and hence + * will be part of that activity's stack. * - * @throws RuntimeException if an error occurred while calling the Android System. + * @param intentSender intent that will be launched from the context of activity being + * autofilled. */ - public void onSuccess() { + public void onSuccess(@NonNull IntentSender intentSender) { + onSuccessInternal(Preconditions.checkNotNull(intentSender)); + } + + private void onSuccessInternal(@Nullable IntentSender intentSender) { assertNotCalled(); mCalled = true; try { - mCallback.onSuccess(); + mCallback.onSuccess(intentSender); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } @@ -63,11 +83,10 @@ public final class SaveCallback { * the {@link SaveRequest} and call {@link #onSuccess()} instead. * * <p><b>Note:</b> The Android System displays an UI with the supplied error message; if - * you prefer to show your own message, call {@link #onSuccess()} instead. + * you prefer to show your own message, call {@link #onSuccess()} or + * {@link #onSuccess(IntentSender)} instead. * * @param message error message to be displayed to the user. - * - * @throws RuntimeException if an error occurred while calling the Android System. */ public void onFailure(CharSequence message) { assertNotCalled(); diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 999ba7392fab..e4310e1070c8 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4373,7 +4373,7 @@ <string name="package_deleted_device_owner">Deleted by your admin</string> <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description --> - <string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string> + <string name="battery_saver_description">To help improve battery life, Battery Saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery Saver turns off automatically when your device is charging.</string> <!-- [CHAR_LIMIT=NONE] Data saver: Feature description --> <string name="data_saver_description">To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them.</string> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 508c788c519c..ca85445e197e 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -67,7 +67,7 @@ <string name="battery_low_percent_format"><xliff:g id="percentage">%s</xliff:g> remaining</string> <!-- Same as battery_low_percent_format, with a notice about battery saver if on. [CHAR LIMIT=none]--> - <string name="battery_low_percent_format_saver_started"><xliff:g id="percentage">%s</xliff:g> remaining. Battery saver is on.</string> + <string name="battery_low_percent_format_saver_started"><xliff:g id="percentage">%s</xliff:g> remaining. Battery Saver is on.</string> <!-- A message that appears when a USB charger is plugged in and the device does not support charging on it. That is, a charger that fits into the USB port and goes into @@ -86,13 +86,13 @@ <string name="battery_low_why">Settings</string> <!-- Battery saver confirmation dialog title [CHAR LIMIT=NONE]--> - <string name="battery_saver_confirmation_title">Turn on battery saver?</string> + <string name="battery_saver_confirmation_title">Turn on Battery Saver?</string> <!-- Battery saver confirmation dialog ok text [CHAR LIMIT=40]--> <string name="battery_saver_confirmation_ok">Turn on</string> <!-- Battery saver notification action [CHAR LIMIT=NONE]--> - <string name="battery_saver_start_action">Turn on battery saver</string> + <string name="battery_saver_start_action">Turn on Battery Saver</string> <!-- Name of the button that links to the Settings app. [CHAR LIMIT=NONE] --> <string name="status_bar_settings_settings_button">Settings</string> @@ -977,13 +977,13 @@ <string name="user_remove_user_remove">Remove</string> <!-- Battery saver notification title. [CHAR LIMIT=60]--> - <string name="battery_saver_notification_title">Battery saver is on</string> + <string name="battery_saver_notification_title">Battery Saver is on</string> <!-- Battery saver notification text. [CHAR LIMIT=60] --> <string name="battery_saver_notification_text">Reduces performance and background data</string> <!-- Battery saver notification action text. [CHAR LIMIT=60] --> - <string name="battery_saver_notification_action_text">Turn off battery saver</string> + <string name="battery_saver_notification_action_text">Turn off Battery Saver</string> <!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] --> <string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will start capturing everything that\'s displayed on your screen.</string> @@ -1520,10 +1520,10 @@ <string name="battery_panel_title">Battery usage</string> <!-- Summary of battery saver not available [CHAR LIMIT=NONE] --> - <string name="battery_detail_charging_summary">Battery saver not available during charging</string> + <string name="battery_detail_charging_summary">Battery Saver not available during charging</string> <!-- Title of switch for battery saver [CHAR LIMIT=NONE] --> - <string name="battery_detail_switch_title">Battery saver</string> + <string name="battery_detail_switch_title">Battery Saver</string> <!-- Summary of switch for battery saver [CHAR LIMIT=NONE] --> <string name="battery_detail_switch_summary">Reduces performance and background data</string> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index f6fab86cefaa..eb2d12edd059 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -319,32 +319,39 @@ public class ActivityManagerWrapper { mBackgroundExecutor.submit(new Runnable() { @Override public void run() { + boolean result = false; try { - ActivityManager.getService().startActivityFromRecents(taskKey.id, - finalOptions == null ? null : finalOptions.toBundle()); - if (resultCallback != null) { - resultCallbackHandler.post(new Runnable() { - @Override - public void run() { - resultCallback.accept(true); - } - }); - } + result = startActivityFromRecents(taskKey.id, finalOptions); } catch (Exception e) { - if (resultCallback != null) { - resultCallbackHandler.post(new Runnable() { - @Override - public void run() { - resultCallback.accept(false); - } - }); - } + // Fall through + } + final boolean finalResult = result; + if (resultCallback != null) { + resultCallbackHandler.post(new Runnable() { + @Override + public void run() { + resultCallback.accept(finalResult); + } + }); } } }); } /** + * Starts a task from Recents synchronously. + */ + public boolean startActivityFromRecents(int taskId, ActivityOptions options) { + try { + Bundle optsBundle = options == null ? null : options.toBundle(); + ActivityManager.getService().startActivityFromRecents(taskId, optsBundle); + return true; + } catch (Exception e) { + return false; + } + } + + /** * Registers a task stack listener with the system. * This should be called on the main thread. */ diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java new file mode 100644 index 000000000000..705a21522b0a --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.shared.system; + +import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT; +import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; + +import android.app.ActivityOptions; + +/** + * Wrapper around internal ActivityOptions creation. + */ +public abstract class ActivityOptionsCompat { + + /** + * @return ActivityOptions for starting a task in split screen. + */ + public static ActivityOptions makeSplitScreenOptions(boolean dockTopLeft) { + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + options.setSplitScreenCreateMode(dockTopLeft + ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT + : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT); + return options; + } +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java index 1477558a0e97..225dbb4aafbe 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java @@ -19,8 +19,15 @@ package com.android.systemui.shared.system; import static android.view.Display.DEFAULT_DISPLAY; import android.graphics.Rect; +import android.os.Handler; +import android.os.IRemoteCallback; +import android.os.RemoteException; +import android.util.Log; import android.view.WindowManagerGlobal; +import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture; +import com.android.systemui.shared.recents.view.RecentsTransition; + public class WindowManagerWrapper { private static final String TAG = "WindowManagerWrapper"; @@ -38,8 +45,24 @@ public class WindowManagerWrapper { try { WindowManagerGlobal.getWindowManagerService().getStableInsets(DEFAULT_DISPLAY, outStableInsets); - } catch (Exception e) { - e.printStackTrace(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to get stable insets", e); + } + } + + /** + * Overrides a pending app transition. + */ + public void overridePendingAppTransitionMultiThumbFuture( + AppTransitionAnimationSpecsFuture animationSpecFuture, + Runnable animStartedCallback, Handler animStartedCallbackHandler, boolean scaleUp) { + try { + WindowManagerGlobal.getWindowManagerService() + .overridePendingAppTransitionMultiThumbFuture(animationSpecFuture.getFuture(), + RecentsTransition.wrapStartedListener(animStartedCallbackHandler, + animStartedCallback), scaleUp); + } catch (RemoteException e) { + Log.w(TAG, "Failed to override pending app transition (multi-thumbnail future): ", e); } } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index d89bab758bd0..cf3cae5a7c04 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -21,12 +21,10 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManager.StackInfo; import android.app.ActivityOptions; @@ -49,9 +47,6 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.IRemoteCallback; -import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; @@ -63,7 +58,6 @@ import android.service.dreams.IDreamManager; import android.util.Log; import android.util.MutableBoolean; import android.view.Display; -import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IDockedStackListener; import android.view.IWindowManager; import android.view.WindowManager; @@ -78,12 +72,9 @@ import com.android.systemui.R; import com.android.systemui.UiOffloadThread; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsImpl; -import com.android.systemui.shared.recents.model.Task; -import com.android.systemui.shared.system.TaskStackChangeListeners; import com.android.systemui.statusbar.policy.UserInfoController; import java.util.List; -import java.util.function.Consumer; /** * Acts as a shim around the real system services that we need to access data from, and provides @@ -268,22 +259,6 @@ public class SystemServicesProxy { return mIsSafeMode; } - /** Docks a task to the side of the screen and starts it. */ - public boolean startTaskInDockedMode(int taskId, int createMode) { - if (mIam == null) return false; - - try { - final ActivityOptions options = ActivityOptions.makeBasic(); - options.setSplitScreenCreateMode(createMode); - options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - mIam.startActivityFromRecents(taskId, options.toBundle()); - return true; - } catch (Exception e) { - Log.e(TAG, "Failed to dock task: " + taskId + " with createMode: " + createMode, e); - } - return false; - } - /** Moves an already resumed task to the side of the screen to initiate split screen. */ public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, Rect initialBounds) { @@ -540,16 +515,6 @@ public class SystemServicesProxy { } } - public void overridePendingAppTransitionMultiThumbFuture( - IAppTransitionAnimationSpecsFuture future, IRemoteCallback animStartedListener, - boolean scaleUp) { - try { - mIwm.overridePendingAppTransitionMultiThumbFuture(future, animStartedListener, scaleUp); - } catch (RemoteException e) { - Log.w(TAG, "Failed to override transition: " + e); - } - } - /** * Updates the visibility of recents. */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index 1440fc168cc6..e3ed1aaa5506 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -16,13 +16,14 @@ package com.android.systemui.recents.views; +import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; + import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.annotation.Nullable; import android.app.ActivityOptions; -import android.app.ActivityOptions.OnAnimationStartedListener; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Canvas; @@ -33,11 +34,11 @@ import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Handler; +import android.os.IRemoteCallback; import android.util.ArraySet; import android.util.AttributeSet; import android.util.Log; import android.util.MathUtils; -import android.view.AppTransitionAnimationSpec; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -86,13 +87,15 @@ import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; import com.android.systemui.recents.misc.ReferenceCountedTrigger; import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.shared.recents.utilities.Utilities; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.TaskStack; +import com.android.systemui.shared.recents.utilities.Utilities; import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat; import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture; import com.android.systemui.shared.recents.view.RecentsTransition; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.ActivityOptionsCompat; +import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.stackdivider.WindowManagerProxy; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.phone.ScrimController; @@ -608,16 +611,17 @@ public class RecentsView extends FrameLayout { // rect to its final layout-space rect Utilities.setViewFrameFromTranslation(event.taskView); - // Dock the task and launch it - SystemServicesProxy ssp = Recents.getSystemServices(); - if (ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode)) { + final ActivityOptions options = ActivityOptionsCompat.makeSplitScreenOptions( + dockState.createMode == SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT); + if (ActivityManagerWrapper.getInstance().startActivityFromRecents(event.task.key.id, + options)) { final Runnable animStartedListener = () -> { EventBus.getDefault().send(new DockedFirstAnimationFrameEvent()); - // Remove the task and don't bother relaying out, as all the tasks will be - // relaid out when the stack changes on the multiwindow change event + // Remove the task and don't bother relaying out, as all the tasks + // will be relaid out when the stack changes on the multiwindow + // change event getStack().removeTask(event.task, null, true /* fromDockGesture */); }; - final Rect taskRect = getTaskRect(event.taskView); AppTransitionAnimationSpecsFuture future = new AppTransitionAnimationSpecsFuture( getHandler()) { @@ -626,10 +630,8 @@ public class RecentsView extends FrameLayout { return mTransitionHelper.composeDockAnimationSpec(event.taskView, taskRect); } }; - ssp.overridePendingAppTransitionMultiThumbFuture(future.getFuture(), - RecentsTransition.wrapStartedListener(getHandler(), animStartedListener), - true /* scaleUp */); - + WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture( + future, animStartedListener, getHandler(), true /* scaleUp */); MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP, event.task.getTopComponent().flattenToShortString()); } else { @@ -1032,11 +1034,9 @@ public class RecentsView extends FrameLayout { if (taskIndex > -1) { taskIndexFromFront = stack.getTaskCount() - taskIndex - 1; } - EventBus.getDefault().send(new LaunchTaskSucceededEvent( - taskIndexFromFront)); + EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront)); } else { - Log.e(TAG, mContext.getString(R.string.recents_launch_error_message, - task.title)); + Log.e(TAG, mContext.getString(R.string.recents_launch_error_message, task.title)); // Dismiss the task if we fail to launch it if (taskView != null) { diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java index 1cda30111db8..da798848f7e8 100644 --- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java @@ -20,6 +20,8 @@ import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIG import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.os.UserHandle.USER_CURRENT; +import static com.android.systemui.statusbar.phone.NavigationBarGestureHelper.DRAG_MODE_NONE; + import android.app.ActivityManager; import android.content.res.Configuration; import android.os.RemoteException; @@ -36,6 +38,7 @@ import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.stackdivider.Divider; import com.android.systemui.stackdivider.DividerView; +import com.android.systemui.statusbar.phone.NavigationBarGestureHelper; import java.util.List; @@ -89,20 +92,11 @@ public class ShortcutKeyDispatcher extends SystemUI try { int dockSide = mWindowManagerService.getDockedStackSide(); if (dockSide == WindowManager.DOCKED_INVALID) { - // If there is no window docked, we dock the top-most window. + // Split the screen Recents recents = getComponent(Recents.class); - int dockMode = (shortcutCode == SC_DOCK_LEFT) + recents.splitPrimaryTask(DRAG_MODE_NONE, (shortcutCode == SC_DOCK_LEFT) ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT - : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT; - List<ActivityManager.RecentTaskInfo> taskList = - ActivityManagerWrapper.getInstance().getRecentTasks(1, USER_CURRENT); - recents.showRecentApps( - false /* triggeredFromAltTab */, - false /* fromHome */); - if (!taskList.isEmpty()) { - SystemServicesProxy.getInstance(mContext).startTaskInDockedMode( - taskList.get(0).id, dockMode); - } + : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1); } else { // If there is already a docked window, we respond by resizing the docking pane. DividerView dividerView = getComponent(Divider.class).getView(); diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 98efd522970b..32af29d24aa2 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -173,6 +173,7 @@ message MetricsEvent { // Selection invocation methods. Used as sub-type for TEXT_SELECTION_SESSION events. enum TextSelectionInvocationMethod { + TEXT_SELECTION_INVOCATION_UNKNOWN = 0; TEXT_SELECTION_INVOCATION_MANUAL = 1; TEXT_SELECTION_INVOCATION_LINK = 2; } @@ -2805,316 +2806,524 @@ message MetricsEvent { // OS: O TEXT_LONGPRESS = 629; - // OBSOLETE + // ACTION: An app requested an unknown permission + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_UNKNOWN = 630; - // OBSOLETE + // ACTION: An app was granted an unknown permission + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_UNKNOWN = 631; - // OBSOLETE + // ACTION: An app requested an unknown permission and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_UNKNOWN = 632; - // OBSOLETE + // ACTION: An unknown permission was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_UNKNOWN = 633; - // OBSOLETE + // ACTION: An app requested the permission READ_CALENDAR + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_READ_CALENDAR = 634; - // OBSOLETE + // ACTION: An app was granted the permission READ_CALENDAR + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_READ_CALENDAR = 635; - // OBSOLETE + // ACTION: An app requested the permission READ_CALENDAR and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_READ_CALENDAR = 636; - // OBSOLETE + // ACTION: The permission READ_CALENDAR was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_READ_CALENDAR = 637; - // OBSOLETE + // ACTION: An app requested the permission WRITE_CALENDAR + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_WRITE_CALENDAR = 638; - // OBSOLETE + // ACTION: An app was granted the permission WRITE_CALENDAR + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_WRITE_CALENDAR = 639; - // OBSOLETE + // ACTION: An app requested the permission WRITE_CALENDAR and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_WRITE_CALENDAR = 640; - // OBSOLETE + // ACTION: The permission WRITE_CALENDAR was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_WRITE_CALENDAR = 641; - // OBSOLETE + // ACTION: An app requested the permission CAMERA + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_CAMERA = 642; - // OBSOLETE + // ACTION: An app was granted the permission CAMERA + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_CAMERA = 643; - // OBSOLETE + // ACTION: An app requested the permission CAMERA and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_CAMERA = 644; - // OBSOLETE + // ACTION: The permission CAMERA was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_CAMERA = 645; - // AOBSOLETE + // ACTION: An app requested the permission READ_CONTACTS + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_READ_CONTACTS = 646; - // OBSOLETE + // ACTION: An app was granted the permission READ_CONTACTS + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_READ_CONTACTS = 647; - // OBSOLETE + // ACTION: An app requested the permission READ_CONTACTS and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_READ_CONTACTS = 648; - // OBSOLETE + // ACTION: The permission READ_CONTACTS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_READ_CONTACTS = 649; - // OBSOLETE + // ACTION: An app requested the permission WRITE_CONTACTS + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_WRITE_CONTACTS = 650; - // OBSOLETE + // ACTION: An app was granted the permission WRITE_CONTACTS + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_WRITE_CONTACTS = 651; - // OBSOLETE + // ACTION: An app requested the permission WRITE_CONTACTS and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_WRITE_CONTACTS = 652; - // OBSOLETE + // ACTION: The permission WRITE_CONTACTS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_WRITE_CONTACTS = 653; - // OBSOLETE + // ACTION: An app requested the permission GET_ACCOUNTS + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_GET_ACCOUNTS = 654; - // OBSOLETE + // ACTION: An app was granted the permission GET_ACCOUNTS + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_GET_ACCOUNTS = 655; - // OBSOLETE + // ACTION: An app requested the permission GET_ACCOUNTS and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_GET_ACCOUNTS = 656; - // OBSOLETE + // ACTION: The permission GET_ACCOUNTS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_GET_ACCOUNTS = 657; - // AOBSOLETE + // ACTION: An app requested the permission ACCESS_FINE_LOCATION + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 658; - // OBSOLETE + // ACTION: An app was granted the permission ACCESS_FINE_LOCATION + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_ACCESS_FINE_LOCATION = 659; - // OBSOLETE + // ACTION: An app requested the permission ACCESS_FINE_LOCATION and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_ACCESS_FINE_LOCATION = 660; - // OBSOLETE + // ACTION: The permission ACCESS_FINE_LOCATION was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_ACCESS_FINE_LOCATION = 661; - // OBSOLETE + // ACTION: An app requested the permission ACCESS_COARSE_LOCATION + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_ACCESS_COARSE_LOCATION = 662; - // OBSOLETE + // ACTION: An app was granted the permission ACCESS_COARSE_LOCATION + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_ACCESS_COARSE_LOCATION = 663; - // OBSOLETE + // ACTION: An app requested the permission ACCESS_COARSE_LOCATION and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_ACCESS_COARSE_LOCATION = 664; - // OBSOLETE + // ACTION: The permission ACCESS_COARSE_LOCATION was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_ACCESS_COARSE_LOCATION = 665; - // OBSOLETE + // ACTION: An app requested the permission RECORD_AUDIO + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_RECORD_AUDIO = 666; - // OBSOLETE + // ACTION: An app was granted the permission RECORD_AUDIO + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_RECORD_AUDIO = 667; - // OBSOLETE + // ACTION: An app requested the permission RECORD_AUDIO and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_RECORD_AUDIO = 668; - // OBSOLETE + // ACTION: The permission RECORD_AUDIO was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_RECORD_AUDIO = 669; - // OBSOLETE + // ACTION: An app requested the permission READ_PHONE_STATE + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_READ_PHONE_STATE = 670; - // OBSOLETE + // ACTION: An app was granted the permission READ_PHONE_STATE + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_READ_PHONE_STATE = 671; - // OBSOLETE + // ACTION: An app requested the permission READ_PHONE_STATE and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_READ_PHONE_STATE = 672; - // OBSOLETE + // ACTION: The permission READ_PHONE_STATE was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_READ_PHONE_STATE = 673; - // OBSOLETE + // ACTION: An app requested the permission CALL_PHONE + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_CALL_PHONE = 674; - // OBSOLETE + // ACTION: An app was granted the permission CALL_PHONE + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_CALL_PHONE = 675; - // OBSOLETE + // ACTION: An app requested the permission CALL_PHONE and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_CALL_PHONE = 676; - // OBSOLETE + // ACTION: The permission CALL_PHONE was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_CALL_PHONE = 677; - // AOBSOLETE + // ACTION: An app requested the permission READ_CALL_LOG + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_READ_CALL_LOG = 678; - // OBSOLETE + // ACTION: An app was granted the permission READ_CALL_LOG + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_READ_CALL_LOG = 679; - // OBSOLETE + // ACTION: An app requested the permission READ_CALL_LOG and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_READ_CALL_LOG = 680; - // OBSOLETE + // ACTION: The permission READ_CALL_LOG was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_READ_CALL_LOG = 681; - // OBSOLETE + // ACTION: An app requested the permission WRITE_CALL_LOG + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_WRITE_CALL_LOG = 682; - // OBSOLETE + // ACTION: An app was granted the permission WRITE_CALL_LOG + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_WRITE_CALL_LOG = 683; - // OBSOLETE + // ACTION: An app requested the permission WRITE_CALL_LOG and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_WRITE_CALL_LOG = 684; - // OBSOLETE + // ACTION: The permission WRITE_CALL_LOG was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_WRITE_CALL_LOG = 685; - // OBSOLETE + // ACTION: An app requested the permission ADD_VOICEMAIL + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_ADD_VOICEMAIL = 686; - // OBSOLETE + // ACTION: An app was granted the permission ADD_VOICEMAIL + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_ADD_VOICEMAIL = 687; - // OBSOLETE + // ACTION: An app requested the permission ADD_VOICEMAIL and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_ADD_VOICEMAIL = 688; - // OBSOLETE + // ACTION: The permission ADD_VOICEMAIL was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_ADD_VOICEMAIL = 689; - // OBSOLETE + // ACTION: An app requested the permission USE_SIP + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_USE_SIP = 690; - // OBSOLETE + // ACTION: An app was granted the permission USE_SIP + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_USE_SIP = 691; - // OBSOLETE + // ACTION: An app requested the permission USE_SIP and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_USE_SIP = 692; - // OBSOLETE + // ACTION: The permission USE_SIP was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_USE_SIP = 693; - // OBSOLETE + // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_PROCESS_OUTGOING_CALLS = 694; - // OBSOLETE + // ACTION: An app was granted the permission PROCESS_OUTGOING_CALLS + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_PROCESS_OUTGOING_CALLS = 695; - // OBSOLETE + // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_PROCESS_OUTGOING_CALLS = 696; - // OBSOLETE + // ACTION: The permission PROCESS_OUTGOING_CALLS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_PROCESS_OUTGOING_CALLS = 697; - // OBSOLETE + // ACTION: An app requested the permission READ_CELL_BROADCASTS + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_READ_CELL_BROADCASTS = 698; - // OBSOLETE + // ACTION: An app was granted the permission READ_CELL_BROADCASTS + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_READ_CELL_BROADCASTS = 699; - // OBSOLETE + // ACTION: An app requested the permission READ_CELL_BROADCASTS and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_READ_CELL_BROADCASTS = 700; - // OBSOLETE + // ACTION: The permission READ_CELL_BROADCASTS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_READ_CELL_BROADCASTS = 701; - // OBSOLETE + // ACTION: An app requested the permission BODY_SENSORS + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_BODY_SENSORS = 702; - // OBSOLETE + // ACTION: An app was granted the permission BODY_SENSORS + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_BODY_SENSORS = 703; - // OBSOLETE + // ACTION: An app requested the permission BODY_SENSORS and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_BODY_SENSORS = 704; - // OBSOLETE + // ACTION: The permission BODY_SENSORS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_BODY_SENSORS = 705; - // OBSOLETE + // ACTION: An app requested the permission SEND_SMS + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_SEND_SMS = 706; - // OBSOLETE + // ACTION: An app was granted the permission SEND_SMS + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_SEND_SMS = 707; - // OBSOLETE + // ACTION: An app requested the permission SEND_SMS and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_SEND_SMS = 708; - // OBSOLETE + // ACTION: The permission SEND_SMS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_SEND_SMS = 709; - // OBSOLETE + // ACTION: An app requested the permission RECEIVE_SMS + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_RECEIVE_SMS = 710; - // OBSOLETE + // ACTION: An app was granted the permission RECEIVE_SMS + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_RECEIVE_SMS = 711; - // OBSOLETE + // ACTION: An app requested the permission RECEIVE_SMS and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_RECEIVE_SMS = 712; - // OBSOLETE + // ACTION: The permission RECEIVE_SMS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_RECEIVE_SMS = 713; - // OBSOLETE + // ACTION: An app requested the permission READ_SMS + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_READ_SMS = 714; - // OBSOLETE + // ACTION: An app was granted the permission READ_SMS + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_READ_SMS = 715; - // OBSOLETE + // ACTION: An app requested the permission READ_SMS and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_READ_SMS = 716; - // OBSOLETE + // ACTION: The permission READ_SMS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_READ_SMS = 717; - // OBSOLETE + // ACTION: An app requested the permission RECEIVE_WAP_PUSH + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_RECEIVE_WAP_PUSH = 718; - // OBSOLETE + // ACTION: An app was granted the permission RECEIVE_WAP_PUSH + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_RECEIVE_WAP_PUSH = 719; - // OBSOLETE + // ACTION: An app requested the permission RECEIVE_WAP_PUSH and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_RECEIVE_WAP_PUSH = 720; - // OBSOLETE + // ACTION: The permission RECEIVE_WAP_PUSH was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_RECEIVE_WAP_PUSH = 721; - // OBSOLETE + // ACTION: An app requested the permission RECEIVE_MMS + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_RECEIVE_MMS = 722; - // OBSOLETE + // ACTION: An app was granted the permission RECEIVE_MMS + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_RECEIVE_MMS = 723; - // OBSOLETE + // ACTION: An app requested the permission RECEIVE_MMS and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_RECEIVE_MMS = 724; - // OBSOLETE + // ACTION: The permission RECEIVE_MMS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_RECEIVE_MMS = 725; - // OBSOLETE + // ACTION: An app requested the permission READ_EXTERNAL_STORAGE + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 726; - // OBSOLETE + // ACTION: An app was granted the permission READ_EXTERNAL_STORAGE + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_READ_EXTERNAL_STORAGE = 727; - // OBSOLETE + // ACTION: An app requested the permission READ_EXTERNAL_STORAGE and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_READ_EXTERNAL_STORAGE = 728; - // OBSOLETE + // ACTION: The permission READ_EXTERNAL_STORAGE was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_READ_EXTERNAL_STORAGE = 729; - // OBSOLETE + // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 730; - // OBSOLETE + // ACTION: An app was granted the permission WRITE_EXTERNAL_STORAGE + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_WRITE_EXTERNAL_STORAGE = 731; - // OBSOLETE + // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_WRITE_EXTERNAL_STORAGE = 732; - // OBSOLETE + // ACTION: The permission WRITE_EXTERNAL_STORAGE was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_WRITE_EXTERNAL_STORAGE = 733; // ACTION: Logged when a provisioning session has started @@ -3123,16 +3332,24 @@ message MetricsEvent { // ACTION: Logged when a provisioning session has completed PROVISIONING_SESSION_COMPLETED = 735; - // OBSOLETE + // ACTION: An app requested the permission READ_PHONE_NUMBERS + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_REQUEST_READ_PHONE_NUMBERS = 736; - // OBSOLETE + // ACTION: An app was granted the permission READ_PHONE_NUMBERS + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_PERMISSION_GRANT_READ_PHONE_NUMBERS = 737; - // OBSOLETE + // ACTION: An app requested the permission READ_PHONE_NUMBERS and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_PERMISSION_DENIED_READ_PHONE_NUMBERS = 738; - // OBSOLETE + // ACTION: The permission READ_PHONE_NUMBERS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_PERMISSION_REVOKE_READ_PHONE_NUMBERS = 739; // ACTION: QS Brightness Slider (with auto brightness disabled, and VR enabled) @@ -3624,52 +3841,84 @@ message MetricsEvent { // CATEGORY: SETTINGS SETTINGS_LOCK_SCREEN_PREFERENCES = 882; - // OBSOLETE + // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_APPOP_REQUEST_ACCESS_NOTIFICATIONS = 883; - // OBSOLETE + // ACTION: An app was granted the app-op permission ACCESS_NOTIFICATIONS + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_APPOP_GRANT_ACCESS_NOTIFICATIONS = 884; - // OBSOLETE + // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_APPOP_DENIED_ACCESS_NOTIFICATIONS = 885; - // OBSOLETE + // ACTION: The app-op permission ACCESS_NOTIFICATIONS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_APPOP_REVOKE_ACCESS_NOTIFICATIONS = 886; - // OBSOLETE + // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_APPOP_REQUEST_SYSTEM_ALERT_WINDOW = 887; - // OBSOLETE + // ACTION: An app was granted the app-op permission SYSTEM_ALERT_WINDOW + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_APPOP_GRANT_SYSTEM_ALERT_WINDOW = 888; - // OBSOLETE + // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_APPOP_DENIED_SYSTEM_ALERT_WINDOW = 889; - // OBSOLETE + // ACTION: The app-op permission SYSTEM_ALERT_WINDOW was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_APPOP_REVOKE_SYSTEM_ALERT_WINDOW = 890; - // OBSOLETE + // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_APPOP_REQUEST_WRITE_SETTINGS = 891; - // OBSOLETE + // ACTION: An app was granted the app-op permission REQUEST_WRITE_SETTINGS + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_APPOP_GRANT_WRITE_SETTINGS = 892; - // OBSOLETE + // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_APPOP_DENIED_WRITE_SETTINGS = 893; - // OBSOLETE + // ACTION: The app-op permission REQUEST_WRITE_SETTINGS was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_APPOP_REVOKE_WRITE_SETTINGS = 894; - // OBSOLETE + // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_APPOP_REQUEST_REQUEST_INSTALL_PACKAGES = 895; - // OBSOLETE + // ACTION: An app was granted the app-op permission REQUEST_INSTALL_PACKAGES + // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE as of Android P ACTION_APPOP_GRANT_REQUEST_INSTALL_PACKAGES = 896; - // OBSOLETE + // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES and the request was denied + // PACKAGE: The package name of the app requesting the permission + // OBSOLETE as of Android P ACTION_APPOP_DENIED_REQUEST_INSTALL_PACKAGES = 897; - // OBSOLETE + // ACTION: The app-op permission REQUEST_INSTALL_PACKAGES was revoked for an app + // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE as of Android P ACTION_APPOP_REVOKE_REQUEST_INSTALL_PACKAGES = 898; // ACTION: Phase 1 of instant application resolution occurred @@ -3761,7 +4010,8 @@ message MetricsEvent { FIELD_AUTOFILL_NUM_IDS = 917; // ACTION: An autofill service was reqiested to save data - // Type TYPE_SUCCESS: The request succeeded + // Type TYPE_SUCCESS: The request succeeded right away + // Type TYPE_OPEN: The request succeeded but the service launched an IntentSender // Type TYPE_FAILURE: The request failed // Package: Package of app that was autofilled // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request @@ -4763,6 +5013,8 @@ message MetricsEvent { // OS: P FIELD_SELECTION_WIDGET_VERSION = 1262; + // ---- End P Constants, all P 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/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java index af55807ff1f0..831c488e95b2 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java @@ -26,6 +26,7 @@ import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentSender; import android.content.ServiceConnection; import android.os.Handler; import android.os.IBinder; @@ -100,7 +101,8 @@ final class RemoteFillService implements DeathRecipient { @NonNull String servicePackageName); void onFillRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName); - void onSaveRequestSuccess(@NonNull String servicePackageName); + void onSaveRequestSuccess(@NonNull String servicePackageName, + @Nullable IntentSender intentSender); void onSaveRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName); void onServiceDied(RemoteFillService service); @@ -308,10 +310,11 @@ final class RemoteFillService implements DeathRecipient { }); } - private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest) { + private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest, + IntentSender intentSender) { mHandler.getHandler().post(() -> { if (handleResponseCallbackCommon(pendingRequest)) { - mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName()); + mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName(), intentSender); } }); } @@ -624,12 +627,13 @@ final class RemoteFillService implements DeathRecipient { mCallback = new ISaveCallback.Stub() { @Override - public void onSuccess() { + public void onSuccess(IntentSender intentSender) { if (!finish()) return; final RemoteFillService remoteService = getService(); if (remoteService != null) { - remoteService.dispatchOnSaveRequestSuccess(PendingSaveRequest.this); + remoteService.dispatchOnSaveRequestSuccess(PendingSaveRequest.this, + intentSender); } } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 974148623b00..99b92b9c9cd4 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -561,7 +561,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // FillServiceCallbacks @Override - public void onSaveRequestSuccess(@NonNull String servicePackageName) { + public void onSaveRequestSuccess(@NonNull String servicePackageName, + @Nullable IntentSender intentSender) { synchronized (mLock) { mIsSaving = false; @@ -572,8 +573,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName) - .setType(MetricsEvent.TYPE_SUCCESS); + .setType(intentSender == null ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_OPEN); mMetricsLogger.write(log); + if (intentSender != null) { + if (sDebug) Slog.d(TAG, "Starting intent sender on save()"); + startIntentSender(intentSender); + } // Nothing left to do... removeSelf(); diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java index 2289f8572b93..3dbee42f2e79 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/am/ActivityDisplay.java @@ -42,6 +42,8 @@ import android.annotation.Nullable; import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.WindowConfiguration; +import android.graphics.Point; +import android.graphics.Rect; import android.util.IntArray; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -89,6 +91,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { private ActivityStack mPinnedStack = null; private ActivityStack mSplitScreenPrimaryStack = null; + // Used in updating the display size + private Point mTmpDisplaySize = new Point(); + ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) { mSupervisor = supervisor; mDisplayId = displayId; @@ -97,6 +102,13 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { throw new IllegalStateException("Display does not exist displayId=" + displayId); } mDisplay = display; + + updateBounds(); + } + + void updateBounds() { + mDisplay.getSize(mTmpDisplaySize); + setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y); } void addChild(ActivityStack stack, int position) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index aa8a36627ef1..083d30628c83 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -8098,7 +8098,7 @@ public class ActivityManagerService extends IActivityManager.Stub return false; } // An activity is consider to be in multi-window mode if its task isn't fullscreen. - return !r.getTask().mFullscreen; + return r.inMultiWindowMode(); } } finally { Binder.restoreCallingIdentity(origId); @@ -10117,8 +10117,8 @@ public class ActivityManagerService extends IActivityManager.Stub } else { // Task isn't in window manager yet since it isn't associated with a stack. // Return the persist value from activity manager - if (task.mBounds != null) { - rect.set(task.mBounds); + if (!task.matchParentBounds()) { + rect.set(task.getBounds()); } else if (task.mLastNonFullscreenBounds != null) { rect.set(task.mLastNonFullscreenBounds); } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index a2c46f14ed3a..11590d6ca83b 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -165,7 +165,6 @@ import android.view.IApplicationToken; import android.view.WindowManager.LayoutParams; import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity; import com.android.internal.content.ReferrerIntent; import com.android.internal.util.XmlUtils; @@ -343,12 +342,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // on the window. int mRotationAnimationHint = -1; - // The bounds of this activity. Mainly used for aspect-ratio compatibility. - // TODO(b/36505427): Every level on ConfigurationContainer now has bounds information, which - // directly affects the configuration. We should probably move this into that class and have it - // handle calculating override configuration from the bounds. - private final Rect mBounds = new Rect(); - private boolean mShowWhenLocked; private boolean mTurnScreenOn; @@ -414,8 +407,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo if (!getOverrideConfiguration().equals(EMPTY)) { pw.println(prefix + "OverrideConfiguration=" + getOverrideConfiguration()); } - if (!mBounds.isEmpty()) { - pw.println(prefix + "mBounds=" + mBounds); + if (!matchParentBounds()) { + pw.println(prefix + "bounds=" + getBounds()); } if (resultTo != null || resultWho != null) { pw.print(prefix); pw.print("resultTo="); pw.print(resultTo); @@ -648,7 +641,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } // An activity is considered to be in multi-window mode if its task isn't fullscreen. - final boolean inMultiWindowMode = !task.mFullscreen; + final boolean inMultiWindowMode = task.inMultiWindowMode(); if (inMultiWindowMode != mLastReportedMultiWindowMode) { mLastReportedMultiWindowMode = inMultiWindowMode; scheduleMultiWindowModeChanged(getConfiguration()); @@ -966,14 +959,14 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges, task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(), appInfo.targetSdkVersion, mRotationAnimationHint, - ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L, mBounds); + ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L); task.addActivityToTop(this); // When an activity is started directly into a split-screen fullscreen stack, we need to // update the initial multi-window modes so that the callbacks are scheduled correctly when // the user leaves that mode. - mLastReportedMultiWindowMode = !task.mFullscreen; + mLastReportedMultiWindowMode = inMultiWindowMode(); mLastReportedPictureInPictureMode = inPinnedWindowingMode(); } @@ -2172,33 +2165,25 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo mLastReportedConfiguration.setConfiguration(global, override); } - @Override - public void onOverrideConfigurationChanged(Configuration newConfig) { - final Configuration currentConfig = getOverrideConfiguration(); - if (currentConfig.equals(newConfig)) { - return; - } - super.onOverrideConfigurationChanged(newConfig); - if (mWindowContainerController == null) { - return; - } - mWindowContainerController.onOverrideConfigurationChanged(newConfig, mBounds); - } - // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. private void updateOverrideConfiguration() { mTmpConfig.unset(); computeBounds(mTmpBounds); - if (mTmpBounds.equals(mBounds)) { + + if (mTmpBounds.equals(getOverrideBounds())) { return; } - mBounds.set(mTmpBounds); + setBounds(mTmpBounds); + + final Rect updatedBounds = getOverrideBounds(); + // Bounds changed...update configuration to match. - if (!mBounds.isEmpty()) { - task.computeOverrideConfiguration(mTmpConfig, mBounds, null /* insetBounds */, + if (!matchParentBounds()) { + task.computeOverrideConfiguration(mTmpConfig, updatedBounds, null /* insetBounds */, false /* overrideWidth */, false /* overrideHeight */); } + onOverrideConfigurationChanged(mTmpConfig); } @@ -2225,7 +2210,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo outBounds.setEmpty(); final float maxAspectRatio = info.maxAspectRatio; final ActivityStack stack = getStack(); - if (task == null || stack == null || !task.mFullscreen || maxAspectRatio == 0 + if (task == null || stack == null || task.inMultiWindowMode() || maxAspectRatio == 0 || isInVrUiMode(getConfiguration())) { // We don't set override configuration if that activity task isn't fullscreen. I.e. the // activity is in multi-window mode. Or, there isn't a max aspect ratio specified for @@ -2256,11 +2241,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo if (containingAppWidth <= maxActivityWidth && containingAppHeight <= maxActivityHeight) { // The display matches or is less than the activity aspect ratio, so nothing else to do. // Return the existing bounds. If this method is running for the first time, - // {@link mBounds} will be empty (representing no override). If the method has run - // before, then effect of {@link mBounds} will already have been applied to the + // {@link #getOverrideBounds()} will be empty (representing no override). If the method has run + // before, then effect of {@link #getOverrideBounds()} will already have been applied to the // value returned from {@link getConfiguration}. Refer to // {@link TaskRecord#computeOverrideConfiguration}. - outBounds.set(mBounds); + outBounds.set(getOverrideBounds()); return; } @@ -2272,12 +2257,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo outBounds.offsetTo(left, 0 /* top */); } - /** Get bounds of the activity. */ - @VisibleForTesting - Rect getBounds() { - return new Rect(mBounds); - } - /** * Make sure the given activity matches the current configuration. Returns false if the activity * had to be destroyed. Returns true if the configuration is the same, or the activity will diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 6985d6e36ac1..481699833e41 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -156,7 +156,6 @@ import java.util.Set; */ class ActivityStack<T extends StackWindowController> extends ConfigurationContainer implements StackWindowListener { - private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_AM; private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; private static final String TAG_APP = TAG + POSTFIX_APP; @@ -322,11 +321,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai */ boolean mForceHidden = false; - // Whether or not this stack covers the entire screen; by default stacks are fullscreen - boolean mFullscreen = true; - // Current bounds of the stack or null if fullscreen. - Rect mBounds = null; - private boolean mUpdateBoundsDeferred; private boolean mUpdateBoundsDeferredCalled; private final Rect mDeferredBounds = new Rect(); @@ -342,8 +336,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai /** The attached Display's unique identifier, or -1 if detached */ int mDisplayId; - /** Temp variables used during override configuration update. */ - private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>(); private final SparseArray<Rect> mTmpBounds = new SparseArray<>(); private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>(); private final Rect mTmpRect2 = new Rect(); @@ -574,7 +566,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } } - if (!Objects.equals(mBounds, mTmpRect2)) { + if (!Objects.equals(getOverrideBounds(), mTmpRect2)) { resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */); } } finally { @@ -641,9 +633,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai */ private void postAddToDisplay(ActivityDisplay activityDisplay, Rect bounds, boolean onTop) { mDisplayId = activityDisplay.mDisplayId; - mBounds = bounds != null ? new Rect(bounds) : null; - mFullscreen = mBounds == null; - + setBounds(bounds); onParentChanged(); activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM); @@ -651,7 +641,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // If we created a docked stack we want to resize it so it resizes all other stacks // in the system. mStackSupervisor.resizeDockedStackLocked( - mBounds, null, null, null, null, PRESERVE_WINDOWS); + getOverrideBounds(), null, null, null, null, PRESERVE_WINDOWS); } } @@ -766,8 +756,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return false; } - void setBounds(Rect bounds) { - mBounds = mFullscreen ? null : new Rect(bounds); + @Override + public int setBounds(Rect bounds) { + return super.setBounds(!inMultiWindowMode() ? null : bounds); } ActivityRecord topRunningActivityLocked() { @@ -2495,7 +2486,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation. final boolean lastActivityTranslucent = lastStack != null - && (!lastStack.mFullscreen + && (lastStack.inMultiWindowMode() || (lastStack.mLastPausedActivity != null && !lastStack.mLastPausedActivity.fullscreen)); @@ -2739,8 +2730,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai position = getAdjustedPositionForTask(task, position, null /* starting */); mTaskHistory.remove(task); mTaskHistory.add(position, task); - mWindowContainerController.positionChildAt(task.getWindowContainerController(), position, - task.mBounds, task.getOverrideConfiguration()); + mWindowContainerController.positionChildAt(task.getWindowContainerController(), position); updateTaskMovement(task, true); } @@ -4602,8 +4592,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // TODO: Can only be called from special methods in ActivityStackSupervisor. // Need to consolidate those calls points into this resize method so anyone can call directly. void resize(Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds) { - bounds = TaskRecord.validateBounds(bounds); - if (!updateBoundsAllowed(bounds, tempTaskBounds, tempTaskInsetBounds)) { return; } @@ -4613,7 +4601,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final Rect insetBounds = tempTaskInsetBounds != null ? tempTaskInsetBounds : taskBounds; mTmpBounds.clear(); - mTmpConfigs.clear(); mTmpInsetBounds.clear(); for (int i = mTaskHistory.size() - 1; i >= 0; i--) { @@ -4624,7 +4611,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // For freeform stack we don't adjust the size of the tasks to match that // of the stack, but we do try to make sure the tasks are still contained // with the bounds of the stack. - mTmpRect2.set(task.mBounds); + mTmpRect2.set(task.getOverrideBounds()); fitWithinBounds(mTmpRect2, bounds); task.updateOverrideConfiguration(mTmpRect2); } else { @@ -4632,15 +4619,13 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } } - mTmpConfigs.put(task.taskId, task.getOverrideConfiguration()); - mTmpBounds.put(task.taskId, task.mBounds); + mTmpBounds.put(task.taskId, task.getOverrideBounds()); if (tempTaskInsetBounds != null) { mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds); } } - mFullscreen = mWindowContainerController.resize(bounds, mTmpConfigs, mTmpBounds, - mTmpInsetBounds); + mWindowContainerController.resize(bounds, mTmpBounds, mTmpInsetBounds); setBounds(bounds); } @@ -4655,7 +4640,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai * @param stackBounds Bounds within which the other bounds should remain. */ private static void fitWithinBounds(Rect bounds, Rect stackBounds) { - if (stackBounds == null || stackBounds.contains(bounds)) { + if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) { return; } @@ -4873,8 +4858,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai pw.println(""); } pw.println(prefix + "Task id #" + task.taskId); - pw.println(prefix + "mFullscreen=" + task.mFullscreen); - pw.println(prefix + "mBounds=" + task.mBounds); + pw.println(prefix + "mBounds=" + task.getOverrideBounds()); pw.println(prefix + "mMinWidth=" + task.mMinWidth); pw.println(prefix + "mMinHeight=" + task.mMinHeight); pw.println(prefix + "mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds); @@ -4981,7 +4965,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (isOnHomeDisplay() && mode != REMOVE_TASK_MODE_MOVING_TO_TOP && mStackSupervisor.isFocusedStack(this)) { String myReason = reason + " leftTaskHistoryEmpty"; - if (mFullscreen || !adjustFocusToNextFocusableStack(myReason)) { + if (!inMultiWindowMode() || !adjustFocusToNextFocusableStack(myReason)) { mStackSupervisor.moveHomeStackToFront(myReason); } } @@ -5011,8 +4995,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController() .isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY); if (!mStackSupervisor.getLaunchingBoundsController().layoutTask(task, info.windowLayout) - && mBounds != null && task.isResizeable() && !isLockscreenShown) { - task.updateOverrideConfiguration(mBounds); + && !matchParentBounds() && task.isResizeable() && !isLockscreenShown) { + task.updateOverrideConfiguration(getOverrideBounds()); } task.createWindowContainer(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); return task; @@ -5174,10 +5158,13 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); } proto.write(DISPLAY_ID, mDisplayId); - if (mBounds != null) { - mBounds.writeToProto(proto, BOUNDS); + if (!matchParentBounds()) { + final Rect bounds = getOverrideBounds(); + bounds.writeToProto(proto, BOUNDS); } - proto.write(FULLSCREEN, mFullscreen); + + // TODO: Remove, no longer needed with windowingMode. + proto.write(FULLSCREEN, matchParentBounds()); proto.end(token); } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index ddde4bc4957c..5525cdb380b7 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2118,7 +2118,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) { - final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds()); + final Rect bounds = options.getLaunchBounds(); task.updateOverrideConfiguration(bounds); ActivityStack stack = getLaunchStack(null, options, task, ON_TOP); @@ -2626,7 +2626,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // TODO: Checking for isAttached might not be needed as if the user passes in null // dockedBounds then they want the docked stack to be dismissed. - if (stack.mFullscreen || (dockedBounds == null && !stack.isAttached())) { + if (stack.getWindowingMode() == WINDOWING_MODE_FULLSCREEN + || (dockedBounds == null && !stack.isAttached())) { // The dock stack either was dismissed or went fullscreen, which is kinda the same. // In this case we make all other static stacks fullscreen and move all // docked stack tasks to the fullscreen stack. @@ -3058,7 +3059,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Resize the pinned stack to match the current size of the task the activity we are // going to be moving is currently contained in. We do this to have the right starting // animation bounds for the pinned stack to the desired bounds the caller wants. - resizeStackLocked(stack, task.mBounds, null /* tempTaskBounds */, + resizeStackLocked(stack, task.getOverrideBounds(), null /* tempTaskBounds */, null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME); @@ -3782,9 +3783,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D pw.println(" Stack #" + stack.mStackId + ": type=" + activityTypeToString(stack.getActivityType()) + " mode=" + windowingModeToString(stack.getWindowingMode())); - pw.println(" mFullscreen=" + stack.mFullscreen); pw.println(" isSleeping=" + stack.shouldSleepActivities()); - pw.println(" mBounds=" + stack.mBounds); + pw.println(" mBounds=" + stack.getOverrideBounds()); printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, needSep); @@ -4054,6 +4054,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D private void handleDisplayChanged(int displayId) { synchronized (mService) { ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); + // TODO: The following code block should be moved into {@link ActivityDisplay}. if (activityDisplay != null) { // The window policy is responsible for stopping activities on the default display if (displayId != Display.DEFAULT_DISPLAY) { @@ -4067,7 +4068,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D activityDisplay.mOffToken = null; } } - // TODO: Update the bounds. + + activityDisplay.updateBounds(); } mWindowManager.onDisplayChanged(displayId); } @@ -4289,7 +4291,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return; } - scheduleUpdatePictureInPictureModeIfNeeded(task, stack.mBounds); + scheduleUpdatePictureInPictureModeIfNeeded(task, stack.getOverrideBounds()); } void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, Rect targetStackBounds) { diff --git a/services/core/java/com/android/server/am/LaunchingActivityPositioner.java b/services/core/java/com/android/server/am/LaunchingActivityPositioner.java index d5f9cf3ad4d5..793884d08c08 100644 --- a/services/core/java/com/android/server/am/LaunchingActivityPositioner.java +++ b/services/core/java/com/android/server/am/LaunchingActivityPositioner.java @@ -47,10 +47,10 @@ public class LaunchingActivityPositioner implements LaunchingBoundsPositioner { return RESULT_SKIP; } - final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds()); + final Rect bounds = options.getLaunchBounds(); // Bounds weren't valid. - if (bounds == null) { + if (bounds == null || bounds.isEmpty()) { return RESULT_SKIP; } diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java index c958fcac6938..d89568e27506 100644 --- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java +++ b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java @@ -88,7 +88,7 @@ class LaunchingTaskPositioner implements LaunchingBoundsController.LaunchingBoun final ArrayList<TaskRecord> tasks = task.getStack().getAllTasks(); - updateAvailableRect(task, mAvailableRect); + mAvailableRect.set(task.getParent().getBounds()); if (layout == null) { positionCenter(tasks, mAvailableRect, getFreeformWidth(mAvailableRect), @@ -123,17 +123,6 @@ class LaunchingTaskPositioner implements LaunchingBoundsController.LaunchingBoun return RESULT_CONTINUE; } - private void updateAvailableRect(TaskRecord task, Rect availableRect) { - final Rect stackBounds = task.getStack().mBounds; - - if (stackBounds != null) { - availableRect.set(stackBounds); - } else { - task.getStack().getDisplay().mDisplay.getSize(mDisplaySize); - availableRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); - } - } - @VisibleForTesting static int getFreeformStartLeft(Rect bounds) { return bounds.left + bounds.width() / MARGIN_SIZE_DENOMINATOR; @@ -294,9 +283,9 @@ class LaunchingTaskPositioner implements LaunchingBoundsController.LaunchingBoun private static boolean boundsConflict(Rect proposal, ArrayList<TaskRecord> tasks) { for (int i = tasks.size() - 1; i >= 0; i--) { - TaskRecord task = tasks.get(i); - if (!task.mActivities.isEmpty() && task.mBounds != null) { - Rect bounds = task.mBounds; + final TaskRecord task = tasks.get(i); + if (!task.mActivities.isEmpty() && !task.matchParentBounds()) { + final Rect bounds = task.getOverrideBounds(); if (closeLeftTopCorner(proposal, bounds) || closeRightTopCorner(proposal, bounds) || closeLeftBottomCorner(proposal, bounds) || closeRightBottomCorner(proposal, bounds)) { diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java index d35c37b54431..6e6d7e9f2945 100644 --- a/services/core/java/com/android/server/am/RecentTasks.java +++ b/services/core/java/com/android/server/am/RecentTasks.java @@ -1426,9 +1426,6 @@ class RecentTasks { * Creates a new RecentTaskInfo from a TaskRecord. */ ActivityManager.RecentTaskInfo createRecentTaskInfo(TaskRecord tr) { - // Update the task description to reflect any changes in the task stack - tr.updateTaskDescription(); - // Compose the recent task info ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo(); rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId; @@ -1444,8 +1441,8 @@ class RecentTasks { rti.affiliatedTaskId = tr.mAffiliatedTaskId; rti.affiliatedTaskColor = tr.mAffiliatedTaskColor; rti.numActivities = 0; - if (tr.mBounds != null) { - rti.bounds = new Rect(tr.mBounds); + if (!tr.matchParentBounds()) { + rti.bounds = new Rect(tr.getOverrideBounds()); } rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreenWindowingMode(); rti.resizeMode = tr.mResizeMode; diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index a9c6eee05bf6..365990f15835 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -19,9 +19,6 @@ package com.android.server.am; import static android.app.ActivityManager.RESIZE_MODE_FORCED; import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; @@ -293,11 +290,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi final ActivityManagerService mService; - // Whether or not this task covers the entire screen; by default tasks are fullscreen. - boolean mFullscreen = true; - - // Bounds of the Task. null for fullscreen tasks. - Rect mBounds = null; private final Rect mTmpStableBounds = new Rect(); private final Rect mTmpNonDecorBounds = new Rect(); private final Rect mTmpRect = new Rect(); @@ -480,68 +472,76 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) { - if (!isResizeable()) { - Slog.w(TAG, "resizeTask: task " + this + " not resizeable."); - return true; - } + mService.mWindowManager.deferSurfaceLayout(); - // If this is a forced resize, let it go through even if the bounds is not changing, - // as we might need a relayout due to surface size change (to/from fullscreen). - final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0; - if (Objects.equals(mBounds, bounds) && !forced) { - // Nothing to do here... - return true; - } - bounds = validateBounds(bounds); - - if (mWindowContainerController == null) { - // Task doesn't exist in window manager yet (e.g. was restored from recents). - // All we can do for now is update the bounds so it can be used when the task is - // added to window manager. - updateOverrideConfiguration(bounds); - if (!inFreeformWindowingMode()) { - // re-restore the task so it can have the proper stack association. - mService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP); + try { + if (!isResizeable()) { + Slog.w(TAG, "resizeTask: task " + this + " not resizeable."); + return true; } - return true; - } - if (!canResizeToBounds(bounds)) { - throw new IllegalArgumentException("resizeTask: Can not resize task=" + this - + " to bounds=" + bounds + " resizeMode=" + mResizeMode); - } + // If this is a forced resize, let it go through even if the bounds is not changing, + // as we might need a relayout due to surface size change (to/from fullscreen). + final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0; + if (equivalentOverrideBounds(bounds) && !forced) { + // Nothing to do here... + return true; + } - // Do not move the task to another stack here. - // This method assumes that the task is already placed in the right stack. - // we do not mess with that decision and we only do the resize! + if (mWindowContainerController == null) { + // Task doesn't exist in window manager yet (e.g. was restored from recents). + // All we can do for now is update the bounds so it can be used when the task is + // added to window manager. + updateOverrideConfiguration(bounds); + if (!inFreeformWindowingMode()) { + // re-restore the task so it can have the proper stack association. + mService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP); + } + return true; + } - Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + taskId); + if (!canResizeToBounds(bounds)) { + throw new IllegalArgumentException("resizeTask: Can not resize task=" + this + + " to bounds=" + bounds + " resizeMode=" + mResizeMode); + } - final boolean updatedConfig = updateOverrideConfiguration(bounds); - // This variable holds information whether the configuration didn't change in a significant - // way and the activity was kept the way it was. If it's false, it means the activity had - // to be relaunched due to configuration change. - boolean kept = true; - if (updatedConfig) { - final ActivityRecord r = topRunningActivityLocked(); - if (r != null && !deferResume) { - kept = r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindow); - mService.mStackSupervisor.ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS); - if (!kept) { - mService.mStackSupervisor.resumeFocusedStackTopActivityLocked(); + // Do not move the task to another stack here. + // This method assumes that the task is already placed in the right stack. + // we do not mess with that decision and we only do the resize! + + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + taskId); + + final boolean updatedConfig = updateOverrideConfiguration(bounds); + // This variable holds information whether the configuration didn't change in a significant + + // way and the activity was kept the way it was. If it's false, it means the activity + // had + // to be relaunched due to configuration change. + boolean kept = true; + if (updatedConfig) { + final ActivityRecord r = topRunningActivityLocked(); + if (r != null && !deferResume) { + kept = r.ensureActivityConfigurationLocked(0 /* globalChanges */, + preserveWindow); + mService.mStackSupervisor.ensureActivitiesVisibleLocked(r, 0, + !PRESERVE_WINDOWS); + if (!kept) { + mService.mStackSupervisor.resumeFocusedStackTopActivityLocked(); + } } } - } - mWindowContainerController.resize(mBounds, getOverrideConfiguration(), kept, forced); + mWindowContainerController.resize(kept, forced); - Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); - return kept; + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); + return kept; + } finally { + mService.mWindowManager.continueSurfaceLayout(); + } } // TODO: Investigate combining with the resize() method above. void resizeWindowContainer() { - mWindowContainerController.resize(mBounds, getOverrideConfiguration(), false /* relayout */, - false /* forced */); + mWindowContainerController.resize(false /* relayout */, false /* forced */); } void getWindowContainerBounds(Rect bounds) { @@ -686,16 +686,17 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // Make sure the task has the appropriate bounds/size for the stack it is in. final boolean toStackSplitScreenPrimary = toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; + final Rect configBounds = getOverrideBounds(); if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) - && !Objects.equals(mBounds, toStack.mBounds)) { - kept = resize(toStack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow, + && !Objects.equals(configBounds, toStack.getOverrideBounds())) { + kept = resize(toStack.getOverrideBounds(), RESIZE_MODE_SYSTEM, !mightReplaceWindow, deferResume); } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) { Rect bounds = getLaunchBounds(); if (bounds == null) { mService.mStackSupervisor.getLaunchingBoundsController().layoutTask(this, null); - bounds = mBounds; + bounds = configBounds; } kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume); } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) { @@ -704,7 +705,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // mode mService.mStackSupervisor.moveRecentsStackToFront(reason); } - kept = resize(toStack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow, + kept = resize(toStack.getOverrideBounds(), RESIZE_MODE_SYSTEM, !mightReplaceWindow, deferResume); } } finally { @@ -1501,8 +1502,10 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi return true; } final boolean landscape = bounds.width() > bounds.height(); + final Rect configBounds = getOverrideBounds(); if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) { - return mBounds == null || landscape == (mBounds.width() > mBounds.height()); + return configBounds.isEmpty() + || landscape == (configBounds.width() > configBounds.height()); } return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape) && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape); @@ -1623,6 +1626,9 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi final int effectiveRootIndex = findEffectiveRootIndex(); final ActivityRecord r = mActivities.get(effectiveRootIndex); setIntent(r); + + // Update the task description when the activities change + updateTaskDescription(); } void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { @@ -1920,8 +1926,9 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi return; } + final Rect configBounds = getOverrideBounds(); if (adjustWidth) { - if (mBounds != null && bounds.right == mBounds.right) { + if (!configBounds.isEmpty() && bounds.right == configBounds.right) { bounds.left = bounds.right - minWidth; } else { // Either left bounds match, or neither match, or the previous bounds were @@ -1930,7 +1937,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } } if (adjustHeight) { - if (mBounds != null && bounds.bottom == mBounds.bottom) { + if (!configBounds.isEmpty() && bounds.bottom == configBounds.bottom) { bounds.top = bounds.bottom - minHeight; } else { // Either top bounds match, or neither match, or the previous bounds were @@ -1977,38 +1984,37 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi * @return True if the override configuration was updated. */ boolean updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) { - if (Objects.equals(mBounds, bounds)) { + if (equivalentOverrideBounds(bounds)) { return false; } + final Rect currentBounds = getOverrideBounds(); + mTmpConfig.setTo(getOverrideConfiguration()); - final boolean oldFullscreen = mFullscreen; + final boolean oldMatchParentBounds = matchParentBounds(); final Configuration newConfig = getOverrideConfiguration(); - mFullscreen = bounds == null; + final boolean matchParentBounds = bounds == null || bounds.isEmpty(); final boolean persistBounds = getWindowConfiguration().persistTaskBounds(); - if (mFullscreen) { - if (mBounds != null && persistBounds) { - mLastNonFullscreenBounds = mBounds; + if (matchParentBounds) { + if (!currentBounds.isEmpty() && persistBounds) { + mLastNonFullscreenBounds = currentBounds; } - mBounds = null; + setBounds(null); newConfig.unset(); } else { mTmpRect.set(bounds); adjustForMinimalTaskDimensions(mTmpRect); - if (mBounds == null) { - mBounds = new Rect(mTmpRect); - } else { - mBounds.set(mTmpRect); - } + setBounds(mTmpRect); + if (mStack == null || persistBounds) { - mLastNonFullscreenBounds = mBounds; + mLastNonFullscreenBounds = getOverrideBounds(); } computeOverrideConfiguration(newConfig, mTmpRect, insetBounds, mTmpRect.right != bounds.right, mTmpRect.bottom != bounds.bottom); } onOverrideConfigurationChanged(newConfig); - if (mFullscreen != oldFullscreen) { + if (matchParentBounds != oldMatchParentBounds) { mService.mStackSupervisor.scheduleUpdateMultiWindowMode(this); } @@ -2053,23 +2059,19 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp); final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp); config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize); - } Rect updateOverrideConfigurationFromLaunchBounds() { - final Rect bounds = validateBounds(getLaunchBounds()); + final Rect bounds = getLaunchBounds(); updateOverrideConfiguration(bounds); - if (bounds != null) { - bounds.set(mBounds); + if (bounds != null && !bounds.isEmpty()) { + // TODO: Review if we actually want to do this - we are setting the launch bounds + // directly here. + bounds.set(getOverrideBounds()); } return bounds; } - static Rect validateBounds(Rect bounds) { - // TODO: Not needed once we have bounds in WindowConfiguration. - return (bounds != null && bounds.isEmpty()) ? null : bounds; - } - /** Updates the task's bounds and override configuration to match what is expected for the * input stack. */ void updateOverrideConfigurationForStack(ActivityStack inStack) { @@ -2082,7 +2084,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi throw new IllegalArgumentException("Can not position non-resizeable task=" + this + " in stack=" + inStack); } - if (mBounds != null) { + if (!matchParentBounds()) { return; } if (mLastNonFullscreenBounds != null) { @@ -2091,7 +2093,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi mService.mStackSupervisor.getLaunchingBoundsController().layoutTask(this, null); } } else { - updateOverrideConfiguration(inStack.mBounds); + updateOverrideConfiguration(inStack.getOverrideBounds()); } } @@ -2105,9 +2107,9 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi if (!isActivityTypeStandardOrUndefined() || windowingMode == WINDOWING_MODE_FULLSCREEN || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) { - return isResizeable() ? mStack.mBounds : null; + return isResizeable() ? mStack.getOverrideBounds() : null; } else if (!getWindowConfiguration().persistTaskBounds()) { - return mStack.mBounds; + return mStack.getOverrideBounds(); } return mLastNonFullscreenBounds; } @@ -2287,9 +2289,12 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } proto.write(ACTIVITY_TYPE, getActivityType()); proto.write(RESIZE_MODE, mResizeMode); - proto.write(FULLSCREEN, mFullscreen); - if (mBounds != null) { - mBounds.writeToProto(proto, BOUNDS); + // TODO: Remove, no longer needed with windowingMode. + proto.write(FULLSCREEN, matchParentBounds()); + + if (!matchParentBounds()) { + final Rect bounds = getOverrideBounds(); + bounds.writeToProto(proto, BOUNDS); } proto.write(MIN_WIDTH, mMinWidth); proto.write(MIN_HEIGHT, mMinHeight); diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java index a528ecdf537e..00a0d3d18f9c 100644 --- a/services/core/java/com/android/server/wm/AppWindowContainerController.java +++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java @@ -181,13 +181,12 @@ public class AppWindowContainerController IApplicationToken token, AppWindowContainerListener listener, int index, int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges, boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable, - int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos, - Rect bounds) { + int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) { this(taskController, token, listener, index, requestedOrientation, fullscreen, showForAllUsers, configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable, targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos, - WindowManagerService.getInstance(), bounds); + WindowManagerService.getInstance()); } public AppWindowContainerController(TaskWindowContainerController taskController, @@ -195,7 +194,7 @@ public class AppWindowContainerController int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges, boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable, int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos, - WindowManagerService service, Rect bounds) { + WindowManagerService service) { super(listener, service); mHandler = new H(service.mH.getLooper()); mToken = token; @@ -216,7 +215,7 @@ public class AppWindowContainerController atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(), inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion, requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind, - alwaysFocusable, this, bounds); + alwaysFocusable, this); if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken + " controller=" + taskController + " at " + index); task.addChild(atoken, index); @@ -228,11 +227,11 @@ public class AppWindowContainerController boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, int configChanges, boolean launchTaskBehind, - boolean alwaysFocusable, AppWindowContainerController controller, Rect bounds) { + boolean alwaysFocusable, AppWindowContainerController controller) { return new AppWindowToken(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable, - controller, bounds); + controller); } public void removeContainer(int displayId) { @@ -299,17 +298,6 @@ public class AppWindowContainerController } } - // TODO(b/36505427): Maybe move to WindowContainerController so other sub-classes can use it as - // a generic way to set override config. Need to untangle current ways the override config is - // currently set for tasks and displays before we are doing that though. - public void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) { - synchronized(mWindowMap) { - if (mContainer != null) { - mContainer.onOverrideConfigurationChanged(overrideConfiguration, bounds); - } - } - } - public void setDisablePreviewScreenshots(boolean disable) { synchronized (mWindowMap) { if (mContainer == null) { diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 627f8cee3fd1..c39ce982e4cb 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -175,11 +175,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree private boolean mLastContainsShowWhenLockedWindow; private boolean mLastContainsDismissKeyguardWindow; - // The bounds of this activity. Mainly used for aspect-ratio compatibility. - // TODO(b/36505427): Every level on WindowContainer now has bounds information, which directly - // affects the configuration. We should probably move this into that class. - private final Rect mBounds = new Rect(); - ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>(); ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>(); @@ -196,8 +191,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, int configChanges, boolean launchTaskBehind, boolean alwaysFocusable, - AppWindowContainerController controller, Rect bounds) { - this(service, token, voiceInteraction, dc, fullscreen, bounds); + AppWindowContainerController controller) { + this(service, token, voiceInteraction, dc, fullscreen); setController(controller); mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos; mShowForAllUsers = showForAllUsers; @@ -214,7 +209,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, - DisplayContent dc, boolean fillsParent, Rect bounds) { + DisplayContent dc, boolean fillsParent) { super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc, false /* ownerCanManageAppTokens */); appToken = token; @@ -222,27 +217,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mFillsParent = fillsParent; mInputApplicationHandle = new InputApplicationHandle(this); mAppAnimator = new AppWindowAnimator(this, service); - if (bounds != null) { - mBounds.set(bounds); - } - } - - void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) { - onOverrideConfigurationChanged(overrideConfiguration); - if (mBounds.equals(bounds)) { - return; - } - // TODO(b/36505427): If bounds is in WC, then we can automatically call onResize() when set. - mBounds.set(bounds); - onResize(); - } - - void getBounds(Rect outBounds) { - outBounds.set(mBounds); - } - - boolean hasBounds() { - return !mBounds.isEmpty(); } void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) { diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index b534b8ac2244..d340923b754e 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -36,6 +36,7 @@ import static com.android.server.wm.proto.ConfigurationContainerProto.OVERRIDE_C import android.annotation.CallSuper; import android.app.WindowConfiguration; import android.content.res.Configuration; +import android.graphics.Rect; import android.util.proto.ProtoOutputStream; import java.io.PrintWriter; @@ -46,6 +47,11 @@ import java.util.ArrayList; * hierarchy. */ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { + /** + * {@link #Rect} returned from {@link #getOverrideBounds()} to prevent original value from being + * set directly. + */ + private Rect mReturnBounds = new Rect(); /** Contains override configuration settings applied to this configuration container. */ private Configuration mOverrideConfiguration = new Configuration(); @@ -71,6 +77,16 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { // TODO: Can't have ag/2592611 soon enough! private final Configuration mTmpConfig = new Configuration(); + // Used for setting bounds + private final Rect mTmpRect = new Rect(); + + static final int BOUNDS_CHANGE_NONE = 0; + // Return value from {@link setBounds} indicating the position of the override bounds changed. + static final int BOUNDS_CHANGE_POSITION = 1; + // Return value from {@link setBounds} indicating the size of the override bounds changed. + static final int BOUNDS_CHANGE_SIZE = 1 << 1; + + /** * Returns full configuration applied to this configuration container. * This method should be used for getting settings applied in each particular level of the @@ -148,6 +164,118 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { } } + /** + * Indicates whether this container has not specified any bounds different from its parent. In + * this case, it will inherit the bounds of the first ancestor which specifies a bounds. + * @return {@code true} if no explicit bounds have been set at this container level. + * {@code false} otherwise. + */ + public boolean matchParentBounds() { + return getOverrideBounds().isEmpty(); + } + + /** + * Returns whether the bounds specified is considered the same as the existing override bounds. + * This is either when the two bounds are equal or the override bounds is empty and the + * specified bounds is null. + * + * @return {@code true} if the bounds are equivalent, {@code false} otherwise + */ + public boolean equivalentOverrideBounds(Rect bounds) { + return equivalentBounds(getOverrideBounds(), bounds); + } + + /** + * Returns whether the two bounds are equal to each other or are a combination of null or empty. + */ + public static boolean equivalentBounds(Rect bounds, Rect other) { + return bounds == other + || (bounds != null && (bounds.equals(other) || (bounds.isEmpty() && other == null))) + || (other != null && other.isEmpty() && bounds == null); + } + + /** + * Returns the effective bounds of this container, inheriting the first non-empty bounds set in + * its ancestral hierarchy, including itself. + * @return + */ + public Rect getBounds() { + mReturnBounds.set(getConfiguration().windowConfiguration.getBounds()); + return mReturnBounds; + } + + public void getBounds(Rect outBounds) { + outBounds.set(getBounds()); + } + + /** + * Returns the current bounds explicitly set on this container. The {@link Rect} handed back is + * shared for all calls to this method and should not be modified. + */ + public Rect getOverrideBounds() { + mReturnBounds.set(getOverrideConfiguration().windowConfiguration.getBounds()); + + return mReturnBounds; + } + + /** + * Sets the passed in {@link Rect} to the current bounds. + * @see {@link #getOverrideBounds()}. + */ + public void getOverrideBounds(Rect outBounds) { + outBounds.set(getOverrideBounds()); + } + + /** + * Sets the bounds at the current hierarchy level, overriding any bounds set on an ancestor. + * This value will be reported when {@link #getBounds()} and {@link #getOverrideBounds()}. If + * an empty {@link Rect} or null is specified, this container will be considered to match its + * parent bounds {@see #matchParentBounds} and will inherit bounds from its parent. + * @param bounds The bounds defining the container size. + * @return a bitmask representing the types of changes made to the bounds. + */ + public int setBounds(Rect bounds) { + int boundsChange = diffOverrideBounds(bounds); + + if (boundsChange == BOUNDS_CHANGE_NONE) { + return boundsChange; + } + + + mTmpConfig.setTo(getOverrideConfiguration()); + mTmpConfig.windowConfiguration.setBounds(bounds); + onOverrideConfigurationChanged(mTmpConfig); + + return boundsChange; + } + + public int setBounds(int left, int top, int right, int bottom) { + mTmpRect.set(left, top, right, bottom); + return setBounds(mTmpRect); + } + + int diffOverrideBounds(Rect bounds) { + if (equivalentOverrideBounds(bounds)) { + return BOUNDS_CHANGE_NONE; + } + + int boundsChange = BOUNDS_CHANGE_NONE; + + final Rect existingBounds = getOverrideBounds(); + + if (bounds == null || existingBounds.left != bounds.left + || existingBounds.top != bounds.top) { + boundsChange |= BOUNDS_CHANGE_POSITION; + } + + if (bounds == null || existingBounds.width() != bounds.width() + || existingBounds.height() != bounds.height()) { + boundsChange |= BOUNDS_CHANGE_SIZE; + } + + return boundsChange; + } + public WindowConfiguration getWindowConfiguration() { return mFullConfiguration.windowConfiguration; } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 44dfa07794d2..3fb377385220 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -314,6 +314,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private final Matrix mTmpMatrix = new Matrix(); private final Region mTmpRegion = new Region(); + /** Used for handing back size of display */ + private final Rect mTmpBounds = new Rect(); + WindowManagerService mService; /** Remove this display when animation on it has completed. */ @@ -1223,6 +1226,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(mDisplayMetrics, mCompatDisplayMetrics); } + + updateBounds(); return mDisplayInfo; } @@ -1541,8 +1546,17 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // See {@link PhoneWindowManager#setInitialDisplaySize}...sigh... mService.reconfigureDisplayLocked(this); - getDockedDividerController().onConfigurationChanged(); - getPinnedStackController().onConfigurationChanged(); + final DockedStackDividerController dividerController = getDockedDividerController(); + + if (dividerController != null) { + getDockedDividerController().onConfigurationChanged(); + } + + final PinnedStackController pinnedStackController = getPinnedStackController(); + + if (pinnedStackController != null) { + getPinnedStackController().onConfigurationChanged(); + } } /** @@ -1681,33 +1695,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi; } - void getLogicalDisplayRect(Rect out) { - // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked. - final int orientation = mDisplayInfo.rotation; - boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270); - final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth; - final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight; - int width = mDisplayInfo.logicalWidth; - int left = (physWidth - width) / 2; - int height = mDisplayInfo.logicalHeight; - int top = (physHeight - height) / 2; - out.set(left, top, left + width, top + height); - } - - private void getLogicalDisplayRect(Rect out, int orientation) { - getLogicalDisplayRect(out); - - // Rotate the Rect if needed. - final int currentRotation = mDisplayInfo.rotation; - final int rotationDelta = deltaRotation(currentRotation, orientation); - if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) { - createRotationMatrix(rotationDelta, mBaseDisplayWidth, mBaseDisplayHeight, mTmpMatrix); - mTmpRectF.set(out); - mTmpMatrix.mapRect(mTmpRectF); - mTmpRectF.round(out); - } - } - /** * If display metrics changed, overrides are not set and it's not just a rotation - update base * values. @@ -1775,6 +1762,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight); + + updateBounds(); } void getContentRect(Rect out) { @@ -2104,7 +2093,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } void rotateBounds(int oldRotation, int newRotation, Rect bounds) { - getLogicalDisplayRect(mTmpRect, newRotation); + getBounds(mTmpRect, newRotation); // Compute a transform matrix to undo the coordinate space transformation, // and present the window at the same physical position it previously occupied. @@ -2881,6 +2870,44 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mTmpApplySurfaceChangesTransactionState.focusDisplayed; } + private void updateBounds() { + calculateBounds(mTmpBounds); + setBounds(mTmpBounds); + } + + // Determines the current display bounds based on the current state + private void calculateBounds(Rect out) { + // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked. + final int orientation = mDisplayInfo.rotation; + boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270); + final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth; + final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight; + int width = mDisplayInfo.logicalWidth; + int left = (physWidth - width) / 2; + int height = mDisplayInfo.logicalHeight; + int top = (physHeight - height) / 2; + out.set(left, top, left + width, top + height); + } + + @Override + public void getBounds(Rect out) { + calculateBounds(out); + } + + private void getBounds(Rect out, int orientation) { + getBounds(out); + + // Rotate the Rect if needed. + final int currentRotation = mDisplayInfo.rotation; + final int rotationDelta = deltaRotation(currentRotation, orientation); + if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) { + createRotationMatrix(rotationDelta, mBaseDisplayWidth, mBaseDisplayHeight, mTmpMatrix); + mTmpRectF.set(out); + mTmpMatrix.mapRect(mTmpRectF); + mTmpRectF.round(out); + } + } + void performLayout(boolean initial, boolean updateInputWindows) { if (!isLayoutNeeded()) { return; diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 8308417fa141..a37598e706c6 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -655,8 +655,8 @@ public class DockedStackDividerController { } private boolean isWithinDisplay(Task task) { - task.mStack.getBounds(mTmpRect); - mDisplayContent.getLogicalDisplayRect(mTmpRect2); + task.getBounds(mTmpRect); + mDisplayContent.getBounds(mTmpRect2); return mTmpRect.intersect(mTmpRect2); } diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 18b0f976dbd2..7e29a3aa811e 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -661,8 +661,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { if (w.inPinnedWindowingMode()) { if (mAddPipInputConsumerHandle && (inputWindowHandle.layer <= pipInputConsumer.mWindowHandle.layer)) { - // Update the bounds of the Pip input consumer to match the Pinned stack - w.getStack().getBounds(pipTouchableBounds); + // Update the bounds of the Pip input consumer to match the window bounds. + w.getBounds(pipTouchableBounds); pipInputConsumer.mWindowHandle.touchableRegion.set(pipTouchableBounds); addInputWindowHandle(pipInputConsumer.mWindowHandle); mAddPipInputConsumerHandle = false; diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java index 41f076d7b6af..b021a7223e2e 100644 --- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java +++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java @@ -106,7 +106,7 @@ public class PinnedStackWindowController extends StackWindowController { } else { // Otherwise, use the display bounds toBounds = new Rect(); - mContainer.getDisplayContent().getLogicalDisplayRect(toBounds); + mContainer.getDisplayContent().getBounds(toBounds); } } else if (fromFullscreen) { schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END; diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index 70bf15ceb4c3..5a39de5c3242 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -28,7 +28,6 @@ import static com.android.server.wm.proto.ScreenRotationAnimationProto.STARTED; import android.content.Context; import android.graphics.Matrix; -import android.graphics.PixelFormat; import android.graphics.Rect; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -230,7 +229,7 @@ class ScreenRotationAnimation { mService = service; mContext = context; mDisplayContent = displayContent; - displayContent.getLogicalDisplayRect(mOriginalDisplayRect); + displayContent.getBounds(mOriginalDisplayRect); // Screenshot does NOT include rotation! final Display display = displayContent.getDisplay(); @@ -312,7 +311,7 @@ class ScreenRotationAnimation { float x = mTmpFloats[Matrix.MTRANS_X]; float y = mTmpFloats[Matrix.MTRANS_Y]; if (mForceDefaultOrientation) { - mDisplayContent.getLogicalDisplayRect(mCurrentDisplayRect); + mDisplayContent.getBounds(mCurrentDisplayRect); x -= mCurrentDisplayRect.left; y -= mCurrentDisplayRect.top; } diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java index 95c1d536123f..c2a4be55e30a 100644 --- a/services/core/java/com/android/server/wm/StackWindowController.java +++ b/services/core/java/com/android/server/wm/StackWindowController.java @@ -111,8 +111,7 @@ public class StackWindowController } } - public void positionChildAt(TaskWindowContainerController child, int position, Rect bounds, - Configuration overrideConfig) { + public void positionChildAt(TaskWindowContainerController child, int position) { synchronized (mWindowMap) { if (DEBUG_STACK) Slog.i(TAG_WM, "positionChildAt: positioning task=" + child + " at " + position); @@ -126,7 +125,7 @@ public class StackWindowController "positionChildAt: could not find stack for task=" + mContainer); return; } - child.mContainer.positionAt(position, bounds, overrideConfig); + child.mContainer.positionAt(position); mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); } } @@ -178,24 +177,22 @@ public class StackWindowController * Re-sizes a stack and its containing tasks. * * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen. - * @param configs Configurations for tasks in the resized stack, keyed by task id. * @param taskBounds Bounds for tasks in the resized stack, keyed by task id. - * @return True if the stack is now fullscreen. + * @param taskTempInsetBounds Inset bounds for individual tasks, keyed by task id. */ - public boolean resize(Rect bounds, SparseArray<Configuration> configs, - SparseArray<Rect> taskBounds, SparseArray<Rect> taskTempInsetBounds) { + public void resize(Rect bounds, SparseArray<Rect> taskBounds, + SparseArray<Rect> taskTempInsetBounds) { synchronized (mWindowMap) { if (mContainer == null) { throw new IllegalArgumentException("resizeStack: stack " + this + " not found."); } // We might trigger a configuration change. Save the current task bounds for freezing. mContainer.prepareFreezingTaskBounds(); - if (mContainer.setBounds(bounds, configs, taskBounds, taskTempInsetBounds) + if (mContainer.setBounds(bounds, taskBounds, taskTempInsetBounds) && mContainer.isVisible()) { mContainer.getDisplayContent().setLayoutNeeded(); mService.mWindowPlacerLocked.performSurfacePlacement(); } - return mContainer.getRawFullscreen(); } } @@ -227,7 +224,7 @@ public class StackWindowController public void getRawBounds(Rect outBounds) { synchronized (mWindowMap) { - if (mContainer.getRawFullscreen()) { + if (mContainer.matchParentBounds()) { outBounds.setEmpty(); } else { mContainer.getRawBounds(outBounds); @@ -275,6 +272,7 @@ public class StackWindowController final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds(); + config.windowConfiguration.setBounds(bounds); config.windowConfiguration.setAppBounds(!bounds.isEmpty() ? bounds : null); boolean intersectParentBounds = false; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index f70845e52bb9..8aa129a45373 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -53,12 +53,6 @@ import java.util.function.Consumer; class Task extends WindowContainer<AppWindowToken> { static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM; - // Return value from {@link setBounds} indicating no change was made to the Task bounds. - private static final int BOUNDS_CHANGE_NONE = 0; - // Return value from {@link setBounds} indicating the position of the Task bounds changed. - private static final int BOUNDS_CHANGE_POSITION = 1; - // Return value from {@link setBounds} indicating the size of the Task bounds changed. - private static final int BOUNDS_CHANGE_SIZE = 1 << 1; // TODO: Track parent marks like this in WindowContainer. TaskStack mStack; @@ -67,8 +61,6 @@ class Task extends WindowContainer<AppWindowToken> { private boolean mDeferRemoval = false; final WindowManagerService mService; - // Content limits relative to the DisplayContent this sits in. - private Rect mBounds = new Rect(); final Rect mPreparedFrozenBounds = new Rect(); final Configuration mPreparedFrozenMergedConfig = new Configuration(); @@ -78,13 +70,12 @@ class Task extends WindowContainer<AppWindowToken> { // Device rotation as of the last time {@link #mBounds} was set. private int mRotation; - // Whether mBounds is fullscreen - private boolean mFillsParent = true; - // For comparison with DisplayContent bounds. private Rect mTmpRect = new Rect(); // For handling display rotations. private Rect mTmpRect2 = new Rect(); + // For retrieving dim bounds + private Rect mTmpRect3 = new Rect(); // Resize mode of the task. See {@link ActivityInfo#resizeMode} private int mResizeMode; @@ -108,8 +99,8 @@ class Task extends WindowContainer<AppWindowToken> { private Dimmer mDimmer = new Dimmer(this); private final Rect mTmpDimBoundsRect = new Rect(); - Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, - int resizeMode, boolean supportsPictureInPicture, TaskDescription taskDescription, + Task(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode, + boolean supportsPictureInPicture, TaskDescription taskDescription, TaskWindowContainerController controller) { mTaskId = taskId; mStack = stack; @@ -118,7 +109,7 @@ class Task extends WindowContainer<AppWindowToken> { mResizeMode = resizeMode; mSupportsPictureInPicture = supportsPictureInPicture; setController(controller); - setBounds(bounds, getOverrideConfiguration()); + setBounds(getOverrideBounds()); mTaskDescription = taskDescription; // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED). @@ -227,9 +218,8 @@ class Task extends WindowContainer<AppWindowToken> { } /** @see com.android.server.am.ActivityManagerService#positionTaskInStack(int, int, int). */ - void positionAt(int position, Rect bounds, Configuration overrideConfig) { + void positionAt(int position) { mStack.positionChildAt(position, this, false /* includingParents */); - resizeLocked(bounds, overrideConfig, false /* force */); } @Override @@ -271,48 +261,37 @@ class Task extends WindowContainer<AppWindowToken> { } } - /** Set the task bounds. Passing in null sets the bounds to fullscreen. */ - // TODO: There is probably not a need to pass in overrideConfig anymore since any change to it - // will be automatically propagated from the AM. Also, mBound is going to be in - // WindowConfiguration long term. - private int setBounds(Rect bounds, Configuration overrideConfig) { - if (overrideConfig == null) { - overrideConfig = EMPTY; + public int setBounds(Rect bounds, boolean forceResize) { + final int boundsChanged = setBounds(bounds); + + if (forceResize && (boundsChanged & BOUNDS_CHANGE_SIZE) != BOUNDS_CHANGE_SIZE) { + onResize(); + return BOUNDS_CHANGE_SIZE | boundsChanged; } - boolean oldFullscreen = mFillsParent; + return boundsChanged; + } + + /** Set the task bounds. Passing in null sets the bounds to fullscreen. */ + @Override + public int setBounds(Rect bounds) { int rotation = Surface.ROTATION_0; final DisplayContent displayContent = mStack.getDisplayContent(); if (displayContent != null) { - displayContent.getLogicalDisplayRect(mTmpRect); rotation = displayContent.getDisplayInfo().rotation; - mFillsParent = bounds == null; - if (mFillsParent) { - bounds = mTmpRect; - } - } - - if (bounds == null) { + } else if (bounds == null) { // Can't set to fullscreen if we don't have a display to get bounds from... return BOUNDS_CHANGE_NONE; } - if (mBounds.equals(bounds) && oldFullscreen == mFillsParent && mRotation == rotation) { - return BOUNDS_CHANGE_NONE; - } - int boundsChange = BOUNDS_CHANGE_NONE; - if (mBounds.left != bounds.left || mBounds.top != bounds.top) { - boundsChange |= BOUNDS_CHANGE_POSITION; - } - if (mBounds.width() != bounds.width() || mBounds.height() != bounds.height()) { - boundsChange |= BOUNDS_CHANGE_SIZE; + if (equivalentOverrideBounds(bounds)) { + return BOUNDS_CHANGE_NONE; } - mBounds.set(bounds); + final int boundsChange = super.setBounds(bounds); mRotation = rotation; - onOverrideConfigurationChanged(overrideConfig); return boundsChange; } @@ -360,28 +339,12 @@ class Task extends WindowContainer<AppWindowToken> { return isResizeable(); } - boolean resizeLocked(Rect bounds, Configuration overrideConfig, boolean forced) { - int boundsChanged = setBounds(bounds, overrideConfig); - if (forced) { - boundsChanged |= BOUNDS_CHANGE_SIZE; - } - if (boundsChanged == BOUNDS_CHANGE_NONE) { - return false; - } - if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) { - onResize(); - } else { - onMovedByResize(); - } - return true; - } - /** * Prepares the task bounds to be frozen with the current size. See * {@link AppWindowToken#freezeBounds}. */ void prepareFreezingBounds() { - mPreparedFrozenBounds.set(mBounds); + mPreparedFrozenBounds.set(getBounds()); mPreparedFrozenMergedConfig.setTo(getConfiguration()); } @@ -407,30 +370,30 @@ class Task extends WindowContainer<AppWindowToken> { mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top); } setTempInsetBounds(tempInsetBounds); - resizeLocked(mTmpRect2, getOverrideConfiguration(), false /* forced */); + setBounds(mTmpRect2, false /* forced */); } /** Return true if the current bound can get outputted to the rest of the system as-is. */ private boolean useCurrentBounds() { final DisplayContent displayContent = getDisplayContent(); - return mFillsParent + return matchParentBounds() || !inSplitScreenSecondaryWindowingMode() || displayContent == null || displayContent.getSplitScreenPrimaryStackIgnoringVisibility() != null; } - /** Original bounds of the task if applicable, otherwise fullscreen rect. */ - void getBounds(Rect out) { + @Override + public void getBounds(Rect out) { if (useCurrentBounds()) { // No need to adjust the output bounds if fullscreen or the docked stack is visible // since it is already what we want to represent to the rest of the system. - out.set(mBounds); + super.getBounds(out); return; } // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is // not currently visible. Go ahead a represent it as fullscreen to the rest of the system. - mStack.getDisplayContent().getLogicalDisplayRect(out); + mStack.getDisplayContent().getBounds(out); } /** @@ -490,7 +453,7 @@ class Task extends WindowContainer<AppWindowToken> { return; } - if (!mFillsParent) { + if (!matchParentBounds()) { // When minimizing the docked stack when going home, we don't adjust the task bounds // so we need to intersect the task bounds with the stack bounds here. // @@ -501,11 +464,11 @@ class Task extends WindowContainer<AppWindowToken> { mStack.getBounds(out); } else { mStack.getBounds(mTmpRect); - mTmpRect.intersect(mBounds); + mTmpRect.intersect(getBounds()); } out.set(mTmpRect); } else { - out.set(mBounds); + out.set(getBounds()); } return; } @@ -513,7 +476,7 @@ class Task extends WindowContainer<AppWindowToken> { // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is // not currently visible. Go ahead a represent it as fullscreen to the rest of the system. if (displayContent != null) { - displayContent.getLogicalDisplayRect(out); + displayContent.getBounds(out); } } @@ -541,10 +504,10 @@ class Task extends WindowContainer<AppWindowToken> { if (displayContent == null) { return; } - if (mFillsParent) { + if (matchParentBounds()) { // TODO: Yeah...not sure if this works with WindowConfiguration, but shouldn't be a // problem once we move mBounds into WindowConfiguration. - setBounds(null, getOverrideConfiguration()); + setBounds(null); return; } final int newRotation = displayContent.getDisplayInfo().rotation; @@ -557,18 +520,18 @@ class Task extends WindowContainer<AppWindowToken> { // task bounds so it stays in the same place. // - Rotate the bounds and notify activity manager if the task can be resized independently // from its stack. The stack will take care of task rotation for the other case. - mTmpRect2.set(mBounds); + mTmpRect2.set(getBounds()); if (!getWindowConfiguration().canResizeTask()) { - setBounds(mTmpRect2, getOverrideConfiguration()); + setBounds(mTmpRect2); return; } displayContent.rotateBounds(mRotation, newRotation, mTmpRect2); - if (setBounds(mTmpRect2, getOverrideConfiguration()) != BOUNDS_CHANGE_NONE) { + if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) { final TaskWindowContainerController controller = getController(); if (controller != null) { - controller.requestResize(mBounds, RESIZE_MODE_SYSTEM_SCREEN_ROTATION); + controller.requestResize(getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION); } } } @@ -632,7 +595,7 @@ class Task extends WindowContainer<AppWindowToken> { boolean isFullscreen() { if (useCurrentBounds()) { - return mFillsParent; + return matchParentBounds(); } // The bounds has been adjusted to accommodate for a docked stack, but the docked stack // is not currently visible. Go ahead a represent it as fullscreen to the rest of the @@ -661,7 +624,7 @@ class Task extends WindowContainer<AppWindowToken> { @Override boolean fillsParent() { - return mFillsParent || !getWindowConfiguration().canResizeTask(); + return matchParentBounds() || !getWindowConfiguration().canResizeTask(); } @Override @@ -711,8 +674,8 @@ class Task extends WindowContainer<AppWindowToken> { final AppWindowToken appWindowToken = mChildren.get(i); appWindowToken.writeToProto(proto, APP_WINDOW_TOKENS, trim); } - proto.write(FILLS_PARENT, mFillsParent); - mBounds.writeToProto(proto, BOUNDS); + proto.write(FILLS_PARENT, matchParentBounds()); + getBounds().writeToProto(proto, BOUNDS); mTempInsetBounds.writeToProto(proto, TEMP_INSET_BOUNDS); proto.end(token); } @@ -721,8 +684,7 @@ class Task extends WindowContainer<AppWindowToken> { final String doublePrefix = prefix + " "; pw.println(prefix + "taskId=" + mTaskId); - pw.println(doublePrefix + "mFillsParent=" + mFillsParent); - pw.println(doublePrefix + "mBounds=" + mBounds.toShortString()); + pw.println(doublePrefix + "mBounds=" + getBounds().toShortString()); pw.println(doublePrefix + "mdr=" + mDeferRemoval); pw.println(doublePrefix + "appTokens=" + mChildren); pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString()); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index e3c7515a0179..41915a32704d 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -18,9 +18,7 @@ package com.android.server.wm; import static android.graphics.Color.WHITE; import static android.graphics.Color.alpha; -import static android.view.SurfaceControl.HIDDEN; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; -import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES; import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE; diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 8a930efea678..4a3a3fc960a5 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -36,7 +36,6 @@ import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVID import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM; import static com.android.server.wm.proto.StackProto.ANIMATION_BACKGROUND_SURFACE_IS_DIMMING; import static com.android.server.wm.proto.StackProto.BOUNDS; import static com.android.server.wm.proto.StackProto.FILLS_PARENT; @@ -88,9 +87,6 @@ public class TaskStack extends WindowContainer<Task> implements private Rect mTmpRect2 = new Rect(); private Rect mTmpRect3 = new Rect(); - /** Content limits relative to the DisplayContent this sits in. */ - private Rect mBounds = new Rect(); - /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */ private final Rect mAdjustedBounds = new Rect(); @@ -100,9 +96,6 @@ public class TaskStack extends WindowContainer<Task> implements */ private final Rect mFullyAdjustedImeBounds = new Rect(); - /** Whether mBounds is fullscreen */ - private boolean mFillsParent = true; - // Device rotation as of the last time {@link #mBounds} was set. private int mRotation; @@ -180,27 +173,20 @@ public class TaskStack extends WindowContainer<Task> implements /** * Set the bounds of the stack and its containing tasks. * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen. - * @param configs Configuration for individual tasks, keyed by task id. * @param taskBounds Bounds for individual tasks, keyed by task id. + * @param taskTempInsetBounds Inset bounds for individual tasks, keyed by task id. * @return True if the stack bounds was changed. * */ boolean setBounds( - Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds, - SparseArray<Rect> taskTempInsetBounds) { + Rect stackBounds, SparseArray<Rect> taskBounds, SparseArray<Rect> taskTempInsetBounds) { setBounds(stackBounds); // Update bounds of containing tasks. for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) { final Task task = mChildren.get(taskNdx); - Configuration config = configs.get(task.mTaskId); - if (config != null) { - Rect bounds = taskBounds.get(task.mTaskId); - task.resizeLocked(bounds, config, false /* forced */); - task.setTempInsetBounds(taskTempInsetBounds != null ? - taskTempInsetBounds.get(task.mTaskId) : null); - } else { - Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?"); - } + task.setBounds(taskBounds.get(task.mTaskId), false /* forced */); + task.setTempInsetBounds(taskTempInsetBounds != null ? + taskTempInsetBounds.get(task.mTaskId) : null); } return true; } @@ -227,20 +213,20 @@ public class TaskStack extends WindowContainer<Task> implements final boolean adjusted = !mAdjustedBounds.isEmpty(); Rect insetBounds = null; if (adjusted && isAdjustedForMinimizedDockedStack()) { - insetBounds = mBounds; + insetBounds = getRawBounds(); } else if (adjusted && mAdjustedForIme) { if (mImeGoingAway) { - insetBounds = mBounds; + insetBounds = getRawBounds(); } else { insetBounds = mFullyAdjustedImeBounds; } } - alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, insetBounds); + alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : getRawBounds(), insetBounds); mDisplayContent.setLayoutNeeded(); } private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) { - if (mFillsParent) { + if (matchParentBounds()) { return; } @@ -253,13 +239,15 @@ public class TaskStack extends WindowContainer<Task> implements } } - private void setAnimationBackgroundBounds(Rect bounds) { + private void updateAnimationBackgroundBounds() { if (mAnimationBackgroundSurface == null) { return; } + getRawBounds(mTmpRect); // TODO: Should be in relative coordinates. - getPendingTransaction().setSize(mAnimationBackgroundSurface, bounds.width(), bounds.height()) - .setPosition(mAnimationBackgroundSurface, bounds.left, bounds.top); + getPendingTransaction().setSize(mAnimationBackgroundSurface, mTmpRect.width(), + mTmpRect.height()).setPosition(mAnimationBackgroundSurface, mTmpRect.left, + mTmpRect.top); scheduleAnimation(); } @@ -283,50 +271,53 @@ public class TaskStack extends WindowContainer<Task> implements scheduleAnimation(); } - private boolean setBounds(Rect bounds) { - boolean oldFullscreen = mFillsParent; + @Override + public int setBounds(Rect bounds) { + return setBounds(getOverrideBounds(), bounds); + } + + private int setBounds(Rect existing, Rect bounds) { int rotation = Surface.ROTATION_0; int density = DENSITY_DPI_UNDEFINED; if (mDisplayContent != null) { - mDisplayContent.getLogicalDisplayRect(mTmpRect); + mDisplayContent.getBounds(mTmpRect); rotation = mDisplayContent.getDisplayInfo().rotation; density = mDisplayContent.getDisplayInfo().logicalDensityDpi; - mFillsParent = bounds == null; - if (mFillsParent) { - bounds = mTmpRect; - } } - if (bounds == null) { - // Can't set to fullscreen if we don't have a display to get bounds from... - return false; - } - if (mBounds.equals(bounds) && oldFullscreen == mFillsParent && mRotation == rotation) { - return false; + if (equivalentBounds(existing, bounds) && mRotation == rotation) { + return BOUNDS_CHANGE_NONE; } - setAnimationBackgroundBounds(bounds); + final int result = super.setBounds(bounds); + + if (mDisplayContent != null) { + updateAnimationBackgroundBounds(); + } - mBounds.set(bounds); mRotation = rotation; mDensity = density; updateAdjustedBounds(); - return true; + return result; } /** Bounds of the stack without adjusting for other factors in the system like visibility * of docked stack. - * Most callers should be using {@link #getBounds} as it take into consideration other system - * factors. */ + * Most callers should be using {@link ConfigurationContainer#getOverrideBounds} as it take into + * consideration other system factors. */ void getRawBounds(Rect out) { - out.set(mBounds); + out.set(getRawBounds()); + } + + Rect getRawBounds() { + return super.getBounds(); } /** Return true if the current bound can get outputted to the rest of the system as-is. */ private boolean useCurrentBounds() { - if (mFillsParent + if (matchParentBounds() || !inSplitScreenSecondaryWindowingMode() || mDisplayContent == null || mDisplayContent.getSplitScreenPrimaryStack() != null) { @@ -335,24 +326,29 @@ public class TaskStack extends WindowContainer<Task> implements return false; } - public void getBounds(Rect out) { + @Override + public void getBounds(Rect bounds) { + bounds.set(getBounds()); + } + + @Override + public Rect getBounds() { if (useCurrentBounds()) { // If we're currently adjusting for IME or minimized docked stack, we use the adjusted // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked // stack is visible since it is already what we want to represent to the rest of the // system. if (!mAdjustedBounds.isEmpty()) { - out.set(mAdjustedBounds); + return mAdjustedBounds; } else { - out.set(mBounds); + return super.getBounds(); } - return; } // The bounds has been adjusted to accommodate for a docked stack, but the docked stack // is not currently visible. Go ahead a represent it as fullscreen to the rest of the // system. - mDisplayContent.getLogicalDisplayRect(out); + return mDisplayContent.getBounds(); } /** @@ -373,7 +369,7 @@ public class TaskStack extends WindowContainer<Task> implements mBoundsAnimationSourceHintBounds.setEmpty(); } - mPreAnimationBounds.set(mBounds); + mPreAnimationBounds.set(getRawBounds()); } /** @@ -418,12 +414,12 @@ public class TaskStack extends WindowContainer<Task> implements if (bounds != null) { setBounds(bounds); return; - } else if (mFillsParent) { + } else if (matchParentBounds()) { setBounds(null); return; } - mTmpRect2.set(mBounds); + mTmpRect2.set(getRawBounds()); final int newRotation = mDisplayContent.getDisplayInfo().rotation; final int newDensity = mDisplayContent.getDisplayInfo().logicalDensityDpi; if (mRotation == newRotation && mDensity == newDensity) { @@ -466,14 +462,14 @@ public class TaskStack extends WindowContainer<Task> implements return false; } - if (mFillsParent) { + if (matchParentBounds()) { // Update stack bounds again since rotation changed since updateDisplayInfo(). setBounds(null); // Return false since we don't need the client to resize. return false; } - mTmpRect2.set(mBounds); + mTmpRect2.set(getRawBounds()); mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2); if (inSplitScreenPrimaryWindowingMode()) { repositionPrimarySplitScreenStackAfterRotation(mTmpRect2); @@ -510,7 +506,7 @@ public class TaskStack extends WindowContainer<Task> implements if (mDisplayContent.getDockedDividerController().canPrimaryStackDockTo(dockSide)) { return; } - mDisplayContent.getLogicalDisplayRect(mTmpRect); + mDisplayContent.getBounds(mTmpRect); dockSide = DockedDividerUtils.invertDockSide(dockSide); switch (dockSide) { case DOCKED_LEFT: @@ -755,7 +751,7 @@ public class TaskStack extends WindowContainer<Task> implements // not fullscreen. If it's fullscreen, it means that we are in the transition of // dismissing it, so we must not resize this stack. bounds = new Rect(); - mDisplayContent.getLogicalDisplayRect(mTmpRect); + mDisplayContent.getBounds(mTmpRect); mTmpRect2.setEmpty(); if (splitScreenStack != null) { splitScreenStack.getRawBounds(mTmpRect2); @@ -818,7 +814,7 @@ public class TaskStack extends WindowContainer<Task> implements } if (!inSplitScreenWindowingMode() || mDisplayContent == null) { - outStackBounds.set(mBounds); + outStackBounds.set(getRawBounds()); return; } @@ -833,7 +829,7 @@ public class TaskStack extends WindowContainer<Task> implements // The docked stack is being dismissed, but we caught before it finished being // dismissed. In that case we want to treat it as if it is not occupying any space and // let others occupy the whole display. - mDisplayContent.getLogicalDisplayRect(outStackBounds); + mDisplayContent.getBounds(outStackBounds); return; } @@ -841,11 +837,11 @@ public class TaskStack extends WindowContainer<Task> implements if (dockedSide == DOCKED_INVALID) { // Not sure how you got here...Only thing we can do is return current bounds. Slog.e(TAG_WM, "Failed to get valid docked side for docked stack=" + dockedStack); - outStackBounds.set(mBounds); + outStackBounds.set(getRawBounds()); return; } - mDisplayContent.getLogicalDisplayRect(mTmpRect); + mDisplayContent.getBounds(mTmpRect); dockedStack.getRawBounds(mTmpRect2); final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT; getStackDockedModeBounds(mTmpRect, outStackBounds, mTmpRect2, @@ -1146,14 +1142,14 @@ public class TaskStack extends WindowContainer<Task> implements // occluded by IME. We shift its bottom up by the height of the IME, but // leaves at least 30% of the top stack visible. final int minTopStackBottom = - getMinTopStackBottom(displayContentRect, mBounds.bottom); + getMinTopStackBottom(displayContentRect, getRawBounds().bottom); final int bottom = Math.max( - mBounds.bottom - yOffset + dividerWidth - dividerWidthInactive, + getRawBounds().bottom - yOffset + dividerWidth - dividerWidthInactive, minTopStackBottom); - mTmpAdjustedBounds.set(mBounds); - mTmpAdjustedBounds.bottom = - (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom); - mFullyAdjustedImeBounds.set(mBounds); + mTmpAdjustedBounds.set(getRawBounds()); + mTmpAdjustedBounds.bottom = (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) + * getRawBounds().bottom); + mFullyAdjustedImeBounds.set(getRawBounds()); } else { // When the stack is on bottom and has no focus, it's only adjusted for divider width. final int dividerWidthDelta = dividerWidthInactive - dividerWidth; @@ -1163,22 +1159,24 @@ public class TaskStack extends WindowContainer<Task> implements // We try to move it up by the height of the IME window, but only to the extent // that leaves at least 30% of the top stack visible. // 'top' is where the top of bottom stack will move to in this case. - final int topBeforeImeAdjust = mBounds.top - dividerWidth + dividerWidthInactive; + final int topBeforeImeAdjust = + getRawBounds().top - dividerWidth + dividerWidthInactive; final int minTopStackBottom = - getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth); + getMinTopStackBottom(displayContentRect, + getRawBounds().top - dividerWidth); final int top = Math.max( - mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive); + getRawBounds().top - yOffset, minTopStackBottom + dividerWidthInactive); - mTmpAdjustedBounds.set(mBounds); + mTmpAdjustedBounds.set(getRawBounds()); // Account for the adjustment for IME and divider width separately. // (top - topBeforeImeAdjust) is the amount of movement due to IME only, // and dividerWidthDelta is due to divider width change only. - mTmpAdjustedBounds.top = mBounds.top + + mTmpAdjustedBounds.top = getRawBounds().top + (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) + mAdjustDividerAmount * dividerWidthDelta); - mFullyAdjustedImeBounds.set(mBounds); + mFullyAdjustedImeBounds.set(getRawBounds()); mFullyAdjustedImeBounds.top = top; - mFullyAdjustedImeBounds.bottom = top + mBounds.height(); + mFullyAdjustedImeBounds.bottom = top + getRawBounds().height(); } return true; } @@ -1192,21 +1190,21 @@ public class TaskStack extends WindowContainer<Task> implements if (dockSide == DOCKED_TOP) { mService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect); int topInset = mTmpRect.top; - mTmpAdjustedBounds.set(mBounds); - mTmpAdjustedBounds.bottom = - (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom); + mTmpAdjustedBounds.set(getRawBounds()); + mTmpAdjustedBounds.bottom = (int) (minimizeAmount * topInset + (1 - minimizeAmount) + * getRawBounds().bottom); } else if (dockSide == DOCKED_LEFT) { - mTmpAdjustedBounds.set(mBounds); - final int width = mBounds.width(); + mTmpAdjustedBounds.set(getRawBounds()); + final int width = getRawBounds().width(); mTmpAdjustedBounds.right = (int) (minimizeAmount * mDockedStackMinimizeThickness - + (1 - minimizeAmount) * mBounds.right); + + (1 - minimizeAmount) * getRawBounds().right); mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width; } else if (dockSide == DOCKED_RIGHT) { - mTmpAdjustedBounds.set(mBounds); - mTmpAdjustedBounds.left = - (int) (minimizeAmount * (mBounds.right - mDockedStackMinimizeThickness) - + (1 - minimizeAmount) * mBounds.left); + mTmpAdjustedBounds.set(getRawBounds()); + mTmpAdjustedBounds.left = (int) (minimizeAmount * + (getRawBounds().right - mDockedStackMinimizeThickness) + + (1 - minimizeAmount) * getRawBounds().left); } return true; } @@ -1228,9 +1226,9 @@ public class TaskStack extends WindowContainer<Task> implements if (dockSide == DOCKED_TOP) { mService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect); int topInset = mTmpRect.top; - return mBounds.bottom - topInset; + return getRawBounds().bottom - topInset; } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) { - return mBounds.width() - mDockedStackMinimizeThickness; + return getRawBounds().width() - mDockedStackMinimizeThickness; } else { return 0; } @@ -1264,11 +1262,12 @@ public class TaskStack extends WindowContainer<Task> implements return; } - final Rect insetBounds = mImeGoingAway ? mBounds : mFullyAdjustedImeBounds; + final Rect insetBounds = mImeGoingAway ? getRawBounds() : mFullyAdjustedImeBounds; task.alignToAdjustedBounds(mAdjustedBounds, insetBounds, getDockSide() == DOCKED_TOP); mDisplayContent.setLayoutNeeded(); } + boolean isAdjustedForMinimizedDockedStack() { return mMinimizeAmount != 0f; } @@ -1282,8 +1281,8 @@ public class TaskStack extends WindowContainer<Task> implements for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) { mChildren.get(taskNdx).writeToProto(proto, TASKS, trim); } - proto.write(FILLS_PARENT, mFillsParent); - mBounds.writeToProto(proto, BOUNDS); + proto.write(FILLS_PARENT, matchParentBounds()); + getRawBounds().writeToProto(proto, BOUNDS); proto.write(ANIMATION_BACKGROUND_SURFACE_IS_DIMMING, mAnimationBackgroundSurfaceIsShown); proto.end(token); } @@ -1291,8 +1290,7 @@ public class TaskStack extends WindowContainer<Task> implements public void dump(String prefix, PrintWriter pw) { pw.println(prefix + "mStackId=" + mStackId); pw.println(prefix + "mDeferRemoval=" + mDeferRemoval); - pw.println(prefix + "mFillsParent=" + mFillsParent); - pw.println(prefix + "mBounds=" + mBounds.toShortString()); + pw.println(prefix + "mBounds=" + getRawBounds().toShortString()); if (mMinimizeAmount != 0f) { pw.println(prefix + "mMinimizeAmount=" + mMinimizeAmount); } @@ -1323,18 +1321,10 @@ public class TaskStack extends WindowContainer<Task> implements } } - /** Fullscreen status of the stack without adjusting for other factors in the system like - * visibility of docked stack. - * Most callers should be using {@link #fillsParent} as it take into consideration other - * system factors. */ - boolean getRawFullscreen() { - return mFillsParent; - } - @Override boolean fillsParent() { if (useCurrentBounds()) { - return mFillsParent; + return matchParentBounds(); } // The bounds has been adjusted to accommodate for a docked stack, but the docked stack // is not currently visible. Go ahead a represent it as fullscreen to the rest of the @@ -1360,7 +1350,7 @@ public class TaskStack extends WindowContainer<Task> implements * information which side of the screen was the dock anchored. */ int getDockSide() { - return getDockSide(mBounds); + return getDockSide(getRawBounds()); } private int getDockSide(Rect bounds) { @@ -1370,7 +1360,7 @@ public class TaskStack extends WindowContainer<Task> implements if (mDisplayContent == null) { return DOCKED_INVALID; } - mDisplayContent.getLogicalDisplayRect(mTmpRect); + mDisplayContent.getBounds(mTmpRect); final int orientation = mDisplayContent.getConfiguration().orientation; return getDockSideUnchecked(bounds, mTmpRect, orientation); } @@ -1490,7 +1480,7 @@ public class TaskStack extends WindowContainer<Task> implements */ if (task.isActivityTypeHome() && isMinimizedDockAndHomeStackResizable()) { - mDisplayContent.getLogicalDisplayRect(mTmpRect); + mDisplayContent.getBounds(mTmpRect); } else { task.getDimBounds(mTmpRect); } diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java index b3bb0b7e001d..5caae32dbeb4 100644 --- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java +++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java @@ -18,7 +18,6 @@ package com.android.server.wm; import android.app.ActivityManager.TaskDescription; import android.app.ActivityManager.TaskSnapshot; -import android.content.res.Configuration; import android.graphics.Rect; import android.os.Handler; import android.os.Looper; @@ -30,6 +29,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.lang.ref.WeakReference; import static com.android.server.EventLogTags.WM_TASK_CREATED; +import static com.android.server.wm.ConfigurationContainer.BOUNDS_CHANGE_NONE; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; import static com.android.server.wm.WindowContainer.POSITION_TOP; @@ -75,7 +75,7 @@ public class TaskWindowContainerController + stackController); } EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId); - final Task task = createTask(taskId, stack, userId, bounds, resizeMode, + final Task task = createTask(taskId, stack, userId, resizeMode, supportsPictureInPicture, taskDescription); final int position = toTop ? POSITION_TOP : POSITION_BOTTOM; // We only want to move the parents to the parents if we are creating this task at the @@ -85,10 +85,10 @@ public class TaskWindowContainerController } @VisibleForTesting - Task createTask(int taskId, TaskStack stack, int userId, Rect bounds, int resizeMode, + Task createTask(int taskId, TaskStack stack, int userId, int resizeMode, boolean supportsPictureInPicture, TaskDescription taskDescription) { - return new Task(taskId, stack, userId, mService, bounds, resizeMode, - supportsPictureInPicture, taskDescription, this); + return new Task(taskId, stack, userId, mService, resizeMode, supportsPictureInPicture, + taskDescription, this); } @Override @@ -151,14 +151,14 @@ public class TaskWindowContainerController } } - public void resize(Rect bounds, Configuration overrideConfig, boolean relayout, - boolean forced) { + public void resize(boolean relayout, boolean forced) { synchronized (mWindowMap) { if (mContainer == null) { throw new IllegalArgumentException("resizeTask: taskId " + mTaskId + " not found."); } - if (mContainer.resizeLocked(bounds, overrideConfig, forced) && relayout) { + if (mContainer.setBounds(mContainer.getOverrideBounds(), forced) != BOUNDS_CHANGE_NONE + && relayout) { mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); } } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index a5e62884a9fb..610453e6e92b 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -318,11 +318,24 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * @see #mFullConfiguration */ @Override - final public void onOverrideConfigurationChanged(Configuration overrideConfiguration) { + public void onOverrideConfigurationChanged(Configuration overrideConfiguration) { + // We must diff before the configuration is applied so that we can capture the change + // against the existing bounds. + final int diff = diffOverrideBounds(overrideConfiguration.windowConfiguration.getBounds()); super.onOverrideConfigurationChanged(overrideConfiguration); if (mParent != null) { mParent.onDescendantOverrideConfigurationChanged(); } + + if (diff == BOUNDS_CHANGE_NONE) { + return; + } + + if ((diff & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) { + onResize(); + } else { + onMovedByResize(); + } } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d88cf4dad14f..1cd40806619f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -126,7 +126,6 @@ import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.IAssistDataReceiver; import android.content.BroadcastReceiver; -import android.content.ClipData; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -5517,7 +5516,7 @@ public class WindowManagerService extends IWindowManager.Stub } void reconfigureDisplayLocked(@NonNull DisplayContent displayContent) { - if (!mDisplayReady) { + if (!displayContent.isReady()) { return; } displayContent.configureDisplayPolicy(); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index e53fccf3e943..90e9c230b501 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -814,7 +814,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP layoutXDiff = 0; layoutYDiff = 0; } else { - getContainerBounds(mContainingFrame); + getBounds(mContainingFrame); if (mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) { // If the bounds are frozen, we still want to translate the window freely and only @@ -972,7 +972,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mContentInsets.setEmpty(); mVisibleInsets.setEmpty(); } else { - getDisplayContent().getLogicalDisplayRect(mTmpRect); + getDisplayContent().getBounds(mTmpRect); // Override right and/or bottom insets in case if the frame doesn't fit the screen in // non-fullscreen mode. boolean overrideRightInset = !windowsAreFloating && !inFullscreenContainer @@ -1044,6 +1044,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP + " of=" + mOutsets.toShortString()); } + // TODO: Look into whether this override is still necessary. + @Override + public Rect getBounds() { + if (isInMultiWindowMode()) { + return getTask().getBounds(); + } else if (mAppToken != null){ + return mAppToken.getBounds(); + } else { + return super.getBounds(); + } + } + @Override public Rect getFrameLw() { return mFrame; @@ -2951,33 +2963,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP /** Is this window in a container that takes up the entire screen space? */ private boolean inFullscreenContainer() { - if (mAppToken == null) { - return true; - } - if (mAppToken.hasBounds()) { - return false; - } - return !isInMultiWindowMode(); + return mAppToken == null || (mAppToken.matchParentBounds() && !isInMultiWindowMode()); } /** @return true when the window is in fullscreen task, but has non-fullscreen bounds set. */ boolean isLetterboxedAppWindow() { - final Task task = getTask(); - final boolean taskIsFullscreen = task != null && task.isFullscreen(); - final boolean appWindowIsFullscreen = mAppToken != null && !mAppToken.hasBounds(); - - return taskIsFullscreen && !appWindowIsFullscreen; - } - - /** Returns the appropriate bounds to use for computing frames. */ - private void getContainerBounds(Rect outBounds) { - if (isInMultiWindowMode()) { - getTask().getBounds(outBounds); - } else if (mAppToken != null){ - mAppToken.getBounds(outBounds); - } else { - outBounds.setEmpty(); - } + return !isInMultiWindowMode() && mAppToken != null && !mAppToken.matchParentBounds(); } boolean isDragResizeChanged() { diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index d11b0dbcc130..d2b37481a429 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1971,7 +1971,7 @@ class WindowStateAnimator { final float width = w.mFrame.width(); final float height = w.mFrame.height(); - mService.getDefaultDisplayContentLocked().getLogicalDisplayRect(displayRect); + mService.getDefaultDisplayContentLocked().getBounds(displayRect); final float displayWidth = displayRect.width(); final float displayHeight = displayRect.height(); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java index d90e284d44a0..ee45595f9a87 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java @@ -37,7 +37,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.ComponentName; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.support.test.filters.MediumTest; diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java index bc503c49a99a..b4919b6f9c52 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java @@ -28,7 +28,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import android.app.ActivityOptions; import android.app.IApplicationThread; -import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; @@ -108,8 +107,8 @@ public class ActivityStarterTests extends ActivityTestsBase { final Rect bounds = new Rect(10, 10, 100, 100); mStarter.updateBounds(task, bounds); - assertEquals(task.mBounds, bounds); - assertEquals(task.getStack().mBounds, null); + assertEquals(task.getOverrideBounds(), bounds); + assertEquals(new Rect(), task.getStack().getOverrideBounds()); // When in a resizeable stack, the stack bounds should be updated as well. final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor) @@ -124,10 +123,10 @@ public class ActivityStarterTests extends ActivityTestsBase { // In the case of no animation, the stack and task bounds should be set immediately. if (!ANIMATE) { - assertEquals(task2.getStack().mBounds, bounds); - assertEquals(task2.mBounds, bounds); + assertEquals(task2.getStack().getOverrideBounds(), bounds); + assertEquals(task2.getOverrideBounds(), bounds); } else { - assertEquals(task2.mBounds, null); + assertEquals(task2.getOverrideBounds(), new Rect()); } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java index 9683e229d50f..2fffb892c5f0 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -19,6 +19,7 @@ package com.android.server.am; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.view.Display.DEFAULT_DISPLAY; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.doNothing; @@ -415,6 +416,12 @@ public class ActivityTestsBase { @Override protected T createStackWindowController(int displayId, boolean onTop, Rect outBounds) { mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController(); + + // Primary pinned stacks require a non-empty out bounds to be set or else all tasks + // will be moved to the full screen stack. + if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + outBounds.set(0, 0, 100, 100); + } return mContainerController; } diff --git a/services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java b/services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java index 01e2da61f0d4..13daf3e94508 100644 --- a/services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java +++ b/services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java @@ -16,7 +16,6 @@ package com.android.server.am; -import android.content.ComponentName; import android.content.pm.ActivityInfo.WindowLayout; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; @@ -93,8 +92,8 @@ public class LaunchingTaskPositionerTests extends ActivityTestsBase { */ @Test public void testInitialBounds() throws Exception { - assertEquals(mStack.mBounds, STACK_BOUNDS); - assertEquals(mTask.mBounds, null); + assertEquals(mStack.getOverrideBounds(), STACK_BOUNDS); + assertEquals(mTask.getOverrideBounds(), new Rect()); } /** @@ -182,7 +181,7 @@ public class LaunchingTaskPositionerTests extends ActivityTestsBase { mService.mStackSupervisor.getLaunchingBoundsController().layoutTask(mTask, layout); // Second task will be laid out on top of the first so starting bounds is the same. - final Rect expectedBounds = new Rect(mTask.mBounds); + final Rect expectedBounds = new Rect(mTask.getOverrideBounds()); ActivityRecord activity = null; TaskRecord secondTask = null; @@ -203,14 +202,16 @@ public class LaunchingTaskPositionerTests extends ActivityTestsBase { if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT) || (gravity & (Gravity.BOTTOM | Gravity.RIGHT)) == (Gravity.BOTTOM | Gravity.RIGHT)) { - expectedBounds.offset(-LaunchingTaskPositioner.getHorizontalStep(mStack.mBounds), - 0); + expectedBounds.offset(-LaunchingTaskPositioner.getHorizontalStep( + mStack.getOverrideBounds()), 0); } else if ((gravity & Gravity.TOP) == Gravity.TOP || (gravity & Gravity.BOTTOM) == Gravity.BOTTOM) { - expectedBounds.offset(LaunchingTaskPositioner.getHorizontalStep(mStack.mBounds), 0); + expectedBounds.offset( + LaunchingTaskPositioner.getHorizontalStep(mStack.getOverrideBounds()), 0); } else { - expectedBounds.offset(LaunchingTaskPositioner.getHorizontalStep(mStack.mBounds), - LaunchingTaskPositioner.getVerticalStep(mStack.mBounds)); + expectedBounds.offset( + LaunchingTaskPositioner.getHorizontalStep(mStack.getOverrideBounds()), + LaunchingTaskPositioner.getVerticalStep(mStack.getOverrideBounds())); } assertEquals(mResult, expectedBounds); @@ -228,10 +229,12 @@ public class LaunchingTaskPositionerTests extends ActivityTestsBase { private Rect getDefaultBounds(int gravity) { final Rect bounds = new Rect(); - bounds.set(mStack.mBounds); + bounds.set(mStack.getOverrideBounds()); - final int verticalInset = LaunchingTaskPositioner.getFreeformStartTop(mStack.mBounds); - final int horizontalInset = LaunchingTaskPositioner.getFreeformStartLeft(mStack.mBounds); + final int verticalInset = + LaunchingTaskPositioner.getFreeformStartTop(mStack.getOverrideBounds()); + final int horizontalInset = + LaunchingTaskPositioner.getFreeformStartLeft(mStack.getOverrideBounds()); bounds.inset(horizontalInset, verticalInset); diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java index 5d2bb4d92620..503e1ac4563d 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java @@ -21,7 +21,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import android.app.ActivityManager.TaskDescription; -import android.content.Context; +import android.content.res.Configuration; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.support.test.InstrumentationRegistry; @@ -75,11 +75,23 @@ public class WindowFrameTests extends WindowTestsBase { final Rect mInsetBounds = new Rect(); boolean mFullscreenForTest = true; TaskWithBounds(Rect bounds) { - super(0, mStubStack, 0, sWm, null, 0, false, new TaskDescription(), null); + super(0, mStubStack, 0, sWm, 0, false, new TaskDescription(), null); mBounds = bounds; + setBounds(bounds); } + + @Override + public Rect getBounds() { + return mBounds; + } + + @Override + public void getBounds(Rect out) { + out.set(mBounds); + } + @Override - void getBounds(Rect outBounds) { + public void getOverrideBounds(Rect outBounds) { outBounds.set(mBounds); } @Override @@ -395,7 +407,9 @@ public class WindowFrameTests extends WindowTestsBase { final int xInset = logicalWidth / 10; final int yInset = logicalWidth / 10; final Rect cf = new Rect(xInset, yInset, logicalWidth - xInset, logicalHeight - yInset); - w.mAppToken.onOverrideConfigurationChanged(w.mAppToken.getOverrideConfiguration(), cf); + Configuration config = new Configuration(w.mAppToken.getOverrideConfiguration()); + config.windowConfiguration.setBounds(cf); + w.mAppToken.onOverrideConfigurationChanged(config); pf.set(0, 0, logicalWidth, logicalHeight); task.mFullscreenForTest = true; diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java index 1aafac66bae4..b2334e848d4d 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java @@ -29,11 +29,17 @@ import android.view.WindowManager; import static android.app.AppOpsManager.OP_NONE; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.content.res.Configuration.EMPTY; + import static com.android.server.wm.WindowContainer.POSITION_TOP; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.anyFloat; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import org.mockito.invocation.InvocationOnMock; + /** * A collection of static functions that can be referenced by other test packages to provide access * to WindowManager related test functionality. @@ -64,13 +70,24 @@ public class WindowTestUtils { public static StackWindowController createMockStackWindowContainerController() { StackWindowController controller = mock(StackWindowController.class); controller.mContainer = mock(TestTaskStack.class); + + // many components rely on the {@link StackWindowController#adjustConfigurationForBounds} + // to properly set bounds values in the configuration. We must mimick those actions here. + doAnswer((InvocationOnMock invocationOnMock) -> { + final Configuration config = invocationOnMock.<Configuration>getArgument(7); + final Rect bounds = invocationOnMock.<Rect>getArgument(0); + config.windowConfiguration.setBounds(bounds); + return null; + }).when(controller).adjustConfigurationForBounds(any(), any(), any(), any(), + anyBoolean(), anyBoolean(), anyFloat(), any(), any()); + return controller; } /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */ public static Task createTaskInStack(WindowManagerService service, TaskStack stack, int userId) { - final Task newTask = new Task(sNextTaskId++, stack, userId, service, null, 0, false, + final Task newTask = new Task(sNextTaskId++, stack, userId, service, 0, false, new ActivityManager.TaskDescription(), null); stack.addTask(newTask, POSITION_TOP); return newTask; @@ -98,17 +115,17 @@ public class WindowTestUtils { TestAppWindowToken(DisplayContent dc) { super(dc.mService, new IApplicationToken.Stub() { public String getName() {return null;} - }, false, dc, true /* fillsParent */, null /* bounds */); + }, false, dc, true /* fillsParent */); } TestAppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, int configChanges, boolean launchTaskBehind, - boolean alwaysFocusable, AppWindowContainerController controller, Rect bounds) { + boolean alwaysFocusable, AppWindowContainerController controller) { super(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges, - launchTaskBehind, alwaysFocusable, controller, bounds); + launchTaskBehind, alwaysFocusable, controller); } int getWindowsCount() { @@ -175,10 +192,10 @@ public class WindowTestUtils { private boolean mUseLocalIsAnimating = false; private boolean mIsAnimating = false; - TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, + TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode, boolean supportsPictureInPicture, TaskWindowContainerController controller) { - super(taskId, stack, userId, service, bounds, resizeMode, supportsPictureInPicture, + super(taskId, stack, userId, service, resizeMode, supportsPictureInPicture, new ActivityManager.TaskDescription(), controller); } @@ -247,9 +264,9 @@ public class WindowTestUtils { } @Override - TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds, int resizeMode, + TestTask createTask(int taskId, TaskStack stack, int userId, int resizeMode, boolean supportsPictureInPicture, ActivityManager.TaskDescription taskDescription) { - return new TestTask(taskId, stack, userId, mService, bounds, resizeMode, + return new TestTask(taskId, stack, userId, mService, resizeMode, supportsPictureInPicture, this); } } @@ -269,8 +286,7 @@ public class WindowTestUtils { true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */, false /* launchTaskBehind */, false /* alwaysFocusable */, 0 /* targetSdkVersion */, 0 /* rotationAnimationHint */, - 0 /* inputDispatchingTimeoutNanos */, taskController.mService, - null /* bounds */); + 0 /* inputDispatchingTimeoutNanos */, taskController.mService); mToken = token; } @@ -279,12 +295,12 @@ public class WindowTestUtils { boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, int configChanges, boolean launchTaskBehind, - boolean alwaysFocusable, AppWindowContainerController controller, Rect bounds) { + boolean alwaysFocusable, AppWindowContainerController controller) { return new TestAppWindowToken(service, token, voiceInteraction, dc, inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation, rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable, - controller, bounds); + controller); } AppWindowToken getAppWindowToken(DisplayContent dc) { diff --git a/telephony/java/android/telephony/data/DataProfile.aidl b/telephony/java/android/telephony/data/DataProfile.aidl new file mode 100644 index 000000000000..65fdf9164843 --- /dev/null +++ b/telephony/java/android/telephony/data/DataProfile.aidl @@ -0,0 +1,20 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** @hide */ +package android.telephony.data; + +parcelable DataProfile; diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java new file mode 100644 index 000000000000..41c1430e386f --- /dev/null +++ b/telephony/java/android/telephony/data/DataProfile.java @@ -0,0 +1,280 @@ +/* + * Copyright 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony.data; + +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.internal.telephony.RILConstants; + +/** + * Description of a mobile data profile used for establishing + * data connections. + * + * @hide + */ +@SystemApi +public final class DataProfile implements Parcelable { + + // The types indicating the data profile is used on GSM (3GPP) or CDMA (3GPP2) network. + public static final int TYPE_COMMON = 0; + public static final int TYPE_3GPP = 1; + public static final int TYPE_3GPP2 = 2; + + private final int mProfileId; + + private final String mApn; + + private final String mProtocol; + + private final int mAuthType; + + private final String mUserName; + + private final String mPassword; + + private final int mType; + + private final int mMaxConnsTime; + + private final int mMaxConns; + + private final int mWaitTime; + + private final boolean mEnabled; + + private final int mSupportedApnTypesBitmap; + + private final String mRoamingProtocol; + + private final int mBearerBitmap; + + private final int mMtu; + + private final String mMvnoType; + + private final String mMvnoMatchData; + + private final boolean mModemCognitive; + + public DataProfile(int profileId, String apn, String protocol, int authType, + String userName, String password, int type, int maxConnsTime, int maxConns, + int waitTime, boolean enabled, int supportedApnTypesBitmap, String roamingProtocol, + int bearerBitmap, int mtu, String mvnoType, String mvnoMatchData, + boolean modemCognitive) { + + this.mProfileId = profileId; + this.mApn = apn; + this.mProtocol = protocol; + if (authType == -1) { + authType = TextUtils.isEmpty(userName) ? RILConstants.SETUP_DATA_AUTH_NONE + : RILConstants.SETUP_DATA_AUTH_PAP_CHAP; + } + this.mAuthType = authType; + this.mUserName = userName; + this.mPassword = password; + this.mType = type; + this.mMaxConnsTime = maxConnsTime; + this.mMaxConns = maxConns; + this.mWaitTime = waitTime; + this.mEnabled = enabled; + + this.mSupportedApnTypesBitmap = supportedApnTypesBitmap; + this.mRoamingProtocol = roamingProtocol; + this.mBearerBitmap = bearerBitmap; + this.mMtu = mtu; + this.mMvnoType = mvnoType; + this.mMvnoMatchData = mvnoMatchData; + this.mModemCognitive = modemCognitive; + } + + public DataProfile(Parcel source) { + mProfileId = source.readInt(); + mApn = source.readString(); + mProtocol = source.readString(); + mAuthType = source.readInt(); + mUserName = source.readString(); + mPassword = source.readString(); + mType = source.readInt(); + mMaxConnsTime = source.readInt(); + mMaxConns = source.readInt(); + mWaitTime = source.readInt(); + mEnabled = source.readBoolean(); + mSupportedApnTypesBitmap = source.readInt(); + mRoamingProtocol = source.readString(); + mBearerBitmap = source.readInt(); + mMtu = source.readInt(); + mMvnoType = source.readString(); + mMvnoMatchData = source.readString(); + mModemCognitive = source.readBoolean(); + } + + /** + * @return Id of the data profile. + */ + public int getProfileId() { return mProfileId; } + + /** + * @return The APN to establish data connection. + */ + public String getApn() { return mApn; } + + /** + * @return The connection protocol, should be one of the PDP_type values in TS 27.007 section + * 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP". + */ + public String getProtocol() { return mProtocol; } + + /** + * @return The authentication protocol used for this PDP context + * (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3) + */ + public int getAuthType() { return mAuthType; } + + /** + * @return The username for APN. Can be null. + */ + public String getUserName() { return mUserName; } + + /** + * @return The password for APN. Can be null. + */ + public String getPassword() { return mPassword; } + + /** + * @return The profile type. Could be one of TYPE_COMMON, TYPE_3GPP, or TYPE_3GPP2. + */ + public int getType() { return mType; } + + /** + * @return The period in seconds to limit the maximum connections. + */ + public int getMaxConnsTime() { return mMaxConnsTime; } + + /** + * @return The maximum connections allowed. + */ + public int getMaxConns() { return mMaxConns; } + + /** + * @return The required wait time in seconds after a successful UE initiated disconnect of a + * given PDN connection before the device can send a new PDN connection request for that given + * PDN. + */ + public int getWaitTime() { return mWaitTime; } + + /** + * @return True if the profile is enabled. + */ + public boolean isEnabled() { return mEnabled; } + + /** + * @return The supported APN types bitmap. See RIL_ApnTypes for the value of each bit. + */ + public int getSupportedApnTypesBitmap() { return mSupportedApnTypesBitmap; } + + /** + * @return The connection protocol on roaming network, should be one of the PDP_type values in + * TS 27.007 section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP". + */ + public String getRoamingProtocol() { return mRoamingProtocol; } + + /** + * @return The bearer bitmap. See RIL_RadioAccessFamily for the value of each bit. + */ + public int getBearerBitmap() { return mBearerBitmap; } + + /** + * @return The maximum transmission unit (MTU) size in bytes. + */ + public int getMtu() { return mMtu; } + + /** + * @return The MVNO type: possible values are "imsi", "gid", "spn". + */ + public String getMvnoType() { return mMvnoType; } + + /** + * @return The MVNO match data. For example, + * SPN: A MOBILE, BEN NL, ... + * IMSI: 302720x94, 2060188, ... + * GID: 4E, 33, ... + */ + public String getMvnoMatchData() { return mMvnoMatchData; } + + /** + * @return True if the data profile was sent to the modem through setDataProfile earlier. + */ + public boolean isModemCognitive() { return mModemCognitive; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + return "DataProfile=" + mProfileId + "/" + mApn + "/" + mProtocol + "/" + mAuthType + + "/" + mUserName + "/" + mPassword + "/" + mType + "/" + mMaxConnsTime + + "/" + mMaxConns + "/" + mWaitTime + "/" + mEnabled + "/" + + mSupportedApnTypesBitmap + "/" + mRoamingProtocol + "/" + mBearerBitmap + "/" + + mMtu + "/" + mMvnoType + "/" + mMvnoMatchData + "/" + mModemCognitive; + } + + @Override + public boolean equals(Object o) { + if (o instanceof DataProfile == false) return false; + return (o == this || toString().equals(o.toString())); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mProfileId); + dest.writeString(mApn); + dest.writeString(mProtocol); + dest.writeInt(mAuthType); + dest.writeString(mUserName); + dest.writeString(mPassword); + dest.writeInt(mType); + dest.writeInt(mMaxConnsTime); + dest.writeInt(mMaxConns); + dest.writeInt(mWaitTime); + dest.writeBoolean(mEnabled); + dest.writeInt(mSupportedApnTypesBitmap); + dest.writeString(mRoamingProtocol); + dest.writeInt(mBearerBitmap); + dest.writeInt(mMtu); + dest.writeString(mMvnoType); + dest.writeString(mMvnoMatchData); + dest.writeBoolean(mModemCognitive); + } + + public static final Parcelable.Creator<DataProfile> CREATOR = + new Parcelable.Creator<DataProfile>() { + @Override + public DataProfile createFromParcel(Parcel source) { + return new DataProfile(source); + } + + @Override + public DataProfile[] newArray(int size) { + return new DataProfile[size]; + } + }; +} diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index cca12947d26e..423d0285e96f 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -18,6 +18,10 @@ using namespace std; namespace android { namespace stats_log_api_gen { +const int PULL_ATOM_START_ID = 1000; + +int maxPushedAtomId = 2; + using android::os::statsd::Atom; // TODO: Support WorkSources @@ -195,12 +199,18 @@ write_stats_log_header(FILE* out, const Atoms& atoms) fprintf(out, " */\n"); char const* const comma = (i == atoms.decls.size() - 1) ? "" : ","; fprintf(out, " %s = %d%s\n", constant.c_str(), atom->code, comma); + if (atom->code < PULL_ATOM_START_ID && atom->code > maxPushedAtomId) { + maxPushedAtomId = atom->code; + } i++; } fprintf(out, "\n"); fprintf(out, "};\n"); fprintf(out, "\n"); + fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", + maxPushedAtomId); + // Print write methods fprintf(out, "//\n"); fprintf(out, "// Write methods\n"); |