diff options
119 files changed, 2761 insertions, 1429 deletions
diff --git a/Android.mk b/Android.mk index 1ed8a2506600..a7cb362b677e 100644 --- a/Android.mk +++ b/Android.mk @@ -218,6 +218,7 @@ LOCAL_SRC_FILES += \ core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \ core/java/android/hardware/location/IContextHubCallback.aidl \ core/java/android/hardware/location/IContextHubService.aidl \ + core/java/android/hardware/location/IContextHubTransactionCallback.aidl \ core/java/android/hardware/radio/IRadioService.aidl \ core/java/android/hardware/radio/ITuner.aidl \ core/java/android/hardware/radio/ITunerCallback.aidl \ diff --git a/api/current.txt b/api/current.txt index 5a947ddcddf9..7074de5790f5 100644 --- a/api/current.txt +++ b/api/current.txt @@ -484,6 +484,7 @@ package android { field public static final int detailSocialSummary = 16843428; // 0x10102a4 field public static final int detailsElementBackground = 16843598; // 0x101034e field public static final int dial = 16843010; // 0x1010102 + field public static final int dialogCornerRadius = 16844145; // 0x1010571 field public static final int dialogIcon = 16843252; // 0x10101f4 field public static final int dialogLayout = 16843255; // 0x10101f7 field public static final int dialogMessage = 16843251; // 0x10101f3 @@ -39924,8 +39925,8 @@ package android.telephony { field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int"; field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool"; field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool"; - field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array"; field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool"; + field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array"; field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool"; field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool"; field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int"; diff --git a/api/system-current.txt b/api/system-current.txt index c0d106f5b615..af15a0042c1f 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -88,6 +88,7 @@ package android { field public static final java.lang.String CAPTURE_SECURE_VIDEO_OUTPUT = "android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"; field public static final java.lang.String CAPTURE_TV_INPUT = "android.permission.CAPTURE_TV_INPUT"; field public static final java.lang.String CAPTURE_VIDEO_OUTPUT = "android.permission.CAPTURE_VIDEO_OUTPUT"; + field public static final java.lang.String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE"; field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE"; field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION"; field public static final java.lang.String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"; @@ -616,6 +617,7 @@ package android { field public static final int detailSocialSummary = 16843428; // 0x10102a4 field public static final int detailsElementBackground = 16843598; // 0x101034e field public static final int dial = 16843010; // 0x1010102 + field public static final int dialogCornerRadius = 16844145; // 0x1010571 field public static final int dialogIcon = 16843252; // 0x10101f4 field public static final int dialogLayout = 16843255; // 0x10101f7 field public static final int dialogMessage = 16843251; // 0x10101f3 @@ -7676,6 +7678,7 @@ package android.app.usage { method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long); method public android.app.usage.UsageEvents queryEvents(long, long); method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long); + method public void setAppStandbyBucket(java.lang.String, int); method public void whitelistAppTemporarily(java.lang.String, long, android.os.UserHandle); field public static final int INTERVAL_BEST = 4; // 0x4 field public static final int INTERVAL_DAILY = 0; // 0x0 @@ -10234,6 +10237,7 @@ package android.content { field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY"; field public static final java.lang.String EXTRA_QUICK_VIEW_FEATURES = "android.intent.extra.QUICK_VIEW_FEATURES"; field public static final java.lang.String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE"; + field public static final java.lang.String EXTRA_REASON = "android.intent.extra.REASON"; field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER"; field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME"; field public static final java.lang.String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK"; @@ -43440,8 +43444,8 @@ package android.telephony { field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int"; field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool"; field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool"; - field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array"; field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool"; + field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array"; field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool"; field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool"; field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int"; diff --git a/api/test-current.txt b/api/test-current.txt index 9c0bc92f2566..0bc0cd9efd7f 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -484,6 +484,7 @@ package android { field public static final int detailSocialSummary = 16843428; // 0x10102a4 field public static final int detailsElementBackground = 16843598; // 0x101034e field public static final int dial = 16843010; // 0x1010102 + field public static final int dialogCornerRadius = 16844145; // 0x1010571 field public static final int dialogIcon = 16843252; // 0x10101f4 field public static final int dialogLayout = 16843255; // 0x10101f7 field public static final int dialogMessage = 16843251; // 0x10101f3 @@ -3873,6 +3874,7 @@ package android.app { method public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException; method public deprecated void restartPackage(java.lang.String); method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException; + method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect) throws java.lang.SecurityException; method public static void setVrThread(int); method public void setWatchHeapLimit(long); method public static boolean supportsMultiWindow(android.content.Context); @@ -3886,6 +3888,8 @@ package android.app { field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1 field public static final int RECENT_IGNORE_UNAVAILABLE = 2; // 0x2 field public static final int RECENT_WITH_EXCLUDED = 1; // 0x1 + field public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1; // 0x1 + field public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0; // 0x0 } public static class ActivityManager.AppTask { @@ -40318,8 +40322,8 @@ package android.telephony { field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int"; field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool"; field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool"; - field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array"; field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool"; + field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array"; field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool"; field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool"; field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int"; diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index 54ade3563851..c5805fbb2eca 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -29,7 +29,8 @@ statsd_common_src := \ src/config/ConfigKey.cpp \ src/config/ConfigListener.cpp \ src/config/ConfigManager.cpp \ - src/external/KernelWakelockPuller.cpp \ + src/external/StatsCompanionServicePuller.cpp \ + src/external/ResourcePowerManagerPuller.cpp \ src/external/StatsPullerManager.cpp \ src/logd/LogEvent.cpp \ src/logd/LogListener.cpp \ @@ -71,7 +72,15 @@ statsd_common_shared_libraries := \ libutils \ libservices \ libandroidfw \ - libprotoutil + libprotoutil \ + libstatslog \ + libhardware \ + libhardware_legacy \ + libhidlbase \ + libhidltransport \ + libhwbinder \ + android.hardware.power@1.0 \ + android.hardware.power@1.1 # ========= # statsd diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index edb1a0f94e2b..11c5de172721 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -373,12 +373,15 @@ status_t StatsService::cmd_print_uid_map(FILE* out) { status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) { int s = atoi(args[1].c_str()); - auto stats = m_stats_puller_manager.Pull(s, time(nullptr)); - for (const auto& it : stats) { - fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str()); + vector<shared_ptr<LogEvent> > stats; + if (mStatsPullerManager.Pull(s, &stats)) { + for (const auto& it : stats) { + fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str()); + } + fprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size()); + return NO_ERROR; } - fprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size()); - return NO_ERROR; + return UNKNOWN_ERROR; } Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version, @@ -440,7 +443,7 @@ Status StatsService::informPollAlarmFired() { "Only system uid can call informPollAlarmFired"); } - m_stats_puller_manager.OnAlarmFired(); + mStatsPullerManager.OnAlarmFired(); if (DEBUG) ALOGD("StatsService::informPollAlarmFired succeeded"); diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 3930d319ce8d..1d7e5a618cc9 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -157,7 +157,7 @@ private: /** * Fetches external metrics. */ - StatsPullerManager& m_stats_puller_manager = StatsPullerManager::GetInstance(); + StatsPullerManager& mStatsPullerManager = StatsPullerManager::GetInstance(); /** * Tracks the configurations that have been passed to statsd. diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp index 88127194753f..890f44b689d6 100644 --- a/cmds/statsd/src/config/ConfigManager.cpp +++ b/cmds/statsd/src/config/ConfigManager.cpp @@ -139,7 +139,7 @@ static StatsdConfig build_fake_config() { int UID_PROCESS_STATE_TAG_ID = 27; int UID_PROCESS_STATE_UID_KEY = 1; - int KERNEL_WAKELOCK_TAG_ID = 41; + int KERNEL_WAKELOCK_TAG_ID = 1004; int KERNEL_WAKELOCK_NAME_KEY = 4; // Count Screen ON events. @@ -301,6 +301,12 @@ static StatsdConfig build_fake_config() { keyValueMatcher->mutable_key_matcher()->set_key(WAKE_LOCK_STATE_KEY); keyValueMatcher->set_eq_int(WAKE_LOCK_RELEASE_VALUE); + // pulled events + eventMatcher = config.add_log_entry_matcher(); + eventMatcher->set_name("KERNEL_WAKELOCK"); + simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher(); + simpleLogEntryMatcher->set_tag(KERNEL_WAKELOCK_TAG_ID); + // Conditions............. Condition* condition = config.add_condition(); condition->set_name("SCREEN_IS_ON"); diff --git a/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp b/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp new file mode 100644 index 000000000000..38953f182586 --- /dev/null +++ b/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp @@ -0,0 +1,165 @@ +/* + * 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. + */ + +#define DEBUG true // STOPSHIP if true +#include "Log.h" + +#include <android/hardware/power/1.0/IPower.h> +#include <android/hardware/power/1.1/IPower.h> +#include <fcntl.h> +#include <hardware/power.h> +#include <hardware_legacy/power.h> +#include <inttypes.h> +#include <semaphore.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include "external/ResourcePowerManagerPuller.h" +#include "external/StatsPuller.h" + +#include "logd/LogEvent.h" + +using android::hardware::hidl_vec; +using android::hardware::power::V1_0::IPower; +using android::hardware::power::V1_0::PowerStatePlatformSleepState; +using android::hardware::power::V1_0::PowerStateVoter; +using android::hardware::power::V1_0::Status; +using android::hardware::power::V1_1::PowerStateSubsystem; +using android::hardware::power::V1_1::PowerStateSubsystemSleepState; +using android::hardware::Return; +using android::hardware::Void; + +using std::make_shared; +using std::shared_ptr; + +namespace android { +namespace os { +namespace statsd { + +sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr; +sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr; +std::mutex gPowerHalMutex; +bool gPowerHalExists = true; + +static const int power_state_platform_sleep_state_tag = 1011; +static const int power_state_voter_tag = 1012; +static const int power_state_subsystem_state_tag = 1013; + +bool getPowerHal() { + if (gPowerHalExists && gPowerHalV1_0 == nullptr) { + gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService(); + if (gPowerHalV1_0 != nullptr) { + gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0); + ALOGI("Loaded power HAL service"); + } else { + ALOGW("Couldn't load power HAL service"); + gPowerHalExists = false; + } + } + return gPowerHalV1_0 != nullptr; +} + +bool ResourcePowerManagerPuller::Pull(const int tagId, vector<shared_ptr<LogEvent>>* data) { + std::lock_guard<std::mutex> lock(gPowerHalMutex); + + if (!getPowerHal()) { + ALOGE("Power Hal not loaded"); + return false; + } + + data->clear(); + Return<void> ret = gPowerHalV1_0->getPlatformLowPowerStats( + [&data](hidl_vec<PowerStatePlatformSleepState> states, Status status) { + + if (status != Status::SUCCESS) return; + + for (size_t i = 0; i < states.size(); i++) { + const PowerStatePlatformSleepState& state = states[i]; + + auto statePtr = make_shared<LogEvent>(power_state_platform_sleep_state_tag); + auto elemList = statePtr->GetAndroidLogEventList(); + *elemList << state.name; + *elemList << state.residencyInMsecSinceBoot; + *elemList << state.totalTransitions; + *elemList << state.supportedOnlyInSuspend; + data->push_back(statePtr); + + VLOG("powerstate: %s, %lld, %lld, %d", state.name.c_str(), + (long long)state.residencyInMsecSinceBoot, + (long long)state.totalTransitions, state.supportedOnlyInSuspend ? 1 : 0); + for (auto voter : state.voters) { + auto voterPtr = make_shared<LogEvent>(power_state_voter_tag); + auto elemList = voterPtr->GetAndroidLogEventList(); + *elemList << state.name; + *elemList << voter.name; + *elemList << voter.totalTimeInMsecVotedForSinceBoot; + *elemList << voter.totalNumberOfTimesVotedSinceBoot; + data->push_back(voterPtr); + VLOG("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(), + voter.name.c_str(), (long long)voter.totalTimeInMsecVotedForSinceBoot, + (long long)voter.totalNumberOfTimesVotedSinceBoot); + } + } + }); + if (!ret.isOk()) { + ALOGE("getLowPowerStats() failed: power HAL service not available"); + gPowerHalV1_0 = nullptr; + return false; + } + + // Trying to cast to IPower 1.1, this will succeed only for devices supporting 1.1 + sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1 = + android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0); + if (gPowerHal_1_1 != nullptr) { + ret = gPowerHal_1_1->getSubsystemLowPowerStats( + [&data](hidl_vec<PowerStateSubsystem> subsystems, Status status) { + + if (status != Status::SUCCESS) return; + + if (subsystems.size() > 0) { + for (size_t i = 0; i < subsystems.size(); i++) { + const PowerStateSubsystem& subsystem = subsystems[i]; + for (size_t j = 0; j < subsystem.states.size(); j++) { + const PowerStateSubsystemSleepState& state = subsystem.states[j]; + auto subsystemStatePtr = + make_shared<LogEvent>(power_state_subsystem_state_tag); + auto elemList = subsystemStatePtr->GetAndroidLogEventList(); + *elemList << subsystem.name; + *elemList << state.name; + *elemList << state.residencyInMsecSinceBoot; + *elemList << state.totalTransitions; + *elemList << state.lastEntryTimestampMs; + *elemList << state.supportedOnlyInSuspend; + data->push_back(subsystemStatePtr); + VLOG("subsystemstate: %s, %s, %lld, %lld, %lld", + subsystem.name.c_str(), state.name.c_str(), + (long long)state.residencyInMsecSinceBoot, + (long long)state.totalTransitions, + (long long)state.lastEntryTimestampMs); + } + } + } + }); + } + return true; +} + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/external/KernelWakelockPuller.h b/cmds/statsd/src/external/ResourcePowerManagerPuller.h index cc8059d80601..c396c12de0d7 100644 --- a/cmds/statsd/src/external/KernelWakelockPuller.h +++ b/cmds/statsd/src/external/ResourcePowerManagerPuller.h @@ -23,12 +23,12 @@ namespace android { namespace os { namespace statsd { -class KernelWakelockPuller : public StatsPuller { +/** + * Reads hal for sleep states + */ +class ResourcePowerManagerPuller : public StatsPuller { public: - // a number of stats need to be pulled from StatsCompanionService - // - const static int PULL_CODE_KERNEL_WAKELOCKS; - vector<StatsLogEventWrapper> Pull() override; + bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) override; }; } // namespace statsd diff --git a/cmds/statsd/src/external/KernelWakelockPuller.cpp b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp index 00259a83d3db..8e9639971679 100644 --- a/cmds/statsd/src/external/KernelWakelockPuller.cpp +++ b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp @@ -20,37 +20,49 @@ #include <android/os/IStatsCompanionService.h> #include <binder/IPCThreadState.h> #include <private/android_filesystem_config.h> -#include "KernelWakelockPuller.h" +#include "StatsCompanionServicePuller.h" #include "StatsService.h" using namespace android; using namespace android::base; using namespace android::binder; using namespace android::os; -using namespace std; +using std::make_shared; +using std::shared_ptr; +using std::vector; namespace android { namespace os { namespace statsd { -const int KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS = 1004; +const int kLogMsgHeaderSize = 28; // The reading and parsing are implemented in Java. It is not difficult to port over. But for now // let StatsCompanionService handle that and send the data back. -vector<StatsLogEventWrapper> KernelWakelockPuller::Pull() { +bool StatsCompanionServicePuller::Pull(const int tagId, vector<shared_ptr<LogEvent> >* data) { sp<IStatsCompanionService> statsCompanion = StatsService::getStatsCompanionService(); vector<StatsLogEventWrapper> returned_value; if (statsCompanion != NULL) { - Status status = statsCompanion->pullData(KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS, - &returned_value); + Status status = statsCompanion->pullData(tagId, &returned_value); if (!status.isOk()) { ALOGW("error pulling kernel wakelock"); + return false; + } + data->clear(); + for (const StatsLogEventWrapper& it : returned_value) { + log_msg tmp; + tmp.entry_v1.len = it.bytes.size(); + // Manually set the header size to 28 bytes to match the pushed log events. + tmp.entry.hdr_size = kLogMsgHeaderSize; + // And set the received bytes starting after the 28 bytes reserved for header. + std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + kLogMsgHeaderSize); + data->push_back(make_shared<LogEvent>(tmp)); } ALOGD("KernelWakelockPuller::pull succeeded!"); - return returned_value; + return true; } else { ALOGW("statsCompanion not found!"); - return returned_value; + return false; } } diff --git a/cmds/statsd/src/external/StatsCompanionServicePuller.h b/cmds/statsd/src/external/StatsCompanionServicePuller.h new file mode 100644 index 000000000000..3ff2274f1d65 --- /dev/null +++ b/cmds/statsd/src/external/StatsCompanionServicePuller.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#pragma once + +#include <utils/String16.h> +#include "StatsPuller.h" + +namespace android { +namespace os { +namespace statsd { + +class StatsCompanionServicePuller : public StatsPuller { +public: + bool Pull(const int tagId, vector<std::shared_ptr<LogEvent> >* data) override; +}; + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h index 774e7f093087..940ad9c788ef 100644 --- a/cmds/statsd/src/external/StatsPuller.h +++ b/cmds/statsd/src/external/StatsPuller.h @@ -19,6 +19,7 @@ #include <android/os/StatsLogEventWrapper.h> #include <utils/String16.h> #include <vector> +#include "logd/LogEvent.h" using android::os::StatsLogEventWrapper; using std::vector; @@ -31,7 +32,7 @@ class StatsPuller { public: virtual ~StatsPuller(){}; - virtual vector<StatsLogEventWrapper> Pull() = 0; + virtual bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) = 0; }; } // namespace statsd diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index f45cb1ccaa74..003b5c41a507 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -21,89 +21,69 @@ #include <cutils/log.h> #include <algorithm> #include <climits> -#include "KernelWakelockPuller.h" +#include "ResourcePowerManagerPuller.h" +#include "StatsCompanionServicePuller.h" #include "StatsPullerManager.h" #include "StatsService.h" #include "logd/LogEvent.h" +#include "statslog.h" #include <iostream> +using std::map; using std::string; using std::vector; +using std::make_shared; +using std::shared_ptr; namespace android { namespace os { namespace statsd { -const int kernel_wakelock = 1; -const unordered_map<string, int> StatsPullerManager::kPullCodes({{"KERNEL_WAKELOCK", - kernel_wakelock}}); - StatsPullerManager::StatsPullerManager() : mCurrentPullingInterval(LONG_MAX), mPullStartTimeMs(get_pull_start_time_ms()) { - mPullers.insert({kernel_wakelock, make_unique<KernelWakelockPuller>()}); - mStatsCompanionService = get_stats_companion_service(); - if (mStatsCompanionService != nullptr) { - mStatsCompanionService->cancelPullingAlarms(); - } else { - VLOG("Failed to update pulling interval"); - } + shared_ptr<StatsPuller> statsCompanionServicePuller = make_shared<StatsCompanionServicePuller>(); + shared_ptr <StatsPuller> + resourcePowerManagerPuller = make_shared<ResourcePowerManagerPuller>(); + + mPullers.insert({android::util::KERNEL_WAKELOCK_PULLED, + statsCompanionServicePuller}); + mPullers.insert({android::util::WIFI_BYTES_TRANSFERRED, + statsCompanionServicePuller}); + mPullers.insert({android::util::MOBILE_BYTES_TRANSFERRED, + statsCompanionServicePuller}); + mPullers.insert({android::util::WIFI_BYTES_TRANSFERRED_BY_FG_BG, + statsCompanionServicePuller}); + mPullers.insert({android::util::MOBILE_BYTES_TRANSFERRED_BY_FG_BG, + statsCompanionServicePuller}); + mPullers.insert({android::util::POWER_STATE_PLATFORM_SLEEP_STATE_PULLED, + resourcePowerManagerPuller}); + mPullers.insert({android::util::POWER_STATE_VOTER_PULLED, + resourcePowerManagerPuller}); + mPullers.insert({android::util::POWER_STATE_SUBSYSTEM_SLEEP_STATE_PULLED, + resourcePowerManagerPuller}); + + mStatsCompanionService = StatsService::getStatsCompanionService(); } -static const int log_msg_header_size = 28; - -vector<shared_ptr<LogEvent>> StatsPullerManager::Pull(int pullCode, uint64_t timestampSec) { - if (DEBUG) ALOGD("Initiating pulling %d", pullCode); - - vector<shared_ptr<LogEvent>> ret; - auto itr = mPullers.find(pullCode); - if (itr != mPullers.end()) { - vector<StatsLogEventWrapper> outputs = itr->second->Pull(); - for (const StatsLogEventWrapper& it : outputs) { - log_msg tmp; - tmp.entry_v1.sec = timestampSec; - tmp.entry_v1.nsec = 0; - tmp.entry_v1.len = it.bytes.size(); - // Manually set the header size to 28 bytes to match the pushed log events. - tmp.entry.hdr_size = log_msg_header_size; - // And set the received bytes starting after the 28 bytes reserved for header. - copy(it.bytes.begin(), it.bytes.end(), tmp.buf + log_msg_header_size); - shared_ptr<LogEvent> evt = make_shared<LogEvent>(tmp); - ret.push_back(evt); - } - return ret; - } else { - ALOGD("Unknown pull code %d", pullCode); - return ret; // Return early since we don't know what to pull. - } -} + bool StatsPullerManager::Pull(int tagId, vector<shared_ptr<LogEvent>>* data) { + if (DEBUG) ALOGD("Initiating pulling %d", tagId); -sp<IStatsCompanionService> StatsPullerManager::get_stats_companion_service() { - sp<IStatsCompanionService> statsCompanion = nullptr; - // Get statscompanion service from service manager - const sp<IServiceManager> sm(defaultServiceManager()); - if (sm != nullptr) { - const String16 name("statscompanion"); - statsCompanion = interface_cast<IStatsCompanionService>(sm->checkService(name)); - if (statsCompanion == nullptr) { - ALOGW("statscompanion service unavailable!"); - return nullptr; + if (mPullers.find(tagId) != mPullers.end()) { + return mPullers.find(tagId)->second->Pull(tagId, data); + } else { + ALOGD("Unknown tagId %d", tagId); + return false; // Return early since we don't know what to pull. + } } - } - return statsCompanion; -} StatsPullerManager& StatsPullerManager::GetInstance() { static StatsPullerManager instance; return instance; } -int StatsPullerManager::GetPullCode(string atomName) { - if (kPullCodes.find(atomName) != kPullCodes.end()) { - return kPullCodes.find(atomName)->second; - } else { - return -1; - } +bool StatsPullerManager::PullerForMatcherExists(int tagId) { + return mPullers.find(tagId) != mPullers.end(); } long StatsPullerManager::get_pull_start_time_ms() { @@ -111,9 +91,9 @@ long StatsPullerManager::get_pull_start_time_ms() { return time(nullptr) * 1000; } -void StatsPullerManager::RegisterReceiver(int pullCode, sp<PullDataReceiver> receiver, long intervalMs) { +void StatsPullerManager::RegisterReceiver(int tagId, sp<PullDataReceiver> receiver, long intervalMs) { AutoMutex _l(mReceiversLock); - vector<ReceiverInfo>& receivers = mReceivers[pullCode]; + vector<ReceiverInfo>& receivers = mReceivers[tagId]; for (auto it = receivers.begin(); it != receivers.end(); it++) { if (it->receiver.get() == receiver.get()) { VLOG("Receiver already registered of %d", (int)receivers.size()); @@ -135,20 +115,20 @@ void StatsPullerManager::RegisterReceiver(int pullCode, sp<PullDataReceiver> rec VLOG("Failed to update pulling interval"); } } - VLOG("Puller for pullcode %d registered of %d", pullCode, (int)receivers.size()); + VLOG("Puller for tagId %d registered of %d", tagId, (int)receivers.size()); } -void StatsPullerManager::UnRegisterReceiver(int pullCode, sp<PullDataReceiver> receiver) { +void StatsPullerManager::UnRegisterReceiver(int tagId, sp<PullDataReceiver> receiver) { AutoMutex _l(mReceiversLock); - if (mReceivers.find(pullCode) == mReceivers.end()) { - VLOG("Unknown pull code or no receivers: %d", pullCode); + if (mReceivers.find(tagId) == mReceivers.end()) { + VLOG("Unknown pull code or no receivers: %d", tagId); return; } - auto& receivers = mReceivers.find(pullCode)->second; + auto& receivers = mReceivers.find(tagId)->second; for (auto it = receivers.begin(); it != receivers.end(); it++) { if (receiver.get() == it->receiver.get()) { receivers.erase(it); - VLOG("Puller for pullcode %d unregistered of %d", pullCode, (int)receivers.size()); + VLOG("Puller for tagId %d unregistered of %d", tagId, (int)receivers.size()); return; } } @@ -176,10 +156,12 @@ void StatsPullerManager::OnAlarmFired() { } for (const auto& pullInfo : needToPull) { - const vector<shared_ptr<LogEvent>>& data = Pull(pullInfo.first, currentTimeMs/1000); - for(const auto& receiverInfo : pullInfo.second) { - receiverInfo->receiver->onDataPulled(data); - receiverInfo->timeInfo.second = currentTimeMs; + vector<shared_ptr<LogEvent>> data; + if (Pull(pullInfo.first, &data)) { + for (const auto& receiverInfo : pullInfo.second) { + receiverInfo->receiver->onDataPulled(data); + receiverInfo->timeInfo.second = currentTimeMs; + } } } } diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h index e599b6904ed4..67580d68c6f1 100644 --- a/cmds/statsd/src/external/StatsPullerManager.h +++ b/cmds/statsd/src/external/StatsPullerManager.h @@ -37,44 +37,42 @@ class StatsPullerManager : public virtual RefBase { public: static StatsPullerManager& GetInstance(); - void RegisterReceiver(int pullCode, sp<PullDataReceiver> receiver, long intervalMs); + void RegisterReceiver(int tagId, sp<PullDataReceiver> receiver, long intervalMs); - void UnRegisterReceiver(int pullCode, sp<PullDataReceiver> receiver); + void UnRegisterReceiver(int tagId, sp<PullDataReceiver> receiver); - // We return a vector of shared_ptr since LogEvent's copy constructor is not available. - vector<std::shared_ptr<LogEvent>> Pull(const int pullCode, const uint64_t timestampSec); - - // Translate metric name to pullCodes. - // return -1 if no valid pullCode is found - int GetPullCode(std::string metricName); + // Verify if we know how to pull for this matcher + bool PullerForMatcherExists(int tagId); void OnAlarmFired(); + bool Pull(const int pullCode, vector<std::shared_ptr<LogEvent>>* data); + private: StatsPullerManager(); + // use this to update alarm sp<IStatsCompanionService> mStatsCompanionService = nullptr; sp<IStatsCompanionService> get_stats_companion_service(); - std::unordered_map<int, std::unique_ptr<StatsPuller>> mPullers; - + // mapping from simple matcher tagId to puller + std::map<int, std::shared_ptr<StatsPuller>> mPullers; - - // internal state of a bucket. typedef struct { // pull_interval_sec : last_pull_time_sec std::pair<uint64_t, uint64_t> timeInfo; sp<PullDataReceiver> receiver; } ReceiverInfo; + // mapping from simple matcher tagId to receivers std::map<int, std::vector<ReceiverInfo>> mReceivers; Mutex mReceiversLock; long mCurrentPullingInterval; - // for value metrics, it is important for the buckets to be aligned to multiple of smallest + // for pulled metrics, it is important for the buckets to be aligned to multiple of smallest // bucket size. All pulled metrics start pulling based on this time, so that they can be // correctly attributed to the correct buckets. Pulled data attach a timestamp which is the // request time. @@ -83,10 +81,8 @@ private: long get_pull_start_time_ms(); LogEvent parse_pulled_data(String16 data); - - static const std::unordered_map<std::string, int> kPullCodes; }; } // namespace statsd } // namespace os -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index 26a82cbf84bc..8220fcb95a8c 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -24,6 +24,7 @@ namespace android { namespace os { namespace statsd { +using namespace android::util; using std::ostringstream; using std::string; using android::util::ProtoOutputStream; @@ -207,20 +208,20 @@ string LogEvent::ToString() const { } void LogEvent::ToProto(ProtoOutputStream& proto) const { - long long atomToken = proto.start(TYPE_MESSAGE + mTagId); + long long atomToken = proto.start(FIELD_TYPE_MESSAGE | mTagId); const size_t N = mElements.size(); for (size_t i=0; i<N; i++) { const int key = i + 1; const android_log_list_element& elem = mElements[i]; if (elem.type == EVENT_TYPE_INT) { - proto.write(TYPE_INT32 + key, elem.data.int32); + proto.write(FIELD_TYPE_INT32 | key, elem.data.int32); } else if (elem.type == EVENT_TYPE_LONG) { - proto.write(TYPE_INT64 + key, (long long)elem.data.int64); + proto.write(FIELD_TYPE_INT64 | key, (long long)elem.data.int64); } else if (elem.type == EVENT_TYPE_FLOAT) { - proto.write(TYPE_FLOAT + key, elem.data.float32); + proto.write(FIELD_TYPE_FLOAT | key, elem.data.float32); } else if (elem.type == EVENT_TYPE_STRING) { - proto.write(TYPE_STRING + key, elem.data.string); + proto.write(FIELD_TYPE_STRING | key, elem.data.string); } } proto.end(atomToken); diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp index 9f8558d59baf..71cb7717d2d7 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.cpp +++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp @@ -24,6 +24,8 @@ #include <limits.h> #include <stdlib.h> +using namespace android::util; +using android::util::ProtoOutputStream; using std::map; using std::string; using std::unordered_map; @@ -33,6 +35,27 @@ namespace android { namespace os { namespace statsd { +// for StatsLogReport +const int FIELD_ID_METRIC_ID = 1; +const int FIELD_ID_START_REPORT_NANOS = 2; +const int FIELD_ID_END_REPORT_NANOS = 3; +const int FIELD_ID_COUNT_METRICS = 5; +// for CountMetricDataWrapper +const int FIELD_ID_DATA = 1; +// for CountMetricData +const int FIELD_ID_DIMENSION = 1; +const int FIELD_ID_BUCKET_INFO = 2; +// for KeyValuePair +const int FIELD_ID_KEY = 1; +const int FIELD_ID_VALUE_STR = 2; +const int FIELD_ID_VALUE_INT = 3; +const int FIELD_ID_VALUE_BOOL = 4; +const int FIELD_ID_VALUE_FLOAT = 5; +// for CountBucketInfo +const int FIELD_ID_START_BUCKET_NANOS = 1; +const int FIELD_ID_END_BUCKET_NANOS = 2; +const int FIELD_ID_COUNT = 3; + // TODO: add back AnomalyTracker. CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex, const sp<ConditionWizard>& wizard) @@ -66,6 +89,8 @@ CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int co mConditionSliced = true; } + startNewProtoOutputStream(mStartTimeNs); + VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(), (long long)mBucketSizeNs, (long long)mStartTimeNs); } @@ -74,23 +99,14 @@ CountMetricProducer::~CountMetricProducer() { VLOG("~CountMetricProducer() called"); } -void CountMetricProducer::finish() { - // TODO: write the StatsLogReport to dropbox using - // DropboxWriter. +void CountMetricProducer::startNewProtoOutputStream(long long startTime) { + mProto = std::make_unique<ProtoOutputStream>(); + mProto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, mMetric.metric_id()); + mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime); + mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS); } -static void addSlicedCounterToReport(StatsLogReport_CountMetricDataWrapper& wrapper, - const vector<KeyValuePair>& key, - const vector<CountBucketInfo>& buckets) { - CountMetricData* data = wrapper.add_data(); - for (const auto& kv : key) { - data->add_dimension()->CopyFrom(kv); - } - for (const auto& bucket : buckets) { - data->add_bucket_info()->CopyFrom(bucket); - VLOG("\t bucket [%lld - %lld] count: %lld", bucket.start_bucket_nanos(), - bucket.end_bucket_nanos(), bucket.count()); - } +void CountMetricProducer::finish() { } void CountMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) { @@ -98,33 +114,81 @@ void CountMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) { } StatsLogReport CountMetricProducer::onDumpReport() { - VLOG("metric %lld dump report now...", mMetric.metric_id()); - - StatsLogReport report; - report.set_metric_id(mMetric.metric_id()); - report.set_start_report_nanos(mStartTimeNs); + long long endTime = time(nullptr) * NANO_SECONDS_IN_A_SECOND; // Dump current bucket if it's stale. // If current bucket is still on-going, don't force dump current bucket. // In finish(), We can force dump current bucket. - flushCounterIfNeeded(time(nullptr) * NANO_SECONDS_IN_A_SECOND); - report.set_end_report_nanos(mCurrentBucketStartTimeNs); - - StatsLogReport_CountMetricDataWrapper* wrapper = report.mutable_count_metrics(); + flushCounterIfNeeded(endTime); - for (const auto& pair : mPastBuckets) { - const HashableDimensionKey& hashableKey = pair.first; + for (const auto& counter : mPastBucketProtos) { + const HashableDimensionKey& hashableKey = counter.first; auto it = mDimensionKeyMap.find(hashableKey); if (it == mDimensionKeyMap.end()) { ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str()); continue; } + long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA); + + // First fill dimension (KeyValuePairs). + for (const auto& kv : it->second) { + long long dimensionToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION); + mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key()); + if (kv.has_value_str()) { + mProto->write(FIELD_TYPE_INT32 | FIELD_ID_VALUE_STR, kv.value_str()); + } else if (kv.has_value_int()) { + mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int()); + } else if (kv.has_value_bool()) { + mProto->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool()); + } else if (kv.has_value_float()) { + mProto->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float()); + } + mProto->end(dimensionToken); + } - VLOG(" dimension key %s", hashableKey.c_str()); - addSlicedCounterToReport(*wrapper, it->second, pair.second); + // Then fill bucket_info (CountBucketInfo). + for (const auto& proto : counter.second) { + size_t bufferSize = proto->size(); + char* buffer(new char[bufferSize]); + size_t pos = 0; + auto it = proto->data(); + while (it.readBuffer() != NULL) { + size_t toRead = it.currentToRead(); + std::memcpy(&buffer[pos], it.readBuffer(), toRead); + pos += toRead; + it.rp()->move(toRead); + } + mProto->write(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION, buffer, bufferSize); + } + + mProto->end(wrapperToken); + } + + mProto->end(mProtoToken); + mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, + (long long)mCurrentBucketStartTimeNs); + + size_t bufferSize = mProto->size(); + VLOG("metric %lld dump report now...", mMetric.metric_id()); + std::unique_ptr<uint8_t[]> buffer(new uint8_t[bufferSize]); + size_t pos = 0; + auto it = mProto->data(); + while (it.readBuffer() != NULL) { + size_t toRead = it.currentToRead(); + std::memcpy(&buffer[pos], it.readBuffer(), toRead); + pos += toRead; + it.rp()->move(toRead); } - return report; - // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped. + + startNewProtoOutputStream(endTime); + mPastBucketProtos.clear(); + mByteSize = 0; + + // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this: + // return std::move(buffer); + return StatsLogReport(); + + // TODO: Clear mDimensionKeyMap once the report is dumped. } void CountMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) { @@ -175,15 +239,17 @@ void CountMetricProducer::flushCounterIfNeeded(const uint64_t eventTimeNs) { // adjust the bucket start time int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs; - CountBucketInfo info; - info.set_start_bucket_nanos(mCurrentBucketStartTimeNs); - info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs); - for (const auto& counter : mCurrentSlicedCounter) { - info.set_count(counter.second); - // it will auto create new vector of CountbucketInfo if the key is not found. - auto& bucketList = mPastBuckets[counter.first]; - bucketList.push_back(info); + unique_ptr<ProtoOutputStream> proto = make_unique<ProtoOutputStream>(); + proto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS, + (long long)mCurrentBucketStartTimeNs); + proto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS, + (long long)mCurrentBucketStartTimeNs + mBucketSizeNs); + proto->write(FIELD_TYPE_INT64 | FIELD_ID_COUNT, (long long)counter.second); + + auto& bucketList = mPastBucketProtos[counter.first]; + bucketList.push_back(std::move(proto)); + mByteSize += proto->size(); VLOG("metric %lld, dump key value: %s -> %d", mMetric.metric_id(), counter.first.c_str(), counter.second); @@ -202,11 +268,11 @@ void CountMetricProducer::flushCounterIfNeeded(const uint64_t eventTimeNs) { (long long)mCurrentBucketStartTimeNs); } +// Rough estimate of CountMetricProducer buffer stored. This number will be +// greater than actual data size as it contains each dimension of +// CountMetricData is duplicated. size_t CountMetricProducer::byteSize() { -// TODO: return actual proto size when ProtoOutputStream is ready for use for -// CountMetricsProducer. -// return mProto->size(); - return 0; + return mByteSize; } } // namespace statsd diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h index 80e80d95d801..473a4ba4f428 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.h +++ b/cmds/statsd/src/metrics/CountMetricProducer.h @@ -19,6 +19,7 @@ #include <unordered_map> +#include <android/util/ProtoOutputStream.h> #include "../condition/ConditionTracker.h" #include "../matchers/matcher_util.h" #include "CountAnomalyTracker.h" @@ -65,8 +66,10 @@ protected: private: const CountMetric mMetric; - // Save the past buckets and we can clear when the StatsLogReport is dumped. - std::unordered_map<HashableDimensionKey, std::vector<CountBucketInfo>> mPastBuckets; + std::unordered_map<HashableDimensionKey, + std::vector<unique_ptr<android::util::ProtoOutputStream>>> mPastBucketProtos; + + size_t mByteSize; // The current bucket. std::unordered_map<HashableDimensionKey, int> mCurrentSlicedCounter; @@ -74,6 +77,12 @@ private: vector<unique_ptr<CountAnomalyTracker>> mAnomalyTrackers; void flushCounterIfNeeded(const uint64_t newEventTime); + + std::unique_ptr<android::util::ProtoOutputStream> mProto; + + long long mProtoToken; + + void startNewProtoOutputStream(long long timestamp); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp index d71417936bfd..cbae1d343f03 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.cpp +++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp @@ -23,6 +23,7 @@ #include <limits.h> #include <stdlib.h> +using namespace android::util; using android::util::ProtoOutputStream; using std::map; using std::string; @@ -36,13 +37,13 @@ namespace statsd { // for StatsLogReport const int FIELD_ID_METRIC_ID = 1; const int FIELD_ID_START_REPORT_NANOS = 2; -const int FIELD_ID_END_REPORT_NANOS = 2; +const int FIELD_ID_END_REPORT_NANOS = 3; const int FIELD_ID_EVENT_METRICS = 4; +// for EventMetricDataWrapper +const int FIELD_ID_DATA = 1; // for EventMetricData const int FIELD_ID_TIMESTAMP_NANOS = 1; const int FIELD_ID_STATS_EVENTS = 2; -// for CountMetricDataWrapper -const int FIELD_ID_DATA = 1; EventMetricProducer::EventMetricProducer(const EventMetric& metric, const int conditionIndex, const sp<ConditionWizard>& wizard) @@ -69,9 +70,9 @@ void EventMetricProducer::startNewProtoOutputStream(long long startTime) { mProto = std::make_unique<ProtoOutputStream>(); // TODO: We need to auto-generate the field IDs for StatsLogReport, EventMetricData, // and StatsEvent. - mProto->write(TYPE_INT32 + FIELD_ID_METRIC_ID, mMetric.metric_id()); - mProto->write(TYPE_INT64 + FIELD_ID_START_REPORT_NANOS, startTime); - mProtoToken = mProto->start(TYPE_MESSAGE + FIELD_ID_EVENT_METRICS); + mProto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, mMetric.metric_id()); + mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime); + mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS); } void EventMetricProducer::finish() { @@ -83,7 +84,7 @@ void EventMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) { StatsLogReport EventMetricProducer::onDumpReport() { long long endTime = time(nullptr) * NANO_SECONDS_IN_A_SECOND; mProto->end(mProtoToken); - mProto->write(TYPE_INT64 + FIELD_ID_END_REPORT_NANOS, endTime); + mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, endTime); size_t bufferSize = mProto->size(); VLOG("metric %lld dump report now... proto size: %zu ", mMetric.metric_id(), bufferSize); @@ -118,9 +119,9 @@ void EventMetricProducer::onMatchedLogEventInternal( return; } - long long wrapperToken = mProto->start(TYPE_MESSAGE + FIELD_ID_DATA); - mProto->write(TYPE_INT64 + FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs()); - long long eventToken = mProto->start(TYPE_MESSAGE + FIELD_ID_STATS_EVENTS); + long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA); + mProto->write(FIELD_TYPE_INT64 | FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs()); + long long eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_STATS_EVENTS); event.ToProto(*mProto); mProto->end(eventToken); mProto->end(wrapperToken); diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index cb6166dafa3a..ca33371e033a 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -36,11 +36,11 @@ namespace statsd { // ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int conditionIndex, - const sp<ConditionWizard>& wizard) + const sp<ConditionWizard>& wizard, const int pullTagId) : MetricProducer((time(nullptr) / 600 * 600 * NANO_SECONDS_IN_A_SECOND), conditionIndex, wizard), mMetric(metric), - mPullCode(mStatsPullerManager.GetPullCode(mMetric.what())) { + mPullTagId(pullTagId) { // TODO: valuemetric for pushed events may need unlimited bucket length mBucketSizeNs = mMetric.bucket().bucket_size_millis() * 1000 * 1000; @@ -52,8 +52,8 @@ ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int co mConditionSliced = true; } - if (!metric.has_condition() && mPullCode != -1) { - mStatsPullerManager.RegisterReceiver(mPullCode, this, metric.bucket().bucket_size_millis()); + if (!metric.has_condition() && mPullTagId != -1) { + mStatsPullerManager.RegisterReceiver(mPullTagId, this, metric.bucket().bucket_size_millis()); } VLOG("value metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(), @@ -120,27 +120,27 @@ StatsLogReport ValueMetricProducer::onDumpReport() { void ValueMetricProducer::onConditionChanged(const bool condition, const uint64_t eventTime) { mCondition = condition; - if (mPullCode != -1) { - vector<shared_ptr<LogEvent>> allData = mStatsPullerManager.Pull(mPullCode, eventTime); + if (mPullTagId != -1) { if (mCondition == true) { - mStatsPullerManager.RegisterReceiver(mPullCode, this, + mStatsPullerManager.RegisterReceiver(mPullTagId, this, mMetric.bucket().bucket_size_millis()); } else if (mCondition == ConditionState::kFalse) { - mStatsPullerManager.UnRegisterReceiver(mPullCode, this); + mStatsPullerManager.UnRegisterReceiver(mPullTagId, this); } - if (allData.size() == 0) { - return; - } - AutoMutex _l(mLock); - if (allData.size() == 0) { - return; - } - for (const auto& data : allData) { - onMatchedLogEvent(0, *data, false); + + vector<shared_ptr<LogEvent>> allData; + if (mStatsPullerManager.Pull(mPullTagId, &allData)) { + if (allData.size() == 0) { + return; + } + AutoMutex _l(mLock); + for (const auto& data : allData) { + onMatchedLogEvent(0, *data, false); + } + flush_if_needed(eventTime); } - flush_if_needed(eventTime); + return; } - return; } void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) { @@ -188,7 +188,7 @@ void ValueMetricProducer::onMatchedLogEventInternal( } } } - if (mPullCode == -1) { + if (mPullTagId == -1) { flush_if_needed(eventTimeNs); } } diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index 4f1791351f87..865398127b47 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -33,7 +33,7 @@ namespace statsd { class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver { public: ValueMetricProducer(const ValueMetric& valueMetric, const int conditionIndex, - const sp<ConditionWizard>& wizard); + const sp<ConditionWizard>& wizard, const int pullTagId); virtual ~ValueMetricProducer(); @@ -67,7 +67,8 @@ private: Mutex mLock; - const int mPullCode; + // tagId for pulled data. -1 if this is not pulled + const int mPullTagId; // internal state of a bucket. typedef struct { diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index 3d4036e8d176..3ff2a773327e 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -192,12 +192,12 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l unordered_map<int, std::vector<int>>& trackerToMetricMap) { sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers); const int allMetricsCount = - config.count_metric_size() + config.duration_metric_size() + config.event_metric_size(); + config.count_metric_size() + config.duration_metric_size() + config.event_metric_size() + config.value_metric_size(); allMetricProducers.reserve(allMetricsCount); StatsPullerManager& statsPullerManager = StatsPullerManager::GetInstance(); // Build MetricProducers for each metric defined in config. - // (1) build CountMetricProducer + // build CountMetricProducer for (int i = 0; i < config.count_metric_size(); i++) { const CountMetric& metric = config.count_metric(i); if (!metric.has_what()) { @@ -224,6 +224,7 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l allMetricProducers.push_back(countProducer); } + // build DurationMetricProducer for (int i = 0; i < config.duration_metric_size(); i++) { int metricIndex = allMetricProducers.size(); const DurationMetric& metric = config.duration_metric(i); @@ -285,6 +286,7 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l allMetricProducers.push_back(durationMetric); } + // build EventMetricProducer for (int i = 0; i < config.event_metric_size(); i++) { int metricIndex = allMetricProducers.size(); const EventMetric& metric = config.event_metric(i); @@ -310,7 +312,7 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l allMetricProducers.push_back(eventMetric); } - // value metrics + // build ValueMetricProducer for (int i = 0; i < config.value_metric_size(); i++) { const ValueMetric& metric = config.value_metric(i); if (!metric.has_what()) { @@ -318,24 +320,35 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l return false; } - int pullCode = statsPullerManager.GetPullCode(metric.what()); - if (pullCode == -1) { - ALOGW("cannot find %s in pulled metrics", metric.what().c_str()); + int metricIndex = allMetricProducers.size(); + int trackerIndex; + if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.dimension_size() > 0, + allLogEntryMatchers, logTrackerMap, trackerToMetricMap, + trackerIndex)) { return false; } - sp<MetricProducer> valueProducer; - auto condition_it = conditionTrackerMap.find(metric.condition()); - if (condition_it == conditionTrackerMap.end()) { - ALOGW("cannot find the Condition %s in the config", metric.condition().c_str()); - return false; + sp<LogMatchingTracker> atomMatcher = allLogEntryMatchers.at(trackerIndex); + // If it is pulled atom, it should be simple matcher with one tagId. + int pullTagId = -1; + for (int tagId : atomMatcher->getTagIds()) { + if (statsPullerManager.PullerForMatcherExists(tagId)) { + if (atomMatcher->getTagIds().size() != 1) { + return false; + } + pullTagId = tagId; + } + } + + int conditionIndex = -1; + if (metric.has_condition()) { + handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap, + metric.links(), allConditionTrackers, conditionIndex, + conditionToMetricMap); } - int metricIndex = allMetricProducers.size(); - valueProducer = new ValueMetricProducer(metric, condition_it->second, wizard); - // will create new vector if not exist before. - auto& metricList = conditionToMetricMap[condition_it->second]; - metricList.push_back(metricIndex); + sp<MetricProducer> valueProducer = + new ValueMetricProducer(metric, conditionIndex, wizard, pullTagId); allMetricProducers.push_back(valueProducer); } return true; diff --git a/cmds/statsd/src/stats_events.proto b/cmds/statsd/src/stats_events.proto index 51244c6bdf4b..82d975914682 100644 --- a/cmds/statsd/src/stats_events.proto +++ b/cmds/statsd/src/stats_events.proto @@ -72,6 +72,7 @@ message StatsEvent { PhoneSignalStrengthChanged phone_signal_strength_changed = 40; SettingChanged setting_changed = 41; ActivityForegroundStateChanged activity_foreground_state_changed = 42; + // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15. } @@ -81,7 +82,10 @@ message StatsEvent { WifiBytesTransferredByFgBg wifi_bytes_transferred_by_fg_bg = 1001; MobileBytesTransferred mobile_bytes_transferred = 1002; MobileBytesTransferredByFgBg mobile_bytes_transferred_by_fg_bg = 1003; - KernelWakelocksReported kernel_wakelocks_reported = 1004; + KernelWakelockPulled kernel_wakelock_pulled = 1004; + PowerStatePlatformSleepStatePulled power_state_platform_sleep_state_pulled = 1005; + PowerStateVoterPulled power_state_voter_pulled = 1006; + PowerStateSubsystemSleepStatePulled power_state_subsystem_sleep_state_pulled = 1007; } } @@ -794,7 +798,7 @@ message MobileBytesTransferredByFgBg { * Pulled from: * StatsCompanionService using KernelWakelockReader. */ -message KernelWakelocksReported { +message KernelWakelockPulled { optional string name = 1; optional int32 count = 2; @@ -803,3 +807,44 @@ message KernelWakelocksReported { optional int64 time = 4; } + +/* + * Pulls PowerStatePlatformSleepState. + * + * Definition here: + * hardware/interfaces/power/1.0/types.hal + */ +message PowerStatePlatformSleepStatePulled { + optional string name = 1; + optional uint64 residency_in_msec_since_boot = 2; + optional uint64 total_transitions = 3; + optional bool supported_only_in_suspend = 4; +} + +/** + * Pulls PowerStateVoter. + * + * Definition here: + * hardware/interfaces/power/1.0/types.hal + */ +message PowerStateVoterPulled { + optional string power_state_platform_sleep_state_name = 1; + optional string power_state_voter_name = 2; + optional uint64 total_time_in_msec_voted_for_since_boot = 3; + optional uint64 total_number_of_times_voted_since_boot = 4; +} + +/** + * Pulls PowerStateSubsystemSleepState. + * + * Definition here: + * hardware/interfaces/power/1.1/types.hal + */ +message PowerStateSubsystemSleepStatePulled { + optional string power_state_subsystem_name = 1; + optional string power_state_subsystem_sleep_state_name = 2; + optional uint64 residency_in_msec_since_boot = 3; + optional uint64 total_transitions = 4; + optional uint64 last_entry_timestamp_ms = 5; + optional bool supported_only_in_suspend = 6; +} diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h index a428752ba634..d3d7e3709644 100644 --- a/cmds/statsd/src/stats_util.h +++ b/cmds/statsd/src/stats_util.h @@ -30,14 +30,6 @@ namespace statsd { #define MATCHER_NOT_FOUND -2 #define NANO_SECONDS_IN_A_SECOND (1000 * 1000 * 1000) -// TODO: Remove the following constants once they are exposed in ProtOutputStream.h -const uint64_t FIELD_TYPE_SHIFT = 32; -const uint64_t TYPE_MESSAGE = 11ULL << FIELD_TYPE_SHIFT; -const uint64_t TYPE_INT64 = 3ULL << FIELD_TYPE_SHIFT; -const uint64_t TYPE_INT32 = 5ULL << FIELD_TYPE_SHIFT; -const uint64_t TYPE_FLOAT = 2ULL << FIELD_TYPE_SHIFT; -const uint64_t TYPE_STRING = 9ULL << FIELD_TYPE_SHIFT; - typedef std::string HashableDimensionKey; typedef std::map<std::string, HashableDimensionKey> ConditionKey; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 23059576fdc4..064e97828f06 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -687,6 +687,7 @@ public class ActivityManager { * in portrait mode or at the left half of the screen if in landscape mode. * @hide */ + @TestApi public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0; /** @@ -696,6 +697,7 @@ public class ActivityManager { * in portrait mode or at the right half of the screen if in landscape mode. * @hide */ + @TestApi public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1; /** @@ -1926,6 +1928,33 @@ public class ActivityManager { } /** + * Moves the input task to the primary-split-screen stack. + * @param taskId Id of task to move. + * @param createMode The mode the primary split screen stack should be created in if it doesn't + * exist already. See + * {@link android.app.ActivityManager#SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT} + * and + * {@link android.app.ActivityManager + * #SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT} + * @param toTop If the task and stack should be moved to the top. + * @param animate Whether we should play an animation for the moving the task + * @param initialBounds If the primary stack gets created, it will use these bounds for the + * docked stack. Pass {@code null} to use default bounds. + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public void setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop, + boolean animate, Rect initialBounds) throws SecurityException { + try { + getService().setTaskWindowingModeSplitScreenPrimary(taskId, createMode, toTop, animate, + initialBounds); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Resizes the input stack id to the given bounds. * @param stackId Id of the stack to resize. * @param bounds Bounds to resize the stack to or {@code null} for fullscreen. diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 388459fbbc6e..bbc90c81fae8 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -232,7 +232,7 @@ interface IActivityManager { boolean requireFull, in String name, in String callerPackage); void addPackageDependency(in String packageName); void killApplication(in String pkg, int appId, int userId, in String reason); - oneway void closeSystemDialogs(in String reason); + void closeSystemDialogs(in String reason); Debug.MemoryInfo[] getProcessMemoryInfo(in int[] pids); void killApplicationProcess(in String processName, int uid); int startActivityIntentSender(in IApplicationThread caller, diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java index 5c6ffa39e6f7..392387a99897 100644 --- a/core/java/android/app/VrManager.java +++ b/core/java/android/app/VrManager.java @@ -198,4 +198,20 @@ public class VrManager { e.rethrowFromSystemServer(); } } + + /** + * Sets the current standby status of the VR device. Standby mode is only used on standalone vr + * devices. Standby mode is a deep sleep state where it's appropriate to turn off vr mode. + * + * @param standby True if the device is entering standby, false if it's exiting standby. + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_VR_MANAGER) + public void setStandbyEnabled(boolean standby) { + try { + mService.setStandbyEnabled(standby); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index c827432a8b0b..3a3e16e0956c 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -261,7 +261,10 @@ public final class UsageStatsManager { /** * @hide + * Changes the app standby state to the provided bucket. */ + @SystemApi + @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE) public void setAppStandbyBucket(String packageName, @StandbyBuckets int bucket) { try { mService.setAppStandbyBucket(packageName, bucket, mContext.getUserId()); diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index e47de752ec70..dd729a36875d 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3444,11 +3444,12 @@ public class Intent implements Parcelable, Cloneable { /** * A broadcast action to trigger a factory reset. * - * <p> The sender must hold the {@link android.Manifest.permission#MASTER_CLEAR} permission. + * <p>The sender must hold the {@link android.Manifest.permission#MASTER_CLEAR} permission. The + * reason for the factory reset should be specified as {@link #EXTRA_REASON}. * * <p>Not for use by third-party applications. * - * @see #EXTRA_FORCE_MASTER_CLEAR + * @see #EXTRA_FORCE_FACTORY_RESET * * {@hide} */ @@ -4827,7 +4828,13 @@ public class Intent implements Parcelable, Cloneable { /** @hide */ public static final int EXTRA_TIME_PREF_VALUE_USE_LOCALE_DEFAULT = 2; - /** {@hide} */ + /** + * Intent extra: the reason that the operation associated with this intent is being performed. + * + * <p>Type: String + * @hide + */ + @SystemApi public static final String EXTRA_REASON = "android.intent.extra.REASON"; /** diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index b94a410b0ba0..05c555685384 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -671,9 +671,13 @@ public class LauncherApps { } /** - * Returns whether the caller can access the shortcut information. + * Returns whether the caller can access the shortcut information. Access is currently + * available to: * - * <p>Only the default launcher can access the shortcut information. + * <ul> + * <li>The current launcher (or default launcher if there is no set current launcher).</li> + * <li>The currently active voice interaction service.</li> + * </ul> * * <p>Note when this method returns {@code false}, it may be a temporary situation because * the user is trying a new launcher application. The user may decide to change the default diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java index 7fc25d82870c..dadfaa9f1a66 100644 --- a/core/java/android/content/pm/ShortcutServiceInternal.java +++ b/core/java/android/content/pm/ShortcutServiceInternal.java @@ -73,6 +73,9 @@ public abstract class ShortcutServiceInternal { public abstract boolean hasShortcutHostPermission(int launcherUserId, @NonNull String callingPackage, int callingPid, int callingUid); + public abstract void setShortcutHostPackage(@NonNull String type, @Nullable String packageName, + int userId); + public abstract boolean requestPinAppWidget(@NonNull String callingPackage, @NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras, @Nullable IntentSender resultIntent, int userId); diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index 7cbb436c84ee..241172784262 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -271,6 +271,59 @@ public final class ContextHubManager { throw new UnsupportedOperationException("TODO: Implement this"); } + /* + * Helper function to generate a stub for a non-query transaction callback. + * + * @param transaction the transaction to unblock when complete + * + * @return the callback + * + * @hide + */ + private IContextHubTransactionCallback createTransactionCallback( + ContextHubTransaction<Void> transaction) { + return new IContextHubTransactionCallback.Stub() { + @Override + public void onQueryResponse(int result, List<NanoAppState> nanoappList) { + Log.e(TAG, "Received a query callback on a non-query request"); + transaction.setResponse(new ContextHubTransaction.Response<Void>( + ContextHubTransaction.TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE, null)); + } + + @Override + public void onTransactionComplete(int result) { + transaction.setResponse(new ContextHubTransaction.Response<Void>(result, null)); + } + }; + } + + /* + * Helper function to generate a stub for a query transaction callback. + * + * @param transaction the transaction to unblock when complete + * + * @return the callback + * + * @hide + */ + private IContextHubTransactionCallback createQueryCallback( + ContextHubTransaction<List<NanoAppState>> transaction) { + return new IContextHubTransactionCallback.Stub() { + @Override + public void onQueryResponse(int result, List<NanoAppState> nanoappList) { + transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>( + result, nanoappList)); + } + + @Override + public void onTransactionComplete(int result) { + Log.e(TAG, "Received a non-query callback on a query request"); + transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>( + ContextHubTransaction.TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE, null)); + } + }; + } + /** * Loads a nanoapp at the specified Context Hub. * @@ -411,7 +464,7 @@ public final class ContextHubManager { * * @param callback the notification callback to register * @param hubInfo the hub to attach this client to - * @param handler the handler to invoke the callback, if null uses the current thread Looper + * @param handler the handler to invoke the callback, if null uses the main thread's Looper * * @return the registered client object * diff --git a/core/java/android/hardware/location/ContextHubTransaction.java b/core/java/android/hardware/location/ContextHubTransaction.java index 4877d38b37e0..a8569ef479a1 100644 --- a/core/java/android/hardware/location/ContextHubTransaction.java +++ b/core/java/android/hardware/location/ContextHubTransaction.java @@ -16,11 +16,16 @@ package android.hardware.location; import android.annotation.IntDef; +import android.annotation.NonNull; import android.os.Handler; +import android.os.Looper; +import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** * A class describing a request sent to the Context Hub Service. @@ -29,17 +34,15 @@ import java.util.concurrent.TimeUnit; * through the ContextHubManager APIs. The caller can either retrieve the result * synchronously through a blocking call ({@link #waitForResponse(long, TimeUnit)}) or * asynchronously through a user-defined callback - * ({@link #onComplete(ContextHubTransaction.Callback<T>, Handler)}). - * - * A transaction can be invalidated if the caller of the transaction is no longer active - * and the reference to this object is lost, or if timeout period has passed in - * {@link #waitForResponse(long, TimeUnit)}. + * ({@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}). * * @param <T> the type of the contents in the transaction response * * @hide */ public class ContextHubTransaction<T> { + private static final String TAG = "ContextHubTransaction"; + /** * Constants describing the type of a transaction through the Context Hub Service. */ @@ -68,7 +71,8 @@ public class ContextHubTransaction<T> { TRANSACTION_FAILED_UNINITIALIZED, TRANSACTION_FAILED_PENDING, TRANSACTION_FAILED_AT_HUB, - TRANSACTION_FAILED_TIMEOUT}) + TRANSACTION_FAILED_TIMEOUT, + TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE}) public @interface Result {} public static final int TRANSACTION_SUCCESS = 0; /** @@ -95,6 +99,10 @@ public class ContextHubTransaction<T> { * Failure mode when the transaction has timed out. */ public static final int TRANSACTION_FAILED_TIMEOUT = 6; + /** + * Failure mode when the transaction has failed internally at the service. + */ + public static final int TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE = 7; /** * A class describing the response for a ContextHubTransaction. @@ -146,11 +154,6 @@ public class ContextHubTransaction<T> { } /* - * The unique identifier representing the transaction. - */ - private int mTransactionId; - - /* * The type of the transaction. */ @Type @@ -171,8 +174,17 @@ public class ContextHubTransaction<T> { */ private ContextHubTransaction.Callback<T> mCallback = null; - ContextHubTransaction(int id, @Type int type) { - mTransactionId = id; + /* + * Synchronization latch used to block on response. + */ + private final CountDownLatch mDoneSignal = new CountDownLatch(1); + + /* + * true if the response has been set throught setResponse, false otherwise. + */ + private boolean mIsResponseSet = false; + + ContextHubTransaction(@Type int type) { mTransactionType = type; } @@ -191,17 +203,26 @@ public class ContextHubTransaction<T> { * for the transaction represented by this object by the Context Hub, or a * specified timeout period has elapsed. * - * If the specified timeout has passed, the transaction represented by this object - * is invalidated by the Context Hub Service (resulting in a timeout failure in the - * response). + * If the specified timeout has passed, a TimeoutException will be thrown and the caller may + * retry the invocation of this method at a later time. * * @param timeout the timeout duration * @param unit the unit of the timeout * * @return the transaction response + * + * @throws InterruptedException if the current thread is interrupted while waiting for response + * @throws TimeoutException if the timeout period has passed */ - public ContextHubTransaction.Response<T> waitForResponse(long timeout, TimeUnit unit) { - throw new UnsupportedOperationException("TODO: Implement this"); + public ContextHubTransaction.Response<T> waitForResponse( + long timeout, TimeUnit unit) throws InterruptedException, TimeoutException { + boolean success = mDoneSignal.await(timeout, unit); + + if (!success) { + throw new TimeoutException("Timed out while waiting for transaction"); + } + + return mResponse; } /** @@ -215,15 +236,100 @@ public class ContextHubTransaction<T> { * will be immediately posted by the handler. If the transaction has been invalidated, * the callback will never be invoked. * + * A transaction can be invalidated if the process owning the transaction is no longer active + * and the reference to this object is lost. + * + * This method or {@link #setCallbackOnCompletecan(ContextHubTransaction.Callback)} can only be + * invoked once, or an IllegalStateException will be thrown. + * * @param callback the callback to be invoked upon completion * @param handler the handler to post the callback + * + * @throws IllegalStateException if this method is called multiple times + * @throws NullPointerException if the callback or handler is null */ - public void onComplete(ContextHubTransaction.Callback<T> callback, Handler handler) { - throw new UnsupportedOperationException("TODO: Implement this"); + public void setCallbackOnComplete( + @NonNull ContextHubTransaction.Callback<T> callback, @NonNull Handler handler) { + synchronized (this) { + if (callback == null) { + throw new NullPointerException("Callback cannot be null"); + } + if (handler == null) { + throw new NullPointerException("Handler cannot be null"); + } + if (mCallback != null) { + throw new IllegalStateException( + "Cannot set ContextHubTransaction callback multiple times"); + } + + mCallback = callback; + mHandler = handler; + + if (mDoneSignal.getCount() == 0) { + boolean callbackPosted = mHandler.post(() -> { + mCallback.onComplete(this, mResponse); + }); + + if (!callbackPosted) { + Log.e(TAG, "Failed to post callback to Handler"); + } + } + } } - private void setResponse(ContextHubTransaction.Response<T> response) { - mResponse = response; - throw new UnsupportedOperationException("TODO: Unblock waitForResponse"); + /** + * Sets a callback to be invoked when the transaction completes. + * + * Equivalent to {@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)} + * with the handler being that of the main thread's Looper. + * + * This method or {@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)} + * can only be invoked once, or an IllegalStateException will be thrown. + * + * @param callback the callback to be invoked upon completion + * + * @throws IllegalStateException if this method is called multiple times + * @throws NullPointerException if the callback is null + */ + public void setCallbackOnComplete(@NonNull ContextHubTransaction.Callback<T> callback) { + setCallbackOnComplete(callback, new Handler(Looper.getMainLooper())); + } + + /** + * Sets the response of the transaction. + * + * This method should only be invoked by ContextHubManager as a result of a callback from + * the Context Hub Service indicating the response from a transaction. This method should not be + * invoked more than once. + * + * @param response the response to set + * + * @throws IllegalStateException if this method is invoked multiple times + * @throws NullPointerException if the response is null + */ + void setResponse(ContextHubTransaction.Response<T> response) { + synchronized (this) { + if (response == null) { + throw new NullPointerException("Response cannot be null"); + } + if (mIsResponseSet) { + throw new IllegalStateException( + "Cannot set response of ContextHubTransaction multiple times"); + } + + mResponse = response; + mIsResponseSet = true; + + mDoneSignal.countDown(); + if (mCallback != null) { + boolean callbackPosted = mHandler.post(() -> { + mCallback.onComplete(this, mResponse); + }); + + if (!callbackPosted) { + Log.e(TAG, "Failed to post callback to Handler"); + } + } + } } } diff --git a/core/java/android/hardware/location/IContextHubTransactionCallback.aidl b/core/java/android/hardware/location/IContextHubTransactionCallback.aidl new file mode 100644 index 000000000000..5419cd7e60d8 --- /dev/null +++ b/core/java/android/hardware/location/IContextHubTransactionCallback.aidl @@ -0,0 +1,35 @@ +/* + * 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.hardware.location; + +import android.hardware.location.NanoAppState; + +/** + * An interface used by the Context Hub Service to invoke callbacks notifying the complete of a + * transaction. The callbacks are unique for each type of transaction, and the service is + * responsible for invoking the correct callback. + * + * @hide + */ +oneway interface IContextHubTransactionCallback { + + // Callback to be invoked when a query request completes + void onQueryResponse(int result, in List<NanoAppState> nanoappList); + + // Callback to be invoked when a non-query request completes + void onTransactionComplete(int result); +} diff --git a/core/java/android/hardware/location/NanoAppBinary.java b/core/java/android/hardware/location/NanoAppBinary.java index 545422773aed..934e9e48c01a 100644 --- a/core/java/android/hardware/location/NanoAppBinary.java +++ b/core/java/android/hardware/location/NanoAppBinary.java @@ -22,6 +22,7 @@ import android.util.Log; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.Arrays; /** * @hide @@ -57,7 +58,7 @@ public final class NanoAppBinary implements Parcelable { private static final int EXPECTED_HEADER_VERSION = 1; /* - * The magic value expected in the header. + * The magic value expected in the header as defined in context_hub.h. */ private static final int EXPECTED_MAGIC_VALUE = (((int) 'N' << 0) | ((int) 'A' << 8) | ((int) 'N' << 16) | ((int) 'O' << 24)); @@ -67,6 +68,17 @@ public final class NanoAppBinary implements Parcelable { */ private static final ByteOrder HEADER_ORDER = ByteOrder.LITTLE_ENDIAN; + /* + * The size of the header in bytes as defined in context_hub.h. + */ + private static final int HEADER_SIZE_BYTES = 40; + + /* + * The bit fields for mFlags as defined in context_hub.h. + */ + private static final int NANOAPP_SIGNED_FLAG_BIT = 0x1; + private static final int NANOAPP_ENCRYPTED_FLAG_BIT = 0x2; + public NanoAppBinary(byte[] appBinary) { mNanoAppBinary = appBinary; parseBinaryHeader(); @@ -111,11 +123,26 @@ public final class NanoAppBinary implements Parcelable { /** * @return the app binary byte array */ - public byte[] getNanoAppBinary() { + public byte[] getBinary() { return mNanoAppBinary; } /** + * @return the app binary byte array without the leading header + * + * @throws IndexOutOfBoundsException if the nanoapp binary size is smaller than the header size + * @throws NullPointerException if the nanoapp binary is null + */ + public byte[] getBinaryNoHeader() { + if (mNanoAppBinary.length < HEADER_SIZE_BYTES) { + throw new IndexOutOfBoundsException("NanoAppBinary binary byte size (" + + mNanoAppBinary.length + ") is less than header size (" + HEADER_SIZE_BYTES + ")"); + } + + return Arrays.copyOfRange(mNanoAppBinary, HEADER_SIZE_BYTES, mNanoAppBinary.length); + } + + /** * @return {@code true} if the header is valid, {@code false} otherwise */ public boolean hasValidHeader() { @@ -164,6 +191,31 @@ public final class NanoAppBinary implements Parcelable { return mTargetChreApiMinorVersion; } + /** + * Returns the flags for the nanoapp as defined in context_hub.h. + * + * This method is meant to be used by the Context Hub Service. + * + * @return the flags for the nanoapp + */ + public int getFlags() { + return mFlags; + } + + /** + * @return {@code true} if the nanoapp binary is signed, {@code false} otherwise + */ + public boolean isSigned() { + return (mFlags & NANOAPP_SIGNED_FLAG_BIT) != 0; + } + + /** + * @return {@code true} if the nanoapp binary is encrypted, {@code false} otherwise + */ + public boolean isEncrypted() { + return (mFlags & NANOAPP_ENCRYPTED_FLAG_BIT) != 0; + } + private NanoAppBinary(Parcel in) { int binaryLength = in.readInt(); mNanoAppBinary = new byte[binaryLength]; diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 7f4dee6ef2da..01b6535bf171 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -513,6 +513,34 @@ public final class PowerManager { */ public static final int SHUTDOWN_REASON_BATTERY_THERMAL = 6; + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ServiceType.GPS, + ServiceType.VIBRATION, + ServiceType.ANIMATION, + ServiceType.FULL_BACKUP, + ServiceType.KEYVALUE_BACKUP, + ServiceType.NETWORK_FIREWALL, + ServiceType.SCREEN_BRIGHTNESS, + ServiceType.SOUND, + ServiceType.BATTERY_STATS, + ServiceType.DATA_SAVER}) + public @interface ServiceType { + int NULL = 0; + int GPS = 1; + int VIBRATION = 2; + int ANIMATION = 3; + int FULL_BACKUP = 4; + int KEYVALUE_BACKUP = 5; + int NETWORK_FIREWALL = 6; + int SCREEN_BRIGHTNESS = 7; + int SOUND = 8; + int BATTERY_STATS = 9; + int DATA_SAVER = 10; + } + final Context mContext; final IPowerManager mService; final Handler mHandler; @@ -1055,15 +1083,14 @@ public final class PowerManager { /** * Get data about the battery saver mode for a specific service - * @param serviceType unique key for the service, one of - * {@link com.android.server.power.BatterySaverPolicy.ServiceType} + * @param serviceType unique key for the service, one of {@link ServiceType} * @return Battery saver state data. * * @hide * @see com.android.server.power.BatterySaverPolicy * @see PowerSaveState */ - public PowerSaveState getPowerSaveState(int serviceType) { + public PowerSaveState getPowerSaveState(@ServiceType int serviceType) { try { return mService.getPowerSaveState(serviceType); } catch (RemoteException e) { diff --git a/core/java/android/os/PowerSaveState.java b/core/java/android/os/PowerSaveState.java index 7058a1dca34d..de1128dfdef5 100644 --- a/core/java/android/os/PowerSaveState.java +++ b/core/java/android/os/PowerSaveState.java @@ -27,7 +27,7 @@ public class PowerSaveState implements Parcelable { /** * Whether we should enable battery saver for this service. * - * @see com.android.server.power.BatterySaverPolicy.ServiceType + * @see com.android.server.power.BatterySaverPolicy */ public final boolean batterySaverEnabled; /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 2d6a7b0133aa..433878e9511a 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8012,28 +8012,40 @@ public final class Settings { public static final String HDMI_SYSTEM_AUDIO_CONTROL_ENABLED = "hdmi_system_audio_control_enabled"; - /** - * Whether TV will automatically turn on upon reception of the CEC command - * <Text View On> or <Image View On>. (0 = false, 1 = true) - * @hide - */ - public static final String HDMI_CONTROL_AUTO_WAKEUP_ENABLED = - "hdmi_control_auto_wakeup_enabled"; + /** + * Whether TV will automatically turn on upon reception of the CEC command + * <Text View On> or <Image View On>. (0 = false, 1 = true) + * + * @hide + */ + public static final String HDMI_CONTROL_AUTO_WAKEUP_ENABLED = + "hdmi_control_auto_wakeup_enabled"; - /** - * Whether TV will also turn off other CEC devices when it goes to standby mode. - * (0 = false, 1 = true) - * @hide - */ - public static final String HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED = - "hdmi_control_auto_device_off_enabled"; + /** + * Whether TV will also turn off other CEC devices when it goes to standby mode. + * (0 = false, 1 = true) + * + * @hide + */ + public static final String HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED = + "hdmi_control_auto_device_off_enabled"; - /** - * The interval in milliseconds at which location requests will be throttled when they are - * coming from the background. - * @hide - */ - public static final String LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS = + /** + * If <b>true</b>, enables out-of-the-box execution for priv apps. + * Default: false + * Values: 0 = false, 1 = true + * + * @hide + */ + public static final String PRIV_APP_OOB_ENABLED = "priv_app_oob_enabled"; + + /** + * The interval in milliseconds at which location requests will be throttled when they are + * coming from the background. + * + * @hide + */ + public static final String LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS = "location_background_throttle_interval_ms"; /** diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl index fef92230e7b8..7285fb40ae02 100644 --- a/core/java/android/service/vr/IVrManager.aidl +++ b/core/java/android/service/vr/IVrManager.aidl @@ -101,5 +101,13 @@ interface IVrManager { * application's compositor process to bind to, or null to clear the current binding. */ void setAndBindCompositor(in String componentName); + + /** + * Sets the current standby status of the VR device. Standby mode is only used on standalone vr + * devices. Standby mode is a deep sleep state where it's appropriate to turn off vr mode. + * + * @param standy True if the device is entering standby, false if it's exiting standby. + */ + void setStandbyEnabled(boolean standby); } diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java index a9ccae114ba8..180812340ba8 100644 --- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java +++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java @@ -16,9 +16,6 @@ package android.util.apk; -import android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; import android.util.ArrayMap; import android.util.Pair; @@ -30,7 +27,6 @@ import java.math.BigInteger; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.nio.DirectByteBuffer; import java.security.DigestException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -122,40 +118,6 @@ public class ApkSignatureSchemeV2Verifier { } /** - * APK Signature Scheme v2 block and additional information relevant to verifying the signatures - * contained in the block against the file. - */ - private static class SignatureInfo { - /** Contents of APK Signature Scheme v2 block. */ - private final ByteBuffer signatureBlock; - - /** Position of the APK Signing Block in the file. */ - private final long apkSigningBlockOffset; - - /** Position of the ZIP Central Directory in the file. */ - private final long centralDirOffset; - - /** Position of the ZIP End of Central Directory (EoCD) in the file. */ - private final long eocdOffset; - - /** Contents of ZIP End of Central Directory (EoCD) of the file. */ - private final ByteBuffer eocd; - - private SignatureInfo( - ByteBuffer signatureBlock, - long apkSigningBlockOffset, - long centralDirOffset, - long eocdOffset, - ByteBuffer eocd) { - this.signatureBlock = signatureBlock; - this.apkSigningBlockOffset = apkSigningBlockOffset; - this.centralDirOffset = centralDirOffset; - this.eocdOffset = eocdOffset; - this.eocd = eocd; - } - } - - /** * Returns the APK Signature Scheme v2 block contained in the provided APK file and the * additional information relevant for verifying the block against the file. * @@ -497,6 +459,7 @@ public class ApkSignatureSchemeV2Verifier { // TODO: Compute digests of chunks in parallel when beneficial. This requires some research // into how to parallelize (if at all) based on the capabilities of the hardware on which // this code is running and based on the size of input. + DataDigester digester = new MultipleDigestDataDigester(mds); int dataSourceIndex = 0; for (DataSource input : contents) { long inputOffset = 0; @@ -508,7 +471,7 @@ public class ApkSignatureSchemeV2Verifier { mds[i].update(chunkContentPrefix); } try { - input.feedIntoMessageDigests(mds, inputOffset, chunkSize); + input.feedIntoDataDigester(digester, inputOffset, chunkSize); } catch (IOException e) { throw new DigestException( "Failed to digest chunk #" + chunkIndex + " of section #" @@ -967,155 +930,26 @@ public class ApkSignatureSchemeV2Verifier { } /** - * Source of data to be digested. + * {@link DataDigester} that updates multiple {@link MessageDigest}s whenever data is feeded. */ - private static interface DataSource { - - /** - * Returns the size (in bytes) of the data offered by this source. - */ - long size(); - - /** - * Feeds the specified region of this source's data into the provided digests. Each digest - * instance gets the same data. - * - * @param offset offset of the region inside this data source. - * @param size size (in bytes) of the region. - */ - void feedIntoMessageDigests(MessageDigest[] mds, long offset, int size) throws IOException; - } + private static class MultipleDigestDataDigester implements DataDigester { + private final MessageDigest[] mMds; - /** - * {@link DataSource} which provides data from a file descriptor by memory-mapping the sections - * of the file requested by - * {@link DataSource#feedIntoMessageDigests(MessageDigest[], long, int) feedIntoMessageDigests}. - */ - private static final class MemoryMappedFileDataSource implements DataSource { - private static final long MEMORY_PAGE_SIZE_BYTES = Os.sysconf(OsConstants._SC_PAGESIZE); - - private final FileDescriptor mFd; - private final long mFilePosition; - private final long mSize; - - /** - * Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file. - * - * @param position start position of the region in the file. - * @param size size (in bytes) of the region. - */ - public MemoryMappedFileDataSource(FileDescriptor fd, long position, long size) { - mFd = fd; - mFilePosition = position; - mSize = size; + MultipleDigestDataDigester(MessageDigest[] mds) { + mMds = mds; } @Override - public long size() { - return mSize; - } - - @Override - public void feedIntoMessageDigests( - MessageDigest[] mds, long offset, int size) throws IOException { - // IMPLEMENTATION NOTE: After a lot of experimentation, the implementation of this - // method was settled on a straightforward mmap with prefaulting. - // - // This method is not using FileChannel.map API because that API does not offset a way - // to "prefault" the resulting memory pages. Without prefaulting, performance is about - // 10% slower on small to medium APKs, but is significantly worse for APKs in 500+ MB - // range. FileChannel.load (which currently uses madvise) doesn't help. Finally, - // invoking madvise (MADV_SEQUENTIAL) after mmap with prefaulting wastes quite a bit of - // time, which is not compensated for by faster reads. - - // We mmap the smallest region of the file containing the requested data. mmap requires - // that the start offset in the file must be a multiple of memory page size. We thus may - // need to mmap from an offset less than the requested offset. - long filePosition = mFilePosition + offset; - long mmapFilePosition = - (filePosition / MEMORY_PAGE_SIZE_BYTES) * MEMORY_PAGE_SIZE_BYTES; - int dataStartOffsetInMmapRegion = (int) (filePosition - mmapFilePosition); - long mmapRegionSize = size + dataStartOffsetInMmapRegion; - long mmapPtr = 0; - try { - mmapPtr = Os.mmap( - 0, // let the OS choose the start address of the region in memory - mmapRegionSize, - OsConstants.PROT_READ, - OsConstants.MAP_SHARED | OsConstants.MAP_POPULATE, // "prefault" all pages - mFd, - mmapFilePosition); - // Feeding a memory region into MessageDigest requires the region to be represented - // as a direct ByteBuffer. - ByteBuffer buf = new DirectByteBuffer( - size, - mmapPtr + dataStartOffsetInMmapRegion, - mFd, // not really needed, but just in case - null, // no need to clean up -- it's taken care of by the finally block - true // read only buffer - ); - for (MessageDigest md : mds) { - buf.position(0); - md.update(buf); - } - } catch (ErrnoException e) { - throw new IOException("Failed to mmap " + mmapRegionSize + " bytes", e); - } finally { - if (mmapPtr != 0) { - try { - Os.munmap(mmapPtr, mmapRegionSize); - } catch (ErrnoException ignored) {} - } + public void consume(ByteBuffer buffer) { + buffer = buffer.slice(); + for (MessageDigest md : mMds) { + buffer.position(0); + md.update(buffer); } } - } - - /** - * {@link DataSource} which provides data from a {@link ByteBuffer}. - */ - private static final class ByteBufferDataSource implements DataSource { - /** - * Underlying buffer. The data is stored between position 0 and the buffer's capacity. - * The buffer's position is 0 and limit is equal to capacity. - */ - private final ByteBuffer mBuf; - - public ByteBufferDataSource(ByteBuffer buf) { - // Defensive copy, to avoid changes to mBuf being visible in buf. - mBuf = buf.slice(); - } @Override - public long size() { - return mBuf.capacity(); - } - - @Override - public void feedIntoMessageDigests( - MessageDigest[] mds, long offset, int size) throws IOException { - // There's no way to tell MessageDigest to read data from ByteBuffer from a position - // other than the buffer's current position. We thus need to change the buffer's - // position to match the requested offset. - // - // In the future, it may be necessary to compute digests of multiple regions in - // parallel. Given that digest computation is a slow operation, we enable multiple - // such requests to be fulfilled by this instance. This is achieved by serially - // creating a new ByteBuffer corresponding to the requested data range and then, - // potentially concurrently, feeding these buffers into MessageDigest instances. - ByteBuffer region; - synchronized (mBuf) { - mBuf.position((int) offset); - mBuf.limit((int) offset + size); - region = mBuf.slice(); - } - - for (MessageDigest md : mds) { - // Need to reset position to 0 at the start of each iteration because - // MessageDigest.update below sets it to the buffer's limit. - region.position(0); - md.update(region); - } - } + public void finish() {} } /** diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java new file mode 100644 index 000000000000..0b9552e6afa9 --- /dev/null +++ b/core/java/android/util/apk/ApkVerityBuilder.java @@ -0,0 +1,347 @@ +/* + * 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 android.util.apk; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; + +/** + * ApkVerityBuilder builds the APK verity tree and the verity header, which will be used by the + * kernel to verity the APK content on access. + * + * <p>Unlike a regular Merkle tree, APK verity tree does not cover the content fully. Due to + * the existing APK format, it has to skip APK Signing Block and also has some special treatment for + * the "Central Directory offset" field of ZIP End of Central Directory. + * + * @hide + */ +abstract class ApkVerityBuilder { + private ApkVerityBuilder() {} + + private static final int CHUNK_SIZE_BYTES = 4096; // Typical Linux block size + private static final int DIGEST_SIZE_BYTES = 32; // SHA-256 size + private static final int FSVERITY_HEADER_SIZE_BYTES = 64; + private static final int ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE = 4; + private static final int ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET = 16; + private static final String JCA_DIGEST_ALGORITHM = "SHA-256"; + private static final byte[] DEFAULT_SALT = new byte[8]; + + static class ApkVerityResult { + public final ByteBuffer fsverityData; + public final byte[] rootHash; + + ApkVerityResult(ByteBuffer fsverityData, byte[] rootHash) { + this.fsverityData = fsverityData; + this.rootHash = rootHash; + } + } + + /** + * Generates fsverity metadata and the Merkle tree into the {@link ByteBuffer} created by the + * {@link ByteBufferFactory}. The bytes layout in the buffer will be used by the kernel and is + * ready to be appended to the target file to set up fsverity. For fsverity to work, this data + * must be placed at the next page boundary, and the caller must add additional padding in that + * case. + * + * @return ApkVerityResult containing the fsverity data and the root hash of the Merkle tree. + */ + static ApkVerityResult generateApkVerity(RandomAccessFile apk, + SignatureInfo signatureInfo, ByteBufferFactory bufferFactory) + throws IOException, SecurityException, NoSuchAlgorithmException { + assertSigningBlockAlignedAndHasFullPages(signatureInfo); + + long signingBlockSize = + signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset; + long dataSize = apk.length() - signingBlockSize - ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE; + int[] levelOffset = calculateVerityLevelOffset(dataSize); + ByteBuffer output = bufferFactory.create( + CHUNK_SIZE_BYTES + // fsverity header + extensions + padding + levelOffset[levelOffset.length - 1] + // Merkle tree size + FSVERITY_HEADER_SIZE_BYTES); // second fsverity header (verbatim copy) + + // Start generating the tree from the block boundary as the kernel will expect. + ByteBuffer treeOutput = slice(output, CHUNK_SIZE_BYTES, + output.limit() - FSVERITY_HEADER_SIZE_BYTES); + byte[] rootHash = generateApkVerityTree(apk, signatureInfo, DEFAULT_SALT, levelOffset, + treeOutput); + + ByteBuffer integrityHeader = generateFsverityHeader(apk.length(), DEFAULT_SALT); + output.put(integrityHeader); + output.put(generateFsverityExtensions()); + + integrityHeader.rewind(); + output.put(integrityHeader); + output.rewind(); + return new ApkVerityResult(output, rootHash); + } + + /** + * A helper class to consume and digest data by block continuously, and write into a buffer. + */ + private static class BufferedDigester implements DataDigester { + /** Amount of the data to digest in each cycle before writting out the digest. */ + private static final int BUFFER_SIZE = CHUNK_SIZE_BYTES; + + /** + * Amount of data the {@link MessageDigest} has consumed since the last reset. This must be + * always less than BUFFER_SIZE since {@link MessageDigest} is reset whenever it has + * consumed BUFFER_SIZE of data. + */ + private int mBytesDigestedSinceReset; + + /** The final output {@link ByteBuffer} to write the digest to sequentially. */ + private final ByteBuffer mOutput; + + private final MessageDigest mMd; + private final byte[] mSalt; + + private BufferedDigester(byte[] salt, ByteBuffer output) throws NoSuchAlgorithmException { + mSalt = salt; + mOutput = output.slice(); + mMd = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM); + mMd.update(mSalt); + mBytesDigestedSinceReset = 0; + } + + /** + * Consumes and digests data up to BUFFER_SIZE (may continue from the previous remaining), + * then writes the final digest to the output buffer. Repeat until all data are consumed. + * If the last consumption is not enough for BUFFER_SIZE, the state will stay and future + * consumption will continuous from there. + */ + @Override + public void consume(ByteBuffer buffer) { + int offset = buffer.position(); + int remaining = buffer.remaining(); + while (remaining > 0) { + int allowance = (int) Math.min(remaining, BUFFER_SIZE - mBytesDigestedSinceReset); + mMd.update(slice(buffer, offset, offset + allowance)); + offset += allowance; + remaining -= allowance; + mBytesDigestedSinceReset += allowance; + + if (mBytesDigestedSinceReset == BUFFER_SIZE) { + byte[] digest = mMd.digest(); + mOutput.put(digest); + + mMd.reset(); + mMd.update(mSalt); + mBytesDigestedSinceReset = 0; + } + } + } + + /** Finish the current digestion if any. */ + @Override + public void finish() { + if (mBytesDigestedSinceReset == 0) { + return; + } + byte[] digest = mMd.digest(); + mOutput.put(digest); + } + + private void fillUpLastOutputChunk() { + int extra = (int) (BUFFER_SIZE - mOutput.position() % BUFFER_SIZE); + if (extra == 0) { + return; + } + mOutput.put(ByteBuffer.allocate(extra)); + } + } + + /** + * Digest the source by chunk in the given range. If the last chunk is not a full chunk, + * digest the remaining. + */ + private static void consumeByChunk(DataDigester digester, DataSource source, int chunkSize) + throws IOException { + long inputRemaining = source.size(); + long inputOffset = 0; + while (inputRemaining > 0) { + int size = (int) Math.min(inputRemaining, chunkSize); + source.feedIntoDataDigester(digester, inputOffset, size); + inputOffset += size; + inputRemaining -= size; + } + } + + // Rationale: 1) 1 MB should fit in memory space on all devices. 2) It is not too granular + // thus the syscall overhead is not too big. + private static final int MMAP_REGION_SIZE_BYTES = 1024 * 1024; + + private static void generateApkVerityDigestAtLeafLevel(RandomAccessFile apk, + SignatureInfo signatureInfo, byte[] salt, ByteBuffer output) + throws IOException, NoSuchAlgorithmException { + BufferedDigester digester = new BufferedDigester(salt, output); + + // 1. Digest from the beginning of the file, until APK Signing Block is reached. + consumeByChunk(digester, + new MemoryMappedFileDataSource(apk.getFD(), 0, signatureInfo.apkSigningBlockOffset), + MMAP_REGION_SIZE_BYTES); + + // 2. Skip APK Signing Block and continue digesting, until the Central Directory offset + // field in EoCD is reached. + long eocdCdOffsetFieldPosition = + signatureInfo.eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET; + consumeByChunk(digester, + new MemoryMappedFileDataSource(apk.getFD(), signatureInfo.centralDirOffset, + eocdCdOffsetFieldPosition - signatureInfo.centralDirOffset), + MMAP_REGION_SIZE_BYTES); + + // 3. Fill up the rest of buffer with 0s. + ByteBuffer alternativeCentralDirOffset = ByteBuffer.allocate( + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE).order(ByteOrder.LITTLE_ENDIAN); + alternativeCentralDirOffset.putInt(Math.toIntExact(signatureInfo.apkSigningBlockOffset)); + alternativeCentralDirOffset.flip(); + digester.consume(alternativeCentralDirOffset); + + // 4. Read from end of the Central Directory offset field in EoCD to the end of the file. + long offsetAfterEocdCdOffsetField = + eocdCdOffsetFieldPosition + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE; + consumeByChunk(digester, + new MemoryMappedFileDataSource(apk.getFD(), offsetAfterEocdCdOffsetField, + apk.length() - offsetAfterEocdCdOffsetField), + MMAP_REGION_SIZE_BYTES); + digester.finish(); + + // 5. Fill up the rest of buffer with 0s. + digester.fillUpLastOutputChunk(); + } + + private static byte[] generateApkVerityTree(RandomAccessFile apk, SignatureInfo signatureInfo, + byte[] salt, int[] levelOffset, ByteBuffer output) + throws IOException, NoSuchAlgorithmException { + // 1. Digest the apk to generate the leaf level hashes. + generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output, + levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1])); + + // 2. Digest the lower level hashes bottom up. + for (int level = levelOffset.length - 3; level >= 0; level--) { + ByteBuffer inputBuffer = slice(output, levelOffset[level + 1], levelOffset[level + 2]); + ByteBuffer outputBuffer = slice(output, levelOffset[level], levelOffset[level + 1]); + + DataSource source = new ByteBufferDataSource(inputBuffer); + BufferedDigester digester = new BufferedDigester(salt, outputBuffer); + consumeByChunk(digester, source, CHUNK_SIZE_BYTES); + digester.finish(); + + digester.fillUpLastOutputChunk(); + } + + // 3. Digest the first block (i.e. first level) to generate the root hash. + byte[] rootHash = new byte[DIGEST_SIZE_BYTES]; + BufferedDigester digester = new BufferedDigester(salt, ByteBuffer.wrap(rootHash)); + digester.consume(slice(output, 0, CHUNK_SIZE_BYTES)); + return rootHash; + } + + private static ByteBuffer generateFsverityHeader(long fileSize, byte[] salt) { + if (salt.length != 8) { + throw new IllegalArgumentException("salt is not 8 bytes long"); + } + + ByteBuffer buffer = ByteBuffer.allocate(FSVERITY_HEADER_SIZE_BYTES); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + // TODO(b/30972906): insert a reference when there is a public one. + buffer.put("TrueBrew".getBytes()); // magic + buffer.put((byte) 1); // major version + buffer.put((byte) 0); // minor version + buffer.put((byte) 12); // log2(block-size) == log2(4096) + buffer.put((byte) 7); // log2(leaves-per-node) == log2(block-size / digest-size) + // == log2(4096 / 32) + buffer.putShort((short) 1); // meta algorithm, 1: SHA-256 FIXME finalize constant + buffer.putShort((short) 1); // data algorithm, 1: SHA-256 FIXME finalize constant + buffer.putInt(0x1); // flags, 0x1: has extension, FIXME also hide it + buffer.putInt(0); // reserved + buffer.putLong(fileSize); // original i_size + buffer.put(salt); // salt (8 bytes) + + // TODO(b/30972906): Add extension. + + buffer.rewind(); + return buffer; + } + + private static ByteBuffer generateFsverityExtensions() { + return ByteBuffer.allocate(64); // TODO(b/30972906): implement this. + } + + /** + * Returns an array of summed area table of level size in the verity tree. In other words, the + * returned array is offset of each level in the verity tree file format, plus an additional + * offset of the next non-existing level (i.e. end of the last level + 1). Thus the array size + * is level + 1. Thus, the returned array is guarantee to have at least 2 elements. + */ + private static int[] calculateVerityLevelOffset(long fileSize) { + ArrayList<Long> levelSize = new ArrayList<>(); + while (true) { + long levelDigestSize = divideRoundup(fileSize, CHUNK_SIZE_BYTES) * DIGEST_SIZE_BYTES; + long chunksSize = CHUNK_SIZE_BYTES * divideRoundup(levelDigestSize, CHUNK_SIZE_BYTES); + levelSize.add(chunksSize); + if (levelDigestSize <= CHUNK_SIZE_BYTES) { + break; + } + fileSize = levelDigestSize; + } + + // Reverse and convert to summed area table. + int[] levelOffset = new int[levelSize.size() + 1]; + levelOffset[0] = 0; + for (int i = 0; i < levelSize.size(); i++) { + // We don't support verity tree if it is larger then Integer.MAX_VALUE. + levelOffset[i + 1] = levelOffset[i] + + Math.toIntExact(levelSize.get(levelSize.size() - i - 1)); + } + return levelOffset; + } + + private static void assertSigningBlockAlignedAndHasFullPages(SignatureInfo signatureInfo) { + if (signatureInfo.apkSigningBlockOffset % CHUNK_SIZE_BYTES != 0) { + throw new IllegalArgumentException( + "APK Signing Block does not start at the page boundary: " + + signatureInfo.apkSigningBlockOffset); + } + + if ((signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset) + % CHUNK_SIZE_BYTES != 0) { + throw new IllegalArgumentException( + "Size of APK Signing Block is not a multiple of 4096: " + + (signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset)); + } + } + + /** Returns a slice of the buffer which shares content with the provided buffer. */ + private static ByteBuffer slice(ByteBuffer buffer, int begin, int end) { + ByteBuffer b = buffer.duplicate(); + b.position(0); // to ensure position <= limit invariant. + b.limit(end); + b.position(begin); + return b.slice(); + } + + /** Divides a number and round up to the closest integer. */ + private static long divideRoundup(long dividend, long divisor) { + return (dividend + divisor - 1) / divisor; + } +} diff --git a/core/java/android/util/apk/ByteBufferDataSource.java b/core/java/android/util/apk/ByteBufferDataSource.java new file mode 100644 index 000000000000..c2b9eff2c161 --- /dev/null +++ b/core/java/android/util/apk/ByteBufferDataSource.java @@ -0,0 +1,65 @@ +/* + * 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 android.util.apk; + +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * {@link DataSource} which provides data from a {@link ByteBuffer}. + */ +class ByteBufferDataSource implements DataSource { + /** + * Underlying buffer. The data is stored between position 0 and the buffer's capacity. + * The buffer's position is 0 and limit is equal to capacity. + */ + private final ByteBuffer mBuf; + + ByteBufferDataSource(ByteBuffer buf) { + // Defensive copy, to avoid changes to mBuf being visible in buf, and to ensure position is + // 0 and limit == capacity. + mBuf = buf.slice(); + } + + @Override + public long size() { + return mBuf.capacity(); + } + + @Override + public void feedIntoDataDigester(DataDigester md, long offset, int size) + throws IOException { + // There's no way to tell MessageDigest to read data from ByteBuffer from a position + // other than the buffer's current position. We thus need to change the buffer's + // position to match the requested offset. + // + // In the future, it may be necessary to compute digests of multiple regions in + // parallel. Given that digest computation is a slow operation, we enable multiple + // such requests to be fulfilled by this instance. This is achieved by serially + // creating a new ByteBuffer corresponding to the requested data range and then, + // potentially concurrently, feeding these buffers into MessageDigest instances. + ByteBuffer region; + synchronized (mBuf) { + mBuf.position(0); + mBuf.limit((int) offset + size); + mBuf.position((int) offset); + region = mBuf.slice(); + } + + md.consume(region); + } +} diff --git a/core/java/android/util/apk/ByteBufferFactory.java b/core/java/android/util/apk/ByteBufferFactory.java new file mode 100644 index 000000000000..7a998822c870 --- /dev/null +++ b/core/java/android/util/apk/ByteBufferFactory.java @@ -0,0 +1,28 @@ +/* + * 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 android.util.apk; + +import java.nio.ByteBuffer; + +/** + * Provider of {@link ByteBuffer} instances. + * @hide + */ +public interface ByteBufferFactory { + /** Initiates a {@link ByteBuffer} with the given size. */ + ByteBuffer create(int capacity); +} diff --git a/core/java/android/util/apk/DataDigester.java b/core/java/android/util/apk/DataDigester.java new file mode 100644 index 000000000000..74dce7e17628 --- /dev/null +++ b/core/java/android/util/apk/DataDigester.java @@ -0,0 +1,27 @@ +/* + * 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 android.util.apk; + +import java.nio.ByteBuffer; + +interface DataDigester { + /** Consumes the {@link ByteBuffer}. */ + void consume(ByteBuffer buffer); + + /** Finishes the digestion. Must be called after the last {@link #consume(ByteBuffer)}. */ + void finish(); +} diff --git a/core/java/android/util/apk/DataSource.java b/core/java/android/util/apk/DataSource.java new file mode 100644 index 000000000000..2b39f491421c --- /dev/null +++ b/core/java/android/util/apk/DataSource.java @@ -0,0 +1,36 @@ +/* + * 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 android.util.apk; + +import java.io.IOException; + +/** Source of data to be digested. */ +interface DataSource { + + /** + * Returns the size (in bytes) of the data offered by this source. + */ + long size(); + + /** + * Feeds the specified region of this source's data into the provided digester. + * + * @param offset offset of the region inside this data source. + * @param size size (in bytes) of the region. + */ + void feedIntoDataDigester(DataDigester md, long offset, int size) throws IOException; +} diff --git a/core/java/android/util/apk/MemoryMappedFileDataSource.java b/core/java/android/util/apk/MemoryMappedFileDataSource.java new file mode 100644 index 000000000000..04a1c6b6bfc5 --- /dev/null +++ b/core/java/android/util/apk/MemoryMappedFileDataSource.java @@ -0,0 +1,104 @@ +/* + * 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 android.util.apk; + +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.DirectByteBuffer; + +/** + * {@link DataSource} which provides data from a file descriptor by memory-mapping the sections + * of the file. + */ +class MemoryMappedFileDataSource implements DataSource { + private static final long MEMORY_PAGE_SIZE_BYTES = Os.sysconf(OsConstants._SC_PAGESIZE); + + private final FileDescriptor mFd; + private final long mFilePosition; + private final long mSize; + + /** + * Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file. + * + * @param position start position of the region in the file. + * @param size size (in bytes) of the region. + */ + MemoryMappedFileDataSource(FileDescriptor fd, long position, long size) { + mFd = fd; + mFilePosition = position; + mSize = size; + } + + @Override + public long size() { + return mSize; + } + + @Override + public void feedIntoDataDigester(DataDigester md, long offset, int size) + throws IOException { + // IMPLEMENTATION NOTE: After a lot of experimentation, the implementation of this + // method was settled on a straightforward mmap with prefaulting. + // + // This method is not using FileChannel.map API because that API does not offset a way + // to "prefault" the resulting memory pages. Without prefaulting, performance is about + // 10% slower on small to medium APKs, but is significantly worse for APKs in 500+ MB + // range. FileChannel.load (which currently uses madvise) doesn't help. Finally, + // invoking madvise (MADV_SEQUENTIAL) after mmap with prefaulting wastes quite a bit of + // time, which is not compensated for by faster reads. + + // We mmap the smallest region of the file containing the requested data. mmap requires + // that the start offset in the file must be a multiple of memory page size. We thus may + // need to mmap from an offset less than the requested offset. + long filePosition = mFilePosition + offset; + long mmapFilePosition = + (filePosition / MEMORY_PAGE_SIZE_BYTES) * MEMORY_PAGE_SIZE_BYTES; + int dataStartOffsetInMmapRegion = (int) (filePosition - mmapFilePosition); + long mmapRegionSize = size + dataStartOffsetInMmapRegion; + long mmapPtr = 0; + try { + mmapPtr = Os.mmap( + 0, // let the OS choose the start address of the region in memory + mmapRegionSize, + OsConstants.PROT_READ, + OsConstants.MAP_SHARED | OsConstants.MAP_POPULATE, // "prefault" all pages + mFd, + mmapFilePosition); + ByteBuffer buf = new DirectByteBuffer( + size, + mmapPtr + dataStartOffsetInMmapRegion, + mFd, // not really needed, but just in case + null, // no need to clean up -- it's taken care of by the finally block + true // read only buffer + ); + md.consume(buf); + } catch (ErrnoException e) { + throw new IOException("Failed to mmap " + mmapRegionSize + " bytes", e); + } finally { + if (mmapPtr != 0) { + try { + Os.munmap(mmapPtr, mmapRegionSize); + } catch (ErrnoException ignored) { } + } + } + } +} diff --git a/core/java/android/util/apk/SignatureInfo.java b/core/java/android/util/apk/SignatureInfo.java new file mode 100644 index 000000000000..8e1233af34a1 --- /dev/null +++ b/core/java/android/util/apk/SignatureInfo.java @@ -0,0 +1,49 @@ +/* + * 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 android.util.apk; + +import java.nio.ByteBuffer; + +/** + * APK Signature Scheme v2 block and additional information relevant to verifying the signatures + * contained in the block against the file. + */ +class SignatureInfo { + /** Contents of APK Signature Scheme v2 block. */ + public final ByteBuffer signatureBlock; + + /** Position of the APK Signing Block in the file. */ + public final long apkSigningBlockOffset; + + /** Position of the ZIP Central Directory in the file. */ + public final long centralDirOffset; + + /** Position of the ZIP End of Central Directory (EoCD) in the file. */ + public final long eocdOffset; + + /** Contents of ZIP End of Central Directory (EoCD) of the file. */ + public final ByteBuffer eocd; + + SignatureInfo(ByteBuffer signatureBlock, long apkSigningBlockOffset, long centralDirOffset, + long eocdOffset, ByteBuffer eocd) { + this.signatureBlock = signatureBlock; + this.apkSigningBlockOffset = apkSigningBlockOffset; + this.centralDirOffset = centralDirOffset; + this.eocdOffset = eocdOffset; + this.eocd = eocd; + } +} diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java index 580456023d68..ab0b3eec8753 100644 --- a/core/java/android/view/NotificationHeaderView.java +++ b/core/java/android/view/NotificationHeaderView.java @@ -20,6 +20,7 @@ import android.annotation.Nullable; import android.app.Notification; import android.content.Context; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Outline; import android.graphics.Rect; @@ -43,6 +44,7 @@ public class NotificationHeaderView extends ViewGroup { public static final int NO_COLOR = Notification.COLOR_INVALID; private final int mChildMinWidth; private final int mContentEndMargin; + private final int mGravity; private View mAppName; private View mHeaderText; private OnClickListener mExpandClickListener; @@ -50,7 +52,6 @@ public class NotificationHeaderView extends ViewGroup { private ImageView mExpandButton; private CachingIconView mIcon; private View mProfileBadge; - private View mInfo; private int mIconColor; private int mOriginalNotificationColor; private boolean mExpanded; @@ -61,6 +62,7 @@ public class NotificationHeaderView extends ViewGroup { private boolean mEntireHeaderClickable; private boolean mExpandOnlyOnButton; private boolean mAcceptAllTouches; + private int mTotalWidth; ViewOutlineProvider mProvider = new ViewOutlineProvider() { @Override @@ -92,6 +94,11 @@ public class NotificationHeaderView extends ViewGroup { mHeaderBackgroundHeight = res.getDimensionPixelSize( R.dimen.notification_header_background_height); mEntireHeaderClickable = res.getBoolean(R.bool.config_notificationHeaderClickableForExpand); + + int[] attrIds = { android.R.attr.gravity }; + TypedArray ta = context.obtainStyledAttributes(attrs, attrIds, defStyleAttr, defStyleRes); + mGravity = ta.getInt(0, 0); + ta.recycle(); } @Override @@ -146,6 +153,7 @@ public class NotificationHeaderView extends ViewGroup { mHeaderText.measure(childWidthSpec, wrapContentHeightSpec); } } + mTotalWidth = Math.min(totalWidth, givenWidth); setMeasuredDimension(givenWidth, givenHeight); } @@ -153,6 +161,10 @@ public class NotificationHeaderView extends ViewGroup { protected void onLayout(boolean changed, int l, int t, int r, int b) { int left = getPaddingStart(); int end = getMeasuredWidth(); + final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0; + if (centerAligned) { + left += getMeasuredWidth() / 2 - mTotalWidth / 2; + } int childCount = getChildCount(); int ownHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); for (int i = 0; i < childCount; i++) { diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 6f8315ae51bf..cd8414791acb 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -1206,56 +1206,65 @@ public class SurfaceControl { } public Transaction show(SurfaceControl sc) { + sc.checkNotReleased(); nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN); return this; } public Transaction hide(SurfaceControl sc) { + sc.checkNotReleased(); nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN); return this; } public Transaction setPosition(SurfaceControl sc, float x, float y) { + sc.checkNotReleased(); nativeSetPosition(mNativeObject, sc.mNativeObject, x, y); return this; } public Transaction setSize(SurfaceControl sc, int w, int h) { - nativeSetSize(mNativeObject, sc.mNativeObject, - w, h); + sc.checkNotReleased(); + nativeSetSize(mNativeObject, sc.mNativeObject, w, h); return this; } public Transaction setLayer(SurfaceControl sc, int z) { + sc.checkNotReleased(); nativeSetLayer(mNativeObject, sc.mNativeObject, z); return this; } public Transaction setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo, int z) { + sc.checkNotReleased(); nativeSetRelativeLayer(mNativeObject, sc.mNativeObject, relativeTo.getHandle(), z); return this; } public Transaction setTransparentRegionHint(SurfaceControl sc, Region transparentRegion) { + sc.checkNotReleased(); nativeSetTransparentRegionHint(mNativeObject, sc.mNativeObject, transparentRegion); return this; } public Transaction setAlpha(SurfaceControl sc, float alpha) { + sc.checkNotReleased(); nativeSetAlpha(mNativeObject, sc.mNativeObject, alpha); return this; } public Transaction setMatrix(SurfaceControl sc, float dsdx, float dtdx, float dtdy, float dsdy) { + sc.checkNotReleased(); nativeSetMatrix(mNativeObject, sc.mNativeObject, dsdx, dtdx, dtdy, dsdy); return this; } public Transaction setWindowCrop(SurfaceControl sc, Rect crop) { + sc.checkNotReleased(); if (crop != null) { nativeSetWindowCrop(mNativeObject, sc.mNativeObject, crop.left, crop.top, crop.right, crop.bottom); @@ -1267,6 +1276,7 @@ public class SurfaceControl { } public Transaction setFinalCrop(SurfaceControl sc, Rect crop) { + sc.checkNotReleased(); if (crop != null) { nativeSetFinalCrop(mNativeObject, sc.mNativeObject, crop.left, crop.top, crop.right, crop.bottom); @@ -1278,40 +1288,48 @@ public class SurfaceControl { } public Transaction setLayerStack(SurfaceControl sc, int layerStack) { + sc.checkNotReleased(); nativeSetLayerStack(mNativeObject, sc.mNativeObject, layerStack); return this; } - public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle, long frameNumber) { + public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle, + long frameNumber) { + sc.checkNotReleased(); nativeDeferTransactionUntil(mNativeObject, sc.mNativeObject, handle, frameNumber); return this; } public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface, long frameNumber) { + sc.checkNotReleased(); nativeDeferTransactionUntilSurface(mNativeObject, sc.mNativeObject, barrierSurface.mNativeObject, frameNumber); return this; } public Transaction reparentChildren(SurfaceControl sc, IBinder newParentHandle) { + sc.checkNotReleased(); nativeReparentChildren(mNativeObject, sc.mNativeObject, newParentHandle); return this; } /** Re-parents a specific child layer to a new parent */ public Transaction reparent(SurfaceControl sc, IBinder newParentHandle) { + sc.checkNotReleased(); nativeReparent(mNativeObject, sc.mNativeObject, newParentHandle); return this; } public Transaction detachChildren(SurfaceControl sc) { + sc.checkNotReleased(); nativeSeverChildren(mNativeObject, sc.mNativeObject); return this; } public Transaction setOverrideScalingMode(SurfaceControl sc, int overrideScalingMode) { + sc.checkNotReleased(); nativeSetOverrideScalingMode(mNativeObject, sc.mNativeObject, overrideScalingMode); return this; @@ -1322,6 +1340,7 @@ public class SurfaceControl { * @param color A float array with three values to represent r, g, b in range [0..1] */ public Transaction setColor(SurfaceControl sc, @Size(3) float[] color) { + sc.checkNotReleased(); nativeSetColor(mNativeObject, sc.mNativeObject, color); return this; } @@ -1334,6 +1353,7 @@ public class SurfaceControl { * (at which point the geometry influencing aspects of this transaction will then occur) */ public Transaction setGeometryAppliesWithResize(SurfaceControl sc) { + sc.checkNotReleased(); nativeSetGeometryAppliesWithResize(mNativeObject, sc.mNativeObject); return this; } @@ -1343,6 +1363,7 @@ public class SurfaceControl { * Surface with the {@link #SECURE} flag. */ Transaction setSecure(SurfaceControl sc, boolean isSecure) { + sc.checkNotReleased(); if (isSecure) { nativeSetFlags(mNativeObject, sc.mNativeObject, SECURE, SECURE); } else { @@ -1356,6 +1377,7 @@ public class SurfaceControl { * Surface with the {@link #OPAQUE} flag. */ public Transaction setOpaque(SurfaceControl sc, boolean isOpaque) { + sc.checkNotReleased(); if (isOpaque) { nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_OPAQUE, SURFACE_OPAQUE); } else { diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index 19213ca06c5e..c3d6c695982d 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -187,8 +187,11 @@ public final class AccessibilityInteractionClient Log.i(LOG_TAG, "Window cache miss"); } final long identityToken = Binder.clearCallingIdentity(); - window = connection.getWindow(accessibilityWindowId); - Binder.restoreCallingIdentity(identityToken); + try { + window = connection.getWindow(accessibilityWindowId); + } finally { + Binder.restoreCallingIdentity(identityToken); + } if (window != null) { sAccessibilityCache.addWindow(window); return window; @@ -225,8 +228,11 @@ public final class AccessibilityInteractionClient Log.i(LOG_TAG, "Windows cache miss"); } final long identityToken = Binder.clearCallingIdentity(); - windows = connection.getWindows(); - Binder.restoreCallingIdentity(identityToken); + try { + windows = connection.getWindows(); + } finally { + Binder.restoreCallingIdentity(identityToken); + } if (windows != null) { sAccessibilityCache.setWindows(windows); return windows; @@ -283,10 +289,14 @@ public final class AccessibilityInteractionClient } final int interactionId = mInteractionIdCounter.getAndIncrement(); final long identityToken = Binder.clearCallingIdentity(); - final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId( - accessibilityWindowId, accessibilityNodeId, interactionId, this, - prefetchFlags, Thread.currentThread().getId(), arguments); - Binder.restoreCallingIdentity(identityToken); + final boolean success; + try { + success = connection.findAccessibilityNodeInfoByAccessibilityId( + accessibilityWindowId, accessibilityNodeId, interactionId, this, + prefetchFlags, Thread.currentThread().getId(), arguments); + } finally { + Binder.restoreCallingIdentity(identityToken); + } if (success) { List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( interactionId); @@ -333,10 +343,15 @@ public final class AccessibilityInteractionClient if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); final long identityToken = Binder.clearCallingIdentity(); - final boolean success = connection.findAccessibilityNodeInfosByViewId( - accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this, - Thread.currentThread().getId()); - Binder.restoreCallingIdentity(identityToken); + final boolean success; + try { + success = connection.findAccessibilityNodeInfosByViewId( + accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this, + Thread.currentThread().getId()); + } finally { + Binder.restoreCallingIdentity(identityToken); + } + if (success) { List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( interactionId); @@ -381,10 +396,15 @@ public final class AccessibilityInteractionClient if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); final long identityToken = Binder.clearCallingIdentity(); - final boolean success = connection.findAccessibilityNodeInfosByText( - accessibilityWindowId, accessibilityNodeId, text, interactionId, this, - Thread.currentThread().getId()); - Binder.restoreCallingIdentity(identityToken); + final boolean success; + try { + success = connection.findAccessibilityNodeInfosByText( + accessibilityWindowId, accessibilityNodeId, text, interactionId, this, + Thread.currentThread().getId()); + } finally { + Binder.restoreCallingIdentity(identityToken); + } + if (success) { List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( interactionId); @@ -428,10 +448,15 @@ public final class AccessibilityInteractionClient if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); final long identityToken = Binder.clearCallingIdentity(); - final boolean success = connection.findFocus(accessibilityWindowId, - accessibilityNodeId, focusType, interactionId, this, - Thread.currentThread().getId()); - Binder.restoreCallingIdentity(identityToken); + final boolean success; + try { + success = connection.findFocus(accessibilityWindowId, + accessibilityNodeId, focusType, interactionId, this, + Thread.currentThread().getId()); + } finally { + Binder.restoreCallingIdentity(identityToken); + } + if (success) { AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( interactionId); @@ -472,10 +497,15 @@ public final class AccessibilityInteractionClient if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); final long identityToken = Binder.clearCallingIdentity(); - final boolean success = connection.focusSearch(accessibilityWindowId, - accessibilityNodeId, direction, interactionId, this, - Thread.currentThread().getId()); - Binder.restoreCallingIdentity(identityToken); + final boolean success; + try { + success = connection.focusSearch(accessibilityWindowId, + accessibilityNodeId, direction, interactionId, this, + Thread.currentThread().getId()); + } finally { + Binder.restoreCallingIdentity(identityToken); + } + if (success) { AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( interactionId); @@ -515,10 +545,15 @@ public final class AccessibilityInteractionClient if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); final long identityToken = Binder.clearCallingIdentity(); - final boolean success = connection.performAccessibilityAction( - accessibilityWindowId, accessibilityNodeId, action, arguments, - interactionId, this, Thread.currentThread().getId()); - Binder.restoreCallingIdentity(identityToken); + final boolean success; + try { + success = connection.performAccessibilityAction( + accessibilityWindowId, accessibilityNodeId, action, arguments, + interactionId, this, Thread.currentThread().getId()); + } finally { + Binder.restoreCallingIdentity(identityToken); + } + if (success) { return getPerformAccessibilityActionResultAndClear(interactionId); } diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 0b9bc5760fa8..35f6acba04dc 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -436,8 +436,11 @@ public final class AccessibilityManager { // client using it is called through Binder from another process. Example: MMS // app adds a SMS notification and the NotificationManagerService calls this method long identityToken = Binder.clearCallingIdentity(); - service.sendAccessibilityEvent(event, userId); - Binder.restoreCallingIdentity(identityToken); + try { + service.sendAccessibilityEvent(event, userId); + } finally { + Binder.restoreCallingIdentity(identityToken); + } if (DEBUG) { Log.i(LOG_TAG, event + " sent"); } diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 6a0669b022f7..a56f86d70cbd 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -1897,7 +1897,7 @@ public final class AutofillManager { public abstract static class AutofillCallback { /** @hide */ - @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN}) + @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN, EVENT_INPUT_UNAVAILABLE}) @Retention(RetentionPolicy.SOURCE) public @interface AutofillEventType {} diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java index e6ef10b3b7c6..71baaf177eac 100644 --- a/core/java/com/android/internal/colorextraction/types/Tonal.java +++ b/core/java/com/android/internal/colorextraction/types/Tonal.java @@ -51,9 +51,11 @@ public class Tonal implements ExtractionType { private static final boolean DEBUG = true; + public static final int THRESHOLD_COLOR_LIGHT = 0xffe0e0e0; public static final int MAIN_COLOR_LIGHT = 0xffe0e0e0; public static final int SECONDARY_COLOR_LIGHT = 0xff9e9e9e; - public static final int MAIN_COLOR_DARK = 0xff212121; + public static final int THRESHOLD_COLOR_DARK = 0xff212121; + public static final int MAIN_COLOR_DARK = 0xff000000; public static final int SECONDARY_COLOR_DARK = 0xff000000; private final TonalPalette mGreyPalette; @@ -197,12 +199,12 @@ public class Tonal implements ExtractionType { // light fallback or darker than our dark fallback. ColorUtils.colorToHSL(mainColor, mTmpHSL); final float mainLuminosity = mTmpHSL[2]; - ColorUtils.colorToHSL(MAIN_COLOR_LIGHT, mTmpHSL); + ColorUtils.colorToHSL(THRESHOLD_COLOR_LIGHT, mTmpHSL); final float lightLuminosity = mTmpHSL[2]; if (mainLuminosity > lightLuminosity) { return false; } - ColorUtils.colorToHSL(MAIN_COLOR_DARK, mTmpHSL); + ColorUtils.colorToHSL(THRESHOLD_COLOR_DARK, mTmpHSL); final float darkLuminosity = mTmpHSL[2]; if (mainLuminosity < darkLuminosity) { return false; diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java index fb6b8b0b2e16..3af3e2ad2772 100644 --- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java +++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java @@ -16,6 +16,10 @@ package com.android.internal.policy; +import static android.view.WindowManager.DOCKED_INVALID; +import static android.view.WindowManager.DOCKED_LEFT; +import static android.view.WindowManager.DOCKED_RIGHT; + import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -99,11 +103,12 @@ public class DividerSnapAlgorithm { public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize, boolean isHorizontalDivision, Rect insets) { - this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets, false); + this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets, + DOCKED_INVALID, false); } public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize, - boolean isHorizontalDivision, Rect insets, boolean isMinimizedMode) { + boolean isHorizontalDivision, Rect insets, int dockSide, boolean isMinimizedMode) { mMinFlingVelocityPxPerSecond = MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density; mMinDismissVelocityPxPerSecond = @@ -121,7 +126,7 @@ public class DividerSnapAlgorithm { com.android.internal.R.dimen.default_minimal_size_resizable_task); mTaskHeightInMinimizedMode = res.getDimensionPixelSize( com.android.internal.R.dimen.task_height_of_minimized_mode); - calculateTargets(isHorizontalDivision); + calculateTargets(isHorizontalDivision, dockSide); mFirstSplitTarget = mTargets.get(1); mLastSplitTarget = mTargets.get(mTargets.size() - 2); mDismissStartTarget = mTargets.get(0); @@ -254,7 +259,7 @@ public class DividerSnapAlgorithm { return mTargets.get(minIndex); } - private void calculateTargets(boolean isHorizontalDivision) { + private void calculateTargets(boolean isHorizontalDivision, int dockedSide) { mTargets.clear(); int dividerMax = isHorizontalDivision ? mDisplayHeight @@ -273,7 +278,7 @@ public class DividerSnapAlgorithm { addMiddleTarget(isHorizontalDivision); break; case SNAP_MODE_MINIMIZED: - addMinimizedTarget(isHorizontalDivision); + addMinimizedTarget(isHorizontalDivision, dockedSide); break; } mTargets.add(new SnapTarget(dividerMax - navBarSize, dividerMax, @@ -331,12 +336,16 @@ public class DividerSnapAlgorithm { mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE)); } - private void addMinimizedTarget(boolean isHorizontalDivision) { + private void addMinimizedTarget(boolean isHorizontalDivision, int dockedSide) { // In portrait offset the position by the statusbar height, in landscape add the statusbar // height as well to match portrait offset int position = mTaskHeightInMinimizedMode + mInsets.top; if (!isHorizontalDivision) { - position += mInsets.left; + if (dockedSide == DOCKED_LEFT) { + position += mInsets.left; + } else if (dockedSide == DOCKED_RIGHT) { + position = mDisplayWidth - position - mInsets.right; + } } mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE)); } diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java index 073aac542e31..26023b499919 100644 --- a/core/java/com/android/internal/widget/NotificationActionListLayout.java +++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java @@ -16,7 +16,10 @@ package com.android.internal.widget; +import android.annotation.Nullable; import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Pair; @@ -37,6 +40,7 @@ import java.util.Comparator; @RemoteViews.RemoteView public class NotificationActionListLayout extends LinearLayout { + private final int mGravity; private int mTotalWidth = 0; private ArrayList<Pair<Integer, TextView>> mMeasureOrderTextViews = new ArrayList<>(); private ArrayList<View> mMeasureOrderOther = new ArrayList<>(); @@ -45,7 +49,20 @@ public class NotificationActionListLayout extends LinearLayout { private Drawable mDefaultBackground; public NotificationActionListLayout(Context context, AttributeSet attrs) { - super(context, attrs); + this(context, attrs, 0); + } + + public NotificationActionListLayout(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public NotificationActionListLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + + int[] attrIds = { android.R.attr.gravity }; + TypedArray ta = context.obtainStyledAttributes(attrs, attrIds, defStyleAttr, defStyleRes); + mGravity = ta.getInt(0, 0); + ta.recycle(); } @Override @@ -95,6 +112,7 @@ public class NotificationActionListLayout extends LinearLayout { final boolean constrained = MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED; + final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0; final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight; final int otherSize = mMeasureOrderOther.size(); @@ -137,7 +155,7 @@ public class NotificationActionListLayout extends LinearLayout { // Make sure to measure the last child full-width if we didn't use up the entire width, // or we didn't measure yet because there's just one child. - if (lastNotGoneChild != null && (constrained && usedWidth < innerWidth + if (lastNotGoneChild != null && !centerAligned && (constrained && usedWidth < innerWidth || notGoneChildren == 1)) { MarginLayoutParams lp = (MarginLayoutParams) lastNotGoneChild.getLayoutParams(); if (notGoneChildren > 1) { @@ -201,9 +219,10 @@ public class NotificationActionListLayout extends LinearLayout { } final boolean isLayoutRtl = isLayoutRtl(); final int paddingTop = mPaddingTop; + final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0; int childTop; - int childLeft; + int childLeft = centerAligned ? left + (right - left) / 2 - mTotalWidth / 2 : 0; // Where bottom of child should go final int height = bottom - top; @@ -216,13 +235,12 @@ public class NotificationActionListLayout extends LinearLayout { final int layoutDirection = getLayoutDirection(); switch (Gravity.getAbsoluteGravity(Gravity.START, layoutDirection)) { case Gravity.RIGHT: - // mTotalWidth contains the padding already - childLeft = mPaddingLeft + right - left - mTotalWidth; + childLeft += mPaddingLeft + right - left - mTotalWidth; break; case Gravity.LEFT: default: - childLeft = mPaddingLeft; + childLeft += mPaddingLeft; break; } diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp index 737ec47e8ffb..bb916d2431c5 100644 --- a/core/jni/android_os_HwBlob.cpp +++ b/core/jni/android_os_HwBlob.cpp @@ -26,6 +26,7 @@ #include <android_runtime/AndroidRuntime.h> #include <hidl/Status.h> #include <nativehelper/ScopedLocalRef.h> +#include <nativehelper/ScopedPrimitiveArray.h> #include "core_jni_helpers.h" @@ -349,6 +350,13 @@ static void JHwBlob_native_copyTo ## Suffix ## Array( \ static_cast<const uint8_t *>(blob->data()) + offset)); \ } +DEFINE_BLOB_ARRAY_COPIER(Int8,jbyte,Byte) +DEFINE_BLOB_ARRAY_COPIER(Int16,jshort,Short) +DEFINE_BLOB_ARRAY_COPIER(Int32,jint,Int) +DEFINE_BLOB_ARRAY_COPIER(Int64,jlong,Long) +DEFINE_BLOB_ARRAY_COPIER(Float,jfloat,Float) +DEFINE_BLOB_ARRAY_COPIER(Double,jdouble,Double) + static void JHwBlob_native_copyToBoolArray( JNIEnv *env, jobject thiz, @@ -386,13 +394,6 @@ static void JHwBlob_native_copyToBoolArray( dst = nullptr; } -DEFINE_BLOB_ARRAY_COPIER(Int8,jbyte,Byte) -DEFINE_BLOB_ARRAY_COPIER(Int16,jshort,Short) -DEFINE_BLOB_ARRAY_COPIER(Int32,jint,Int) -DEFINE_BLOB_ARRAY_COPIER(Int64,jlong,Long) -DEFINE_BLOB_ARRAY_COPIER(Float,jfloat,Float) -DEFINE_BLOB_ARRAY_COPIER(Double,jdouble,Double) - #define DEFINE_BLOB_PUTTER(Suffix,Type) \ static void JHwBlob_native_put ## Suffix( \ JNIEnv *env, jobject thiz, jlong offset, Type x) { \ @@ -458,23 +459,17 @@ static void JHwBlob_native_putString( #define DEFINE_BLOB_ARRAY_PUTTER(Suffix,Type,NewType) \ static void JHwBlob_native_put ## Suffix ## Array( \ JNIEnv *env, jobject thiz, jlong offset, Type ## Array array) { \ + Scoped ## NewType ## ArrayRO autoArray(env, array); \ \ if (array == nullptr) { \ - jniThrowException(env, "java/lang/NullPointerException", nullptr); \ + /* NullpointerException already pending */ \ return; \ } \ \ sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz); \ \ - jsize len = env->GetArrayLength(array); \ - \ - Type *src = \ - env->Get ## NewType ## ArrayElements(array, nullptr /* isCopy */); \ - \ - status_t err = blob->write(offset, src, len * sizeof(Type)); \ - \ - env->Release ## NewType ## ArrayElements(array, src, 0 /* mode */); \ - src = nullptr; \ + status_t err = blob->write( \ + offset, autoArray.get(), autoArray.size() * sizeof(Type)); \ \ if (err != OK) { \ signalExceptionForError(env, err); \ @@ -490,35 +485,28 @@ DEFINE_BLOB_ARRAY_PUTTER(Double,jdouble,Double) static void JHwBlob_native_putBoolArray( JNIEnv *env, jobject thiz, jlong offset, jbooleanArray array) { + ScopedBooleanArrayRO autoArray(env, array); if (array == nullptr) { - jniThrowException(env, "java/lang/NullPointerException", nullptr); + /* NullpointerException already pending */ return; } sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz); - jsize len = env->GetArrayLength(array); - - if ((offset + len * sizeof(bool)) > blob->size()) { + if ((offset + autoArray.size() * sizeof(bool)) > blob->size()) { signalExceptionForError(env, -ERANGE); return; } - const jboolean *src = - env->GetBooleanArrayElements(array, nullptr /* isCopy */); + const jboolean *src = autoArray.get(); bool *dst = reinterpret_cast<bool *>( static_cast<uint8_t *>(blob->data()) + offset); - for (jsize i = 0; i < len; ++i) { + for (size_t i = 0; i < autoArray.size(); ++i) { dst[i] = src[i]; } - - env->ReleaseBooleanArrayElements( - array, const_cast<jboolean *>(src), 0 /* mode */); - - src = nullptr; } static void JHwBlob_native_putBlob( diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index dea38e81cd54..1350f3f46aca 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -171,6 +171,7 @@ static std::atomic<uint32_t> gCollectedAtRefs(0); // Garbage collect if we've allocated at least GC_INTERVAL refs since the last time. // TODO: Consider removing this completely. We should no longer be generating GlobalRefs // that are reclaimed as a result of GC action. +__attribute__((no_sanitize("unsigned-integer-overflow"))) static void gcIfManyNewRefs(JNIEnv* env) { uint32_t totalRefs = gNumLocalRefsCreated.load(std::memory_order_relaxed) diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 77bfec345b1f..4a4de248b2a1 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3062,10 +3062,10 @@ android:protectionLevel="signature|privileged|development|appop" /> <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" /> - <!-- @hide Allows an application to change the app idle state of an app. + <!-- @hide @SystemApi Allows an application to change the app idle state of an app. <p>Not for use by third-party applications. --> <permission android:name="android.permission.CHANGE_APP_IDLE_STATE" - android:protectionLevel="signature" /> + android:protectionLevel="signature|privileged" /> <!-- @hide @SystemApi Allows an application to temporarily whitelist an inactive app to access the network and acquire wakelocks. diff --git a/core/res/res/drawable/dialog_background_material.xml b/core/res/res/drawable/dialog_background_material.xml index 2f8d1fa13eed..e017d3c861a7 100644 --- a/core/res/res/drawable/dialog_background_material.xml +++ b/core/res/res/drawable/dialog_background_material.xml @@ -17,7 +17,7 @@ <inset xmlns:android="http://schemas.android.com/apk/res/android" android:inset="16dp"> <shape android:shape="rectangle"> - <corners android:radius="2dp" /> + <corners android:radius="?attr/dialogCornerRadius" /> <solid android:color="?attr/colorBackground" /> </shape> </inset> diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml index f0c980c703cc..3a28f4d76f7c 100644 --- a/core/res/res/layout/notification_template_header.xml +++ b/core/res/res/layout/notification_template_header.xml @@ -37,6 +37,7 @@ android:textAppearance="?attr/notificationHeaderTextAppearance" android:layout_marginStart="@dimen/notification_header_app_name_margin_start" android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:visibility="?attr/notificationHeaderAppNameVisibility" android:singleLine="true" /> <TextView diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml index ee5c758cc130..865685ff26f5 100644 --- a/core/res/res/layout/notification_template_material_ambient.xml +++ b/core/res/res/layout/notification_template_material_ambient.xml @@ -23,8 +23,8 @@ android:paddingStart="@dimen/notification_extra_margin_ambient" android:paddingEnd="@dimen/notification_extra_margin_ambient" > - <include layout="@layout/notification_template_header" - android:theme="@style/Theme.Material.Notification.Ambient" /> + <include layout="@layout/notification_template_ambient_header" + android:theme="@style/Theme.Material.Notification.Ambient" /> <LinearLayout android:id="@+id/notification_action_list_margin_target" @@ -53,6 +53,7 @@ android:textAppearance="@style/TextAppearance.Material.Notification.Title" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:gravity="top|center_horizontal" android:singleLine="true" android:ellipsize="marquee" android:fadingEdge="horizontal" @@ -65,7 +66,7 @@ android:textAppearance="@style/TextAppearance.Material.Notification" android:singleLine="false" android:layout_weight="1" - android:gravity="top" + android:gravity="top|center_horizontal" android:visibility="gone" android:textSize="16sp" android:textColor="#eeffffff" @@ -75,5 +76,19 @@ /> </LinearLayout> </LinearLayout> - <include layout="@layout/notification_material_action_list" /> + <FrameLayout android:id="@+id/actions_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom"> + <com.android.internal.widget.NotificationActionListLayout + android:id="@+id/actions" + android:layout_width="match_parent" + android:layout_height="@dimen/notification_action_list_height" + android:paddingEnd="4dp" + android:orientation="horizontal" + android:gravity="center" + android:visibility="gone" + android:background="@color/notification_action_list" + /> + </FrameLayout> </FrameLayout> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index db4dcd2ec1a9..0eefec91e390 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -984,6 +984,8 @@ <attr name="dialogTitleDecorLayout" format="reference" /> <!-- Preferred padding for dialog content. --> <attr name="dialogPreferredPadding" format="dimension" /> + <!-- Corner radius of dialogs. --> + <attr name="dialogCornerRadius" format="dimension" /> <!-- Theme to use for alert dialogs spawned from this theme. --> <attr name="alertDialogTheme" format="reference" /> @@ -8713,6 +8715,14 @@ <attr name="notificationHeaderStyle" format="reference" /> <attr name="notificationHeaderTextAppearance" format="reference" /> <attr name="notificationHeaderIconSize" format="dimension" /> + <attr name="notificationHeaderAppNameVisibility" format="enum"> + <!-- Visible on screen; the default value. --> + <enum name="visible" value="0" /> + <!-- Not displayed, but taken into account during layout (space is left for it). --> + <enum name="invisible" value="1" /> + <!-- Completely hidden, as if the view had not been added. --> + <enum name="gone" value="2" /> + </attr> </declare-styleable> <attr name="lockPatternStyle" format="reference" /> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index bce950df77f8..1c2e5a406772 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2524,7 +2524,13 @@ <bool name="config_networkSamplingWakesDevice">true</bool> - <string-array translatable="false" name="config_cdma_home_system" /> + <!-- Home (non-roaming) values for CDMA roaming indicator. + Carriers can override this table by resource overlay. If not, + the default values come from 3GPP2 C.R1001 table + 8.1-1. Enhanced Roaming Indicator Number Assignments --> + <string-array translatable="false" name="config_cdma_home_system"> + <item>1</item> + </string-array> <!--From SmsMessage--> <!--Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet @@ -3152,4 +3158,7 @@ <!-- Component name of media projection permission dialog --> <string name="config_mediaProjectionPermissionDialogComponent" translateable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string> + + <!-- Corner radius of system dialogs --> + <dimen name="config_dialogCornerRadius">2dp</dimen> </resources> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index dc75ba6077e7..947fcf127b9c 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -624,4 +624,7 @@ <dimen name="slice_icon_size">24dp</dimen> <!-- Standard padding used in a slice view --> <dimen name="slice_padding">16dp</dimen> + + <!-- Default dialog corner radius --> + <dimen name="dialog_corner_radius">2dp</dimen> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 083bf90210a5..fdd56c410ed2 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2847,6 +2847,7 @@ <public name="cantSaveState" /> <public name="ttcIndex" /> <public name="fontVariationSettings" /> + <public name="dialogCornerRadius" /> </public-group> <public-group type="style" first-id="0x010302e0"> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index 470ac522aa33..cddf99a2df23 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -1296,6 +1296,11 @@ please see styles_device_defaults.xml. <item name="layout_marginBottom">@dimen/notification_header_margin_bottom</item> <item name="paddingStart">@dimen/notification_content_margin_start</item> <item name="paddingEnd">16dp</item> + <item name="gravity">top</item> + </style> + + <style name="Notification.Header.Ambient"> + <item name="gravity">top|center_horizontal</item> </style> </resources> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index bf0c90660392..68d552367423 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -88,6 +88,7 @@ easier. <!-- Dialog attributes --> <item name="dialogTheme">@style/Theme.DeviceDefault.Dialog</item> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> <!-- AlertDialog attributes --> <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> @@ -214,6 +215,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme @@ -223,6 +228,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and @@ -234,6 +243,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent @@ -244,6 +257,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be @@ -263,6 +280,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a @@ -272,6 +293,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar --> @@ -280,6 +305,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width @@ -289,6 +318,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. --> @@ -314,6 +347,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- DeviceDefault theme for a window without an action bar that will be displayed either @@ -324,6 +361,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- DeviceDefault theme for a presentation window on a secondary display. --> @@ -332,6 +373,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- DeviceDefault theme for panel windows. This removes all extraneous window @@ -342,6 +387,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear @@ -351,6 +400,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear @@ -360,6 +413,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- DeviceDefault style for input methods, which is used by the @@ -369,6 +426,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- DeviceDefault style for input methods, which is used by the @@ -378,11 +439,19 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert"> <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item> + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> + <!-- Color palette --> <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> @@ -394,6 +463,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame"> @@ -401,6 +474,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style --> @@ -441,6 +518,7 @@ easier. <!-- Dialog attributes --> <item name="dialogTheme">@style/Theme.DeviceDefault.Light.Dialog</item> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> <!-- AlertDialog attributes --> <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> @@ -562,6 +640,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_dark</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar --> @@ -570,6 +652,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar. @@ -579,6 +665,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar @@ -590,6 +680,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent @@ -600,6 +694,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be @@ -609,6 +707,10 @@ easier. <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item> <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item> + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> + <item name="buttonBarStyle">@style/DeviceDefault.Light.ButtonBar.AlertDialog</item> <item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Light.Button.Borderless.Small</item> @@ -628,6 +730,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar --> @@ -636,6 +742,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum @@ -645,6 +755,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. --> @@ -680,6 +794,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- DeviceDefault light theme for a window without an action bar that will be displayed either @@ -690,6 +808,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- DeviceDefault light theme for a presentation window on a secondary display. --> @@ -698,6 +820,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- DeviceDefault light theme for panel windows. This removes all extraneous window @@ -708,6 +834,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert"> @@ -717,6 +847,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar"> @@ -724,6 +858,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice"> @@ -731,6 +869,10 @@ easier. <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- DeviceDefault theme for a window that should look like the Settings app. --> @@ -750,6 +892,10 @@ easier. <item name="navigationBarDividerColor">#1f000000</item> <item name="navigationBarColor">@android:color/white</item> <item name="windowLightNavigationBar">true</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- @hide DeviceDefault theme for a window that should use Settings theme colors @@ -761,6 +907,7 @@ easier. <item name="colorSecondary">@color/secondary_device_default_settings_light</item> <item name="colorAccent">@color/accent_device_default_light</item> <item name="colorControlNormal">?attr/textColorPrimary</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Light.Dialog"> @@ -769,6 +916,7 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_settings_light</item> <item name="colorSecondary">@color/secondary_device_default_settings_light</item> <item name="colorAccent">@color/accent_device_default_light</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar --> @@ -778,6 +926,10 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item> <item name="colorSecondary">@color/secondary_device_default_settings</item> <item name="colorAccent">@color/accent_device_default_dark</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> </style> <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.Material.Settings.Dialog"> @@ -786,6 +938,10 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item> <item name="colorSecondary">@color/secondary_device_default_settings</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.Material.Settings.DialogWhenLarge"> @@ -794,6 +950,10 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item> <item name="colorSecondary">@color/secondary_device_default_settings</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert"> @@ -802,9 +962,13 @@ easier. <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item> <item name="colorSecondary">@color/secondary_device_default_settings</item> <item name="colorAccent">@color/accent_device_default_light</item> + + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> </style> - <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar"/> + <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" /> <!-- Theme used for the intent picker activity. --> <style name="Theme.DeviceDefault.Resolver" parent="Theme.Material.Light"> @@ -820,6 +984,10 @@ easier. <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item> <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item> + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> + <!-- Color palette --> <item name="colorPrimary">@color/primary_device_default_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item> @@ -831,7 +999,7 @@ easier. <style name="ThemeOverlay.DeviceDefault" /> - <!-- @hide Theme overlay that inherits from material actionbar, and use accent color for + <!-- @hide Theme overlay that inherits from material actionbar, and use accent color for primary text --> <style name="ThemeOverlay.DeviceDefault.ActionBar.Accent" parent="ThemeOverlay.Material.ActionBar"> <item name="textColorPrimary">@color/btn_colored_borderless_text_material</item> diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml index 9bea3eeeb9ac..c31712136eed 100644 --- a/core/res/res/values/themes_material.xml +++ b/core/res/res/values/themes_material.xml @@ -186,6 +186,7 @@ please see themes_device_defaults.xml. <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item> <item name="dialogTitleDecorLayout">@layout/dialog_title_material</item> <item name="dialogPreferredPadding">@dimen/dialog_padding_material</item> + <item name="dialogCornerRadius">@dimen/dialog_corner_radius</item> <!-- AlertDialog attributes --> <item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog.Alert</item> @@ -554,6 +555,7 @@ please see themes_device_defaults.xml. <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item> <item name="dialogTitleDecorLayout">@layout/dialog_title_material</item> <item name="dialogPreferredPadding">@dimen/dialog_padding_material</item> + <item name="dialogCornerRadius">@dimen/dialog_corner_radius</item> <!-- AlertDialog attributes --> <item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog.Alert</item> @@ -1325,12 +1327,15 @@ please see themes_device_defaults.xml. <style name="Theme.Material.Notification" parent=""> <item name="notificationHeaderStyle">@style/Notification.Header</item> <item name="notificationHeaderTextAppearance">@style/TextAppearance.Material.Notification.Info</item> + <item name="notificationHeaderAppNameVisibility">visible</item> <item name="notificationHeaderIconSize">@dimen/notification_header_icon_size</item> </style> <!-- Theme for inflating ambient notification --> <style name="Theme.Material.Notification.Ambient"> + <item name="notificationHeaderStyle">@style/Notification.Header.Ambient</item> <item name="notificationHeaderTextAppearance">@style/TextAppearance.Material.Notification.Info.Ambient</item> + <item name="notificationHeaderAppNameVisibility">gone</item> <item name="notificationHeaderIconSize">@dimen/notification_header_icon_size_ambient</item> </style> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 2f9ae578ade1..82aa803ef0ca 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -232,6 +232,7 @@ applications that come with the platform <permission name="android.permission.BACKUP"/> <permission name="android.permission.BATTERY_STATS"/> <permission name="android.permission.BLUETOOTH_PRIVILEGED"/> + <permission name="android.permission.CHANGE_APP_IDLE_STATE"/> <permission name="android.permission.CHANGE_CONFIGURATION"/> <permission name="android.permission.DELETE_PACKAGES"/> <permission name="android.permission.FORCE_STOP_PACKAGES"/> @@ -266,6 +267,7 @@ applications that come with the platform <permission name="android.permission.BACKUP"/> <permission name="android.permission.BATTERY_STATS"/> <permission name="android.permission.BIND_APPWIDGET"/> + <permission name="android.permission.CHANGE_APP_IDLE_STATE"/> <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> <permission name="android.permission.CHANGE_CONFIGURATION"/> <permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" /> diff --git a/data/keyboards/Vendor_045e_Product_02e0.kl b/data/keyboards/Vendor_045e_Product_02e0.kl new file mode 100644 index 000000000000..1012fb1eb28d --- /dev/null +++ b/data/keyboards/Vendor_045e_Product_02e0.kl @@ -0,0 +1,59 @@ +# 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. + +# +# Xbox Wireless Controller +# + + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 0x132 BUTTON_X +key 0x130 BUTTON_A +key 0x131 BUTTON_B +key 0x133 BUTTON_Y + +key 0x134 BUTTON_L1 +key 0x135 BUTTON_R1 + +# LT axis +axis 0x02 LTRIGGER +# RT axis +axis 0x05 RTRIGGER + + +# Left Analog Stick +axis 0x00 X +axis 0x01 Y +# Right Analog Stick +axis 0x03 Z +axis 0x04 RZ + +# Left stick click +key 0x138 BUTTON_THUMBL +# Right stick click +key 0x139 BUTTON_THUMBR + +# Hat +axis 0x10 HAT_X +axis 0x11 HAT_Y + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 0x136 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 0x137 BUTTON_START + +# Xbox key +key 0x8b HOME
\ No newline at end of file diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp index 5abfc8ee917e..5d243da2097c 100644 --- a/libs/androidfw/ZipUtils.cpp +++ b/libs/androidfw/ZipUtils.cpp @@ -20,10 +20,11 @@ #define LOG_TAG "ziputil" +#include "android-base/file.h" #include <androidfw/ZipUtils.h> -#include <androidfw/ZipFileRO.h> #include <utils/Log.h> #include <utils/Compat.h> +#include <ziparchive/zip_archive.h> #include <stdlib.h> #include <string.h> @@ -33,211 +34,121 @@ using namespace android; -static inline unsigned long get4LE(const unsigned char* buf) { - return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); -} - - -static const unsigned long kReadBufSize = 32768; - -/* - * Utility function that expands zip/gzip "deflate" compressed data - * into a buffer. - * - * (This is a clone of the previous function, but it takes a FILE* instead - * of an fd. We could pass fileno(fd) to the above, but we can run into - * trouble when "fp" has a different notion of what fd's file position is.) - * - * "fp" is an open file positioned at the start of the "deflate" data - * "buf" must hold at least "uncompressedLen" bytes. - */ -/*static*/ template<typename T> bool inflateToBuffer(T& reader, void* buf, - long uncompressedLen, long compressedLen) -{ - bool result = false; - - z_stream zstream; - int zerr; - unsigned long compRemaining; - - assert(uncompressedLen >= 0); - assert(compressedLen >= 0); - - compRemaining = compressedLen; - - /* - * Initialize the zlib stream. - */ - memset(&zstream, 0, sizeof(zstream)); - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.next_in = NULL; - zstream.avail_in = 0; - zstream.next_out = (Bytef*) buf; - zstream.avail_out = uncompressedLen; - zstream.data_type = Z_UNKNOWN; - - /* - * Use the undocumented "negative window bits" feature to tell zlib - * that there's no zlib header waiting for it. - */ - zerr = inflateInit2(&zstream, -MAX_WBITS); - if (zerr != Z_OK) { - if (zerr == Z_VERSION_ERROR) { - ALOGE("Installed zlib is not compatible with linked version (%s)\n", - ZLIB_VERSION); - } else { - ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr); - } - goto bail; +// TODO: This can go away once the only remaining usage in aapt goes away. +class FileReader : public zip_archive::Reader { + public: + FileReader(FILE* fp) : Reader(), mFp(fp), mCurrentOffset(0) { } - /* - * Loop while we have data. - */ - do { - unsigned long getSize; - - /* read as much as we can */ - if (zstream.avail_in == 0) { - getSize = (compRemaining > kReadBufSize) ? - kReadBufSize : compRemaining; - ALOGV("+++ reading %ld bytes (%ld left)\n", - getSize, compRemaining); - - unsigned char* nextBuffer = NULL; - const unsigned long nextSize = reader.read(&nextBuffer, getSize); - - if (nextSize < getSize || nextBuffer == NULL) { - ALOGD("inflate read failed (%ld vs %ld)\n", nextSize, getSize); - goto z_bail; + bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const { + // Data is usually requested sequentially, so this helps avoid pointless + // fseeks every time we perform a read. There's an impedence mismatch + // here because the original API was designed around pread and pwrite. + if (offset != mCurrentOffset) { + if (fseek(mFp, offset, SEEK_SET) != 0) { + return false; } - compRemaining -= nextSize; - - zstream.next_in = nextBuffer; - zstream.avail_in = nextSize; + mCurrentOffset = offset; } - /* uncompress the data */ - zerr = inflate(&zstream, Z_NO_FLUSH); - if (zerr != Z_OK && zerr != Z_STREAM_END) { - ALOGD("zlib inflate call failed (zerr=%d)\n", zerr); - goto z_bail; + size_t read = fread(buf, 1, len, mFp); + if (read != len) { + return false; } - /* output buffer holds all, so no need to write the output */ - } while (zerr == Z_OK); - - assert(zerr == Z_STREAM_END); /* other errors should've been caught */ - - if ((long) zstream.total_out != uncompressedLen) { - ALOGW("Size mismatch on inflated file (%ld vs %ld)\n", - zstream.total_out, uncompressedLen); - goto z_bail; + mCurrentOffset += read; + return true; } - // success! - result = true; - -z_bail: - inflateEnd(&zstream); /* free up any allocated structures */ - -bail: - return result; -} - -class FileReader { -public: - explicit FileReader(FILE* fp) : - mFp(fp), mReadBuf(new unsigned char[kReadBufSize]) - { - } + private: + FILE* mFp; + mutable uint32_t mCurrentOffset; +}; - ~FileReader() { - delete[] mReadBuf; - } +class FdReader : public zip_archive::Reader { + public: + explicit FdReader(int fd) : mFd(fd) { + } - long read(unsigned char** nextBuffer, long readSize) const { - *nextBuffer = mReadBuf; - return fread(mReadBuf, 1, readSize, mFp); - } + bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const { + return android::base::ReadFullyAtOffset(mFd, buf, len, static_cast<off_t>(offset)); + } - FILE* mFp; - unsigned char* mReadBuf; + private: + const int mFd; }; -class FdReader { -public: - explicit FdReader(int fd) : - mFd(fd), mReadBuf(new unsigned char[kReadBufSize]) - { - } +class BufferReader : public zip_archive::Reader { + public: + BufferReader(const void* input, size_t inputSize) : Reader(), + mInput(reinterpret_cast<const uint8_t*>(input)), + mInputSize(inputSize) { + } - ~FdReader() { - delete[] mReadBuf; - } + bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const { + if (offset + len > mInputSize) { + return false; + } - long read(unsigned char** nextBuffer, long readSize) const { - *nextBuffer = mReadBuf; - return TEMP_FAILURE_RETRY(::read(mFd, mReadBuf, readSize)); - } + memcpy(buf, mInput + offset, len); + return true; + } - int mFd; - unsigned char* mReadBuf; + private: + const uint8_t* mInput; + const size_t mInputSize; }; -class BufferReader { -public: - BufferReader(void* input, size_t inputSize) : - mInput(reinterpret_cast<unsigned char*>(input)), - mInputSize(inputSize), - mBufferReturned(false) - { +class BufferWriter : public zip_archive::Writer { + public: + BufferWriter(void* output, size_t outputSize) : Writer(), + mOutput(reinterpret_cast<uint8_t*>(output)), mOutputSize(outputSize), mBytesWritten(0) { } - long read(unsigned char** nextBuffer, long /*readSize*/) { - if (!mBufferReturned) { - mBufferReturned = true; - *nextBuffer = mInput; - return mInputSize; + bool Append(uint8_t* buf, size_t bufSize) override { + if (mBytesWritten + bufSize > mOutputSize) { + return false; } - *nextBuffer = NULL; - return 0; + memcpy(mOutput + mBytesWritten, buf, bufSize); + mBytesWritten += bufSize; + return true; } - unsigned char* mInput; - const size_t mInputSize; - bool mBufferReturned; + private: + uint8_t* const mOutput; + const size_t mOutputSize; + size_t mBytesWritten; }; /*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf, long uncompressedLen, long compressedLen) { FileReader reader(fp); - return ::inflateToBuffer<FileReader>(reader, buf, - uncompressedLen, compressedLen); + BufferWriter writer(buf, uncompressedLen); + return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0); } /*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf, long uncompressedLen, long compressedLen) { FdReader reader(fd); - return ::inflateToBuffer<FdReader>(reader, buf, - uncompressedLen, compressedLen); + BufferWriter writer(buf, uncompressedLen); + return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0); } -/*static*/ bool ZipUtils::inflateToBuffer(void* in, void* buf, +/*static*/ bool ZipUtils::inflateToBuffer(const void* in, void* buf, long uncompressedLen, long compressedLen) { BufferReader reader(in, compressedLen); - return ::inflateToBuffer<BufferReader>(reader, buf, - uncompressedLen, compressedLen); + BufferWriter writer(buf, uncompressedLen); + return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0); } - +static inline unsigned long get4LE(const unsigned char* buf) { + return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); +} /* * Look at the contents of a gzip archive. We want to know where the @@ -275,7 +186,7 @@ public: /* quick sanity checks */ if (method == EOF || flags == EOF) return false; - if (method != ZipFileRO::kCompressDeflated) + if (method != kCompressDeflated) return false; /* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */ diff --git a/libs/androidfw/include/androidfw/ZipUtils.h b/libs/androidfw/include/androidfw/ZipUtils.h index 55575d774522..4d35e992cc89 100644 --- a/libs/androidfw/include/androidfw/ZipUtils.h +++ b/libs/androidfw/include/androidfw/ZipUtils.h @@ -40,7 +40,7 @@ public: long compressedLen); static bool inflateToBuffer(int fd, void* buf, long uncompressedLen, long compressedLen); - static bool inflateToBuffer(void *in, void* buf, long uncompressedLen, + static bool inflateToBuffer(const void *in, void* buf, long uncompressedLen, long compressedLen); /* diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp index a5b4c42d68d2..8e7b6b64cb30 100644 --- a/libs/hwui/hwui/MinikinSkia.cpp +++ b/libs/hwui/hwui/MinikinSkia.cpp @@ -31,22 +31,23 @@ MinikinFontSkia::MinikinFontSkia(sk_sp<SkTypeface> typeface, const void* fontDat } static void MinikinFontSkia_SetSkiaPaint(const minikin::MinikinFont* font, SkPaint* skPaint, - const minikin::MinikinPaint& paint) { + const minikin::MinikinPaint& paint, const minikin::FontFakery& fakery) { skPaint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); skPaint->setTextSize(paint.size); skPaint->setTextScaleX(paint.scaleX); skPaint->setTextSkewX(paint.skewX); MinikinFontSkia::unpackPaintFlags(skPaint, paint.paintFlags); // Apply font fakery on top of user-supplied flags. - MinikinFontSkia::populateSkPaint(skPaint, font, paint.fakery); + MinikinFontSkia::populateSkPaint(skPaint, font, fakery); } float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id, - const minikin::MinikinPaint &paint) const { + const minikin::MinikinPaint &paint, + const minikin::FontFakery& fakery) const { SkPaint skPaint; uint16_t glyph16 = glyph_id; SkScalar skWidth; - MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint); + MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint, fakery); skPaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, NULL); #ifdef VERBOSE ALOGD("width for typeface %d glyph %d = %f", mTypeface->uniqueID(), glyph_id, skWidth); @@ -55,11 +56,12 @@ float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id, } void MinikinFontSkia::GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id, - const minikin::MinikinPaint& paint) const { + const minikin::MinikinPaint& paint, + const minikin::FontFakery& fakery) const { SkPaint skPaint; uint16_t glyph16 = glyph_id; SkRect skBounds; - MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint); + MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint, fakery); skPaint.getTextWidths(&glyph16, sizeof(glyph16), NULL, &skBounds); bounds->mLeft = skBounds.fLeft; bounds->mTop = skBounds.fTop; @@ -68,9 +70,10 @@ void MinikinFontSkia::GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id, } void MinikinFontSkia::GetFontExtent(minikin::MinikinExtent* extent, - const minikin::MinikinPaint& paint) const { + const minikin::MinikinPaint& paint, + const minikin::FontFakery& fakery) const { SkPaint skPaint; - MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint); + MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint, fakery); SkPaint::FontMetrics metrics; skPaint.getFontMetrics(&metrics); extent->ascent = metrics.fAscent; diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h index a19f4a769444..30fd500b4598 100644 --- a/libs/hwui/hwui/MinikinSkia.h +++ b/libs/hwui/hwui/MinikinSkia.h @@ -32,13 +32,16 @@ public: int ttcIndex, const std::vector<minikin::FontVariation>& axes); float GetHorizontalAdvance(uint32_t glyph_id, - const minikin::MinikinPaint &paint) const; + const minikin::MinikinPaint& paint, + const minikin::FontFakery& fakery) const override; void GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id, - const minikin::MinikinPaint &paint) const; + const minikin::MinikinPaint& paint, + const minikin::FontFakery& fakery) const override; void GetFontExtent(minikin::MinikinExtent* extent, - const minikin::MinikinPaint &paint) const; + const minikin::MinikinPaint& paint, + const minikin::FontFakery& fakery) const override; SkTypeface* GetSkTypeface() const; sk_sp<SkTypeface> RefSkTypeface() const; diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java index 88b1c5ffcc7e..1feea8907cd4 100644 --- a/media/java/android/media/MediaDrm.java +++ b/media/java/android/media/MediaDrm.java @@ -994,7 +994,6 @@ public final class MediaDrm { * {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION}, * {@link #PROPERTY_DESCRIPTION}, {@link #PROPERTY_ALGORITHMS} */ - /* FIXME this throws IllegalStateException for invalid property names */ @NonNull public native String getPropertyString(@NonNull @StringProperty String propertyName); @@ -1002,7 +1001,6 @@ public final class MediaDrm { * Byte array property name: the device unique identifier is established during * device provisioning and provides a means of uniquely identifying each device. */ - /* FIXME this throws IllegalStateException for invalid property names */ public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId"; /** @hide */ diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index d0c2aea1affc..51c9e5f1c7da 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -282,7 +282,7 @@ static bool throwExceptionAsNecessary( drmMessage = "Decrypt error"; break; case ERROR_DRM_CANNOT_HANDLE: - drmMessage = "Unsupported scheme or data format"; + drmMessage = "Invalid parameter or data format"; break; case ERROR_DRM_TAMPER_DETECTED: drmMessage = "Invalid state"; @@ -297,7 +297,7 @@ static bool throwExceptionAsNecessary( drmMessage = vendorMessage.string(); } - if (err == BAD_VALUE) { + if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) { jniThrowException(env, "java/lang/IllegalArgumentException", msg); return true; } else if (err == ERROR_DRM_NOT_PROVISIONED) { diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java index 32e6389dc34f..c3a36e97be3a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java @@ -28,6 +28,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.graphics.drawable.Drawable; import android.os.RemoteException; @@ -343,7 +344,8 @@ public class RestrictedLockUtils { } DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( Context.DEVICE_POLICY_SERVICE); - if (dpm == null) { + PackageManager pm = context.getPackageManager(); + if (!pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) || dpm == null) { return null; } boolean isAccountTypeDisabled = false; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java index ca366ea4b6cc..64de63520f87 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java @@ -33,6 +33,7 @@ import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.UserManager; @@ -56,6 +57,8 @@ public class RestrictedLockUtilsTest { private DevicePolicyManager mDevicePolicyManager; @Mock private UserManager mUserManager; + @Mock + private PackageManager mPackageManager; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private RestrictedLockUtils.Proxy mProxy; @@ -72,11 +75,32 @@ public class RestrictedLockUtilsTest { .thenReturn(mDevicePolicyManager); when(mContext.getSystemService(Context.USER_SERVICE)) .thenReturn(mUserManager); + when(mContext.getPackageManager()) + .thenReturn(mPackageManager); RestrictedLockUtils.sProxy = mProxy; } @Test + public void checkIfDevicePolicyServiceDisabled_noEnforceAdminForManagedProfile() { + when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(null); + final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfAccountManagementDisabled( + mContext, "account_type", mUserId); + + assertThat(enforcedAdmin).isEqualTo(null); + } + + @Test + public void checkIfDeviceAdminFeatureDisabled_noEnforceAdminForManagedProfile() { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) + .thenReturn(false); + final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfAccountManagementDisabled( + mContext, "account_type", mUserId); + + assertThat(enforcedAdmin).isEqualTo(null); + } + + @Test public void checkIfKeyguardFeaturesDisabled_noEnforcedAdminForManagedProfile() { setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2}); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java index 806a07387b69..f92509d8ab5b 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java @@ -70,21 +70,6 @@ public class RecentsTaskLoadPlan { } /** - * An optimization to preload the raw list of tasks. The raw tasks are saved in least-recent - * to most-recent order. - * - * Note: Do not lock, callers should synchronize on the loader before making this call. - */ - void preloadRawTasks() { - int currentUserId = ActivityManagerWrapper.getInstance().getCurrentUserId(); - mRawTasks = ActivityManagerWrapper.getInstance().getRecentTasks( - ActivityManager.getMaxRecentTasksStatic(), currentUserId); - - // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it - Collections.reverse(mRawTasks); - } - - /** * Preloads the list of recent tasks from the system. After this call, the TaskStack will * have a list of all the recent tasks with their metadata, not including icons or * thumbnails which were not cached and have to be loaded. @@ -95,11 +80,15 @@ public class RecentsTaskLoadPlan { * Note: Do not lock, since this can be calling back to the loader, which separately also drives * this call (callers should synchronize on the loader before making this call). */ - void preloadPlan(RecentsTaskLoader loader, int runningTaskId) { + public void preloadPlan(RecentsTaskLoader loader, int runningTaskId, int currentUserId) { Resources res = mContext.getResources(); ArrayList<Task> allTasks = new ArrayList<>(); if (mRawTasks == null) { - preloadRawTasks(); + mRawTasks = ActivityManagerWrapper.getInstance().getRecentTasks( + ActivityManager.getMaxRecentTasksStatic(), currentUserId); + + // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it + Collections.reverse(mRawTasks); } int taskCount = mRawTasks.size(); @@ -160,7 +149,7 @@ public class RecentsTaskLoadPlan { * Note: Do not lock, since this can be calling back to the loader, which separately also drives * this call (callers should synchronize on the loader before making this call). */ - void executePlan(Options opts, RecentsTaskLoader loader) { + public void executePlan(Options opts, RecentsTaskLoader loader) { Resources res = mContext.getResources(); // Iterate through each of the tasks and load them according to the load conditions. diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java index de4c72c2ee6a..9a991cfa0699 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java @@ -147,9 +147,15 @@ public class RecentsTaskLoader { /** Preloads recents tasks using the specified plan to store the output. */ public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId) { + preloadTasks(plan, runningTaskId, ActivityManagerWrapper.getInstance().getCurrentUserId()); + } + + /** Preloads recents tasks using the specified plan to store the output. */ + public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId, + int currentUserId) { try { Trace.beginSection("preloadPlan"); - plan.preloadPlan(this, runningTaskId); + plan.preloadPlan(this, runningTaskId, currentUserId); } finally { Trace.endSection(); } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java index 9a1ff544800d..5f3dcd16e074 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java @@ -21,7 +21,7 @@ import android.util.SparseArray; /** * An interface for a task filter to query whether a particular task should show in a stack. */ -interface TaskFilter { +public interface TaskFilter { /** Returns whether the filter accepts the specified task */ boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index); } 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 090617dc89c5..db1583ab132a 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 @@ -17,10 +17,17 @@ package com.android.systemui.shared.system; import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +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.NonNull; import android.app.ActivityManager; import android.app.ActivityManager.RecentTaskInfo; +import android.app.ActivityOptions; import android.app.AppGlobals; import android.content.Context; import android.content.pm.ActivityInfo; @@ -32,15 +39,19 @@ import android.content.res.Resources.NotFoundException; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.util.IconDrawableFactory; import android.util.Log; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.Task.TaskKey; import com.android.systemui.shared.recents.model.ThumbnailData; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; public class ActivityManagerWrapper { @@ -77,6 +88,25 @@ public class ActivityManagerWrapper { } /** + * @return the top running task (can be {@code null}). + */ + public ActivityManager.RunningTaskInfo getRunningTask() { + // Note: The set of running tasks from the system is ordered by recency + try { + List<ActivityManager.RunningTaskInfo> tasks = + ActivityManager.getService().getFilteredTasks(1, + ACTIVITY_TYPE_RECENTS /* ignoreActivityType */, + WINDOWING_MODE_PINNED /* ignoreWindowingMode */); + if (tasks.isEmpty()) { + return null; + } + return tasks.get(0); + } catch (RemoteException e) { + return null; + } + } + + /** * @return a list of the recents tasks. */ public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) { @@ -202,6 +232,60 @@ public class ActivityManagerWrapper { } /** + * Starts a task from Recents. + * + * @see {@link #startActivityFromRecents(TaskKey, ActivityOptions, int, int, Consumer, Handler)} + */ + public void startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options, + Consumer<Boolean> resultCallback, Handler resultCallbackHandler) { + startActivityFromRecents(taskKey, options, WINDOWING_MODE_UNDEFINED, + ACTIVITY_TYPE_UNDEFINED, resultCallback, resultCallbackHandler); + } + + /** + * Starts a task from Recents. + * + * @param resultCallback The result success callback + * @param resultCallbackHandler The handler to receive the result callback + */ + public void startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options, + int windowingMode, int activityType, Consumer<Boolean> resultCallback, + Handler resultCallbackHandler) { + if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + // We show non-visible docked tasks in Recents, but we always want to launch + // them in the fullscreen stack. + if (options == null) { + options = ActivityOptions.makeBasic(); + } + options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + } else if (windowingMode != WINDOWING_MODE_UNDEFINED + || activityType != ACTIVITY_TYPE_UNDEFINED) { + if (options == null) { + options = ActivityOptions.makeBasic(); + } + options.setLaunchWindowingMode(windowingMode); + options.setLaunchActivityType(activityType); + } + final ActivityOptions finalOptions = options; + + // Execute this from another thread such that we can do other things (like caching the + // bitmap for the thumbnail) while AM is busy starting our activity. + mBackgroundExecutor.submit(() -> { + try { + ActivityManager.getService().startActivityFromRecents(taskKey.id, + finalOptions == null ? null : finalOptions.toBundle()); + if (resultCallback != null) { + resultCallbackHandler.post(() -> resultCallback.accept(true)); + } + } catch (Exception e) { + if (resultCallback != null) { + resultCallbackHandler.post(() -> resultCallback.accept(false)); + } + } + }); + } + + /** * Requests that the system close any open system windows (including other SystemUI). */ public void closeSystemWindows(String reason) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index 61c5167c8c02..5b62c7d3c002 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -411,12 +411,12 @@ public class Recents extends SystemUI } int currentUser = sSystemServicesProxy.getCurrentUser(); - SystemServicesProxy ssp = Recents.getSystemServices(); - ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask(); + ActivityManager.RunningTaskInfo runningTask = + ActivityManagerWrapper.getInstance().getRunningTask(); final int activityType = runningTask != null ? runningTask.configuration.windowConfiguration.getActivityType() : ACTIVITY_TYPE_UNDEFINED; - boolean screenPinningActive = ssp.isScreenPinningActive(); + boolean screenPinningActive = sSystemServicesProxy.isScreenPinningActive(); boolean isRunningTaskInHomeOrRecentsStack = activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS; if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 96fae35f5d2a..0b816b5ff820 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -138,8 +138,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } // Load the next task only if we aren't svelte - SystemServicesProxy ssp = Recents.getSystemServices(); - ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask(); + ActivityManager.RunningTaskInfo runningTaskInfo = + ActivityManagerWrapper.getInstance().getRunningTask(); RecentsTaskLoader loader = Recents.getTaskLoader(); RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext); loader.preloadTasks(plan, -1); @@ -353,7 +353,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener boolean forceVisible = launchedWhileDockingTask || draggingInRecents; MutableBoolean isHomeStackVisible = new MutableBoolean(forceVisible); if (forceVisible || !ssp.isRecentsActivityVisible(isHomeStackVisible)) { - ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask(); + ActivityManager.RunningTaskInfo runningTask = + ActivityManagerWrapper.getInstance().getRunningTask(); startRecentsActivity(runningTask, isHomeStackVisible.value || fromHome, animate, growTarget); } @@ -444,7 +445,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } // Otherwise, start the recents activity - ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask(); + ActivityManager.RunningTaskInfo runningTask = + ActivityManagerWrapper.getInstance().getRunningTask(); startRecentsActivity(runningTask, isHomeStackVisible.value, true /* animate */, growTarget); @@ -470,7 +472,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // don't block the touch feedback on the nav bar button which triggers this. mHandler.post(() -> { if (!ssp.isRecentsActivityVisible(null)) { - ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask(); + ActivityManager.RunningTaskInfo runningTask = + ActivityManagerWrapper.getInstance().getRunningTask(); if (runningTask == null) { return; } @@ -524,7 +527,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener if (focusedStack == null || focusedStack.getTaskCount() == 0) return; // Return early if there is no running task - ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask(); + ActivityManager.RunningTaskInfo runningTask = + ActivityManagerWrapper.getInstance().getRunningTask(); if (runningTask == null) return; // Find the task in the recents list @@ -561,8 +565,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } // Launch the task - ssp.startActivityFromRecents( - mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */); + ActivityManagerWrapper.getInstance().startActivityFromRecents(toTask.key, launchOpts, + null /* resultCallback */, null /* resultCallbackHandler */); } /** @@ -579,7 +583,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener if (focusedStack == null || focusedStack.getTaskCount() == 0) return; // Return early if there is no running task (can't determine affiliated tasks in this case) - ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask(); + ActivityManager.RunningTaskInfo runningTask = + ActivityManagerWrapper.getInstance().getRunningTask(); final int activityType = runningTask.configuration.windowConfiguration.getActivityType(); if (runningTask == null) return; // Return early if the running task is in the home/recents stack (optimization) @@ -630,8 +635,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1); // Launch the task - ssp.startActivityFromRecents( - mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */); + ActivityManagerWrapper.getInstance().startActivityFromRecents(toTask.key, launchOpts, + null /* resultListener */, null /* resultCallbackHandler */); } public void showNextAffiliatedTask() { 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 14b91f7aeaa6..a436e177cb51 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -83,6 +83,7 @@ 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 @@ -123,7 +124,6 @@ public class SystemServicesProxy { Paint mBgProtectionPaint; Canvas mBgProtectionCanvas; - private final Handler mHandler = new Handler(); private final Runnable mGcRunnable = new Runnable() { @Override public void run() { @@ -197,24 +197,6 @@ public class SystemServicesProxy { } /** - * Returns the top running task. - */ - public ActivityManager.RunningTaskInfo getRunningTask() { - // Note: The set of running tasks from the system is ordered by recency - try { - List<ActivityManager.RunningTaskInfo> tasks = mIam.getFilteredTasks(1, - ACTIVITY_TYPE_RECENTS /* ignoreActivityType */, - WINDOWING_MODE_PINNED /* ignoreWindowingMode */); - if (tasks.isEmpty()) { - return null; - } - return tasks.get(0); - } catch (RemoteException e) { - return null; - } - } - - /** * Returns whether the recents activity is currently visible. */ public boolean isRecentsActivityVisible() { @@ -376,28 +358,6 @@ public class SystemServicesProxy { } } - /** Removes the task */ - public void removeTask(final int taskId) { - if (mAm == null) return; - - // Remove the task. - mUiOffloadThread.submit(() -> { - try { - mIam.removeTask(taskId); - } catch (RemoteException e) { - e.printStackTrace(); - } - }); - } - - public ActivityManager.TaskDescription getTaskDescription(int taskId) { - try { - return mIam.getTaskDescription(taskId); - } catch (RemoteException e) { - return null; - } - } - /** * Returns whether the provided {@param userId} represents the system user. */ @@ -520,56 +480,6 @@ public class SystemServicesProxy { opts != null ? opts.toBundle() : null, UserHandle.CURRENT)); } - public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName, - ActivityOptions options, - @Nullable final StartActivityFromRecentsResultListener resultListener) { - startActivityFromRecents(context, taskKey, taskName, options, - WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED, resultListener); - } - - /** Starts an activity from recents. */ - public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName, - ActivityOptions options, int windowingMode, int activityType, - @Nullable final StartActivityFromRecentsResultListener resultListener) { - if (mIam == null) { - return; - } - if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - // We show non-visible docked tasks in Recents, but we always want to launch - // them in the fullscreen stack. - if (options == null) { - options = ActivityOptions.makeBasic(); - } - options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); - } else if (windowingMode != WINDOWING_MODE_UNDEFINED - || activityType != ACTIVITY_TYPE_UNDEFINED) { - if (options == null) { - options = ActivityOptions.makeBasic(); - } - options.setLaunchWindowingMode(windowingMode); - options.setLaunchActivityType(activityType); - } - final ActivityOptions finalOptions = options; - - // Execute this from another thread such that we can do other things (like caching the - // bitmap for the thumbnail) while AM is busy starting our activity. - mUiOffloadThread.submit(() -> { - try { - mIam.startActivityFromRecents( - taskKey.id, finalOptions == null ? null : finalOptions.toBundle()); - if (resultListener != null) { - mHandler.post(() -> resultListener.onStartActivityResult(true)); - } - } catch (Exception e) { - Log.e(TAG, context.getString( - R.string.recents_launch_error_message, taskName), e); - if (resultListener != null) { - mHandler.post(() -> resultListener.onStartActivityResult(false)); - } - } - }); - } - /** Starts an in-place animation on the front most application windows. */ public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts) { if (mIam == null) return; 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 f4973d023e76..b82f15eff4b8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -36,6 +36,7 @@ import android.graphics.drawable.Drawable; import android.os.Handler; import android.util.ArraySet; import android.util.AttributeSet; +import android.util.Log; import android.util.MathUtils; import android.view.AppTransitionAnimationSpec; import android.view.LayoutInflater; @@ -1026,29 +1027,30 @@ public class RecentsView extends FrameLayout { private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView, ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture, int windowingMode, int activityType) { - SystemServicesProxy ssp = Recents.getSystemServices(); - ssp.startActivityFromRecents(mContext, task.key, task.title, opts, windowingMode, - activityType, - succeeded -> { - if (succeeded) { - // Keep track of the index of the task launch - int taskIndexFromFront = 0; - int taskIndex = stack.indexOfStackTask(task); - if (taskIndex > -1) { - taskIndexFromFront = stack.getTaskCount() - taskIndex - 1; - } - EventBus.getDefault().send(new LaunchTaskSucceededEvent( - taskIndexFromFront)); - } else { - // Dismiss the task if we fail to launch it - if (taskView != null) { - taskView.dismissTask(); - } + ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key, opts, windowingMode, + activityType, succeeded -> { + if (succeeded) { + // Keep track of the index of the task launch + int taskIndexFromFront = 0; + int taskIndex = stack.indexOfStackTask(task); + if (taskIndex > -1) { + taskIndexFromFront = stack.getTaskCount() - taskIndex - 1; + } + EventBus.getDefault().send(new LaunchTaskSucceededEvent( + taskIndexFromFront)); + } else { + Log.e(TAG, mContext.getString(R.string.recents_launch_error_message, + task.title)); - // Keep track of failed launches - EventBus.getDefault().send(new LaunchTaskFailedEvent()); - } - }); + // Dismiss the task if we fail to launch it + if (taskView != null) { + taskView.dismissTask(); + } + + // Keep track of failed launches + EventBus.getDefault().send(new LaunchTaskFailedEvent()); + } + }, getHandler()); if (transitionFuture != null) { mHandler.post(transitionFuture::composeSpecsSynchronous); } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 7bcef574cfd6..1596d120c16f 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -439,7 +439,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, if (mMinimizedSnapAlgorithm == null) { mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth, mDisplayHeight, mDividerSize, isHorizontalDivision(), - mStableInsets, mDockedStackMinimized && mHomeStackResizable); + mStableInsets, mDockSide, mDockedStackMinimized && mHomeStackResizable); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 7022c479eae8..41cae6b0be57 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -47,6 +47,7 @@ import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.recents.Recents; import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.StatusBarState; @@ -311,8 +312,8 @@ public class CarStatusBar extends StatusBar implements private class TaskStackListenerImpl extends SysUiTaskStackChangeListener { @Override public void onTaskStackChanged() { - SystemServicesProxy ssp = Recents.getSystemServices(); - ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask(); + ActivityManager.RunningTaskInfo runningTaskInfo = + ActivityManagerWrapper.getInstance().getRunningTask(); if (runningTaskInfo != null && runningTaskInfo.baseActivity != null) { mController.taskChanged(runningTaskInfo.baseActivity.getPackageName(), runningTaskInfo); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index d8a9c12f008e..fa34d4a62d1b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -5266,7 +5266,8 @@ public class StatusBar extends SystemUI implements DemoMode, boolean isCameraAllowedByAdmin() { if (mDevicePolicyManager.getCameraDisabled(null, mCurrentUserId)) { return false; - } else if (isKeyguardShowing() && isKeyguardSecure()) { + } else if (mStatusBarKeyguardViewManager == null || + (isKeyguardShowing() && isKeyguardSecure())) { // Check if the admin has disabled the camera specifically for the keyguard return (mDevicePolicyManager.getKeyguardDisabledFeatures(null, mCurrentUserId) & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0; diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 507852eb29f3..faad49e1499f 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -2799,420 +2799,316 @@ message MetricsEvent { // OS: O TEXT_LONGPRESS = 629; - // ACTION: An app requested an unknown permission - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_UNKNOWN = 630; - // ACTION: An app was granted an unknown permission - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_UNKNOWN = 631; - // ACTION: An app requested an unknown permission and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_UNKNOWN = 632; - // ACTION: An unknown permission was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_UNKNOWN = 633; - // ACTION: An app requested the permission READ_CALENDAR - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_READ_CALENDAR = 634; - // ACTION: An app was granted the permission READ_CALENDAR - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_READ_CALENDAR = 635; - // ACTION: An app requested the permission READ_CALENDAR and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_READ_CALENDAR = 636; - // ACTION: The permission READ_CALENDAR was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_READ_CALENDAR = 637; - // ACTION: An app requested the permission WRITE_CALENDAR - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_WRITE_CALENDAR = 638; - // ACTION: An app was granted the permission WRITE_CALENDAR - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_WRITE_CALENDAR = 639; - // ACTION: An app requested the permission WRITE_CALENDAR and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_WRITE_CALENDAR = 640; - // ACTION: The permission WRITE_CALENDAR was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_WRITE_CALENDAR = 641; - // ACTION: An app requested the permission CAMERA - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_CAMERA = 642; - // ACTION: An app was granted the permission CAMERA - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_CAMERA = 643; - // ACTION: An app requested the permission CAMERA and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_CAMERA = 644; - // ACTION: The permission CAMERA was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_CAMERA = 645; - // ACTION: An app requested the permission READ_CONTACTS - // PACKAGE: The package name of the app requesting the permission + // AOBSOLETE ACTION_PERMISSION_REQUEST_READ_CONTACTS = 646; - // ACTION: An app was granted the permission READ_CONTACTS - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_READ_CONTACTS = 647; - // ACTION: An app requested the permission READ_CONTACTS and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_READ_CONTACTS = 648; - // ACTION: The permission READ_CONTACTS was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_READ_CONTACTS = 649; - // ACTION: An app requested the permission WRITE_CONTACTS - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_WRITE_CONTACTS = 650; - // ACTION: An app was granted the permission WRITE_CONTACTS - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_WRITE_CONTACTS = 651; - // ACTION: An app requested the permission WRITE_CONTACTS and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_WRITE_CONTACTS = 652; - // ACTION: The permission WRITE_CONTACTS was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_WRITE_CONTACTS = 653; - // ACTION: An app requested the permission GET_ACCOUNTS - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_GET_ACCOUNTS = 654; - // ACTION: An app was granted the permission GET_ACCOUNTS - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_GET_ACCOUNTS = 655; - // ACTION: An app requested the permission GET_ACCOUNTS and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_GET_ACCOUNTS = 656; - // ACTION: The permission GET_ACCOUNTS was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_GET_ACCOUNTS = 657; - // ACTION: An app requested the permission ACCESS_FINE_LOCATION - // PACKAGE: The package name of the app requesting the permission + // AOBSOLETE ACTION_PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 658; - // ACTION: An app was granted the permission ACCESS_FINE_LOCATION - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_ACCESS_FINE_LOCATION = 659; - // 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 ACTION_PERMISSION_DENIED_ACCESS_FINE_LOCATION = 660; - // ACTION: The permission ACCESS_FINE_LOCATION was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_ACCESS_FINE_LOCATION = 661; - // ACTION: An app requested the permission ACCESS_COARSE_LOCATION - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_ACCESS_COARSE_LOCATION = 662; - // ACTION: An app was granted the permission ACCESS_COARSE_LOCATION - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_ACCESS_COARSE_LOCATION = 663; - // 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 ACTION_PERMISSION_DENIED_ACCESS_COARSE_LOCATION = 664; - // ACTION: The permission ACCESS_COARSE_LOCATION was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_ACCESS_COARSE_LOCATION = 665; - // ACTION: An app requested the permission RECORD_AUDIO - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_RECORD_AUDIO = 666; - // ACTION: An app was granted the permission RECORD_AUDIO - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_RECORD_AUDIO = 667; - // ACTION: An app requested the permission RECORD_AUDIO and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_RECORD_AUDIO = 668; - // ACTION: The permission RECORD_AUDIO was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_RECORD_AUDIO = 669; - // ACTION: An app requested the permission READ_PHONE_STATE - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_READ_PHONE_STATE = 670; - // ACTION: An app was granted the permission READ_PHONE_STATE - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_READ_PHONE_STATE = 671; - // 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 ACTION_PERMISSION_DENIED_READ_PHONE_STATE = 672; - // ACTION: The permission READ_PHONE_STATE was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_READ_PHONE_STATE = 673; - // ACTION: An app requested the permission CALL_PHONE - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_CALL_PHONE = 674; - // ACTION: An app was granted the permission CALL_PHONE - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_CALL_PHONE = 675; - // ACTION: An app requested the permission CALL_PHONE and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_CALL_PHONE = 676; - // ACTION: The permission CALL_PHONE was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_CALL_PHONE = 677; - // ACTION: An app requested the permission READ_CALL_LOG - // PACKAGE: The package name of the app requesting the permission + // AOBSOLETE ACTION_PERMISSION_REQUEST_READ_CALL_LOG = 678; - // ACTION: An app was granted the permission READ_CALL_LOG - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_READ_CALL_LOG = 679; - // 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 ACTION_PERMISSION_DENIED_READ_CALL_LOG = 680; - // ACTION: The permission READ_CALL_LOG was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_READ_CALL_LOG = 681; - // ACTION: An app requested the permission WRITE_CALL_LOG - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_WRITE_CALL_LOG = 682; - // ACTION: An app was granted the permission WRITE_CALL_LOG - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_WRITE_CALL_LOG = 683; - // 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 ACTION_PERMISSION_DENIED_WRITE_CALL_LOG = 684; - // ACTION: The permission WRITE_CALL_LOG was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_WRITE_CALL_LOG = 685; - // ACTION: An app requested the permission ADD_VOICEMAIL - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_ADD_VOICEMAIL = 686; - // ACTION: An app was granted the permission ADD_VOICEMAIL - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_ADD_VOICEMAIL = 687; - // ACTION: An app requested the permission ADD_VOICEMAIL and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_ADD_VOICEMAIL = 688; - // ACTION: The permission ADD_VOICEMAIL was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_ADD_VOICEMAIL = 689; - // ACTION: An app requested the permission USE_SIP - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_USE_SIP = 690; - // ACTION: An app was granted the permission USE_SIP - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_USE_SIP = 691; - // ACTION: An app requested the permission USE_SIP and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_USE_SIP = 692; - // ACTION: The permission USE_SIP was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_USE_SIP = 693; - // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_PROCESS_OUTGOING_CALLS = 694; - // ACTION: An app was granted the permission PROCESS_OUTGOING_CALLS - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_PROCESS_OUTGOING_CALLS = 695; - // 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 ACTION_PERMISSION_DENIED_PROCESS_OUTGOING_CALLS = 696; - // ACTION: The permission PROCESS_OUTGOING_CALLS was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_PROCESS_OUTGOING_CALLS = 697; - // ACTION: An app requested the permission READ_CELL_BROADCASTS - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_READ_CELL_BROADCASTS = 698; - // ACTION: An app was granted the permission READ_CELL_BROADCASTS - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_READ_CELL_BROADCASTS = 699; - // 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 ACTION_PERMISSION_DENIED_READ_CELL_BROADCASTS = 700; - // ACTION: The permission READ_CELL_BROADCASTS was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_READ_CELL_BROADCASTS = 701; - // ACTION: An app requested the permission BODY_SENSORS - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_BODY_SENSORS = 702; - // ACTION: An app was granted the permission BODY_SENSORS - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_BODY_SENSORS = 703; - // ACTION: An app requested the permission BODY_SENSORS and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_BODY_SENSORS = 704; - // ACTION: The permission BODY_SENSORS was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_BODY_SENSORS = 705; - // ACTION: An app requested the permission SEND_SMS - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_SEND_SMS = 706; - // ACTION: An app was granted the permission SEND_SMS - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_SEND_SMS = 707; - // ACTION: An app requested the permission SEND_SMS and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_SEND_SMS = 708; - // ACTION: The permission SEND_SMS was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_SEND_SMS = 709; - // ACTION: An app requested the permission RECEIVE_SMS - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_RECEIVE_SMS = 710; - // ACTION: An app was granted the permission RECEIVE_SMS - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_RECEIVE_SMS = 711; - // ACTION: An app requested the permission RECEIVE_SMS and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_RECEIVE_SMS = 712; - // ACTION: The permission RECEIVE_SMS was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_RECEIVE_SMS = 713; - // ACTION: An app requested the permission READ_SMS - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_READ_SMS = 714; - // ACTION: An app was granted the permission READ_SMS - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_READ_SMS = 715; - // ACTION: An app requested the permission READ_SMS and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_READ_SMS = 716; - // ACTION: The permission READ_SMS was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_READ_SMS = 717; - // ACTION: An app requested the permission RECEIVE_WAP_PUSH - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_RECEIVE_WAP_PUSH = 718; - // ACTION: An app was granted the permission RECEIVE_WAP_PUSH - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_RECEIVE_WAP_PUSH = 719; - // 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 ACTION_PERMISSION_DENIED_RECEIVE_WAP_PUSH = 720; - // ACTION: The permission RECEIVE_WAP_PUSH was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_RECEIVE_WAP_PUSH = 721; - // ACTION: An app requested the permission RECEIVE_MMS - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_RECEIVE_MMS = 722; - // ACTION: An app was granted the permission RECEIVE_MMS - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_RECEIVE_MMS = 723; - // ACTION: An app requested the permission RECEIVE_MMS and the request was denied - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_DENIED_RECEIVE_MMS = 724; - // ACTION: The permission RECEIVE_MMS was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_RECEIVE_MMS = 725; - // ACTION: An app requested the permission READ_EXTERNAL_STORAGE - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 726; - // ACTION: An app was granted the permission READ_EXTERNAL_STORAGE - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_READ_EXTERNAL_STORAGE = 727; - // 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 ACTION_PERMISSION_DENIED_READ_EXTERNAL_STORAGE = 728; - // ACTION: The permission READ_EXTERNAL_STORAGE was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_READ_EXTERNAL_STORAGE = 729; - // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 730; - // ACTION: An app was granted the permission WRITE_EXTERNAL_STORAGE - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_WRITE_EXTERNAL_STORAGE = 731; - // 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 ACTION_PERMISSION_DENIED_WRITE_EXTERNAL_STORAGE = 732; - // ACTION: The permission WRITE_EXTERNAL_STORAGE was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_WRITE_EXTERNAL_STORAGE = 733; // ACTION: Logged when a provisioning session has started @@ -3221,20 +3117,16 @@ message MetricsEvent { // ACTION: Logged when a provisioning session has completed PROVISIONING_SESSION_COMPLETED = 735; - // ACTION: An app requested the permission READ_PHONE_NUMBERS - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_PERMISSION_REQUEST_READ_PHONE_NUMBERS = 736; - // ACTION: An app was granted the permission READ_PHONE_NUMBERS - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_PERMISSION_GRANT_READ_PHONE_NUMBERS = 737; - // 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 ACTION_PERMISSION_DENIED_READ_PHONE_NUMBERS = 738; - // ACTION: The permission READ_PHONE_NUMBERS was revoked for an app - // PACKAGE: The package name of the app the permission was revoked for + // OBSOLETE ACTION_PERMISSION_REVOKE_READ_PHONE_NUMBERS = 739; // ACTION: QS Brightness Slider (with auto brightness disabled, and VR enabled) @@ -3726,68 +3618,52 @@ message MetricsEvent { // CATEGORY: SETTINGS SETTINGS_LOCK_SCREEN_PREFERENCES = 882; - // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_APPOP_REQUEST_ACCESS_NOTIFICATIONS = 883; - // ACTION: An app was granted the app-op permission ACCESS_NOTIFICATIONS - // PACKAGE: The package name of the app that was granted the permission + // OBSOLETE ACTION_APPOP_GRANT_ACCESS_NOTIFICATIONS = 884; - // 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 ACTION_APPOP_DENIED_ACCESS_NOTIFICATIONS = 885; - // 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 ACTION_APPOP_REVOKE_ACCESS_NOTIFICATIONS = 886; - // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_APPOP_REQUEST_SYSTEM_ALERT_WINDOW = 887; - // 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 ACTION_APPOP_GRANT_SYSTEM_ALERT_WINDOW = 888; - // 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 ACTION_APPOP_DENIED_SYSTEM_ALERT_WINDOW = 889; - // 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 ACTION_APPOP_REVOKE_SYSTEM_ALERT_WINDOW = 890; - // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_APPOP_REQUEST_WRITE_SETTINGS = 891; - // 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 ACTION_APPOP_GRANT_WRITE_SETTINGS = 892; - // 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 ACTION_APPOP_DENIED_WRITE_SETTINGS = 893; - // 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 ACTION_APPOP_REVOKE_WRITE_SETTINGS = 894; - // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES - // PACKAGE: The package name of the app requesting the permission + // OBSOLETE ACTION_APPOP_REQUEST_REQUEST_INSTALL_PACKAGES = 895; - // 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 ACTION_APPOP_GRANT_REQUEST_INSTALL_PACKAGES = 896; - // 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 ACTION_APPOP_DENIED_REQUEST_INSTALL_PACKAGES = 897; - // 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 ACTION_APPOP_REVOKE_REQUEST_INSTALL_PACKAGES = 898; // ACTION: Phase 1 of instant application resolution occurred @@ -4759,6 +4635,37 @@ message MetricsEvent { // OS: P ACTION_WIFI_AUTO_SIGN_IN = 1239; + // Open: Settings > System > About phone > IMEI + // CATEGORY: SETTINGS + // OS: P + DIALOG_IMEI_INFO = 1240; + + // In permission action fields tagged like this reference the permission affected + FIELD_PERMISSION = 1241; + + // ACTION: An app requested a permission and we asked to user to approve the request + // PACKAGE: The package name of the app requesting the permission + // Tag FIELD_PERMISSION: Name of the permission requested + ACTION_PERMISSION_REQUESTED = 1242; + + // ACTION: An app was granted the a permission. This can happen after a user approved a request + // or automatically. In the second case there will not be an + // ACTION_PERMISSION_REQUESTED. + // PACKAGE: The package name of the app that was granted the permission + // Tag FIELD_PERMISSION: Name of the permission granted + ACTION_PERMISSION_GRANTED = 1243; + + // ACTION: An app requested the a permission and the request was denied by the user or a device + // policy + // PACKAGE: The package name of the app requesting the permission + // Tag FIELD_PERMISSION: Name of the permission denied + ACTION_PERMISSION_DENIED = 1244; + + // ACTION: A permission was revoked + // PACKAGE: The package name of the app the permission was revoked for + // Tag FIELD_PERMISSION: Name of the permission revoked + ACTION_PERMISSION_REVOKED = 1245; + // Add new aosp constants above this line. // END OF AOSP CONSTANTS } diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 622b84239711..e92a56477579 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -80,6 +80,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; import android.database.ContentObserver; import android.net.Uri; +import android.os.PowerManager.ServiceType; import android.os.PowerSaveState; import android.os.Binder; import android.os.Build; @@ -126,7 +127,6 @@ import com.android.server.EventLogTags; import com.android.server.SystemConfig; import com.android.server.SystemService; import com.android.server.backup.PackageManagerBackupAgent.Metadata; -import com.android.server.power.BatterySaverPolicy.ServiceType; import libcore.io.IoUtils; diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java index 20f236908112..a45a4f0c35d3 100644 --- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java @@ -71,6 +71,7 @@ import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.PowerManager; +import android.os.PowerManager.ServiceType; import android.os.PowerSaveState; import android.os.Process; import android.os.RemoteException; @@ -120,7 +121,6 @@ import com.android.server.backup.utils.AppBackupUtils; import com.android.server.backup.utils.BackupManagerMonitorUtils; import com.android.server.backup.utils.BackupObserverUtils; import com.android.server.backup.utils.SparseArrayUtils; -import com.android.server.power.BatterySaverPolicy.ServiceType; import com.google.android.collect.Sets; diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java index 8d8a0135e3df..a08c19e95914 100644 --- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java +++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java @@ -158,16 +158,19 @@ public class ActiveRestoreSession extends IRestoreSession.Stub { MSG_RESTORE_SESSION_TIMEOUT); long oldId = Binder.clearCallingIdentity(); - backupManagerService.getWakelock().acquire(); - if (MORE_DEBUG) { - Slog.d(TAG, "restoreAll() kicking off"); + try { + backupManagerService.getWakelock().acquire(); + if (MORE_DEBUG) { + Slog.d(TAG, "restoreAll() kicking off"); + } + Message msg = backupManagerService.getBackupHandler().obtainMessage( + MSG_RUN_RESTORE); + msg.obj = new RestoreParams(mRestoreTransport, dirName, + observer, monitor, token); + backupManagerService.getBackupHandler().sendMessage(msg); + } finally { + Binder.restoreCallingIdentity(oldId); } - Message msg = backupManagerService.getBackupHandler().obtainMessage( - MSG_RUN_RESTORE); - msg.obj = new RestoreParams(mRestoreTransport, dirName, - observer, monitor, token); - backupManagerService.getBackupHandler().sendMessage(msg); - Binder.restoreCallingIdentity(oldId); return 0; } } diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 8b79b9ddfef2..0e51fda0f39f 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -27,6 +27,7 @@ import android.database.ContentObserver; import android.hardware.input.InputManager; import android.hardware.vibrator.V1_0.Constants.EffectStrength; import android.media.AudioManager; +import android.os.PowerManager.ServiceType; import android.os.PowerSaveState; import android.os.BatteryStats; import android.os.Handler; @@ -56,7 +57,6 @@ import android.media.AudioAttributes; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IBatteryStats; import com.android.internal.util.DumpUtils; -import com.android.server.power.BatterySaverPolicy.ServiceType; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 52f97020b5a7..a035bd026fea 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.wifi.WifiActivityEnergyInfo; +import android.os.PowerManager.ServiceType; import android.os.PowerSaveState; import android.os.BatteryStats; import android.os.BatteryStatsInternal; @@ -53,7 +54,6 @@ import com.android.internal.os.PowerProfile; import com.android.internal.os.RpmStats; import com.android.internal.util.DumpUtils; import com.android.server.LocalServices; -import com.android.server.power.BatterySaverPolicy.ServiceType; import android.util.StatsLog; import java.io.File; diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 660659fdfa5c..beb7486d7bc2 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -48,6 +48,7 @@ import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.Uri; import android.os.AsyncTask; +import android.os.PowerManager.ServiceType; import android.os.PowerSaveState; import android.os.BatteryStats; import android.os.Binder; @@ -84,7 +85,6 @@ import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; import com.android.server.power.BatterySaverPolicy; -import com.android.server.power.BatterySaverPolicy.ServiceType; import libcore.io.IoUtils; diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index b4056b333fe5..551cb10ffc03 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -142,6 +142,7 @@ import android.os.Message; import android.os.MessageQueue.IdleHandler; import android.os.PersistableBundle; import android.os.PowerManager; +import android.os.PowerManager.ServiceType; import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.Process; @@ -192,7 +193,6 @@ import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.SystemConfig; -import com.android.server.power.BatterySaverPolicy.ServiceType; import libcore.io.IoUtils; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 7837b029830f..6c42f4fc8a35 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -574,37 +574,6 @@ public class PackageManagerService extends IPackageManager.Stub public static final int REASON_LAST = REASON_SHARED; - /** All dangerous permission names in the same order as the events in MetricsEvent */ - private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList( - Manifest.permission.READ_CALENDAR, - Manifest.permission.WRITE_CALENDAR, - Manifest.permission.CAMERA, - Manifest.permission.READ_CONTACTS, - Manifest.permission.WRITE_CONTACTS, - Manifest.permission.GET_ACCOUNTS, - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_COARSE_LOCATION, - Manifest.permission.RECORD_AUDIO, - Manifest.permission.READ_PHONE_STATE, - Manifest.permission.CALL_PHONE, - Manifest.permission.READ_CALL_LOG, - Manifest.permission.WRITE_CALL_LOG, - Manifest.permission.ADD_VOICEMAIL, - Manifest.permission.USE_SIP, - Manifest.permission.PROCESS_OUTGOING_CALLS, - Manifest.permission.READ_CELL_BROADCASTS, - Manifest.permission.BODY_SENSORS, - Manifest.permission.SEND_SMS, - Manifest.permission.RECEIVE_SMS, - Manifest.permission.READ_SMS, - Manifest.permission.RECEIVE_WAP_PUSH, - Manifest.permission.RECEIVE_MMS, - Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_NUMBERS, - Manifest.permission.ANSWER_PHONE_CALLS); - - /** * Version number for the package parser cache. Increment this whenever the format or * extent of cached data changes. See {@code PackageParser#setCacheDir}. @@ -5176,66 +5145,6 @@ public class PackageManagerService extends IPackageManager.Stub getCallingUid(), userId, mPermissionCallback); } - /** - * Get the first event id for the permission. - * - * <p>There are four events for each permission: <ul> - * <li>Request permission: first id + 0</li> - * <li>Grant permission: first id + 1</li> - * <li>Request for permission denied: first id + 2</li> - * <li>Revoke permission: first id + 3</li> - * </ul></p> - * - * @param name name of the permission - * - * @return The first event id for the permission - */ - private static int getBaseEventId(@NonNull String name) { - int eventIdIndex = ALL_DANGEROUS_PERMISSIONS.indexOf(name); - - if (eventIdIndex == -1) { - if (AppOpsManager.permissionToOpCode(name) == AppOpsManager.OP_NONE - || Build.IS_USER) { - Log.i(TAG, "Unknown permission " + name); - - return MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN; - } else { - // Most likely #ALL_DANGEROUS_PERMISSIONS needs to be updated. - // - // Also update - // - EventLogger#ALL_DANGEROUS_PERMISSIONS - // - metrics_constants.proto - throw new IllegalStateException("Unknown permission " + name); - } - } - - return MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + eventIdIndex * 4; - } - - /** - * Log that a permission was revoked. - * - * @param context Context of the caller - * @param name name of the permission - * @param packageName package permission if for - */ - private static void logPermissionRevoked(@NonNull Context context, @NonNull String name, - @NonNull String packageName) { - MetricsLogger.action(context, getBaseEventId(name) + 3, packageName); - } - - /** - * Log that a permission request was granted. - * - * @param context Context of the caller - * @param name name of the permission - * @param packageName package permission if for - */ - private static void logPermissionGranted(@NonNull Context context, @NonNull String name, - @NonNull String packageName) { - MetricsLogger.action(context, getBaseEventId(name) + 1, packageName); - } - @Override public void resetRuntimePermissions() { mContext.enforceCallingOrSelfPermission( diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java index cf9e6f3c0c98..781216c3c43f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java @@ -59,6 +59,8 @@ public class PackageManagerServiceCompilerMapping { // vendor. if ("pm.dexopt.inactive".equals(sysPropName)) { sysPropValue = "verify"; + } else if ("pm.dexopt.shared".equals(sysPropName)) { + sysPropValue = "speed"; } else { sysPropValue = SystemProperties.get(sysPropName); } diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 1c002aa43512..25e923994789 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -2262,6 +2262,10 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutUser user = getUserShortcutsLocked(userId); + if (user.hasHostPackage(packageName)) { + return true; + } + // Always trust the cached component. final ComponentName cached = user.getCachedLauncher(); if (cached != null) { @@ -2361,6 +2365,16 @@ public class ShortcutService extends IShortcutService.Stub { } } + public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName, + int userId) { + synchronized (mLock) { + throwIfUserLockedL(userId); + + final ShortcutUser user = getUserShortcutsLocked(userId); + user.setShortcutHostPackage(type, packageName); + } + } + // === House keeping === private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId, @@ -2697,6 +2711,12 @@ public class ShortcutService extends IShortcutService.Stub { } @Override + public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName, + int userId) { + ShortcutService.this.setShortcutHostPackage(type, packageName, userId); + } + + @Override public boolean requestPinAppWidget(@NonNull String callingPackage, @NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras, @Nullable IntentSender resultIntent, int userId) { diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java index 48eccd02db64..1efd765b18fa 100644 --- a/services/core/java/com/android/server/pm/ShortcutUser.java +++ b/services/core/java/com/android/server/pm/ShortcutUser.java @@ -23,6 +23,7 @@ import android.content.pm.ShortcutManager; import android.text.TextUtils; import android.text.format.Formatter; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.Slog; @@ -123,6 +124,20 @@ class ShortcutUser { /** In-memory-cached default launcher. */ private ComponentName mCachedLauncher; + /** + * Keep track of additional packages that other parts of the system have said are + * allowed to access shortcuts. The key is the part of the system it came from, + * the value is the package name that has access. We don't persist these because + * at boot all relevant system services will push this data back to us they do their + * normal evaluation of the state of the world. + */ + private final ArrayMap<String, String> mHostPackages = new ArrayMap<>(); + + /** + * Set of package name values from above. + */ + private final ArraySet<String> mHostPackageSet = new ArraySet<>(); + private String mKnownLocales; private long mLastAppScanTime; @@ -467,6 +482,23 @@ class ShortcutUser { return mCachedLauncher; } + public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName) { + if (packageName != null) { + mHostPackages.put(type, packageName); + } else { + mHostPackages.remove(type); + } + + mHostPackageSet.clear(); + for (int i = 0; i < mHostPackages.size(); i++) { + mHostPackageSet.add(mHostPackages.valueAt(i)); + } + } + + public boolean hasHostPackage(@NonNull String packageName) { + return mHostPackageSet.contains(packageName); + } + public void resetThrottling() { for (int i = mPackages.size() - 1; i >= 0; i--) { mPackages.valueAt(i).resetThrottling(); @@ -555,6 +587,18 @@ class ShortcutUser { pw.print("Last known launcher: "); pw.print(mLastKnownLauncher); pw.println(); + + if (mHostPackages.size() > 0) { + pw.print(prefix); + pw.println("Host packages:"); + for (int i = 0; i < mHostPackages.size(); i++) { + pw.print(prefix); + pw.print(" "); + pw.print(mHostPackages.keyAt(i)); + pw.print(": "); + pw.println(mHostPackages.valueAt(i)); + } + } } for (int i = 0; i < mLaunchers.size(); i++) { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 76805ce3a9ff..6d2051f28253 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -37,6 +37,7 @@ import android.content.pm.PackageParser; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.content.pm.PackageParser.Package; +import android.metrics.LogMaker; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -92,36 +93,6 @@ import java.util.Set; public class PermissionManagerService { private static final String TAG = "PackageManager"; - /** All dangerous permission names in the same order as the events in MetricsEvent */ - private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList( - Manifest.permission.READ_CALENDAR, - Manifest.permission.WRITE_CALENDAR, - Manifest.permission.CAMERA, - Manifest.permission.READ_CONTACTS, - Manifest.permission.WRITE_CONTACTS, - Manifest.permission.GET_ACCOUNTS, - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_COARSE_LOCATION, - Manifest.permission.RECORD_AUDIO, - Manifest.permission.READ_PHONE_STATE, - Manifest.permission.CALL_PHONE, - Manifest.permission.READ_CALL_LOG, - Manifest.permission.WRITE_CALL_LOG, - Manifest.permission.ADD_VOICEMAIL, - Manifest.permission.USE_SIP, - Manifest.permission.PROCESS_OUTGOING_CALLS, - Manifest.permission.READ_CELL_BROADCASTS, - Manifest.permission.BODY_SENSORS, - Manifest.permission.SEND_SMS, - Manifest.permission.RECEIVE_SMS, - Manifest.permission.READ_SMS, - Manifest.permission.RECEIVE_WAP_PUSH, - Manifest.permission.RECEIVE_MMS, - Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_NUMBERS, - Manifest.permission.ANSWER_PHONE_CALLS); - /** Permission grant: not grant the permission. */ private static final int GRANT_DENIED = 1; /** Permission grant: grant the permission as an install permission. */ @@ -160,6 +131,7 @@ public class PermissionManagerService { private final HandlerThread mHandlerThread; private final Handler mHandler; private final Context mContext; + private final MetricsLogger mMetricsLogger = new MetricsLogger(); /** Internal storage for permissions and related settings */ @GuardedBy("mLock") @@ -1386,7 +1358,7 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages)); } if (bp.isRuntime()) { - logPermissionGranted(mContext, permName, packageName); + logPermission(MetricsEvent.ACTION_PERMISSION_GRANTED, permName, packageName); } if (callback != null) { @@ -1484,7 +1456,7 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages)); } if (bp.isRuntime()) { - logPermissionRevoked(mContext, permName, packageName); + logPermission(MetricsEvent.ACTION_PERMISSION_REVOKED, permName, packageName); } if (callback != null) { @@ -1938,63 +1910,18 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages)); } /** - * Get the first event id for the permission. - * - * <p>There are four events for each permission: <ul> - * <li>Request permission: first id + 0</li> - * <li>Grant permission: first id + 1</li> - * <li>Request for permission denied: first id + 2</li> - * <li>Revoke permission: first id + 3</li> - * </ul></p> - * - * @param name name of the permission - * - * @return The first event id for the permission - */ - private static int getBaseEventId(@NonNull String name) { - int eventIdIndex = ALL_DANGEROUS_PERMISSIONS.indexOf(name); - - if (eventIdIndex == -1) { - if (AppOpsManager.permissionToOpCode(name) == AppOpsManager.OP_NONE - || Build.IS_USER) { - Log.i(TAG, "Unknown permission " + name); - - return MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN; - } else { - // Most likely #ALL_DANGEROUS_PERMISSIONS needs to be updated. - // - // Also update - // - EventLogger#ALL_DANGEROUS_PERMISSIONS - // - metrics_constants.proto - throw new IllegalStateException("Unknown permission " + name); - } - } - - return MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + eventIdIndex * 4; - } - - /** - * Log that a permission was revoked. + * Log that a permission request was granted/revoked. * - * @param context Context of the caller + * @param action the action performed * @param name name of the permission - * @param packageName package permission if for + * @param packageName package permission is for */ - private static void logPermissionRevoked(@NonNull Context context, @NonNull String name, - @NonNull String packageName) { - MetricsLogger.action(context, getBaseEventId(name) + 3, packageName); - } + private void logPermission(int action, @NonNull String name, @NonNull String packageName) { + final LogMaker log = new LogMaker(action); + log.setPackageName(packageName); + log.addTaggedData(MetricsEvent.FIELD_PERMISSION, name); - /** - * Log that a permission request was granted. - * - * @param context Context of the caller - * @param name name of the permission - * @param packageName package permission if for - */ - private static void logPermissionGranted(@NonNull Context context, @NonNull String name, - @NonNull String packageName) { - MetricsLogger.action(context, getBaseEventId(name) + 1, packageName); + mMetricsLogger.write(log); } private class PermissionManagerInternalImpl extends PermissionManagerInternal { diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java index edd2fdb1b33a..c6ec287d9c6a 100644 --- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java +++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java @@ -52,6 +52,7 @@ import android.widget.Button; import android.widget.FrameLayout; import com.android.internal.R; +import com.android.server.vr.VrManagerService; /** * Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden @@ -147,7 +148,6 @@ public class ImmersiveModeConfirmation { && userSetupComplete && !mVrModeEnabled && !navBarEmpty - && !isLockTaskModeLocked() && !UserManager.isDeviceInDemoMode(mContext)) { mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs); } @@ -156,20 +156,6 @@ public class ImmersiveModeConfirmation { } } - /** - * @return {@code true} if and only if the device is currently in LockTask mode managed by - * {@link android.app.admin.DevicePolicyManager}. Note that this differs from the screen pinning - * mode which is initiated by the user. - */ - private boolean isLockTaskModeLocked() { - try { - return ActivityManager.getService().getLockTaskModeState() - == ActivityManager.LOCK_TASK_MODE_LOCKED; - } catch (RemoteException e) { - return false; - } - } - public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode, boolean navBarEmpty) { if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) { diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java index 1781d8c657c3..273b945d4597 100644 --- a/services/core/java/com/android/server/power/BatterySaverPolicy.java +++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java @@ -20,6 +20,8 @@ import android.content.ContentResolver; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; +import android.os.PowerManager; +import android.os.PowerManager.ServiceType; import android.provider.Settings; import android.util.KeyValueListParser; import android.util.Slog; @@ -34,31 +36,6 @@ import java.lang.annotation.RetentionPolicy; * Class to decide whether to turn on battery saver mode for specific service */ public class BatterySaverPolicy extends ContentObserver { - @Retention(RetentionPolicy.SOURCE) - @IntDef({ServiceType.GPS, - ServiceType.VIBRATION, - ServiceType.ANIMATION, - ServiceType.FULL_BACKUP, - ServiceType.KEYVALUE_BACKUP, - ServiceType.NETWORK_FIREWALL, - ServiceType.SCREEN_BRIGHTNESS, - ServiceType.SOUND, - ServiceType.BATTERY_STATS, - ServiceType.DATA_SAVER}) - public @interface ServiceType { - int NULL = 0; - int GPS = 1; - int VIBRATION = 2; - int ANIMATION = 3; - int FULL_BACKUP = 4; - int KEYVALUE_BACKUP = 5; - int NETWORK_FIREWALL = 6; - int SCREEN_BRIGHTNESS = 7; - int SOUND = 8; - int BATTERY_STATS = 9; - int DATA_SAVER = 10; - } - private static final String TAG = "BatterySaverPolicy"; // Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode. diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 2494bded1b86..8f23cf829366 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -43,6 +43,7 @@ import android.os.IPowerManager; import android.os.Looper; import android.os.Message; import android.os.PowerManager; +import android.os.PowerManager.ServiceType; import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.Process; @@ -89,7 +90,6 @@ import com.android.server.Watchdog; import com.android.server.am.BatteryStatsService; import com.android.server.lights.Light; import com.android.server.lights.LightsManager; -import com.android.server.power.BatterySaverPolicy.ServiceType; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 41534cbb641f..248872338928 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -286,10 +286,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - // These values must be kept in sync with cmd/statsd/StatsPullerManager.h. - // TODO: pull the constant from stats_events.proto instead - private static final int PULL_CODE_KERNEL_WAKELOCKS = 20; - private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader(); private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats(); @@ -347,12 +343,12 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } @Override // Binder call - public StatsLogEventWrapper[] pullData(int pullCode) { + public StatsLogEventWrapper[] pullData(int tagId) { enforceCallingPermission(); if (DEBUG) - Slog.d(TAG, "Pulling " + pullCode); + Slog.d(TAG, "Pulling " + tagId); - switch (pullCode) { + switch (tagId) { case StatsLog.WIFI_BYTES_TRANSFERRED: { long token = Binder.clearCallingIdentity(); try { @@ -366,7 +362,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { // Combine all the metrics per Uid into one record. NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null).groupedByUid(); - return addNetworkStats(pullCode, stats, false); + return addNetworkStats(tagId, stats, false); } catch (java.io.IOException e) { Slog.e(TAG, "Pulling netstats for wifi bytes has error", e); } finally { @@ -386,7 +382,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { // Combine all the metrics per Uid into one record. NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null).groupedByUid(); - return addNetworkStats(pullCode, stats, false); + return addNetworkStats(tagId, stats, false); } catch (java.io.IOException e) { Slog.e(TAG, "Pulling netstats for mobile bytes has error", e); } finally { @@ -406,7 +402,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { NetworkStats stats = rollupNetworkStatsByFGBG( nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null)); - return addNetworkStats(pullCode, stats, true); + return addNetworkStats(tagId, stats, true); } catch (java.io.IOException e) { Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e); } finally { @@ -426,7 +422,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { NetworkStats stats = rollupNetworkStatsByFGBG( nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null)); - return addNetworkStats(pullCode, stats, true); + return addNetworkStats(tagId, stats, true); } catch (java.io.IOException e) { Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e); } finally { @@ -434,14 +430,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } break; } - case StatsLog.KERNEL_WAKELOCKS_REPORTED: { + case StatsLog.KERNEL_WAKELOCK_PULLED: { final KernelWakelockStats wakelockStats = mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats); List<StatsLogEventWrapper> ret = new ArrayList(); for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) { String name = ent.getKey(); KernelWakelockStats.Entry kws = ent.getValue(); - StatsLogEventWrapper e = new StatsLogEventWrapper(pullCode, 4); + StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 4); e.writeString(name); e.writeInt(kws.mCount); e.writeInt(kws.mVersion); @@ -451,7 +447,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { return ret.toArray(new StatsLogEventWrapper[ret.size()]); } default: - Slog.w(TAG, "No such pollable data as " + pullCode); + Slog.w(TAG, "No such tagId data as " + tagId); return null; } return null; diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java index e7e4efccea2f..e8ebbe4dd805 100644 --- a/services/core/java/com/android/server/vr/VrManagerService.java +++ b/services/core/java/com/android/server/vr/VrManagerService.java @@ -166,6 +166,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC private boolean mUserUnlocked; private Vr2dDisplay mVr2dDisplay; private boolean mBootsToVr; + private boolean mStandby; + private boolean mUseStandbyToExitVrMode; // Handles events from the managed services (e.g. VrListenerService and any bound VR compositor // service). @@ -203,7 +205,10 @@ public class VrManagerService extends SystemService implements EnabledComponentC * */ private void updateVrModeAllowedLocked() { - boolean allowed = mSystemSleepFlags == FLAG_ALL && mUserUnlocked; + boolean ignoreSleepFlags = mBootsToVr && mUseStandbyToExitVrMode; + boolean disallowedByStandby = mStandby && mUseStandbyToExitVrMode; + boolean allowed = (mSystemSleepFlags == FLAG_ALL || ignoreSleepFlags) && mUserUnlocked + && !disallowedByStandby; if (mVrModeAllowed != allowed) { mVrModeAllowed = allowed; if (DBG) Slog.d(TAG, "VR mode is " + ((allowed) ? "allowed" : "disallowed")); @@ -273,6 +278,17 @@ public class VrManagerService extends SystemService implements EnabledComponentC } } + private void setStandbyEnabled(boolean standby) { + synchronized(mLock) { + if (!mBootsToVr) { + Slog.e(TAG, "Attempting to set standby mode on a non-standalone device"); + return; + } + mStandby = standby; + updateVrModeAllowedLocked(); + } + } + private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { @@ -587,6 +603,12 @@ public class VrManagerService extends SystemService implements EnabledComponentC } @Override + public void setStandbyEnabled(boolean standby) { + enforceCallerPermissionAnyOf(Manifest.permission.ACCESS_VR_MANAGER); + VrManagerService.this.setStandbyEnabled(standby); + } + + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; @@ -733,6 +755,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC } mBootsToVr = SystemProperties.getBoolean("ro.boot.vr", false); + mUseStandbyToExitVrMode = mBootsToVr + && SystemProperties.getBoolean("persist.vr.use_standby_to_exit_vr_mode", false); publishLocalService(VrManagerInternal.class, new LocalService()); publishBinderService(Context.VR_SERVICE, mVrManager.asBinder()); } diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 0ac2cff42be9..6e89e3ea37bb 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -523,7 +523,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm( mService.mContext.getResources(), displayWidth, displayHeight, dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds, - isMinimizedDockAndHomeStackResizable()); + getDockSide(), isMinimizedDockAndHomeStackResizable()); final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition); // Recalculate the bounds based on the position of the target. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index bf5f4bc83e6c..b28bb719188c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -158,6 +158,7 @@ import android.os.Message; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.PowerManager; +import android.os.PowerManager.ServiceType; import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.RemoteException; @@ -243,7 +244,6 @@ import com.android.server.LocalServices; import com.android.server.UiThread; import com.android.server.Watchdog; import com.android.server.input.InputManagerService; -import com.android.server.power.BatterySaverPolicy.ServiceType; import com.android.server.power.ShutdownThread; import com.android.server.utils.PriorityDump; diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java index 69589e7d1f66..50ac41cdf417 100644 --- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java @@ -15,13 +15,12 @@ */ package com.android.server.power; +import android.os.PowerManager.ServiceType; import android.os.PowerSaveState; import android.os.Handler; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; -import com.android.server.power.BatterySaverPolicy.ServiceType; - import org.mockito.Mock; import org.mockito.MockitoAnnotations; diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index 4559660351b0..b60d5bf90766 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -66,7 +66,7 @@ public class PowerManagerServiceTest extends AndroidTestCase { .setBrightnessFactor(BRIGHTNESS_FACTOR) .build(); when(mBatterySaverPolicy.getBatterySaverPolicy( - eq(BatterySaverPolicy.ServiceType.SCREEN_BRIGHTNESS), anyBoolean())) + eq(PowerManager.ServiceType.SCREEN_BRIGHTNESS), anyBoolean())) .thenReturn(mPowerSaveState); mDisplayPowerRequest = new DisplayPowerRequest(); mService = new PowerManagerService(getContext(), mBatterySaverPolicy); diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java index ea4f4b907824..bb882641c55f 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java @@ -46,11 +46,13 @@ import static org.junit.Assert.assertTrue; * bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests */ @SmallTest -@Presubmit +// TODO: b/68267650 +// @Presubmit @RunWith(AndroidJUnit4.class) public class AppWindowTokenTests extends WindowTestsBase { @Test + @Presubmit public void testAddWindow_Order() throws Exception { final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(mDisplayContent); @@ -79,6 +81,7 @@ public class AppWindowTokenTests extends WindowTestsBase { } @Test + @Presubmit public void testFindMainWindow() throws Exception { final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(mDisplayContent); @@ -97,6 +100,7 @@ public class AppWindowTokenTests extends WindowTestsBase { } @Test + @Presubmit public void testGetTopFullscreenWindow() throws Exception { final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(mDisplayContent); @@ -187,6 +191,7 @@ public class AppWindowTokenTests extends WindowTestsBase { } @Test + @Presubmit public void testGetOrientation() throws Exception { final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(mDisplayContent); @@ -211,6 +216,7 @@ public class AppWindowTokenTests extends WindowTestsBase { } @Test + @Presubmit public void testKeyguardFlagsDuringRelaunch() throws Exception { final WindowTestUtils.TestAppWindowToken token = new WindowTestUtils.TestAppWindowToken(mDisplayContent); diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java index f53eb15d482b..25c54b3e51eb 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java @@ -36,12 +36,12 @@ import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent; import android.hardware.soundtrigger.SoundTriggerModule; import android.os.DeadObjectException; import android.os.PowerManager; +import android.os.PowerManager.ServiceType; import android.os.RemoteException; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Slog; import com.android.internal.logging.MetricsLogger; -import com.android.server.power.BatterySaverPolicy.ServiceType; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 1569ac32128b..44e5314ff7dd 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -30,6 +30,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.pm.ShortcutServiceInternal; import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.soundtrigger.IRecognitionStatusCallback; @@ -44,6 +45,7 @@ import android.os.Parcel; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.service.voice.IVoiceInteractionService; import android.service.voice.IVoiceInteractionSession; @@ -53,6 +55,7 @@ import android.service.voice.VoiceInteractionServiceInfo; import android.service.voice.VoiceInteractionSession; import android.speech.RecognitionService; import android.text.TextUtils; +import android.util.ArraySet; import android.util.Log; import android.util.Slog; @@ -63,6 +66,7 @@ import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.PackageMonitor; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; +import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.UiThread; @@ -84,7 +88,9 @@ public class VoiceInteractionManagerService extends SystemService { final ContentResolver mResolver; final DatabaseHelper mDbHelper; final ActivityManagerInternal mAmInternal; - final TreeSet<Integer> mLoadedKeyphraseIds; + final UserManager mUserManager; + final ArraySet<Integer> mLoadedKeyphraseIds = new ArraySet<>(); + ShortcutServiceInternal mShortcutServiceInternal; SoundTriggerInternal mSoundTriggerInternal; private final RemoteCallbackList<IVoiceInteractionSessionListener> @@ -96,8 +102,10 @@ public class VoiceInteractionManagerService extends SystemService { mResolver = context.getContentResolver(); mDbHelper = new DatabaseHelper(context); mServiceStub = new VoiceInteractionManagerServiceStub(); - mAmInternal = LocalServices.getService(ActivityManagerInternal.class); - mLoadedKeyphraseIds = new TreeSet<Integer>(); + mAmInternal = Preconditions.checkNotNull( + LocalServices.getService(ActivityManagerInternal.class)); + mUserManager = Preconditions.checkNotNull( + context.getSystemService(UserManager.class)); PackageManagerInternal packageManagerInternal = LocalServices.getService( PackageManagerInternal.class); @@ -124,6 +132,8 @@ public class VoiceInteractionManagerService extends SystemService { @Override public void onBootPhase(int phase) { if (PHASE_SYSTEM_SERVICES_READY == phase) { + mShortcutServiceInternal = Preconditions.checkNotNull( + LocalServices.getService(ShortcutServiceInternal.class)); mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class); } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { mServiceStub.systemRunning(isSafeMode()); @@ -180,6 +190,7 @@ public class VoiceInteractionManagerService extends SystemService { private boolean mSafeMode; private int mCurUser; + private boolean mCurUserUnlocked; private final boolean mEnableService; VoiceInteractionManagerServiceStub() { @@ -381,6 +392,7 @@ public class VoiceInteractionManagerService extends SystemService { public void switchUser(int userHandle) { synchronized (this) { mCurUser = userHandle; + mCurUserUnlocked = false; switchImplementationIfNeededLocked(false); } } @@ -409,13 +421,24 @@ public class VoiceInteractionManagerService extends SystemService { } } + final boolean hasComponent = serviceComponent != null && serviceInfo != null; + + if (mUserManager.isUserUnlockingOrUnlocked(mCurUser)) { + if (hasComponent) { + mShortcutServiceInternal.setShortcutHostPackage(TAG, + serviceComponent.getPackageName(), mCurUser); + } else { + mShortcutServiceInternal.setShortcutHostPackage(TAG, null, mCurUser); + } + } + if (force || mImpl == null || mImpl.mUser != mCurUser || !mImpl.mComponent.equals(serviceComponent)) { unloadAllKeyphraseModels(); if (mImpl != null) { mImpl.shutdownLocked(); } - if (serviceComponent != null && serviceInfo != null) { + if (hasComponent) { mImpl = new VoiceInteractionManagerServiceImpl(mContext, UiThread.getHandler(), this, mCurUser, serviceComponent); mImpl.startLocked(); @@ -953,12 +976,14 @@ public class VoiceInteractionManagerService extends SystemService { } private synchronized void unloadAllKeyphraseModels() { - for (int keyphraseId : mLoadedKeyphraseIds) { + for (int i = 0; i < mLoadedKeyphraseIds.size(); i++) { final long caller = Binder.clearCallingIdentity(); try { - int status = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId); + int status = mSoundTriggerInternal.unloadKeyphraseModel( + mLoadedKeyphraseIds.valueAt(i)); if (status != SoundTriggerInternal.STATUS_OK) { - Slog.w(TAG, "Failed to unload keyphrase " + keyphraseId + ":" + status); + Slog.w(TAG, "Failed to unload keyphrase " + mLoadedKeyphraseIds.valueAt(i) + + ":" + status); } } finally { Binder.restoreCallingIdentity(caller); diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk new file mode 100644 index 000000000000..e0c9d1c04498 --- /dev/null +++ b/tools/aapt2/Android.mk @@ -0,0 +1,7 @@ +include $(CLEAR_VARS) + +.PHONY: aapt2_run_host_unit_tests +aapt2_run_host_unit_tests: PRIVATE_GTEST_OPTIONS := --gtest_output=xml:$(DIST_DIR)/gtest/aapt2_host_unit_tests_result.xml +aapt2_run_host_unit_tests: $(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests + -$(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests $(PRIVATE_GTEST_OPTIONS) > /dev/null 2>&1 + diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp index 3654901e3e02..afa155f46eb9 100644 --- a/tools/aapt2/configuration/ConfigurationParser_test.cpp +++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp @@ -423,11 +423,11 @@ TEST_F(ConfigurationParserTest, AndroidSdkGroupAction) { TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_NonNumeric) { static constexpr const char* xml = R"xml( - <android-sdk-group label="O"> + <android-sdk-group label="P"> <android-sdk minSdkVersion="M" - targetSdkVersion="O" - maxSdkVersion="O"> + targetSdkVersion="P" + maxSdkVersion="P"> </android-sdk> </android-sdk-group>)xml"; @@ -438,14 +438,14 @@ TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_NonNumeric) { ASSERT_TRUE(ok); ASSERT_EQ(1ul, config.android_sdk_groups.size()); - ASSERT_EQ(1u, config.android_sdk_groups.count("O")); + ASSERT_EQ(1u, config.android_sdk_groups.count("P")); - auto& out = config.android_sdk_groups["O"]; + auto& out = config.android_sdk_groups["P"]; AndroidSdk sdk; sdk.min_sdk_version = {}; // Only the latest development version is supported. - sdk.target_sdk_version = 26; - sdk.max_sdk_version = 26; + sdk.target_sdk_version = 28; + sdk.max_sdk_version = 28; ASSERT_EQ(sdk, out); } diff --git a/tools/aapt2/xml/XmlActionExecutor.cpp b/tools/aapt2/xml/XmlActionExecutor.cpp index cc664a5de722..602a902bfc3e 100644 --- a/tools/aapt2/xml/XmlActionExecutor.cpp +++ b/tools/aapt2/xml/XmlActionExecutor.cpp @@ -16,6 +16,8 @@ #include "xml/XmlActionExecutor.h" +using ::android::StringPiece; + namespace aapt { namespace xml { @@ -46,8 +48,8 @@ static void PrintElementToDiagMessage(const Element* el, DiagMessage* msg) { *msg << el->name << ">"; } -bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag, - Element* el) const { +bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, std::vector<StringPiece>* bread_crumb, + SourcePathDiagnostics* diag, Element* el) const { bool error = false; for (const ActionFuncWithDiag& action : actions_) { error |= !action(el, diag); @@ -57,15 +59,21 @@ bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, SourcePathDiagnostic if (child_el->namespace_uri.empty()) { std::map<std::string, XmlNodeAction>::const_iterator iter = map_.find(child_el->name); if (iter != map_.end()) { - error |= !iter->second.Execute(policy, diag, child_el); + // Use the iterator's copy of the element name, because the element may be modified. + bread_crumb->push_back(iter->first); + error |= !iter->second.Execute(policy, bread_crumb, diag, child_el); + bread_crumb->pop_back(); continue; } if (policy == XmlActionExecutorPolicy::kWhitelist) { DiagMessage error_msg(child_el->line_number); - error_msg << "unknown element "; + error_msg << "unexpected element "; PrintElementToDiagMessage(child_el, &error_msg); - error_msg << " found"; + error_msg << " found in "; + for (const StringPiece& element : *bread_crumb) { + error_msg << "<" << element << ">"; + } diag->Error(error_msg); error = true; } @@ -90,14 +98,15 @@ bool XmlActionExecutor::Execute(XmlActionExecutorPolicy policy, IDiagnostics* di if (el->namespace_uri.empty()) { std::map<std::string, XmlNodeAction>::const_iterator iter = map_.find(el->name); if (iter != map_.end()) { - return iter->second.Execute(policy, &source_diag, el); + std::vector<StringPiece> bread_crumb; + bread_crumb.push_back(iter->first); + return iter->second.Execute(policy, &bread_crumb, &source_diag, el); } if (policy == XmlActionExecutorPolicy::kWhitelist) { DiagMessage error_msg(el->line_number); - error_msg << "unknown element "; + error_msg << "unexpected root element "; PrintElementToDiagMessage(el, &error_msg); - error_msg << " found"; source_diag.Error(error_msg); return false; } diff --git a/tools/aapt2/xml/XmlActionExecutor.h b/tools/aapt2/xml/XmlActionExecutor.h index 1d70045b3023..df70100e882a 100644 --- a/tools/aapt2/xml/XmlActionExecutor.h +++ b/tools/aapt2/xml/XmlActionExecutor.h @@ -40,56 +40,46 @@ enum class XmlActionExecutorPolicy { kWhitelist, }; -/** - * Contains the actions to perform at this XML node. This is a recursive data - * structure that - * holds XmlNodeActions for child XML nodes. - */ +// Contains the actions to perform at this XML node. This is a recursive data structure that +// holds XmlNodeActions for child XML nodes. class XmlNodeAction { public: using ActionFuncWithDiag = std::function<bool(Element*, SourcePathDiagnostics*)>; using ActionFunc = std::function<bool(Element*)>; - /** - * Find or create a child XmlNodeAction that will be performed for the child - * element with the name `name`. - */ - XmlNodeAction& operator[](const std::string& name) { return map_[name]; } + // Find or create a child XmlNodeAction that will be performed for the child element with the + // name `name`. + XmlNodeAction& operator[](const std::string& name) { + return map_[name]; + } - /** - * Add an action to be performed at this XmlNodeAction. - */ + // Add an action to be performed at this XmlNodeAction. void Action(ActionFunc f); void Action(ActionFuncWithDiag); private: friend class XmlActionExecutor; - bool Execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag, Element* el) const; + bool Execute(XmlActionExecutorPolicy policy, std::vector<::android::StringPiece>* bread_crumb, + SourcePathDiagnostics* diag, Element* el) const; std::map<std::string, XmlNodeAction> map_; std::vector<ActionFuncWithDiag> actions_; }; -/** - * Allows the definition of actions to execute at specific XML elements defined - * by their - * hierarchy. - */ +// Allows the definition of actions to execute at specific XML elements defined by their hierarchy. class XmlActionExecutor { public: XmlActionExecutor() = default; - /** - * Find or create a root XmlNodeAction that will be performed for the root XML - * element with the name `name`. - */ - XmlNodeAction& operator[](const std::string& name) { return map_[name]; } + // Find or create a root XmlNodeAction that will be performed for the root XML element with the + // name `name`. + XmlNodeAction& operator[](const std::string& name) { + return map_[name]; + } - /** - * Execute the defined actions for this XmlResource. - * Returns true if all actions return true, otherwise returns false. - */ + // Execute the defined actions for this XmlResource. + // Returns true if all actions return true, otherwise returns false. bool Execute(XmlActionExecutorPolicy policy, IDiagnostics* diag, XmlResource* doc) const; private: diff --git a/tools/aapt2/xml/XmlActionExecutor_test.cpp b/tools/aapt2/xml/XmlActionExecutor_test.cpp index 0fe7ab05ceb2..d39854e5fe4e 100644 --- a/tools/aapt2/xml/XmlActionExecutor_test.cpp +++ b/tools/aapt2/xml/XmlActionExecutor_test.cpp @@ -56,9 +56,13 @@ TEST(XmlActionExecutorTest, FailsWhenUndefinedHierarchyExists) { XmlActionExecutor executor; executor["manifest"]["application"]; - std::unique_ptr<XmlResource> doc = - test::BuildXmlDom("<manifest><application /><activity /></manifest>"); + std::unique_ptr<XmlResource> doc; StdErrDiagnostics diag; + + doc = test::BuildXmlDom("<manifest><application /><activity /></manifest>"); + ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kWhitelist, &diag, doc.get())); + + doc = test::BuildXmlDom("<manifest><application><activity /></application></manifest>"); ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kWhitelist, &diag, doc.get())); } |