diff options
90 files changed, 1606 insertions, 571 deletions
diff --git a/Android.mk b/Android.mk index e219661b19f1..d7d9c900e3bf 100644 --- a/Android.mk +++ b/Android.mk @@ -252,6 +252,11 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS += \ -federate SupportLib https://developer.android.com \ -federationapi SupportLib prebuilts/sdk/current/support-api.txt +# Federate AndroidX references against local API file. +framework_docs_LOCAL_DROIDDOC_OPTIONS += \ + -federate AndroidX https://developer.android.com \ + -federationapi AndroidX prebuilts/sdk/current/androidx-api.txt + # ==== Public API diff =========================== include $(CLEAR_VARS) diff --git a/api/current.txt b/api/current.txt index 406ebac6c5eb..670f6cae1319 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6115,8 +6115,12 @@ package android.app { method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats(); method public android.view.WindowContentFrameStats getWindowContentFrameStats(int); method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows(); + method public void grantRuntimePermission(java.lang.String, java.lang.String); + method public void grantRuntimePermissionAsUser(java.lang.String, java.lang.String, android.os.UserHandle); method public boolean injectInputEvent(android.view.InputEvent, boolean); method public boolean performGlobalAction(int); + method public void revokeRuntimePermission(java.lang.String, java.lang.String); + method public void revokeRuntimePermissionAsUser(java.lang.String, java.lang.String, android.os.UserHandle); method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener); method public boolean setRotation(int); method public void setRunAsMonkey(boolean); @@ -6501,7 +6505,7 @@ package android.app.admin { method public boolean installExistingPackage(android.content.ComponentName, java.lang.String); method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String); method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean); - method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean, boolean); + method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, int); method public boolean isActivePasswordSufficient(); method public boolean isAdminActive(android.content.ComponentName); method public boolean isAffiliatedUser(); @@ -6685,6 +6689,8 @@ package android.app.admin { field public static final int ID_TYPE_IMEI = 4; // 0x4 field public static final int ID_TYPE_MEID = 8; // 0x8 field public static final int ID_TYPE_SERIAL = 2; // 0x2 + field public static final int INSTALLKEY_REQUEST_CREDENTIALS_ACCESS = 1; // 0x1 + field public static final int INSTALLKEY_SET_USER_SELECTABLE = 2; // 0x2 field public static final int KEYGUARD_DISABLE_BIOMETRICS = 416; // 0x1a0 field public static final int KEYGUARD_DISABLE_FACE = 128; // 0x80 field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff @@ -13644,7 +13650,6 @@ package android.graphics { method public android.graphics.ImageDecoder.OnPartialImageListener getOnPartialImageListener(); method public android.graphics.PostProcessor getPostProcessor(); method public boolean getRequireUnpremultiplied(); - method public android.util.Size getSampledSize(int); method public android.graphics.ImageDecoder setAllocator(int); method public android.graphics.ImageDecoder setConserveMemory(boolean); method public android.graphics.ImageDecoder setCrop(android.graphics.Rect); @@ -13653,8 +13658,8 @@ package android.graphics { method public android.graphics.ImageDecoder setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener); method public android.graphics.ImageDecoder setPostProcessor(android.graphics.PostProcessor); method public android.graphics.ImageDecoder setRequireUnpremultiplied(boolean); - method public android.graphics.ImageDecoder setResize(int, int); - method public android.graphics.ImageDecoder setResize(int); + method public android.graphics.ImageDecoder setSampleSize(int); + method public android.graphics.ImageDecoder setTargetSize(int, int); field public static final int ALLOCATOR_DEFAULT = 0; // 0x0 field public static final int ALLOCATOR_HARDWARE = 3; // 0x3 field public static final int ALLOCATOR_SHARED_MEMORY = 2; // 0x2 diff --git a/api/removed.txt b/api/removed.txt index 9fe25c90872b..5863e777bb14 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -184,6 +184,8 @@ package android.graphics { public final class ImageDecoder implements java.lang.AutoCloseable { method public deprecated boolean getAsAlphaMask(); method public deprecated android.graphics.ImageDecoder setAsAlphaMask(boolean); + method public deprecated android.graphics.ImageDecoder setResize(int, int); + method public deprecated android.graphics.ImageDecoder setResize(int); field public static final deprecated int ERROR_SOURCE_ERROR = 3; // 0x3 field public static final deprecated int ERROR_SOURCE_EXCEPTION = 1; // 0x1 field public static final deprecated int ERROR_SOURCE_INCOMPLETE = 2; // 0x2 diff --git a/api/system-current.txt b/api/system-current.txt index 5568dbad0e8c..a81afed5ecdb 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -2101,6 +2101,7 @@ package android.hardware.radio { method public java.lang.String getVersion(); method public boolean isBackgroundScanningSupported(); method public boolean isCaptureSupported(); + method public boolean isInitializationRequired(); method public boolean isProgramIdentifierSupported(int); method public boolean isProgramTypeSupported(int); method public void writeToParcel(android.os.Parcel, int); diff --git a/api/test-current.txt b/api/test-current.txt index d32372517431..b520dfb441d0 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1,8 +1,10 @@ package android { public static final class Manifest.permission { + field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING"; field public static final java.lang.String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE"; field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS"; + field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; } } @@ -127,8 +129,8 @@ package android.app { public final class UiAutomation { method public void destroy(); method public android.os.ParcelFileDescriptor[] executeShellCommandRw(java.lang.String); - method public boolean grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); - method public boolean revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); + method public deprecated boolean grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); + method public deprecated boolean revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); } public class UiModeManager { diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index a458c07394a7..c1ff27545401 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -79,8 +79,6 @@ StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap, mSendBroadcast(sendBroadcast), mTimeBaseSec(timeBaseSec), mLastLogTimestamp(0) { - StatsPullerManager statsPullerManager; - statsPullerManager.SetTimeBaseSec(mTimeBaseSec); } StatsLogProcessor::~StatsLogProcessor() { @@ -177,7 +175,7 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event) { uint64_t curTimeSec = getElapsedRealtimeSec(); if (curTimeSec - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) { - mStatsPullerManager.ClearPullerCacheIfNecessary(curTimeSec); + mStatsPullerManager.ClearPullerCacheIfNecessary(curTimeSec * NS_PER_SEC); mLastPullerCacheClearTimeSec = curTimeSec; } diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index b03b4b4a942c..9f70c75d66e9 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -595,7 +595,7 @@ status_t StatsService::cmd_log_app_breadcrumb(FILE* out, const Vector<String8>& status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) { int s = atoi(args[1].c_str()); vector<shared_ptr<LogEvent> > stats; - if (mStatsPullerManager.Pull(s, &stats)) { + if (mStatsPullerManager.Pull(s, getElapsedRealtimeNs(), &stats)) { for (const auto& it : stats) { fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str()); } diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp index 3b0cd349168d..ec5a5d6f3724 100644 --- a/cmds/statsd/src/external/StatsPuller.cpp +++ b/cmds/statsd/src/external/StatsPuller.cpp @@ -35,26 +35,31 @@ void StatsPuller::SetUidMap(const sp<UidMap>& uidMap) { mUidMap = uidMap; } // ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently StatsPuller::StatsPuller(const int tagId) : mTagId(tagId) { - mCoolDownSec = StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.coolDownSec; - VLOG("Puller for tag %d created. Cooldown set to %ld", mTagId, mCoolDownSec); + mCoolDownNs = StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.coolDownNs; + VLOG("Puller for tag %d created. Cooldown set to %lld", mTagId, (long long)mCoolDownNs); } -bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) { +bool StatsPuller::Pull(const int64_t elapsedTimeNs, std::vector<std::shared_ptr<LogEvent>>* data) { lock_guard<std::mutex> lock(mLock); + int64_t wallClockTimeNs = getWallClockNs(); StatsdStats::getInstance().notePull(mTagId); - long curTime = getElapsedRealtimeSec(); - if (curTime - mLastPullTimeSec < mCoolDownSec) { + if (elapsedTimeNs - mLastPullTimeNs < mCoolDownNs) { (*data) = mCachedData; StatsdStats::getInstance().notePullFromCache(mTagId); return true; } - if (mMinPullIntervalSec > curTime - mLastPullTimeSec) { - mMinPullIntervalSec = curTime - mLastPullTimeSec; - StatsdStats::getInstance().updateMinPullIntervalSec(mTagId, mMinPullIntervalSec); + if (mMinPullIntervalNs > elapsedTimeNs - mLastPullTimeNs) { + mMinPullIntervalNs = elapsedTimeNs - mLastPullTimeNs; + StatsdStats::getInstance().updateMinPullIntervalSec(mTagId, + mMinPullIntervalNs / NS_PER_SEC); } mCachedData.clear(); - mLastPullTimeSec = curTime; + mLastPullTimeNs = elapsedTimeNs; bool ret = PullInternal(&mCachedData); + for (const shared_ptr<LogEvent>& data : mCachedData) { + data->setElapsedTimestampNs(elapsedTimeNs); + data->setLogdWallClockTimestampNs(wallClockTimeNs); + } if (ret) { mergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId); (*data) = mCachedData; @@ -70,12 +75,12 @@ int StatsPuller::clearCache() { lock_guard<std::mutex> lock(mLock); int ret = mCachedData.size(); mCachedData.clear(); - mLastPullTimeSec = 0; + mLastPullTimeNs = 0; return ret; } -int StatsPuller::ClearCacheIfNecessary(long timestampSec) { - if (timestampSec - mLastPullTimeSec > mCoolDownSec) { +int StatsPuller::ClearCacheIfNecessary(int64_t timestampNs) { + if (timestampNs - mLastPullTimeNs > mCoolDownNs) { return clearCache(); } else { return 0; diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h index 936c47e92f2c..caac677ee215 100644 --- a/cmds/statsd/src/external/StatsPuller.h +++ b/cmds/statsd/src/external/StatsPuller.h @@ -37,13 +37,13 @@ public: virtual ~StatsPuller() {} - bool Pull(std::vector<std::shared_ptr<LogEvent>>* data); + bool Pull(const int64_t timeNs, std::vector<std::shared_ptr<LogEvent>>* data); // Clear cache immediately int ForceClearCache(); // Clear cache if elapsed time is more than cooldown time - int ClearCacheIfNecessary(long timestampSec); + int ClearCacheIfNecessary(int64_t timestampNs); static void SetUidMap(const sp<UidMap>& uidMap); @@ -59,9 +59,9 @@ private: // If a pull request comes before cooldown, a cached version from purevious pull // will be returned. // The actual value should be determined by individual pullers. - long mCoolDownSec; + int64_t mCoolDownNs; // For puller stats - long mMinPullIntervalSec = LONG_MAX; + int64_t mMinPullIntervalNs = LONG_MAX; virtual bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) = 0; @@ -69,7 +69,7 @@ private: // cached data will be returned. std::vector<std::shared_ptr<LogEvent>> mCachedData; - long mLastPullTimeSec; + int64_t mLastPullTimeNs; int clearCache(); diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h index 2717d5c2de9c..83d59c0a5830 100644 --- a/cmds/statsd/src/external/StatsPullerManager.h +++ b/cmds/statsd/src/external/StatsPullerManager.h @@ -26,10 +26,9 @@ class StatsPullerManager { public: virtual ~StatsPullerManager() {} - virtual void RegisterReceiver(int tagId, - wp <PullDataReceiver> receiver, - long intervalMs) { - mPullerManager.RegisterReceiver(tagId, receiver, intervalMs); + virtual void RegisterReceiver(int tagId, wp<PullDataReceiver> receiver, int64_t nextPullTimeNs, + int64_t intervalNs) { + mPullerManager.RegisterReceiver(tagId, receiver, nextPullTimeNs, intervalNs); }; virtual void UnRegisterReceiver(int tagId, wp <PullDataReceiver> receiver) { @@ -45,13 +44,9 @@ class StatsPullerManager { mPullerManager.OnAlarmFired(); } - virtual bool - Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) { - return mPullerManager.Pull(tagId, data); - } - - void SetTimeBaseSec(const long timeBaseSec) { - mPullerManager.SetTimeBaseSec(timeBaseSec); + virtual bool Pull(const int tagId, const int64_t timesNs, + vector<std::shared_ptr<LogEvent>>* data) { + return mPullerManager.Pull(tagId, timesNs, data); } int ForceClearPullerCache() { @@ -62,8 +57,8 @@ class StatsPullerManager { mPullerManager.SetStatsCompanionService(statsCompanionService); } - int ClearPullerCacheIfNecessary(long timestampSec) { - return mPullerManager.ClearPullerCacheIfNecessary(timestampSec); + int ClearPullerCacheIfNecessary(int64_t timestampNs) { + return mPullerManager.ClearPullerCacheIfNecessary(timestampNs); } private: diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp index dd6406bb90ca..0e23bf01074c 100644 --- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp +++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp @@ -19,15 +19,17 @@ #include <android/os/IStatsCompanionService.h> #include <cutils/log.h> +#include <math.h> #include <algorithm> #include <climits> +#include "../StatsService.h" #include "../logd/LogEvent.h" #include "../stats_log_util.h" #include "../statscompanion_util.h" #include "ResourceHealthManagerPuller.h" #include "ResourceThermalManagerPuller.h" #include "StatsCompanionServicePuller.h" -#include "StatsService.h" +#include "StatsPullerManagerImpl.h" #include "SubsystemSleepStatePuller.h" #include "statslog.h" @@ -47,89 +49,136 @@ namespace statsd { const std::map<int, PullAtomInfo> StatsPullerManagerImpl::kAllPullAtomInfo = { // wifi_bytes_transfer {android::util::WIFI_BYTES_TRANSFER, - {{2, 3, 4, 5}, {}, 1, + {{2, 3, 4, 5}, + {}, + 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER)}}, // wifi_bytes_transfer_by_fg_bg {android::util::WIFI_BYTES_TRANSFER_BY_FG_BG, - {{3, 4, 5, 6}, {2}, 1, + {{3, 4, 5, 6}, + {2}, + 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}}, // mobile_bytes_transfer {android::util::MOBILE_BYTES_TRANSFER, - {{2, 3, 4, 5}, {}, 1, + {{2, 3, 4, 5}, + {}, + 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}}, // mobile_bytes_transfer_by_fg_bg {android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG, - {{3, 4, 5, 6}, {2}, 1, + {{3, 4, 5, 6}, + {2}, + 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}}, // bluetooth_bytes_transfer {android::util::BLUETOOTH_BYTES_TRANSFER, - {{2, 3}, {}, 1, new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}}, + {{2, 3}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}}, // kernel_wakelock {android::util::KERNEL_WAKELOCK, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}}, + {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}}, // subsystem_sleep_state {android::util::SUBSYSTEM_SLEEP_STATE, - {{}, {}, 1, new SubsystemSleepStatePuller()}}, + {{}, {}, 1 * NS_PER_SEC, new SubsystemSleepStatePuller()}}, // cpu_time_per_freq {android::util::CPU_TIME_PER_FREQ, - {{3}, {2}, 1, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}}, + {{3}, + {2}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}}, // cpu_time_per_uid {android::util::CPU_TIME_PER_UID, - {{2, 3}, {}, 1, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID)}}, + {{2, 3}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID)}}, // cpu_time_per_uid_freq - // the throttling is 3sec, handled in frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader + // the throttling is 3sec, handled in + // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader {android::util::CPU_TIME_PER_UID_FREQ, - {{4}, {2,3}, 0, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID_FREQ)}}, + {{4}, + {2, 3}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID_FREQ)}}, // cpu_active_time - // the throttling is 3sec, handled in frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader + // the throttling is 3sec, handled in + // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader {android::util::CPU_ACTIVE_TIME, - {{2}, {}, 0, new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}}, + {{2}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}}, // cpu_cluster_time - // the throttling is 3sec, handled in frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader + // the throttling is 3sec, handled in + // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader {android::util::CPU_CLUSTER_TIME, - {{3}, {2}, 0, new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}}, + {{3}, + {2}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}}, // wifi_activity_energy_info {android::util::WIFI_ACTIVITY_ENERGY_INFO, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_ENERGY_INFO)}}, + {{}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_ENERGY_INFO)}}, // modem_activity_info {android::util::MODEM_ACTIVITY_INFO, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}}, + {{}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}}, // bluetooth_activity_info {android::util::BLUETOOTH_ACTIVITY_INFO, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}}, + {{}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}}, // system_elapsed_realtime {android::util::SYSTEM_ELAPSED_REALTIME, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}}, + {{}, + {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}}, // system_uptime {android::util::SYSTEM_UPTIME, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}}, + {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}}, // disk_space {android::util::DISK_SPACE, - {{}, {}, 1, new StatsCompanionServicePuller(android::util::DISK_SPACE)}}, + {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DISK_SPACE)}}, // remaining_battery_capacity {android::util::REMAINING_BATTERY_CAPACITY, - {{}, {}, 1, new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}}, + {{}, + {}, + 1 * NS_PER_SEC, + new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}}, // full_battery_capacity {android::util::FULL_BATTERY_CAPACITY, - {{}, {}, 1, new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}, + {{}, + {}, + 1 * NS_PER_SEC, + new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}, // process_memory_state {android::util::PROCESS_MEMORY_STATE, - {{4,5,6,7,8}, - {2,3}, - 0, + {{4, 5, 6, 7, 8}, + {2, 3}, + 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}}, // temperature {android::util::TEMPERATURE, {{}, {}, 1, new ResourceThermalManagerPuller()}}}; -StatsPullerManagerImpl::StatsPullerManagerImpl() - : mCurrentPullingInterval(LONG_MAX) { +StatsPullerManagerImpl::StatsPullerManagerImpl() : mNextPullTimeNs(LONG_MAX) { } -bool StatsPullerManagerImpl::Pull(int tagId, vector<shared_ptr<LogEvent>>* data) { +bool StatsPullerManagerImpl::Pull(const int tagId, const int64_t timeNs, + vector<shared_ptr<LogEvent>>* data) { VLOG("Initiating pulling %d", tagId); if (kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end()) { - bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(data); + bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(timeNs, data); VLOG("pulled %d items", (int)data->size()); return ret; } else { @@ -148,12 +197,14 @@ bool StatsPullerManagerImpl::PullerForMatcherExists(int tagId) const { } void StatsPullerManagerImpl::updateAlarmLocked() { - long currentTimeMs = getElapsedRealtimeMillis(); - long nextAlarmTimeMs = currentTimeMs + mCurrentPullingInterval - - (currentTimeMs - mTimeBaseSec * 1000) % mCurrentPullingInterval; + if (mNextPullTimeNs == LONG_MAX) { + VLOG("No need to set alarms. Skipping"); + return; + } + sp<IStatsCompanionService> statsCompanionServiceCopy = mStatsCompanionService; if (statsCompanionServiceCopy != nullptr) { - statsCompanionServiceCopy->setPullingAlarms(nextAlarmTimeMs, mCurrentPullingInterval); + statsCompanionServiceCopy->setPullingAlarm(mNextPullTimeNs / 1000000); } else { VLOG("StatsCompanionService not available. Alarm not set."); } @@ -174,7 +225,7 @@ void StatsPullerManagerImpl::SetStatsCompanionService( } void StatsPullerManagerImpl::RegisterReceiver(int tagId, wp<PullDataReceiver> receiver, - long intervalMs) { + int64_t nextPullTimeNs, int64_t intervalNs) { AutoMutex _l(mLock); auto& receivers = mReceivers[tagId]; for (auto it = receivers.begin(); it != receivers.end(); it++) { @@ -185,21 +236,24 @@ void StatsPullerManagerImpl::RegisterReceiver(int tagId, wp<PullDataReceiver> re } ReceiverInfo receiverInfo; receiverInfo.receiver = receiver; - receiverInfo.timeInfo.first = intervalMs; - receivers.push_back(receiverInfo); // Round it to the nearest minutes. This is the limit of alarm manager. - // In practice, we should limit it higher. - long roundedIntervalMs = intervalMs/1000/60 * 1000 * 60; + // In practice, we should always have larger buckets. + int64_t roundedIntervalNs = intervalNs / NS_PER_SEC / 60 * NS_PER_SEC * 60; // Scheduled pulling should be at least 1 min apart. // This can be lower in cts tests, in which case we round it to 1 min. - if (roundedIntervalMs < 60 * 1000) { - roundedIntervalMs = 60 * 1000; + if (roundedIntervalNs < 60 * (int64_t)NS_PER_SEC) { + roundedIntervalNs = 60 * (int64_t)NS_PER_SEC; } + + receiverInfo.intervalNs = roundedIntervalNs; + receiverInfo.nextPullTimeNs = nextPullTimeNs; + receivers.push_back(receiverInfo); + // There is only one alarm for all pulled events. So only set it to the smallest denom. - if (roundedIntervalMs < mCurrentPullingInterval) { - VLOG("Updating pulling interval %ld", intervalMs); - mCurrentPullingInterval = roundedIntervalMs; + if (nextPullTimeNs < mNextPullTimeNs) { + VLOG("Updating next pull time %lld", (long long)mNextPullTimeNs); + mNextPullTimeNs = nextPullTimeNs; updateAlarmLocked(); } VLOG("Puller for tagId %d registered of %d", tagId, (int)receivers.size()); @@ -224,16 +278,22 @@ void StatsPullerManagerImpl::UnRegisterReceiver(int tagId, wp<PullDataReceiver> void StatsPullerManagerImpl::OnAlarmFired() { AutoMutex _l(mLock); - uint64_t currentTimeMs = getElapsedRealtimeMillis(); + int64_t currentTimeNs = getElapsedRealtimeNs(); + + int64_t minNextPullTimeNs = LONG_MAX; vector<pair<int, vector<ReceiverInfo*>>> needToPull = vector<pair<int, vector<ReceiverInfo*>>>(); for (auto& pair : mReceivers) { vector<ReceiverInfo*> receivers = vector<ReceiverInfo*>(); if (pair.second.size() != 0) { - for (auto& receiverInfo : pair.second) { - if (receiverInfo.timeInfo.first + receiverInfo.timeInfo.second > currentTimeMs) { + for (ReceiverInfo& receiverInfo : pair.second) { + if (receiverInfo.nextPullTimeNs < currentTimeNs) { receivers.push_back(&receiverInfo); + } else { + if (receiverInfo.nextPullTimeNs < minNextPullTimeNs) { + minNextPullTimeNs = receiverInfo.nextPullTimeNs; + } } } if (receivers.size() > 0) { @@ -244,18 +304,29 @@ void StatsPullerManagerImpl::OnAlarmFired() { for (const auto& pullInfo : needToPull) { vector<shared_ptr<LogEvent>> data; - if (Pull(pullInfo.first, &data)) { + if (Pull(pullInfo.first, currentTimeNs, &data)) { for (const auto& receiverInfo : pullInfo.second) { sp<PullDataReceiver> receiverPtr = receiverInfo->receiver.promote(); if (receiverPtr != nullptr) { receiverPtr->onDataPulled(data); - receiverInfo->timeInfo.second = currentTimeMs; + // we may have just come out of a coma, compute next pull time + receiverInfo->nextPullTimeNs = + ceil((double_t)(currentTimeNs - receiverInfo->nextPullTimeNs) / + receiverInfo->intervalNs) * + receiverInfo->intervalNs + + receiverInfo->nextPullTimeNs; + if (receiverInfo->nextPullTimeNs < minNextPullTimeNs) { + minNextPullTimeNs = receiverInfo->nextPullTimeNs; + } } else { VLOG("receiver already gone."); } } } } + + mNextPullTimeNs = minNextPullTimeNs; + updateAlarmLocked(); } int StatsPullerManagerImpl::ForceClearPullerCache() { @@ -266,10 +337,10 @@ int StatsPullerManagerImpl::ForceClearPullerCache() { return totalCleared; } -int StatsPullerManagerImpl::ClearPullerCacheIfNecessary(long timestampSec) { +int StatsPullerManagerImpl::ClearPullerCacheIfNecessary(int64_t timestampNs) { int totalCleared = 0; for (const auto& pulledAtom : kAllPullAtomInfo) { - totalCleared += pulledAtom.second.puller->ClearCacheIfNecessary(timestampSec); + totalCleared += pulledAtom.second.puller->ClearCacheIfNecessary(timestampNs); } return totalCleared; } diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.h b/cmds/statsd/src/external/StatsPullerManagerImpl.h index 682ad33a8749..8c771f31fdc5 100644 --- a/cmds/statsd/src/external/StatsPullerManagerImpl.h +++ b/cmds/statsd/src/external/StatsPullerManagerImpl.h @@ -41,7 +41,7 @@ typedef struct { std::vector<int> nonAdditiveFields; // How long should the puller wait before doing an actual pull again. Default // 1 sec. Set this to 0 if this is handled elsewhere. - long coolDownSec = 1; + int64_t coolDownNs = 1 * NS_PER_SEC; // The actual puller sp<StatsPuller> puller; } PullAtomInfo; @@ -50,7 +50,8 @@ class StatsPullerManagerImpl : public virtual RefBase { public: static StatsPullerManagerImpl& GetInstance(); - void RegisterReceiver(int tagId, wp<PullDataReceiver> receiver, long intervalMs); + void RegisterReceiver(int tagId, wp<PullDataReceiver> receiver, int64_t nextPullTimeNs, + int64_t intervalNs); void UnRegisterReceiver(int tagId, wp<PullDataReceiver> receiver); @@ -59,13 +60,11 @@ public: void OnAlarmFired(); - bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data); - - void SetTimeBaseSec(long timeBaseSec) {mTimeBaseSec = timeBaseSec;}; + bool Pull(const int tagId, const int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data); int ForceClearPullerCache(); - int ClearPullerCacheIfNecessary(long timestampSec); + int ClearPullerCacheIfNecessary(int64_t timestampNs); void SetStatsCompanionService(sp<IStatsCompanionService> statsCompanionService); @@ -77,8 +76,8 @@ public: sp<IStatsCompanionService> mStatsCompanionService = nullptr; typedef struct { - // pull_interval_sec : last_pull_time_sec - std::pair<uint64_t, uint64_t> timeInfo; + int64_t nextPullTimeNs; + int64_t intervalNs; wp<PullDataReceiver> receiver; } ReceiverInfo; @@ -90,12 +89,7 @@ public: void updateAlarmLocked(); - long mCurrentPullingInterval; - - // 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. - long mTimeBaseSec; + int64_t mNextPullTimeNs; }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index f0e0df18693a..b13c3e7a0487 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -112,7 +112,8 @@ GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric // Kicks off the puller immediately. if (mPullTagId != -1 && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) { - mStatsPullerManager->RegisterReceiver(mPullTagId, this, bucketSizeMills); + mStatsPullerManager->RegisterReceiver( + mPullTagId, this, mCurrentBucketStartTimeNs + mBucketSizeNs, mBucketSizeNs); } VLOG("Gauge metric %lld created. bucket size %lld start_time: %lld sliced %d", @@ -255,7 +256,7 @@ void GaugeMetricProducer::pullLocked() { } vector<std::shared_ptr<LogEvent>> allData; - if (!mStatsPullerManager->Pull(mPullTagId, &allData)) { + if (!mStatsPullerManager->Pull(mPullTagId, getElapsedRealtimeNs(), &allData)) { ALOGE("Gauge Stats puller failed for tag: %d", mPullTagId); return; } diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index e19e2368f751..bd3c78ce839d 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -110,10 +110,12 @@ ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric } mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0); - if (!metric.has_condition() && mPullTagId != -1) { - VLOG("Setting up periodic pulling for %d", mPullTagId); - mStatsPullerManager->RegisterReceiver(mPullTagId, this, bucketSizeMills); + // Kicks off the puller immediately. + if (mPullTagId != -1) { + mStatsPullerManager->RegisterReceiver( + mPullTagId, this, mCurrentBucketStartTimeNs + mBucketSizeNs, mBucketSizeNs); } + VLOG("value metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(), (long long)mBucketSizeNs, (long long)mStartTimeNs); } @@ -194,26 +196,21 @@ void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, // TODO: Clear mDimensionKeyMap once the report is dumped. } -void ValueMetricProducer::onConditionChangedLocked(const bool condition, const uint64_t eventTime) { +void ValueMetricProducer::onConditionChangedLocked(const bool condition, + const uint64_t eventTimeNs) { mCondition = condition; - if (eventTime < mCurrentBucketStartTimeNs) { - VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTime, + if (eventTimeNs < mCurrentBucketStartTimeNs) { + VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs, (long long)mCurrentBucketStartTimeNs); return; } - flushIfNeededLocked(eventTime); + flushIfNeededLocked(eventTimeNs); if (mPullTagId != -1) { - if (mCondition == true) { - mStatsPullerManager->RegisterReceiver(mPullTagId, this, mBucketSizeNs / 1000 / 1000); - } else if (mCondition == false) { - mStatsPullerManager->UnRegisterReceiver(mPullTagId, this); - } - vector<shared_ptr<LogEvent>> allData; - if (mStatsPullerManager->Pull(mPullTagId, &allData)) { + if (mStatsPullerManager->Pull(mPullTagId, eventTimeNs, &allData)) { if (allData.size() == 0) { return; } diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index 796e83af4f1d..ebc6e81d22c9 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -53,7 +53,7 @@ public: if (mPullTagId != -1) { vector<shared_ptr<LogEvent>> allData; - mStatsPullerManager->Pull(mPullTagId, &allData); + mStatsPullerManager->Pull(mPullTagId, eventTimeNs, &allData); if (allData.size() == 0) { // This shouldn't happen since this valuemetric is not useful now. } diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp index cab61e9787c6..efd810f01140 100644 --- a/cmds/statsd/src/stats_log_util.cpp +++ b/cmds/statsd/src/stats_log_util.cpp @@ -221,7 +221,8 @@ void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& value int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) { int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit); - if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL) { + if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL && + uid != AID_ROOT) { bucketSizeMillis = 5 * 60 * 1000LL; } return bucketSizeMillis; diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp index 2583c95b2016..7ca66fd361c2 100644 --- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp @@ -63,7 +63,7 @@ TEST(GaugeMetricProducerTest, TestNoCondition) { // For now we still need this so that it doesn't do real pulling. shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, @@ -213,10 +213,11 @@ TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) { shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, _)) - .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) + .WillOnce(Invoke([](int tagId, int64_t timeNs, + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, eventUpgradeTimeNs); event->write("some value"); @@ -281,10 +282,11 @@ TEST(GaugeMetricProducerTest, TestWithCondition) { shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, _)) - .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) + .WillOnce(Invoke([](int tagId, int64_t timeNs, + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); event->write("some value"); @@ -372,10 +374,11 @@ TEST(GaugeMetricProducerTest, TestWithSlicedCondition) { shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, _)) - .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) + .WillOnce(Invoke([](int tagId, int64_t timeNs, + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); event->write(1000); @@ -420,7 +423,7 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) { shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); GaugeMetric metric; diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index a8eb27037ebf..a0224ec17a78 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -62,7 +62,7 @@ TEST(ValueMetricProducerTest, TestNonDimensionalEvents) { // For now we still need this so that it doesn't do real pulling. shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, @@ -141,11 +141,12 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, _)) - .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) + .WillOnce(Invoke([](int tagId, int64_t timeNs, + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); event->write(tagId); @@ -154,7 +155,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { data->push_back(event); return true; })) - .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + .WillOnce(Invoke([](int tagId, int64_t timeNs, + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10); event->write(tagId); @@ -260,10 +262,11 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) { sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, _)) - .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) + .WillOnce(Invoke([](int tagId, int64_t timeNs, + vector<std::shared_ptr<LogEvent>>* data) { data->clear(); shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); event->write(tagId); diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h index f040bf9f37ae..5afaba6671fa 100644 --- a/cmds/statsd/tests/metrics/metrics_test_helper.h +++ b/cmds/statsd/tests/metrics/metrics_test_helper.h @@ -35,9 +35,11 @@ public: class MockStatsPullerManager : public StatsPullerManager { public: - MOCK_METHOD3(RegisterReceiver, void(int tagId, wp<PullDataReceiver> receiver, long intervalMs)); + MOCK_METHOD4(RegisterReceiver, void(int tagId, wp<PullDataReceiver> receiver, + int64_t nextPulltimeNs, int64_t intervalNs)); MOCK_METHOD2(UnRegisterReceiver, void(int tagId, wp<PullDataReceiver> receiver)); - MOCK_METHOD2(Pull, bool(const int pullCode, vector<std::shared_ptr<LogEvent>>* data)); + MOCK_METHOD3(Pull, bool(const int pullCode, const int64_t timeNs, + vector<std::shared_ptr<LogEvent>>* data)); }; class MockUidMap : public UidMap { diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 0ded5159aa35..70e3fade244f 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -1,4 +1,5 @@ Landroid/accounts/AccountManager;->mContext:Landroid/content/Context; +Landroid/accounts/IAccountAuthenticatorResponse$Stub;-><init>()V Landroid/accounts/IAccountManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/accounts/IAccountManager; Landroid/accounts/IAccountManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/animation/LayoutTransition;->cancel()V @@ -236,6 +237,7 @@ Landroid/app/IActivityManager;->getLaunchedFromPackage(Landroid/os/IBinder;)Ljav Landroid/app/IActivityManager;->getTaskForActivity(Landroid/os/IBinder;Z)I Landroid/app/IActivityManager;->moveTaskToFront(IILandroid/os/Bundle;)V Landroid/app/IActivityManager;->publishContentProviders(Landroid/app/IApplicationThread;Ljava/util/List;)V +Landroid/app/IActivityManager;->requestBugReport(I)V Landroid/app/IActivityManager;->resumeAppSwitches()V Landroid/app/IActivityManager;->setRequestedOrientation(Landroid/os/IBinder;I)V Landroid/app/IActivityManager;->setTaskResizeable(II)V @@ -948,6 +950,7 @@ Landroid/media/IAudioService;->getStreamVolume(I)I Landroid/media/IAudioService;->setStreamVolume(IIILjava/lang/String;)V Landroid/media/IAudioService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IAudioService; Landroid/media/IAudioService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V +Landroid/media/IRemoteDisplayCallback;->onStateChanged(Landroid/media/RemoteDisplayState;)V Landroid/media/IVolumeController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IVolumeController; Landroid/media/JetPlayer;->mNativePlayerInJavaObj:J Landroid/media/JetPlayer;->postEventFromNative(Ljava/lang/Object;III)V @@ -1000,6 +1003,8 @@ Landroid/media/PlaybackParams;->SET_SPEED:I Landroid/media/RemoteDisplay;->notifyDisplayConnected(Landroid/view/Surface;IIII)V Landroid/media/RemoteDisplay;->notifyDisplayDisconnected()V Landroid/media/RemoteDisplay;->notifyDisplayError(I)V +Landroid/media/RemoteDisplayState;->displays:Ljava/util/ArrayList; +Landroid/media/RemoteDisplayState;-><init>()V Landroid/media/RingtoneManager;->getRingtone(Landroid/content/Context;Landroid/net/Uri;I)Landroid/media/Ringtone; Landroid/media/session/MediaSessionLegacyHelper;->getHelper(Landroid/content/Context;)Landroid/media/session/MediaSessionLegacyHelper; Landroid/media/session/MediaSession;->mCallback:Landroid/media/session/MediaSession$CallbackMessageHandler; @@ -1011,6 +1016,11 @@ Landroid/media/soundtrigger/SoundTriggerManager;->startRecognition(Ljava/util/UU Landroid/media/soundtrigger/SoundTriggerManager;->stopRecognition(Ljava/util/UUID;)I Landroid/media/soundtrigger/SoundTriggerManager;->unloadSoundModel(Ljava/util/UUID;)I Landroid/media/SubtitleController;->mHandler:Landroid/os/Handler; +Landroid/media/SubtitleTrack$RenderingWidget;->draw(Landroid/graphics/Canvas;)V +Landroid/media/SubtitleTrack$RenderingWidget;->onAttachedToWindow()V +Landroid/media/SubtitleTrack$RenderingWidget;->onDetachedFromWindow()V +Landroid/media/SubtitleTrack$RenderingWidget;->setOnChangedListener(Landroid/media/SubtitleTrack$RenderingWidget$OnChangedListener;)V +Landroid/media/SubtitleTrack$RenderingWidget;->setSize(II)V Landroid/media/ThumbnailUtils;->createImageThumbnail(Ljava/lang/String;I)Landroid/graphics/Bitmap; Landroid/media/ToneGenerator;->mNativeContext:J Landroid/media/VolumeShaper$Configuration;-><init>(IIIDI[F[F)V @@ -1116,6 +1126,8 @@ Landroid/net/wifi/p2p/WifiP2pManager;->deletePersistentGroup(Landroid/net/wifi/p Landroid/net/wifi/p2p/WifiP2pManager;->requestPersistentGroupInfo(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Landroid/net/wifi/p2p/WifiP2pManager$PersistentGroupInfoListener;)V Landroid/net/wifi/p2p/WifiP2pManager;->setDeviceName(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Ljava/lang/String;Landroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V Landroid/net/wifi/p2p/WifiP2pManager;->setWifiP2pChannels(Landroid/net/wifi/p2p/WifiP2pManager$Channel;IILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V +Landroid/net/wifi/p2p/WifiP2pManager$Channel;->mAsyncChannel:Lcom/android/internal/util/AsyncChannel; +Landroid/net/wifi/p2p/WifiP2pManager$Channel;->putListener(Ljava/lang/Object;)I Landroid/net/wifi/ScanResult;->anqpDomainId:I Landroid/net/wifi/ScanResult;->anqpLines:Ljava/util/List; Landroid/net/wifi/ScanResult;->distanceCm:I @@ -1966,6 +1978,7 @@ Landroid/util/Rational;->mDenominator:I Landroid/util/Rational;->mNumerator:I Landroid/util/Singleton;->mInstance:Ljava/lang/Object; Landroid/util/Slog;->d(Ljava/lang/String;Ljava/lang/String;)I +Landroid/util/Slog;->w(Ljava/lang/String;Ljava/lang/String;)I Landroid/util/SparseIntArray;->mKeys:[I Landroid/util/SparseIntArray;->mSize:I Landroid/util/SparseIntArray;->mValues:[I @@ -2285,6 +2298,7 @@ Landroid/view/Window;->mHardwareAccelerated:Z Landroid/webkit/IWebViewUpdateService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/webkit/WebResourceResponse;->mImmutable:Z Landroid/webkit/WebSyncManager;->mHandler:Landroid/os/Handler; +Landroid/webkit/WebViewClient;->onUnhandledInputEvent(Landroid/webkit/WebView;Landroid/view/InputEvent;)V Landroid/webkit/WebView;->debugDump()V Landroid/webkit/WebView;->disablePlatformNotifications()V Landroid/webkit/WebView;->emulateShiftHeld()V @@ -2714,11 +2728,15 @@ Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOff:I Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOn:I Lcom/android/internal/R$styleable;->CompoundButton_button:I Lcom/android/internal/R$styleable;->CompoundButton:[I +Lcom/android/internal/R$styleable;->DialogPreference_dialogTitle:I +Lcom/android/internal/R$styleable;->DialogPreference:[I Lcom/android/internal/R$styleable;->EdgeEffect_colorEdgeEffect:I Lcom/android/internal/R$styleable;->EdgeEffect:[I Lcom/android/internal/R$styleable;->IconMenuView:[I Lcom/android/internal/R$styleable;->ImageView:[I Lcom/android/internal/R$styleable;->ImageView_src:I +Lcom/android/internal/R$styleable;->ListPreference_entries:I +Lcom/android/internal/R$styleable;->ListPreference:[I Lcom/android/internal/R$styleable;->Preference_defaultValue:I Lcom/android/internal/R$styleable;->Preference_dependency:I Lcom/android/internal/R$styleable;->Preference_enabled:I @@ -2784,6 +2802,7 @@ Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCall()Z Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V +Lcom/android/internal/util/AsyncChannel;->sendMessage(III)V Lcom/android/internal/util/FastPrintWriter;-><init>(Ljava/io/OutputStream;)V Lcom/android/internal/util/XmlUtils;->readMapXml(Ljava/io/InputStream;)Ljava/util/HashMap; Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager; @@ -2960,6 +2979,7 @@ Ljava/lang/Runtime;->load(Ljava/lang/String;Ljava/lang/ClassLoader;)V Ljava/lang/Runtime;->nativeLoad(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String; Ljava/lang/Short;->value:S Ljava/lang/String;-><init>(II[C)V +Ljava/lang/System;->arraycopy([II[III)V Ljava/lang/System;-><init>()V Ljava/lang/Thread;->daemon:Z Ljava/lang/Thread;->dispatchUncaughtException(Ljava/lang/Throwable;)V @@ -3071,5 +3091,7 @@ Llibcore/util/ZoneInfo;->mTransitions:[J Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>(Ljavax/net/ssl/SSLSocketFactory;)V Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>()V Lorg/json/JSONArray;->values:Ljava/util/List; +Lorg/json/JSONObject;->append(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject; +Lorg/json/JSONObject;->keySet()Ljava/util/Set; Lorg/json/JSONObject;->writeTo(Lorg/json/JSONStringer;)V Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe; diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt index 6b528508a8bb..61ae6e77cbfd 100644 --- a/config/hiddenapi-vendor-list.txt +++ b/config/hiddenapi-vendor-list.txt @@ -32,7 +32,6 @@ Landroid/app/IActivityManager;->getRunningAppProcesses()Ljava/util/List; Landroid/app/IActivityManager;->getTaskSnapshot(IZ)Landroid/app/ActivityManager$TaskSnapshot; Landroid/app/IActivityManager;->registerTaskStackListener(Landroid/app/ITaskStackListener;)V Landroid/app/IActivityManager;->removeTask(I)Z -Landroid/app/IActivityManager;->requestBugReport(I)V Landroid/app/IActivityManager;->startActivityAsUser(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;IILandroid/app/ProfilerInfo;Landroid/os/Bundle;I)I Landroid/app/IActivityManager;->startActivityFromRecents(ILandroid/os/Bundle;)I Landroid/app/IActivityManager;->startActivity(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;IILandroid/app/ProfilerInfo;Landroid/os/Bundle;)I diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 8f0168530273..bd4933a2081c 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -24,7 +24,6 @@ import android.accessibilityservice.IAccessibilityServiceConnection; import android.annotation.NonNull; import android.annotation.TestApi; import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; @@ -47,6 +46,7 @@ import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityInteractionConnection; + import libcore.io.IoUtils; import java.io.IOException; @@ -876,16 +876,36 @@ public final class UiAutomation { } /** - * Grants a runtime permission to a package for a user. + * Grants a runtime permission to a package. * @param packageName The package to which to grant. * @param permission The permission to grant. - * @return Whether granting succeeded. - * + * @throws SecurityException if unable to grant the permission. + */ + public void grantRuntimePermission(String packageName, String permission) { + grantRuntimePermissionAsUser(packageName, permission, android.os.Process.myUserHandle()); + } + + /** + * @deprecated replaced by + * {@link #grantRuntimePermissionAsUser(String, String, UserHandle)}. * @hide */ + @Deprecated @TestApi public boolean grantRuntimePermission(String packageName, String permission, UserHandle userHandle) { + grantRuntimePermissionAsUser(packageName, permission, userHandle); + return true; + } + + /** + * Grants a runtime permission to a package for a user. + * @param packageName The package to which to grant. + * @param permission The permission to grant. + * @throws SecurityException if unable to grant the permission. + */ + public void grantRuntimePermissionAsUser(String packageName, String permission, + UserHandle userHandle) { synchronized (mLock) { throwIfNotConnectedLocked(); } @@ -896,25 +916,42 @@ public final class UiAutomation { // Calling out without a lock held. mUiAutomationConnection.grantRuntimePermission(packageName, permission, userHandle.getIdentifier()); - // TODO: The package manager API should return boolean. - return true; - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error granting runtime permission", re); + } catch (Exception e) { + throw new SecurityException("Error granting runtime permission", e); } - return false; } /** - * Revokes a runtime permission from a package for a user. - * @param packageName The package from which to revoke. - * @param permission The permission to revoke. - * @return Whether revoking succeeded. - * + * Revokes a runtime permission from a package. + * @param packageName The package to which to grant. + * @param permission The permission to grant. + * @throws SecurityException if unable to revoke the permission. + */ + public void revokeRuntimePermission(String packageName, String permission) { + revokeRuntimePermissionAsUser(packageName, permission, android.os.Process.myUserHandle()); + } + + /** + * @deprecated replaced by + * {@link #revokeRuntimePermissionAsUser(String, String, UserHandle)}. * @hide */ + @Deprecated @TestApi public boolean revokeRuntimePermission(String packageName, String permission, UserHandle userHandle) { + revokeRuntimePermissionAsUser(packageName, permission, userHandle); + return true; + } + + /** + * Revokes a runtime permission from a package. + * @param packageName The package to which to grant. + * @param permission The permission to grant. + * @throws SecurityException if unable to revoke the permission. + */ + public void revokeRuntimePermissionAsUser(String packageName, String permission, + UserHandle userHandle) { synchronized (mLock) { throwIfNotConnectedLocked(); } @@ -925,12 +962,9 @@ public final class UiAutomation { // Calling out without a lock held. mUiAutomationConnection.revokeRuntimePermission(packageName, permission, userHandle.getIdentifier()); - // TODO: The package manager API should return boolean. - return true; - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error revoking runtime permission", re); + } catch (Exception e) { + throw new SecurityException("Error granting runtime permission", e); } - return false; } /** @@ -949,6 +983,7 @@ public final class UiAutomation { synchronized (mLock) { throwIfNotConnectedLocked(); } + warnIfBetterCommand(command); ParcelFileDescriptor source = null; ParcelFileDescriptor sink = null; @@ -991,6 +1026,7 @@ public final class UiAutomation { synchronized (mLock) { throwIfNotConnectedLocked(); } + warnIfBetterCommand(command); ParcelFileDescriptor source_read = null; ParcelFileDescriptor sink_read = null; @@ -1056,6 +1092,16 @@ public final class UiAutomation { } } + private void warnIfBetterCommand(String cmd) { + if (cmd.startsWith("pm grant ")) { + Log.w(LOG_TAG, "UiAutomation.grantRuntimePermission() " + + "is more robust and should be used instead of 'pm grant'"); + } else if (cmd.startsWith("pm revoke ")) { + Log.w(LOG_TAG, "UiAutomation.revokeRuntimePermission() " + + "is more robust and should be used instead of 'pm revoke'"); + } + } + private class IAccessibilityServiceClientImpl extends IAccessibilityServiceClientWrapper { public IAccessibilityServiceClientImpl(Looper looper) { diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 106b42fba40d..1534a15ab889 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -124,6 +124,7 @@ import java.util.concurrent.Executor; @SystemService(Context.DEVICE_POLICY_SERVICE) @RequiresFeature(PackageManager.FEATURE_DEVICE_ADMIN) public class DevicePolicyManager { + private static String TAG = "DevicePolicyManager"; private final Context mContext; @@ -1751,6 +1752,25 @@ public class DevicePolicyManager { public static final int ID_TYPE_MEID = 8; /** + * Specifies that the calling app should be granted access to the installed credentials + * immediately. Otherwise, access to the credentials will be gated by user approval. + * For use with {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)} + * + * @see #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int) + */ + public static final int INSTALLKEY_REQUEST_CREDENTIALS_ACCESS = 1; + + /** + * Specifies that a user can select the key via the Certificate Selection prompt. + * If this flag is not set when calling {@link #installKeyPair}, the key can only be granted + * access by implementing {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias}. + * For use with {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)} + * + * @see #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int) + */ + public static final int INSTALLKEY_SET_USER_SELECTABLE = 2; + + /** * Broadcast action: sent when the profile owner is set, changed or cleared. * * This broadcast is sent only to the user managed by the new profile owner. @@ -4126,7 +4146,11 @@ public class DevicePolicyManager { */ public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey, @NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess) { - return installKeyPair(admin, privKey, certs, alias, requestAccess, true); + int flags = INSTALLKEY_SET_USER_SELECTABLE; + if (requestAccess) { + flags |= INSTALLKEY_REQUEST_CREDENTIALS_ACCESS; + } + return installKeyPair(admin, privKey, certs, alias, flags); } /** @@ -4150,13 +4174,9 @@ public class DevicePolicyManager { * {@link android.security.KeyChain#getCertificateChain}. * @param alias The private key alias under which to install the certificate. If a certificate * with that alias already exists, it will be overwritten. - * @param requestAccess {@code true} to request that the calling app be granted access to the - * credentials immediately. Otherwise, access to the credentials will be gated by user - * approval. - * @param isUserSelectable {@code true} to indicate that a user can select this key via the - * Certificate Selection prompt, false to indicate that this key can only be granted - * access by implementing - * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias}. + * @param flags Flags to request that the calling app be granted access to the credentials + * and set the key to be user-selectable. See {@link #INSTALLKEY_SET_USER_SELECTABLE} and + * {@link #INSTALLKEY_REQUEST_CREDENTIALS_ACCESS}. * @return {@code true} if the keys were installed, {@code false} otherwise. * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile * owner. @@ -4165,9 +4185,12 @@ public class DevicePolicyManager { * @see #DELEGATION_CERT_INSTALL */ public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey, - @NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess, - boolean isUserSelectable) { + @NonNull Certificate[] certs, @NonNull String alias, int flags) { throwIfParentInstance("installKeyPair"); + boolean requestAccess = (flags & INSTALLKEY_REQUEST_CREDENTIALS_ACCESS) + == INSTALLKEY_REQUEST_CREDENTIALS_ACCESS; + boolean isUserSelectable = (flags & INSTALLKEY_SET_USER_SELECTABLE) + == INSTALLKEY_SET_USER_SELECTABLE; try { final byte[] pemCert = Credentials.convertToPem(certs[0]); byte[] pemChain = null; @@ -4246,6 +4269,8 @@ public class DevicePolicyManager { * algorithm specification in {@code keySpec} is not {@code RSAKeyGenParameterSpec} * or {@code ECGenParameterSpec}, or if Device ID attestation was requested but the * {@code keySpec} does not contain an attestation challenge. + * @throws UnsupportedOperationException if Device ID attestation was requested but the + * underlying hardware does not support it. * @see KeyGenParameterSpec.Builder#setAttestationChallenge(byte[]) */ public AttestedKeyPair generateKeyPair(@Nullable ComponentName admin, diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java index 8fde82ef2012..8263bb8dfd2d 100644 --- a/core/java/android/hardware/radio/RadioManager.java +++ b/core/java/android/hardware/radio/RadioManager.java @@ -211,6 +211,7 @@ public class RadioManager { private final String mSerial; private final int mNumTuners; private final int mNumAudioSources; + private final boolean mIsInitializationRequired; private final boolean mIsCaptureSupported; private final BandDescriptor[] mBands; private final boolean mIsBgScanSupported; @@ -222,7 +223,8 @@ public class RadioManager { /** @hide */ public ModuleProperties(int id, String serviceName, int classId, String implementor, String product, String version, String serial, int numTuners, int numAudioSources, - boolean isCaptureSupported, BandDescriptor[] bands, boolean isBgScanSupported, + boolean isInitializationRequired, boolean isCaptureSupported, + BandDescriptor[] bands, boolean isBgScanSupported, @ProgramSelector.ProgramType int[] supportedProgramTypes, @ProgramSelector.IdentifierType int[] supportedIdentifierTypes, @Nullable Map<String, Integer> dabFrequencyTable, @@ -236,6 +238,7 @@ public class RadioManager { mSerial = serial; mNumTuners = numTuners; mNumAudioSources = numAudioSources; + mIsInitializationRequired = isInitializationRequired; mIsCaptureSupported = isCaptureSupported; mBands = bands; mIsBgScanSupported = isBgScanSupported; @@ -329,6 +332,18 @@ public class RadioManager { return mNumAudioSources; } + /** + * Checks, if BandConfig initialization (after {@link RadioManager#openTuner}) + * is required to be done before other operations or not. + * + * If it is, the client has to wait for {@link RadioTuner.Callback#onConfigurationChanged} + * callback before executing any other operations. Otherwise, such operation will fail + * returning {@link RadioManager#STATUS_INVALID_OPERATION} error code. + */ + public boolean isInitializationRequired() { + return mIsInitializationRequired; + } + /** {@code true} if audio capture is possible from radio tuner output. * This indicates if routing to audio devices not connected to the same HAL as the FM radio * is possible (e.g. to USB) or DAR (Digital Audio Recorder) feature can be implemented. @@ -419,6 +434,7 @@ public class RadioManager { mSerial = in.readString(); mNumTuners = in.readInt(); mNumAudioSources = in.readInt(); + mIsInitializationRequired = in.readInt() == 1; mIsCaptureSupported = in.readInt() == 1; Parcelable[] tmp = in.readParcelableArray(BandDescriptor.class.getClassLoader()); mBands = new BandDescriptor[tmp.length]; @@ -454,6 +470,7 @@ public class RadioManager { dest.writeString(mSerial); dest.writeInt(mNumTuners); dest.writeInt(mNumAudioSources); + dest.writeInt(mIsInitializationRequired ? 1 : 0); dest.writeInt(mIsCaptureSupported ? 1 : 0); dest.writeParcelableArray(mBands, flags); dest.writeInt(mIsBgScanSupported ? 1 : 0); @@ -476,6 +493,7 @@ public class RadioManager { + ", mVersion=" + mVersion + ", mSerial=" + mSerial + ", mNumTuners=" + mNumTuners + ", mNumAudioSources=" + mNumAudioSources + + ", mIsInitializationRequired=" + mIsInitializationRequired + ", mIsCaptureSupported=" + mIsCaptureSupported + ", mIsBgScanSupported=" + mIsBgScanSupported + ", mBands=" + Arrays.toString(mBands) + "]"; @@ -484,8 +502,8 @@ public class RadioManager { @Override public int hashCode() { return Objects.hash(mId, mServiceName, mClassId, mImplementor, mProduct, mVersion, - mSerial, mNumTuners, mNumAudioSources, mIsCaptureSupported, mBands, - mIsBgScanSupported, mDabFrequencyTable, mVendorInfo); + mSerial, mNumTuners, mNumAudioSources, mIsInitializationRequired, + mIsCaptureSupported, mBands, mIsBgScanSupported, mDabFrequencyTable, mVendorInfo); } @Override @@ -503,6 +521,7 @@ public class RadioManager { if (!Objects.equals(mSerial, other.mSerial)) return false; if (mNumTuners != other.mNumTuners) return false; if (mNumAudioSources != other.mNumAudioSources) return false; + if (mIsInitializationRequired != other.mIsInitializationRequired) return false; if (mIsCaptureSupported != other.mIsCaptureSupported) return false; if (!Objects.equals(mBands, other.mBands)) return false; if (mIsBgScanSupported != other.mIsBgScanSupported) return false; diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl index 402c995452e8..116262e347de 100644 --- a/core/java/android/os/IStatsCompanionService.aidl +++ b/core/java/android/os/IStatsCompanionService.aidl @@ -47,10 +47,10 @@ interface IStatsCompanionService { * Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately, * and alarm is inexact. */ - oneway void setPullingAlarms(long timestampMs, long intervalMs); + oneway void setPullingAlarm(long nextPullTimeMs); /** Cancel any repeating pulling alarm. */ - oneway void cancelPullingAlarms(); + oneway void cancelPullingAlarm(); /** * Register an alarm when we want to trigger subscribers at the given diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index 5be72bc5c54b..094f0046649b 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -158,7 +158,7 @@ public final class UserHandle implements Parcelable { * @hide */ public static boolean isCore(int uid) { - if (uid > 0) { + if (uid >= 0) { final int appId = getAppId(uid); return appId < Process.FIRST_APPLICATION_UID; } else { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 70f343ee5f57..b7f6cdef20ed 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7809,6 +7809,14 @@ public final class Settings { "suppress_auto_battery_saver_suggestion"; /** + * List of packages, which data need to be unconditionally cleared before full restore. + * Type: string + * @hide + */ + public static final String PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE = + "packages_to_clear_data_before_full_restore"; + + /** * This are the settings to be backed up. * * NOTE: Settings are backed up and restored in the order they appear diff --git a/core/java/android/service/autofill/AutofillFieldClassificationService.java b/core/java/android/service/autofill/AutofillFieldClassificationService.java index cf1674989fe5..99d45f40c26a 100644 --- a/core/java/android/service/autofill/AutofillFieldClassificationService.java +++ b/core/java/android/service/autofill/AutofillFieldClassificationService.java @@ -113,23 +113,67 @@ public abstract class AutofillFieldClassificationService extends Service { /** * Calculates field classification scores in a batch. * - * <p>See {@link AutofillFieldClassificationService} for more info about field classification - * scores. + * <p>A field classification score is a {@code float} representing how well an + * {@link AutofillValue} filled matches a expected value predicted by an autofill service + * —a full-match is {@code 1.0} (representing 100%), while a full mismatch is {@code 0.0}. * - * @param algorithm name of the algorithm to be used to calculate the scores. If invalid, the - * default algorithm will be used instead. - * @param args optional arguments to be passed to the algorithm. + * <p>The exact score depends on the algorithm used to calculate it— the service must + * provide at least one default algorithm (which is used when the algorithm is not specified + * or is invalid), but it could provide more (in which case the algorithm name should be + * specifiied by the caller when calculating the scores). + * + * <p>For example, if the service provides an algorithm named {@code EXACT_MATCH} that + * returns {@code 1.0} if all characters in match or {@code 0.0} otherwise, a call to: + * + * <pre> + * service.onGetScores("EXACT_MATCH", null, + * Arrays.asList(AutofillValue.forText("email1"), AutofillValue.forText("PHONE1")), + * Arrays.asList("email1", "phone1")); + * </pre> + * + * <p>Returns: + * + * <pre> + * [ + * [1.0, 0.0], // "email1" compared against ["email1", "phone1"] + * [0.0, 0.0] // "PHONE1" compared against ["email1", "phone1"] + * ]; + * </pre> + * + * <p>If the same algorithm allows the caller to specify whether the comparisons should be + * case sensitive by passing a boolean option named {@code "case_sensitive"}, then a call to: + * + * <pre> + * Bundle algorithmOptions = new Bundle(); + * algorithmOptions.putBoolean("case_sensitive", false); + * + * service.onGetScores("EXACT_MATCH", algorithmOptions, + * Arrays.asList(AutofillValue.forText("email1"), AutofillValue.forText("PHONE1")), + * Arrays.asList("email1", "phone1")); + * </pre> + * + * <p>Returns: + * + * <pre> + * [ + * [1.0, 0.0], // "email1" compared against ["email1", "phone1"] + * [0.0, 1.0] // "PHONE1" compared against ["email1", "phone1"] + * ]; + * </pre> + * + * @param algorithm name of the algorithm to be used to calculate the scores. If invalid or + * {@code null}, the default algorithm is used instead. + * @param algorithmOptions optional arguments to be passed to the algorithm. * @param actualValues values entered by the user. * @param userDataValues values predicted from the user data. - * @return the calculated scores, with the first dimension representing actual values and the - * second dimension values from {@link UserData}. + * @return the calculated scores of {@code actualValues} x {@code userDataValues}. * * {@hide} */ @Nullable @SystemApi public float[][] onGetScores(@Nullable String algorithm, - @Nullable Bundle args, @NonNull List<AutofillValue> actualValues, + @Nullable Bundle algorithmOptions, @NonNull List<AutofillValue> actualValues, @NonNull List<String> userDataValues) { Log.e(TAG, "service implementation (" + getClass() + " does not implement onGetScore()"); return null; diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java index b049db379341..f4b7032a774c 100644 --- a/core/java/com/android/internal/backup/LocalTransport.java +++ b/core/java/com/android/internal/backup/LocalTransport.java @@ -187,11 +187,27 @@ public class LocalTransport extends BackupTransport { @Override public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) { + return performBackup(packageInfo, data, /*flags=*/ 0); + } + + @Override + public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data, int flags) { + boolean isIncremental = (flags & FLAG_INCREMENTAL) != 0; + boolean isNonIncremental = (flags & FLAG_NON_INCREMENTAL) != 0; + + if (isIncremental) { + Log.i(TAG, "Performing incremental backup for " + packageInfo.packageName); + } else if (isNonIncremental) { + Log.i(TAG, "Performing non-incremental backup for " + packageInfo.packageName); + } else { + Log.i(TAG, "Performing backup for " + packageInfo.packageName); + } + if (DEBUG) { try { - StructStat ss = Os.fstat(data.getFileDescriptor()); - Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName - + " size=" + ss.st_size); + StructStat ss = Os.fstat(data.getFileDescriptor()); + Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName + + " size=" + ss.st_size + " flags=" + flags); } catch (ErrnoException e) { Log.w(TAG, "Unable to stat input file in performBackup() on " + packageInfo.packageName); @@ -199,7 +215,26 @@ public class LocalTransport extends BackupTransport { } File packageDir = new File(mCurrentSetIncrementalDir, packageInfo.packageName); - packageDir.mkdirs(); + boolean hasDataForPackage = !packageDir.mkdirs(); + + if (isIncremental) { + if (mParameters.isNonIncrementalOnly() || !hasDataForPackage) { + if (mParameters.isNonIncrementalOnly()) { + Log.w(TAG, "Transport is in non-incremental only mode."); + + } else { + Log.w(TAG, + "Requested incremental, but transport currently stores no data for the " + + "package, requesting non-incremental retry."); + } + return TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED; + } + } + if (isNonIncremental && hasDataForPackage) { + Log.w(TAG, "Requested non-incremental, deleting existing data."); + clearBackupData(packageInfo); + packageDir.mkdirs(); + } // Each 'record' in the restore set is kept in its own file, named by // the record key. Wind through the data file, extracting individual diff --git a/core/java/com/android/internal/backup/LocalTransportParameters.java b/core/java/com/android/internal/backup/LocalTransportParameters.java index 154e79d4f7ef..2427d39fd65e 100644 --- a/core/java/com/android/internal/backup/LocalTransportParameters.java +++ b/core/java/com/android/internal/backup/LocalTransportParameters.java @@ -26,8 +26,10 @@ class LocalTransportParameters extends KeyValueSettingObserver { private static final String TAG = "LocalTransportParams"; private static final String SETTING = Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS; private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag"; + private static final String KEY_NON_INCREMENTAL_ONLY = "non_incremental_only"; private boolean mFakeEncryptionFlag; + private boolean mIsNonIncrementalOnly; LocalTransportParameters(Handler handler, ContentResolver resolver) { super(handler, resolver, Settings.Secure.getUriFor(SETTING)); @@ -37,11 +39,16 @@ class LocalTransportParameters extends KeyValueSettingObserver { return mFakeEncryptionFlag; } + boolean isNonIncrementalOnly() { + return mIsNonIncrementalOnly; + } + public String getSettingValue(ContentResolver resolver) { return Settings.Secure.getString(resolver, SETTING); } public void update(KeyValueListParser parser) { mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false); + mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false); } } diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp index d3d68826affe..97abd82eaac5 100644 --- a/core/jni/android/graphics/Path.cpp +++ b/core/jni/android/graphics/Path.cpp @@ -37,6 +37,14 @@ namespace android { class SkPathGlue { public: + static void finalizer(SkPath* obj) { + // Purge entries from the HWUI path cache if this path's data is unique + if (obj->unique() && android::uirenderer::Caches::hasInstance()) { + android::uirenderer::Caches::getInstance().pathCache.removeDeferred(obj); + } + delete obj; + } + // ---------------- Regular JNI ----------------------------- static jlong init(JNIEnv* env, jclass clazz) { @@ -48,13 +56,8 @@ public: return reinterpret_cast<jlong>(new SkPath(*val)); } - static void finalize(JNIEnv* env, jclass clazz, jlong objHandle) { - SkPath* obj = reinterpret_cast<SkPath*>(objHandle); - // Purge entries from the HWUI path cache if this path's data is unique - if (obj->unique() && android::uirenderer::Caches::hasInstance()) { - android::uirenderer::Caches::getInstance().pathCache.removeDeferred(obj); - } - delete obj; + static jlong getFinalizer(JNIEnv* env, jclass clazz) { + return static_cast<jlong>(reinterpret_cast<uintptr_t>(&finalizer)); } static void set(JNIEnv* env, jclass clazz, jlong dstHandle, jlong srcHandle) { @@ -469,7 +472,9 @@ public: SkRect rect; SkPath* obj = reinterpret_cast<SkPath*>(objHandle); jboolean result = obj->isRect(&rect); - GraphicsJNI::rect_to_jrectf(rect, env, jrect); + if (jrect) { + GraphicsJNI::rect_to_jrectf(rect, env, jrect); + } return result; } @@ -510,7 +515,7 @@ public: static const JNINativeMethod methods[] = { {"nInit","()J", (void*) SkPathGlue::init}, {"nInit","(J)J", (void*) SkPathGlue::init_Path}, - {"nFinalize", "(J)V", (void*) SkPathGlue::finalize}, + {"nGetFinalizer", "()J", (void*) SkPathGlue::getFinalizer}, {"nSet","(JJ)V", (void*) SkPathGlue::set}, {"nComputeBounds","(JLandroid/graphics/RectF;)V", (void*) SkPathGlue::computeBounds}, {"nIncReserve","(JI)V", (void*) SkPathGlue::incReserve}, diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index cfb89808b1b2..593747df4ee3 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -145,6 +145,7 @@ message SecureSettingsProto { optional SettingProto transport = 4 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto manager_constants = 5; optional SettingProto local_transport_parameters = 6; + optional SettingProto packages_to_clear_data_before_full_restore = 7; } optional Backup backup = 10; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 48d394a299c3..cb375d5394fa 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2016,11 +2016,11 @@ <permission android:name="android.permission.REMOVE_TASKS" android:protectionLevel="signature" /> - <!-- @SystemApi @hide Allows an application to create/manage/remove stacks --> + <!-- @SystemApi @TestApi @hide Allows an application to create/manage/remove stacks --> <permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" android:protectionLevel="signature|privileged|development" /> - <!-- @SystemApi @hide Allows an application to embed other activities --> + <!-- @SystemApi @TestApi @hide Allows an application to embed other activities --> <permission android:name="android.permission.ACTIVITY_EMBEDDING" android:protectionLevel="signature|privileged|development" /> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 2a3fcadb5144..4b9465d24fc9 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -587,7 +587,8 @@ public class SettingsBackupTest { Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING, Settings.Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED, - Settings.Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION); + Settings.Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, + Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE); @Test public void systemSettingsBackedUpOrBlacklisted() { diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 5ca0ad63159f..6939907bb419 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -766,7 +766,7 @@ public final class ImageDecoder implements AutoCloseable { * * <p>This takes an input that functions like * {@link BitmapFactory.Options#inSampleSize}. It returns a width and - * height that can be acheived by sampling the encoded image. Other widths + * height that can be achieved by sampling the encoded image. Other widths * and heights may be supported, but will require an additional (internal) * scaling step. Such internal scaling is *not* supported with * {@link #setRequireUnpremultiplied} set to {@code true}.</p> @@ -774,6 +774,8 @@ public final class ImageDecoder implements AutoCloseable { * @param sampleSize Sampling rate of the encoded image. * @return {@link android.util.Size} of the width and height after * sampling. + * + * @hide */ @NonNull public Size getSampledSize(int sampleSize) { @@ -789,14 +791,28 @@ public final class ImageDecoder implements AutoCloseable { } // Modifiers + /** @removed + * @deprecated Renamed to {@link #setTargetSize}. + */ + @java.lang.Deprecated + public ImageDecoder setResize(int width, int height) { + return this.setTargetSize(width, height); + } + /** - * Resize the output to have the following size. + * Specify the size of the output {@link Drawable} or {@link Bitmap}. + * + * <p>By default, the output size will match the size of the encoded + * image, which can be retrieved from the {@link ImageInfo} in + * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p> + * + * <p>Only the last call to this or {@link #setSampleSize} is respected.</p> * * @param width must be greater than 0. * @param height must be greater than 0. * @return this object for chaining. */ - public ImageDecoder setResize(int width, int height) { + public ImageDecoder setTargetSize(int width, int height) { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("Dimensions must be positive! " + "provided (" + width + ", " + height + ")"); @@ -807,18 +823,65 @@ public final class ImageDecoder implements AutoCloseable { return this; } + /** @removed + * @deprecated Renamed to {@link #setSampleSize}. + */ + @java.lang.Deprecated + public ImageDecoder setResize(int sampleSize) { + return this.setSampleSize(sampleSize); + } + + private int getTargetDimension(int original, int sampleSize, int computed) { + // Sampling will never result in a smaller size than 1. + if (sampleSize >= original) { + return 1; + } + + // Use integer divide to find the desired size. If that is what + // getSampledSize computed, that is the size to use. + int target = original / sampleSize; + if (computed == target) { + return computed; + } + + // If sampleSize does not divide evenly into original, the decoder + // may round in either direction. It just needs to get a result that + // is close. + int reverse = computed * sampleSize; + if (Math.abs(reverse - original) < sampleSize) { + // This is the size that can be decoded most efficiently. + return computed; + } + + // The decoder could not get close (e.g. it is a DNG image). + return target; + } + /** - * Resize based on a sample size. + * Set the target size with a sampleSize. + * + * <p>By default, the output size will match the size of the encoded + * image, which can be retrieved from the {@link ImageInfo} in + * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p> * - * <p>This has the same effect as passing the result of - * {@link #getSampledSize} to {@link #setResize(int, int)}.</p> + * <p>Requests the decoder to subsample the original image, returning a + * smaller image to save memory. The sample size is the number of pixels + * in either dimension that correspond to a single pixel in the output. + * For example, sampleSize == 4 returns an image that is 1/4 the + * width/height of the original, and 1/16 the number of pixels.</p> + * + * <p>Must be greater than or equal to 1.</p> + * + * <p>Only the last call to this or {@link #setTargetSize} is respected.</p> * * @param sampleSize Sampling rate of the encoded image. * @return this object for chaining. */ - public ImageDecoder setResize(int sampleSize) { + public ImageDecoder setSampleSize(int sampleSize) { Size size = this.getSampledSize(sampleSize); - return this.setResize(size.getWidth(), size.getHeight()); + int targetWidth = getTargetDimension(mWidth, sampleSize, size.getWidth()); + int targetHeight = getTargetDimension(mHeight, sampleSize, size.getHeight()); + return this.setTargetSize(targetWidth, targetHeight); } private boolean requestedResize() { @@ -972,8 +1035,8 @@ public final class ImageDecoder implements AutoCloseable { * Crop the output to {@code subset} of the (possibly) scaled image. * * <p>{@code subset} must be contained within the size set by - * {@link #setResize} or the bounds of the image if setResize was not - * called. Otherwise an {@link IllegalStateException} will be thrown by + * {@link #setTargetSize} or the bounds of the image if setTargetSize was + * not called. Otherwise an {@link IllegalStateException} will be thrown by * {@link #decodeDrawable}/{@link #decodeBitmap}.</p> * * <p>NOT intended as a replacement for @@ -1353,7 +1416,7 @@ public final class ImageDecoder implements AutoCloseable { float scale = (float) dstDensity / srcDensity; int scaledWidth = (int) (decoder.mWidth * scale + 0.5f); int scaledHeight = (int) (decoder.mHeight * scale + 0.5f); - decoder.setResize(scaledWidth, scaledHeight); + decoder.setTargetSize(scaledWidth, scaledHeight); return dstDensity; } diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java index 098cdc67555d..cd0862cd13fe 100644 --- a/graphics/java/android/graphics/Path.java +++ b/graphics/java/android/graphics/Path.java @@ -24,6 +24,8 @@ import android.annotation.Size; import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; +import libcore.util.NativeAllocationRegistry; + /** * The Path class encapsulates compound (multiple contour) geometric paths * consisting of straight line segments, quadratic curves, and cubic curves. @@ -32,10 +34,14 @@ import dalvik.annotation.optimization.FastNative; * text on a path. */ public class Path { + + private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( + Path.class.getClassLoader(), nGetFinalizer(), 48 /* dummy size */); + /** * @hide */ - public long mNativePath; + public final long mNativePath; /** * @hide @@ -52,6 +58,7 @@ public class Path { */ public Path() { mNativePath = nInit(); + sRegistry.registerNativeAllocation(this, mNativePath); } /** @@ -69,6 +76,7 @@ public class Path { } } mNativePath = nInit(valNative); + sRegistry.registerNativeAllocation(this, mNativePath); } /** @@ -297,7 +305,7 @@ public class Path { * a rectangle * @return true if the path specifies a rectangle */ - public boolean isRect(RectF rect) { + public boolean isRect(@Nullable RectF rect) { return nIsRect(mNativePath, rect); } @@ -771,15 +779,6 @@ public class Path { nTransform(mNativePath, matrix.native_instance); } - protected void finalize() throws Throwable { - try { - nFinalize(mNativePath); - mNativePath = 0; // Other finalizers can still call us. - } finally { - super.finalize(); - } - } - /** @hide */ public final long readOnlyNI() { return mNativePath; @@ -820,7 +819,7 @@ public class Path { private static native long nInit(); private static native long nInit(long nPath); - private static native void nFinalize(long nPath); + private static native long nGetFinalizer(); private static native void nSet(long native_dst, long nSrc); private static native void nComputeBounds(long nPath, RectF bounds); private static native void nIncReserve(long nPath, int extraPtCount); diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl index 5a8fa0700328..0d32075d20d2 100644 --- a/keystore/java/android/security/IKeyChainService.aidl +++ b/keystore/java/android/security/IKeyChainService.aidl @@ -33,8 +33,8 @@ interface IKeyChainService { boolean isUserSelectable(String alias); void setUserSelectable(String alias, boolean isUserSelectable); - boolean generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec); - boolean attestKey(in String alias, in byte[] challenge, in int[] idAttestationFlags, + int generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec); + int attestKey(in String alias, in byte[] challenge, in int[] idAttestationFlags, out KeymasterCertificateChain chain); boolean setKeyPairCertificate(String alias, in byte[] userCert, in byte[] certChain); diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index 2daf733d057f..46a7fa8d5e28 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -246,6 +246,82 @@ public final class KeyChain { public static final String EXTRA_KEY_ACCESSIBLE = "android.security.extra.KEY_ACCESSIBLE"; /** + * Indicates that a call to {@link #generateKeyPair} was successful. + * @hide + */ + public static final int KEY_GEN_SUCCESS = 0; + + /** + * An alias was missing from the key specifications when calling {@link #generateKeyPair}. + * @hide + */ + public static final int KEY_GEN_MISSING_ALIAS = 1; + + /** + * A key attestation challenge was provided to {@link #generateKeyPair}, but it shouldn't + * have been provided. + * @hide + */ + public static final int KEY_GEN_SUPERFLUOUS_ATTESTATION_CHALLENGE = 2; + + /** + * Algorithm not supported by {@link #generateKeyPair} + * @hide + */ + public static final int KEY_GEN_NO_SUCH_ALGORITHM = 3; + + /** + * Invalid algorithm parameters when calling {@link #generateKeyPair} + * @hide + */ + public static final int KEY_GEN_INVALID_ALGORITHM_PARAMETERS = 4; + + /** + * Keystore is not available when calling {@link #generateKeyPair} + * @hide + */ + public static final int KEY_GEN_NO_KEYSTORE_PROVIDER = 5; + + /** + * General failure while calling {@link #generateKeyPair} + * @hide + */ + public static final int KEY_GEN_FAILURE = 6; + + /** + * Successful call to {@link #attestKey} + * @hide + */ + public static final int KEY_ATTESTATION_SUCCESS = 0; + + /** + * Attestation challenge missing when calling {@link #attestKey} + * @hide + */ + public static final int KEY_ATTESTATION_MISSING_CHALLENGE = 1; + + /** + * The caller requested Device ID attestation when calling {@link #attestKey}, but has no + * permissions to get device identifiers. + * @hide + */ + public static final int KEY_ATTESTATION_CANNOT_COLLECT_DATA = 2; + + /** + * The underlying hardware does not support Device ID attestation or cannot attest to the + * identifiers that are stored on the device. This indicates permanent inability + * to get attestation records on the device. + * @hide + */ + public static final int KEY_ATTESTATION_CANNOT_ATTEST_IDS = 3; + + /** + * General failure when calling {@link #attestKey} + * @hide + */ + public static final int KEY_ATTESTATION_FAILURE = 4; + + /** * Returns an {@code Intent} that can be used for credential * installation. The intent may be used without any extras, in * which case the user will be able to install credentials from diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 1924bbe764c7..1e2ebf894f99 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -66,6 +66,7 @@ public class KeyStore { public static final int VALUE_CORRUPTED = 8; public static final int UNDEFINED_ACTION = 9; public static final int WRONG_PASSWORD = 10; + public static final int CANNOT_ATTEST_IDS = -66; public static final int HARDWARE_TYPE_UNAVAILABLE = -68; /** diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index a444ac8090d6..f43e719d47a3 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1724,6 +1724,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS, SecureSettingsProto.Backup.LOCAL_TRANSPORT_PARAMETERS); + dumpSetting(s, p, + Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE, + SecureSettingsProto.Backup.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE); p.end(backupToken); // Settings.Secure.BLUETOOTH_ON intentionally excluded since it's deprecated. diff --git a/packages/SystemUI/res/drawable/qs_header_status_dot.xml b/packages/SystemUI/res/drawable/qs_header_status_dot.xml deleted file mode 100644 index 69bfd49255fc..000000000000 --- a/packages/SystemUI/res/drawable/qs_header_status_dot.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2018 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="oval"> - <solid android:color="@android:color/white"/> -</shape> diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml index 03e8451e59dc..54baa4a82a0b 100644 --- a/packages/SystemUI/res/layout/quick_settings_header_info.xml +++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml @@ -54,15 +54,14 @@ android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start" android:textAppearance="@style/TextAppearance.QS.TileLabel" /> - <ImageView + <View android:id="@+id/status_separator" - android:layout_width="2dp" - android:layout_height="2dp" - android:layout_marginStart="8dp" - android:layout_marginEnd="8dp" - android:layout_gravity="center_vertical" - android:src="@drawable/qs_header_status_dot" - android:tint="?android:attr/textColorPrimary" /> + android:layout_width="1dp" + android:layout_height="match_parent" + android:layout_marginStart="10dp" + android:layout_marginEnd="10dp" + android:background="@android:color/white" + android:backgroundTint="?android:attr/textColorPrimary" /> <ImageView android:id="@+id/ringer_mode_icon" diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java index 7ffca173be86..d52746599aa1 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java +++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java @@ -323,10 +323,10 @@ public class StorageNotification extends SystemUI { if (notif != null) { mNotificationManager.notifyAsUser(vol.getId(), SystemMessage.NOTE_STORAGE_PUBLIC, - notif, UserHandle.ALL); + notif, UserHandle.of(vol.getMountUserId())); } else { mNotificationManager.cancelAsUser(vol.getId(), SystemMessage.NOTE_STORAGE_PUBLIC, - UserHandle.ALL); + UserHandle.of(vol.getMountUserId())); } } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 8941b4926584..de112f94f743 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -853,11 +853,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (mSecurityPolicy.findA11yWindowInfoById(windowId) == null) { return null; } - IBinder token = mGlobalWindowTokens.get(windowId); - if (token != null) { - return token; - } - return getCurrentUserStateLocked().mWindowTokens.get(windowId); + return findWindowTokenLocked(windowId); } } @@ -2527,6 +2523,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub getInteractionBridge().clearAccessibilityFocusNotLocked(windowId); } + private IBinder findWindowTokenLocked(int windowId) { + IBinder token = mGlobalWindowTokens.get(windowId); + if (token != null) { + return token; + } + return getCurrentUserStateLocked().mWindowTokens.get(windowId); + } + private int findWindowIdLocked(IBinder token) { final int globalIndex = mGlobalWindowTokens.indexOfValue(token); if (globalIndex >= 0) { @@ -2986,7 +2990,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // the accessibility layer reports which are windows // that a sighted user can touch. default: { - return isRetrievalAllowingWindow(event.getWindowId()); + return isRetrievalAllowingWindowLocked(event.getWindowId()); } } } @@ -3438,7 +3442,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public boolean canGetAccessibilityNodeInfoLocked( AbstractAccessibilityServiceConnection service, int windowId) { - return canRetrieveWindowContentLocked(service) && isRetrievalAllowingWindow(windowId); + return canRetrieveWindowContentLocked(service) + && isRetrievalAllowingWindowLocked(windowId); } public boolean canRetrieveWindowsLocked(AbstractAccessibilityServiceConnection service) { @@ -3523,17 +3528,40 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub || userId == UserHandle.USER_CURRENT_OR_SELF); } - private boolean isRetrievalAllowingWindow(int windowId) { + private boolean isRetrievalAllowingWindowLocked(int windowId) { // The system gets to interact with any window it wants. if (Binder.getCallingUid() == Process.SYSTEM_UID) { return true; } + if (Binder.getCallingUid() == Process.SHELL_UID) { + if (!isShellAllowedToRetrieveWindowLocked(windowId)) { + return false; + } + } if (windowId == mActiveWindowId) { return true; } return findA11yWindowInfoById(windowId) != null; } + private boolean isShellAllowedToRetrieveWindowLocked(int windowId) { + long token = Binder.clearCallingIdentity(); + try { + IBinder windowToken = findWindowTokenLocked(windowId); + if (windowToken == null) { + return false; + } + int userId = mWindowManagerService.getWindowOwnerUserId(windowToken); + if (userId == UserHandle.USER_NULL) { + return false; + } + return !mUserManager.hasUserRestriction( + UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId)); + } finally { + Binder.restoreCallingIdentity(token); + } + } + public AccessibilityWindowInfo findA11yWindowInfoById(int windowId) { return mA11yWindowInfoById.get(windowId); } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index d4ecd8b93859..3253f2e40692 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -19,7 +19,6 @@ package com.android.server.autofill; import static android.Manifest.permission.MANAGE_AUTO_FILL; import static android.content.Context.AUTOFILL_MANAGER_SERVICE; -import static com.android.server.autofill.Helper.bundleToString; import static com.android.server.autofill.Helper.sDebug; import static com.android.server.autofill.Helper.sFullScreenMode; import static com.android.server.autofill.Helper.sPartitionMaxCount; @@ -193,8 +192,7 @@ public final class AutofillManagerService extends SystemService { if (disabledBefore == disabledNow) { // Nothing changed, do nothing. if (sDebug) { - Slog.d(TAG, "Autofill restriction did not change for user " + userId + ": " - + bundleToString(newRestrictions)); + Slog.d(TAG, "Autofill restriction did not change for user " + userId); return; } } diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java index a202aafde53b..78526f53cdde 100644 --- a/services/autofill/java/com/android/server/autofill/Helper.java +++ b/services/autofill/java/com/android/server/autofill/Helper.java @@ -79,28 +79,6 @@ public final class Helper { throw new UnsupportedOperationException("contains static members only"); } - static void append(StringBuilder builder, Bundle bundle) { - if (bundle == null || !sVerbose) { - builder.append("null"); - return; - } - final Set<String> keySet = bundle.keySet(); - builder.append("[Bundle with ").append(keySet.size()).append(" extras:"); - for (String key : keySet) { - final Object value = bundle.get(key); - builder.append(' ').append(key).append('='); - builder.append((value instanceof Object[]) - ? Arrays.toString((Objects[]) value) : value); - } - builder.append(']'); - } - - static String bundleToString(Bundle bundle) { - final StringBuilder builder = new StringBuilder(); - append(builder, bundle); - return builder.toString(); - } - @Nullable static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) { if (set == null) return null; diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 706fb1a72491..706a6ab8436f 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -2502,8 +2502,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } pw.print(prefix); pw.print("mHasCallback: "); pw.println(mHasCallback); - pw.print(prefix); pw.print("mClientState: "); pw.println( - Helper.bundleToString(mClientState)); + if (mClientState != null) { + pw.print(prefix); pw.println("mClientState: "); pw.print(mClientState.getSize()); pw + .println(" items"); + } pw.print(prefix); pw.print("mCompatMode: "); pw.println(mCompatMode); pw.print(prefix); pw.print("mUrlBar: "); if (mUrlBar == null) { diff --git a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java index 4de2c9b8e79f..49fa1ccce5fe 100644 --- a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java +++ b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java @@ -21,6 +21,7 @@ import android.os.Handler; import android.provider.Settings; import android.util.KeyValueListParser; import android.util.KeyValueSettingObserver; +import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -31,6 +32,8 @@ import com.android.internal.annotations.VisibleForTesting; * are represented as a comma-delimited key value list. */ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver { + private static final String TAG = "BackupAgentTimeout"; + @VisibleForTesting public static final String SETTING = Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS; @@ -120,30 +123,50 @@ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver { public long getKvBackupAgentTimeoutMillis() { synchronized (mLock) { + if (BackupManagerService.DEBUG_SCHEDULING) { + Slog.v(TAG, "getKvBackupAgentTimeoutMillis(): " + mKvBackupAgentTimeoutMillis); + } return mKvBackupAgentTimeoutMillis; } } public long getFullBackupAgentTimeoutMillis() { synchronized (mLock) { + if (BackupManagerService.DEBUG_SCHEDULING) { + Slog.v(TAG, "getFullBackupAgentTimeoutMillis(): " + mFullBackupAgentTimeoutMillis); + } return mFullBackupAgentTimeoutMillis; } } public long getSharedBackupAgentTimeoutMillis() { synchronized (mLock) { + if (BackupManagerService.DEBUG_SCHEDULING) { + Slog.v( + TAG, + "getSharedBackupAgentTimeoutMillis(): " + mSharedBackupAgentTimeoutMillis); + } return mSharedBackupAgentTimeoutMillis; } } public long getRestoreAgentTimeoutMillis() { synchronized (mLock) { + if (BackupManagerService.DEBUG_SCHEDULING) { + Slog.v(TAG, "getRestoreAgentTimeoutMillis(): " + mRestoreAgentTimeoutMillis); + } return mRestoreAgentTimeoutMillis; } } public long getRestoreAgentFinishedTimeoutMillis() { synchronized (mLock) { + if (BackupManagerService.DEBUG_SCHEDULING) { + Slog.v( + TAG, + "getRestoreAgentFinishedTimeoutMillis(): " + + mRestoreAgentFinishedTimeoutMillis); + } return mRestoreAgentFinishedTimeoutMillis; } } diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index d6f6c6cf1fc3..bd51af270dd8 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -215,13 +215,6 @@ public class BackupManagerService implements BackupManagerServiceInterface { // Timeout interval for deciding that a bind or clear-data has taken too long private static final long TIMEOUT_INTERVAL = 10 * 1000; - // Timeout intervals for agent backup & restore operations - public static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000; - public static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000; - public static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000; - public static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000; - public static final long TIMEOUT_RESTORE_FINISHED_INTERVAL = 30 * 1000; - // User confirmation timeout for a full backup/restore operation. It's this long in // order to give them time to enter the backup password. private static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000; @@ -232,6 +225,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { private static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2; // two hours private BackupManagerConstants mConstants; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; private Context mContext; private PackageManager mPackageManager; private IPackageManager mPackageManagerBinder; @@ -315,6 +309,10 @@ public class BackupManagerService implements BackupManagerServiceInterface { return mConstants; } + public BackupAgentTimeoutParameters getAgentTimeoutParameters() { + return mAgentTimeoutParameters; + } + public Context getContext() { return mContext; } @@ -799,6 +797,10 @@ public class BackupManagerService implements BackupManagerServiceInterface { mBackupManagerBinder = Trampoline.asInterface(parent.asBinder()); + mAgentTimeoutParameters = new + BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver()); + mAgentTimeoutParameters.start(); + // spin up the backup/restore handler thread mBackupHandler = new BackupHandler(this, backupThread.getLooper()); @@ -3407,7 +3409,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { } mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport); mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, - TIMEOUT_RESTORE_INTERVAL); + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis()); } return mActiveRestoreSession; } diff --git a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java index 7b021c64eaf8..aabe7f611845 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java +++ b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java @@ -191,4 +191,7 @@ public interface BackupManagerServiceInterface { void dump(FileDescriptor fd, PrintWriter pw, String[] args); IBackupManager getBackupManagerBinder(); + + // Gets access to the backup/restore agent timeout parameters. + BackupAgentTimeoutParameters getAgentTimeoutParameters(); } diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java index 47558775d19e..7f0030a5064e 100644 --- a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java +++ b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java @@ -4,8 +4,8 @@ import static android.os.ParcelFileDescriptor.MODE_CREATE; import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; import static android.os.ParcelFileDescriptor.MODE_TRUNCATE; + import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; -import static com.android.server.backup.BackupManagerService.TIMEOUT_BACKUP_INTERVAL; import android.app.ApplicationThreadConstants; import android.app.IBackupAgent; @@ -19,6 +19,7 @@ import android.os.RemoteException; import android.os.SELinux; import android.util.Slog; +import com.android.internal.util.Preconditions; import com.android.server.backup.utils.FullBackupUtils; import libcore.io.IoUtils; @@ -59,6 +60,7 @@ public class KeyValueAdbBackupEngine { private ParcelFileDescriptor mSavedState; private ParcelFileDescriptor mBackupData; private ParcelFileDescriptor mNewState; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; public KeyValueAdbBackupEngine(OutputStream output, PackageInfo packageInfo, BackupManagerServiceInterface backupManagerService, PackageManager packageManager, @@ -81,6 +83,9 @@ public class KeyValueAdbBackupEngine { pkg + BACKUP_KEY_VALUE_NEW_STATE_FILENAME_SUFFIX); mManifestFile = new File(mDataDir, BackupManagerService.BACKUP_MANIFEST_FILENAME); + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); } public void backupOnePackage() throws IOException { @@ -148,8 +153,9 @@ public class KeyValueAdbBackupEngine { // Return true on backup success, false otherwise private boolean invokeAgentForAdbBackup(String packageName, IBackupAgent agent) { int token = mBackupManagerService.generateRandomIntegerToken(); + long kvBackupAgentTimeoutMillis = mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis(); try { - mBackupManagerService.prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, null, + mBackupManagerService.prepareOperationTimeout(token, kvBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT); // Start backup and wait for BackupManagerService to get callback for success or timeout @@ -231,14 +237,14 @@ public class KeyValueAdbBackupEngine { } private void writeBackupData() throws IOException { - int token = mBackupManagerService.generateRandomIntegerToken(); + long kvBackupAgentTimeoutMillis = mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis(); ParcelFileDescriptor[] pipes = null; try { pipes = ParcelFileDescriptor.createPipe(); - mBackupManagerService.prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, null, + mBackupManagerService.prepareOperationTimeout(token, kvBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT); // We will have to create a runnable that will read the manifest and backup data we diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java index 0582abac91d4..56946596eea3 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java +++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java @@ -25,9 +25,6 @@ import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import static com.android.server.backup.BackupManagerService.TAG; -import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL; -import static com.android.server.backup.BackupManagerService - .TIMEOUT_SHARED_BACKUP_INTERVAL; import android.app.ApplicationThreadConstants; import android.app.IBackupAgent; @@ -44,9 +41,11 @@ import android.util.Log; import android.util.Slog; import android.util.StringBuilderPrinter; +import com.android.internal.util.Preconditions; import com.android.server.AppWidgetBackupBridge; -import com.android.server.backup.BackupRestoreTask; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; +import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.utils.FullBackupUtils; import java.io.BufferedOutputStream; @@ -75,6 +74,7 @@ public class FullBackupEngine { private final long mQuota; private final int mOpToken; private final int mTransportFlags; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; class FullBackupRunner implements Runnable { @@ -137,8 +137,8 @@ public class FullBackupEngine { final boolean isSharedStorage = mPackage.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE); final long timeout = isSharedStorage ? - TIMEOUT_SHARED_BACKUP_INTERVAL : - TIMEOUT_FULL_BACKUP_INTERVAL; + mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis() : + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); if (DEBUG) { Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName); @@ -180,6 +180,9 @@ public class FullBackupEngine { mQuota = quota; mOpToken = opToken; mTransportFlags = transportFlags; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); } public int preflightCheck() throws RemoteException { diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java index 40b6967a729a..bc7d9fc691dd 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java +++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java @@ -19,7 +19,6 @@ package com.android.server.backup.fullbackup; import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; import static com.android.server.backup.BackupManagerService.TAG; -import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL; import android.app.backup.IBackupManager; import android.content.ComponentName; @@ -33,6 +32,8 @@ import android.os.UserHandle; import android.util.Slog; import com.android.internal.backup.IObbBackupService; +import com.android.internal.util.Preconditions; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; import com.android.server.backup.utils.FullBackupUtils; @@ -46,10 +47,14 @@ public class FullBackupObbConnection implements ServiceConnection { private BackupManagerService backupManagerService; volatile IObbBackupService mService; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; public FullBackupObbConnection(BackupManagerService backupManagerService) { this.backupManagerService = backupManagerService; mService = null; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); } public void establish() { @@ -75,8 +80,10 @@ public class FullBackupObbConnection implements ServiceConnection { try { pipes = ParcelFileDescriptor.createPipe(); int token = backupManagerService.generateRandomIntegerToken(); + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); backupManagerService.prepareOperationTimeout( - token, TIMEOUT_FULL_BACKUP_INTERVAL, null, OP_TYPE_BACKUP_WAIT); + token, fullBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT); mService.backupObbs(pkg.packageName, pipes[1], token, backupManagerService.getBackupManagerBinder()); FullBackupUtils.routeSocketDataToOutput(pipes[0], out); diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java index 2c2dd8528cb1..a40afc3cfa4d 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java @@ -22,7 +22,6 @@ import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.OP_PENDING; import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP; import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; -import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL; import android.annotation.Nullable; import android.app.IBackupAgent; @@ -43,7 +42,9 @@ import android.util.Log; import android.util.Slog; import com.android.internal.backup.IBackupTransport; +import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.FullBackupJob; import com.android.server.backup.BackupManagerService; @@ -146,6 +147,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba private volatile boolean mIsDoingBackup; private volatile boolean mCancelAll; private final int mCurrentOpToken; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; public PerformFullTransportBackupTask(BackupManagerService backupManagerService, TransportClient transportClient, @@ -167,6 +169,9 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba mUserInitiated = userInitiated; mCurrentOpToken = backupManagerService.generateRandomIntegerToken(); mBackupRunnerOpToken = backupManagerService.generateRandomIntegerToken(); + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); if (backupManagerService.isBackupOperationInProgress()) { if (DEBUG) { @@ -698,9 +703,11 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba @Override public int preflightFullBackup(PackageInfo pkg, IBackupAgent agent) { int result; + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); try { backupManagerService.prepareOperationTimeout( - mCurrentOpToken, TIMEOUT_FULL_BACKUP_INTERVAL, this, OP_TYPE_BACKUP_WAIT); + mCurrentOpToken, fullBackupAgentTimeoutMillis, this, OP_TYPE_BACKUP_WAIT); backupManagerService.addBackupTrace("preflighting"); if (MORE_DEBUG) { Slog.d(TAG, "Preflighting full payload of " + pkg.packageName); @@ -713,7 +720,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba // timeout had been produced. In case of a real backstop timeout, mResult // will still contain the value it was constructed with, AGENT_ERROR, which // intentionaly falls into the "just report failure" code. - mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); + mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); long totalSize = mResult.get(); // If preflight timed out, mResult will contain error code as int. @@ -769,8 +776,10 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba @Override public long getExpectedSizeOrErrorCode() { + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); try { - mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); + mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); return mResult.get(); } catch (InterruptedException e) { return BackupTransport.NO_MORE_DATA; @@ -863,8 +872,10 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba // If preflight succeeded, returns positive number - preflight size, // otherwise return negative error code. long getPreflightResultBlocking() { + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); try { - mPreflightLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); + mPreflightLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); if (mIsCancelled) { return BackupManager.ERROR_BACKUP_CANCELLED; } @@ -879,8 +890,10 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba } int getBackupResultBlocking() { + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); try { - mBackupLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); + mBackupLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); if (mIsCancelled) { return BackupManager.ERROR_BACKUP_CANCELLED; } diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java index 136fada43b1f..69f08ae49a2e 100644 --- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java +++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java @@ -19,7 +19,6 @@ package com.android.server.backup.internal; import static com.android.server.backup.BackupManagerService.DEBUG; import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.TAG; -import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL; import android.app.backup.RestoreSet; import android.content.Intent; @@ -33,7 +32,9 @@ import android.util.Pair; import android.util.Slog; import com.android.internal.backup.IBackupTransport; +import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.DataChangedJournal; @@ -81,10 +82,14 @@ public class BackupHandler extends Handler { public static final int MSG_OP_COMPLETE = 21; private final BackupManagerService backupManagerService; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; public BackupHandler(BackupManagerService backupManagerService, Looper looper) { super(looper); this.backupManagerService = backupManagerService; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); } public void handleMessage(Message msg) { @@ -322,7 +327,8 @@ public class BackupHandler extends Handler { // Done: reset the session timeout clock removeMessages(MSG_RESTORE_SESSION_TIMEOUT); - sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, TIMEOUT_RESTORE_INTERVAL); + sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis()); params.listener.onFinished(callerLogString); } diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java index 11394e66a0f0..ac605b1ddd69 100644 --- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java +++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java @@ -24,7 +24,6 @@ import static com.android.server.backup.BackupManagerService.OP_PENDING; import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP; import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT; import static com.android.server.backup.BackupManagerService.PACKAGE_MANAGER_SENTINEL; -import static com.android.server.backup.BackupManagerService.TIMEOUT_BACKUP_INTERVAL; import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_OPERATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_RESTORE_STEP; @@ -55,8 +54,10 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.backup.IBackupTransport; +import com.android.internal.util.Preconditions; import com.android.server.AppWidgetBackupBridge; import com.android.server.EventLogTags; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.DataChangedJournal; import com.android.server.backup.KeyValueBackupJob; @@ -142,6 +143,7 @@ public class PerformBackupTask implements BackupRestoreTask { private boolean mFinished; private final boolean mUserInitiated; private final boolean mNonIncremental; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; private volatile boolean mCancelAll; @@ -162,6 +164,9 @@ public class PerformBackupTask implements BackupRestoreTask { mPendingFullBackups = pendingFullBackups; mUserInitiated = userInitiated; mNonIncremental = nonIncremental; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); mStateDir = new File(backupManagerService.getBaseStateDir(), dirName); mCurrentOpToken = backupManagerService.generateRandomIntegerToken(); @@ -711,8 +716,10 @@ public class PerformBackupTask implements BackupRestoreTask { // Initiate the target's backup pass backupManagerService.addBackupTrace("setting timeout"); + long kvBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis(); backupManagerService.prepareOperationTimeout( - mEphemeralOpToken, TIMEOUT_BACKUP_INTERVAL, this, OP_TYPE_BACKUP_WAIT); + mEphemeralOpToken, kvBackupAgentTimeoutMillis, this, OP_TYPE_BACKUP_WAIT); backupManagerService.addBackupTrace("calling agent doBackup()"); agent.doBackup( diff --git a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java index e4f3a9d5cd0a..a8c7ce6ad832 100644 --- a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java +++ b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java @@ -18,10 +18,11 @@ package com.android.server.backup.restore; import static com.android.server.backup.BackupManagerService.DEBUG; import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL; import android.util.Slog; +import com.android.internal.util.Preconditions; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; @@ -37,18 +38,24 @@ public class AdbRestoreFinishedLatch implements BackupRestoreTask { private BackupManagerService backupManagerService; final CountDownLatch mLatch; private final int mCurrentOpToken; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; public AdbRestoreFinishedLatch(BackupManagerService backupManagerService, int currentOpToken) { this.backupManagerService = backupManagerService; mLatch = new CountDownLatch(1); mCurrentOpToken = currentOpToken; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); } void await() { boolean latched = false; + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); try { - latched = mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS); + latched = mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Slog.w(TAG, "Interrupted!"); } diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index c1a1c1dc10e7..6bc753000837 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -23,9 +23,6 @@ import static com.android.server.backup.BackupManagerService.MORE_DEBUG; import static com.android.server.backup.BackupManagerService.OP_TYPE_RESTORE_WAIT; import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import static com.android.server.backup.BackupManagerService.TAG; -import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL; -import static com.android.server.backup.BackupManagerService - .TIMEOUT_SHARED_BACKUP_INTERVAL; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT; import android.app.ApplicationThreadConstants; @@ -40,13 +37,17 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.provider.Settings; +import android.text.TextUtils; import android.util.Slog; +import com.android.internal.util.Preconditions; import com.android.server.LocalServices; +import com.android.server.backup.BackupAgentTimeoutParameters; +import com.android.server.backup.BackupManagerService; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.FileMetadata; import com.android.server.backup.KeyValueAdbRestoreEngine; -import com.android.server.backup.BackupManagerService; import com.android.server.backup.fullbackup.FullBackupObbConnection; import com.android.server.backup.utils.BytesReadListener; import com.android.server.backup.utils.FullBackupRestoreObserverUtils; @@ -56,8 +57,11 @@ import com.android.server.backup.utils.TarBackupReader; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; /** * Full restore engine, used by both adb restore and transport-based full restore. @@ -121,6 +125,8 @@ public class FullRestoreEngine extends RestoreEngine { final int mEphemeralOpToken; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; + public FullRestoreEngine(BackupManagerService backupManagerService, BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer, IBackupManagerMonitor monitor, PackageInfo onlyPackage, boolean allowApks, @@ -135,6 +141,9 @@ public class FullRestoreEngine extends RestoreEngine { mAllowObbs = allowObbs; mBuffer = new byte[32 * 1024]; mBytes = 0; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); } public IBackupAgent getAgent() { @@ -320,12 +329,17 @@ public class FullRestoreEngine extends RestoreEngine { pkg, 0); // If we haven't sent any data to this app yet, we probably - // need to clear it first. Check that. + // need to clear it first. Check that. if (!mClearedPackages.contains(pkg)) { - // apps with their own backup agents are - // responsible for coherently managing a full - // restore. - if (mTargetApp.backupAgentName == null) { + // Apps with their own backup agents are responsible for coherently + // managing a full restore. + // In some rare cases they can't, especially in case of deferred + // restore. In this case check whether this app should be forced to + // clear up. + // TODO: Fix this properly with manifest parameter. + boolean forceClear = shouldForceClearAppDataOnFullRestore( + mTargetApp.packageName); + if (mTargetApp.backupAgentName == null || forceClear) { if (DEBUG) { Slog.d(TAG, "Clearing app data preparatory to full restore"); @@ -381,8 +395,8 @@ public class FullRestoreEngine extends RestoreEngine { long toCopy = info.size; final boolean isSharedStorage = pkg.equals(SHARED_BACKUP_AGENT_PACKAGE); final long timeout = isSharedStorage ? - TIMEOUT_SHARED_BACKUP_INTERVAL : - TIMEOUT_RESTORE_INTERVAL; + mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis() : + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(); try { mBackupManagerService.prepareOperationTimeout(token, timeout, @@ -623,6 +637,24 @@ public class FullRestoreEngine extends RestoreEngine { return true; } + /** + * Returns whether the package is in the list of the packages for which clear app data should + * be called despite the fact that they have backup agent. + * + * <p>The list is read from {@link Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE}. + */ + private boolean shouldForceClearAppDataOnFullRestore(String packageName) { + String packageListString = Settings.Secure.getString( + mBackupManagerService.getContext().getContentResolver(), + Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE); + if (TextUtils.isEmpty(packageListString)) { + return false; + } + + List<String> packages = Arrays.asList(packageListString.split(";")); + return packages.contains(packageName); + } + void sendOnRestorePackage(String name) { if (mObserver != null) { try { diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java index dacde0b9af68..77163d348e1c 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java @@ -16,8 +16,6 @@ package com.android.server.backup.restore; -import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT; -import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK; import static com.android.server.backup.BackupManagerService.BACKUP_FILE_HEADER_MAGIC; import static com.android.server.backup.BackupManagerService.BACKUP_FILE_VERSION; import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_FILENAME; @@ -28,8 +26,8 @@ import static com.android.server.backup.BackupManagerService.OP_TYPE_RESTORE_WAI import static com.android.server.backup.BackupManagerService.SETTINGS_PACKAGE; import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE; import static com.android.server.backup.BackupManagerService.TAG; -import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL; -import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL; +import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT; +import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT; import android.app.ApplicationThreadConstants; @@ -48,7 +46,9 @@ import android.os.RemoteException; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; import com.android.server.LocalServices; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; import com.android.server.backup.FileMetadata; import com.android.server.backup.KeyValueAdbRestoreEngine; @@ -101,6 +101,7 @@ public class PerformAdbRestoreTask implements Runnable { private byte[] mWidgetData = null; private long mBytes; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; // Runner that can be placed on a separate thread to do in-process invocation // of the "restore finished" API asynchronously. Used by adb restore. @@ -155,6 +156,9 @@ public class PerformAdbRestoreTask implements Runnable { mAgentPackage = null; mTargetApp = null; mObbConnection = new FullBackupObbConnection(backupManagerService); + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); // Which packages we've already wiped data on. We prepopulate this // with a whitelist of packages known to be unclearable. @@ -643,9 +647,11 @@ public class PerformAdbRestoreTask implements Runnable { if (okay) { boolean agentSuccess = true; long toCopy = info.size; + long restoreAgentTimeoutMillis = + mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(); try { mBackupManagerService.prepareOperationTimeout( - token, TIMEOUT_RESTORE_INTERVAL, null, OP_TYPE_RESTORE_WAIT); + token, restoreAgentTimeoutMillis, null, OP_TYPE_RESTORE_WAIT); if (FullBackup.OBB_TREE_TOKEN.equals(info.domain)) { if (DEBUG) { @@ -820,10 +826,12 @@ public class PerformAdbRestoreTask implements Runnable { // In the adb restore case, we do restore-finished here if (doRestoreFinished) { final int token = mBackupManagerService.generateRandomIntegerToken(); + long fullBackupAgentTimeoutMillis = + mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis(); final AdbRestoreFinishedLatch latch = new AdbRestoreFinishedLatch( mBackupManagerService, token); mBackupManagerService.prepareOperationTimeout( - token, TIMEOUT_FULL_BACKUP_INTERVAL, latch, OP_TYPE_RESTORE_WAIT); + token, fullBackupAgentTimeoutMillis, latch, OP_TYPE_RESTORE_WAIT); if (mTargetApp.processName.equals("system")) { if (MORE_DEBUG) { Slog.d(TAG, "system agent - restoreFinished on thread"); diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 4b467e5a0399..12d72d8a4637 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -23,9 +23,6 @@ import static com.android.server.backup.BackupManagerService.OP_TYPE_RESTORE_WAI import static com.android.server.backup.BackupManagerService.PACKAGE_MANAGER_SENTINEL; import static com.android.server.backup.BackupManagerService.SETTINGS_PACKAGE; import static com.android.server.backup.BackupManagerService.TAG; -import static com.android.server.backup.BackupManagerService - .TIMEOUT_RESTORE_FINISHED_INTERVAL; -import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL; import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_RESTORE_STEP; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT; @@ -56,9 +53,11 @@ import android.util.EventLog; import android.util.Slog; import com.android.internal.backup.IBackupTransport; +import com.android.internal.util.Preconditions; import com.android.server.AppWidgetBackupBridge; import com.android.server.EventLogTags; import com.android.server.LocalServices; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.BackupUtils; import com.android.server.backup.PackageManagerBackupAgent; @@ -160,6 +159,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { ParcelFileDescriptor mNewState; private final int mEphemeralOpToken; + private final BackupAgentTimeoutParameters mAgentTimeoutParameters; // This task can assume that the wakelock is properly held for it and doesn't have to worry // about releasing it. @@ -190,6 +190,9 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { mFinished = false; mDidLaunch = false; mListener = listener; + mAgentTimeoutParameters = Preconditions.checkNotNull( + backupManagerService.getAgentTimeoutParameters(), + "Timeout parameters cannot be null"); if (targetPackage != null) { // Single package restore @@ -760,8 +763,9 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { // Kick off the restore, checking for hung agents. The timeout or // the operationComplete() callback will schedule the next step, // so we do not do that here. + long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(); backupManagerService.prepareOperationTimeout( - mEphemeralOpToken, TIMEOUT_RESTORE_INTERVAL, this, OP_TYPE_RESTORE_WAIT); + mEphemeralOpToken, restoreAgentTimeoutMillis, this, OP_TYPE_RESTORE_WAIT); mAgent.doRestore(mBackupData, appVersionCode, mNewState, mEphemeralOpToken, backupManagerService.getBackupManagerBinder()); } catch (Exception e) { @@ -813,9 +817,11 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { Slog.d(TAG, "restoreFinished packageName=" + mCurrentPackage.packageName); } try { + long restoreAgentFinishedTimeoutMillis = + mAgentTimeoutParameters.getRestoreAgentFinishedTimeoutMillis(); backupManagerService .prepareOperationTimeout(mEphemeralOpToken, - TIMEOUT_RESTORE_FINISHED_INTERVAL, this, + restoreAgentFinishedTimeoutMillis, this, OP_TYPE_RESTORE_WAIT); mAgent.doRestoreFinished(mEphemeralOpToken, backupManagerService.getBackupManagerBinder()); @@ -1109,9 +1115,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { } else { // We were invoked via an active restore session, not by the Package // Manager, so start up the session timeout again. + long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(); backupManagerService.getBackupHandler().sendEmptyMessageDelayed( MSG_RESTORE_SESSION_TIMEOUT, - TIMEOUT_RESTORE_INTERVAL); + restoreAgentTimeoutMillis); } // Kick off any work that may be needed regarding app widget restores diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java index 73a7c3eb32a5..9df321c64c9a 100644 --- a/services/core/java/com/android/server/am/RecentsAnimation.java +++ b/services/core/java/com/android/server/am/RecentsAnimation.java @@ -42,18 +42,13 @@ import com.android.server.wm.WindowManagerService; class RecentsAnimation implements RecentsAnimationCallbacks { private static final String TAG = RecentsAnimation.class.getSimpleName(); - private static final int RECENTS_ANIMATION_TIMEOUT = 10 * 1000; - private final ActivityManagerService mService; private final ActivityStackSupervisor mStackSupervisor; private final ActivityStartController mActivityStartController; private final WindowManagerService mWindowManager; private final UserController mUserController; - private final Handler mHandler; private final int mCallingPid; - private final Runnable mCancelAnimationRunnable; - // The stack to restore the home stack behind when the animation is finished private ActivityStack mRestoreHomeBehindStack; @@ -63,16 +58,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks { mService = am; mStackSupervisor = stackSupervisor; mActivityStartController = activityStartController; - mHandler = new Handler(mStackSupervisor.mLooper); mWindowManager = wm; mUserController = userController; mCallingPid = callingPid; - - mCancelAnimationRunnable = () -> { - // The caller has not finished the animation in a predefined amount of time, so - // force-cancel the animation - mWindowManager.cancelRecentsAnimation(); - }; } void startRecentsActivity(Intent intent, IRecentsAnimationRunner recentsAnimationRunner, @@ -133,10 +121,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks { // duration of the gesture that is driven by the recents component homeActivity.mLaunchTaskBehind = true; - // Post a timeout for the animation. This needs to happen before initializing the - // recents animation on the WM side since we may decide to cancel the animation there - mHandler.postDelayed(mCancelAnimationRunnable, RECENTS_ANIMATION_TIMEOUT); - // Fetch all the surface controls and pass them to the client to get the animation // started mWindowManager.cancelRecentsAnimation(); @@ -157,7 +141,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks { @Override public void onAnimationFinished(boolean moveHomeToTop) { - mHandler.removeCallbacks(mCancelAnimationRunnable); synchronized (mService) { if (mWindowManager.getRecentsAnimationController() == null) return; diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java index 6919282054ed..248151ca2bd3 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java @@ -232,6 +232,7 @@ class Convert { * HAL implementation instance. */ 1, // numTuners 1, // numAudioSources + false, // isInitializationRequired false, // isCaptureSupported amfmConfigToBands(amfmConfig), diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 30125f8199de..77d7c3cfdbf2 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -31,7 +31,6 @@ import android.annotation.Nullable; import android.app.PendingIntent; import android.content.Context; import android.os.Binder; -import android.os.Process; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.os.UserHandle; @@ -100,7 +99,6 @@ public class RecoverableKeyStoreManager { private final RecoverableKeyGenerator mRecoverableKeyGenerator; private final RecoverySnapshotStorage mSnapshotStorage; private final PlatformKeyManager mPlatformKeyManager; - private final KeyStore mKeyStore; private final ApplicationKeyStorage mApplicationKeyStorage; /** @@ -126,11 +124,10 @@ public class RecoverableKeyStoreManager { mInstance = new RecoverableKeyStoreManager( context.getApplicationContext(), - keystore, db, new RecoverySessionStorage(), Executors.newSingleThreadExecutor(), - new RecoverySnapshotStorage(), + RecoverySnapshotStorage.newInstance(), new RecoverySnapshotListenersStorage(), platformKeyManager, applicationKeyStorage); @@ -141,7 +138,6 @@ public class RecoverableKeyStoreManager { @VisibleForTesting RecoverableKeyStoreManager( Context context, - KeyStore keystore, RecoverableKeyStoreDb recoverableKeyStoreDb, RecoverySessionStorage recoverySessionStorage, ExecutorService executorService, @@ -150,7 +146,6 @@ public class RecoverableKeyStoreManager { PlatformKeyManager platformKeyManager, ApplicationKeyStorage applicationKeyStorage) { mContext = context; - mKeyStore = keystore; mDatabase = recoverableKeyStoreDb; mRecoverySessionStorage = recoverySessionStorage; mExecutorService = executorService; diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java index dcaa0b4785cc..f789155cee52 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java @@ -23,6 +23,9 @@ import static com.android.server.locksettings.recoverablekeystore.serialization. import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEYS; + +import static com.android.server.locksettings.recoverablekeystore.serialization + .KeyChainSnapshotSchema.TAG_BACKEND_PUBLIC_KEY; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_COUNTER_ID; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_RECOVERY_KEY_MATERIAL; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS; @@ -128,6 +131,11 @@ public class KeyChainSnapshotDeserializer { } break; + case TAG_BACKEND_PUBLIC_KEY: + builder.setTrustedHardwarePublicKey( + readBlobTag(parser, TAG_BACKEND_PUBLIC_KEY)); + break; + case TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST: builder.setKeyChainProtectionParams(readKeyChainProtectionParamsList(parser)); break; diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java index ee8b2cfd18f5..ff30ecd7d3a7 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java @@ -35,6 +35,7 @@ class KeyChainSnapshotSchema { static final String TAG_RECOVERY_KEY_MATERIAL = "recoveryKeyMaterial"; static final String TAG_SERVER_PARAMS = "serverParams"; static final String TAG_TRUSTED_HARDWARE_CERT_PATH = "thmCertPath"; + static final String TAG_BACKEND_PUBLIC_KEY = "backendPublicKey"; static final String TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST = "keyChainProtectionParamsList"; diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java index f817a8fb02e4..17a16bf5906b 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java @@ -24,6 +24,9 @@ import static com.android.server.locksettings.recoverablekeystore.serialization. import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEYS; + +import static com.android.server.locksettings.recoverablekeystore.serialization + .KeyChainSnapshotSchema.TAG_BACKEND_PUBLIC_KEY; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_COUNTER_ID; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_RECOVERY_KEY_MATERIAL; import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS; @@ -159,6 +162,10 @@ public class KeyChainSnapshotSerializer { writePropertyTag(xmlSerializer, TAG_SERVER_PARAMS, keyChainSnapshot.getServerParams()); writePropertyTag(xmlSerializer, TAG_TRUSTED_HARDWARE_CERT_PATH, keyChainSnapshot.getTrustedHardwareCertPath()); + if (keyChainSnapshot.getTrustedHardwarePublicKey() != null) { + writePropertyTag(xmlSerializer, TAG_BACKEND_PUBLIC_KEY, + keyChainSnapshot.getTrustedHardwarePublicKey()); + } } private static void writePropertyTag( diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java index 3f93cc6f5f88..c02b103f1d33 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java @@ -17,13 +17,28 @@ package com.android.server.locksettings.recoverablekeystore.storage; import android.annotation.Nullable; +import android.os.Environment; import android.security.keystore.recovery.KeyChainSnapshot; +import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.locksettings.recoverablekeystore.serialization + .KeyChainSnapshotDeserializer; +import com.android.server.locksettings.recoverablekeystore.serialization + .KeyChainSnapshotParserException; +import com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSerializer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.security.cert.CertificateEncodingException; +import java.util.Locale; /** - * In-memory storage for recovery snapshots. + * Storage for recovery snapshots. Stores snapshots in memory, backed by disk storage. * * <p>Recovery snapshots are generated after a successful screen unlock. They are only generated if * the recoverable keystore has been mutated since the previous snapshot. This class stores only the @@ -33,14 +48,46 @@ import com.android.internal.annotations.GuardedBy; * {@link com.android.server.locksettings.recoverablekeystore.KeySyncTask} thread. */ public class RecoverySnapshotStorage { + + private static final String TAG = "RecoverySnapshotStorage"; + + private static final String ROOT_PATH = "system"; + private static final String STORAGE_PATH = "recoverablekeystore/snapshots/"; + @GuardedBy("this") private final SparseArray<KeyChainSnapshot> mSnapshotByUid = new SparseArray<>(); + private final File rootDirectory; + + /** + * A new instance, storing snapshots in /data/system/recoverablekeystore/snapshots. + * + * <p>NOTE: calling this multiple times DOES NOT return the same instance, so will NOT be backed + * by the same in-memory store. + */ + public static RecoverySnapshotStorage newInstance() { + return new RecoverySnapshotStorage( + new File(Environment.getDataDirectory(), ROOT_PATH)); + } + + @VisibleForTesting + public RecoverySnapshotStorage(File rootDirectory) { + this.rootDirectory = rootDirectory; + } + /** * Sets the latest {@code snapshot} for the recovery agent {@code uid}. */ public synchronized void put(int uid, KeyChainSnapshot snapshot) { mSnapshotByUid.put(uid, snapshot); + + try { + writeToDisk(uid, snapshot); + } catch (IOException | CertificateEncodingException e) { + Log.e(TAG, + String.format(Locale.US, "Error persisting snapshot for %d to disk", uid), + e); + } } /** @@ -48,7 +95,17 @@ public class RecoverySnapshotStorage { */ @Nullable public synchronized KeyChainSnapshot get(int uid) { - return mSnapshotByUid.get(uid); + KeyChainSnapshot snapshot = mSnapshotByUid.get(uid); + if (snapshot != null) { + return snapshot; + } + + try { + return readFromDisk(uid); + } catch (IOException | KeyChainSnapshotParserException e) { + Log.e(TAG, String.format(Locale.US, "Error reading snapshot for %d from disk", uid), e); + return null; + } } /** @@ -56,5 +113,66 @@ public class RecoverySnapshotStorage { */ public synchronized void remove(int uid) { mSnapshotByUid.remove(uid); + getSnapshotFile(uid).delete(); + } + + /** + * Writes the snapshot for recovery agent {@code uid} to disk. + * + * @throws IOException if an IO error occurs writing to disk. + */ + private void writeToDisk(int uid, KeyChainSnapshot snapshot) + throws IOException, CertificateEncodingException { + File snapshotFile = getSnapshotFile(uid); + + try ( + FileOutputStream fileOutputStream = new FileOutputStream(snapshotFile) + ) { + KeyChainSnapshotSerializer.serialize(snapshot, fileOutputStream); + } catch (IOException | CertificateEncodingException e) { + // If we fail to write the latest snapshot, we should delete any older snapshot that + // happens to be around. Otherwise snapshot syncs might end up going 'back in time'. + snapshotFile.delete(); + throw e; + } + } + + /** + * Reads the last snapshot for recovery agent {@code uid} from disk. + * + * @return The snapshot, or null if none existed. + * @throws IOException if an IO error occurs reading from disk. + */ + @Nullable + private KeyChainSnapshot readFromDisk(int uid) + throws IOException, KeyChainSnapshotParserException { + File snapshotFile = getSnapshotFile(uid); + + try ( + FileInputStream fileInputStream = new FileInputStream(snapshotFile) + ) { + return KeyChainSnapshotDeserializer.deserialize(fileInputStream); + } catch (IOException | KeyChainSnapshotParserException e) { + // If we fail to read the latest snapshot, we should delete it in case it is in some way + // corrupted. We can regenerate snapshots anyway. + snapshotFile.delete(); + throw e; + } + } + + private File getSnapshotFile(int uid) { + File folder = getStorageFolder(); + String fileName = getSnapshotFileName(uid); + return new File(folder, fileName); + } + + private String getSnapshotFileName(int uid) { + return String.format(Locale.US, "%d.xml", uid); + } + + private File getStorageFolder() { + File folder = new File(rootDirectory, STORAGE_PATH); + folder.mkdirs(); + return folder; } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 210857e1b097..31b0461b53b4 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2149,7 +2149,8 @@ public class NotificationManagerService extends SystemService { final NotificationChannel channel = channels.get(i); Preconditions.checkNotNull(channel, "channel in list is null"); mRankingHelper.createNotificationChannel(pkg, uid, channel, - true /* fromTargetApp */); + true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed( + pkg, UserHandle.getUserId(uid))); mListeners.notifyNotificationChannelChanged(pkg, UserHandle.getUserHandleForUid(uid), mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false), @@ -4691,11 +4692,12 @@ public class NotificationManagerService extends SystemService { private boolean playSound(final NotificationRecord record, Uri soundUri) { boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0; - // do not play notifications if there is a user of exclusive audio focus - // or the device is in vibrate mode - if (!mAudioManager.isAudioFocusExclusive() && (mAudioManager.getRingerModeInternal() - != AudioManager.RINGER_MODE_VIBRATE || mAudioManager.getStreamVolume( - AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) { + // play notifications if there is no user of exclusive audio focus + // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or + // VIBRATE ringer mode) + if (!mAudioManager.isAudioFocusExclusive() + && (mAudioManager.getStreamVolume( + AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) { final long identity = Binder.clearCallingIdentity(); try { final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java index b1b0bf26d9ee..af6468333ba0 100644 --- a/services/core/java/com/android/server/notification/RankingConfig.java +++ b/services/core/java/com/android/server/notification/RankingConfig.java @@ -38,7 +38,7 @@ public interface RankingConfig { ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg, int uid, boolean includeDeleted, boolean includeNonGrouped); void createNotificationChannel(String pkg, int uid, NotificationChannel channel, - boolean fromTargetApp); + boolean fromTargetApp, boolean hasDndAccess); void updateNotificationChannel(String pkg, int uid, NotificationChannel channel, boolean fromUser); NotificationChannel getNotificationChannel(String pkg, int uid, String channelId, boolean includeDeleted); void deleteNotificationChannel(String pkg, int uid, String channelId); diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index f16311320972..98d5c9a59f6b 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -569,7 +569,7 @@ public class RankingHelper implements RankingConfig { @Override public void createNotificationChannel(String pkg, int uid, NotificationChannel channel, - boolean fromTargetApp) { + boolean fromTargetApp, boolean hasDndAccess) { Preconditions.checkNotNull(pkg); Preconditions.checkNotNull(channel); Preconditions.checkNotNull(channel.getId()); @@ -610,8 +610,9 @@ public class RankingHelper implements RankingConfig { existing.setImportance(channel.getImportance()); } - // system apps can bypass dnd if the user hasn't changed any fields on the channel yet - if (existing.getUserLockedFields() == 0 & isSystemApp) { + // system apps and dnd access apps can bypass dnd if the user hasn't changed any + // fields on the channel yet + if (existing.getUserLockedFields() == 0 && (isSystemApp || hasDndAccess)) { existing.setBypassDnd(channel.canBypassDnd()); } @@ -624,7 +625,7 @@ public class RankingHelper implements RankingConfig { } // Reset fields that apps aren't allowed to set. - if (fromTargetApp && !isSystemApp) { + if (fromTargetApp && !(isSystemApp || hasDndAccess)) { channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX); } if (fromTargetApp) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 2e6e348c51a4..fd023476c9e4 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -1330,6 +1330,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.post(mHiddenNavPanic); } + // Abort possibly stuck animations. + mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe); + // Latch power key state to detect screenshot chord. if (interactive && !mScreenshotChordPowerKeyTriggered && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { @@ -4362,6 +4365,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { * given the situation with the keyguard. */ void launchHomeFromHotKey(final boolean awakenFromDreams, final boolean respectKeyguard) { + // Abort possibly stuck animations. + mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe); + if (respectKeyguard) { if (isKeyguardShowingAndNotOccluded()) { // don't launch home if keyguard showing @@ -7175,7 +7181,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public int rotationForOrientationLw(int orientation, int lastRotation) { + public int rotationForOrientationLw(int orientation, int lastRotation, boolean defaultDisplay) { if (false) { Slog.v(TAG, "rotationForOrientationLw(orient=" + orientation + ", last=" + lastRotation @@ -7196,7 +7202,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } final int preferredRotation; - if (mLidState == LID_OPEN && mLidOpenRotation >= 0) { + if (!defaultDisplay) { + // For secondary displays we ignore things like displays sensors, docking mode and + // rotation lock, and always prefer a default rotation. + preferredRotation = Surface.ROTATION_0; + } else if (mLidState == LID_OPEN && mLidOpenRotation >= 0) { // Ignore sensor when lid switch is open and rotation is forced. preferredRotation = mLidOpenRotation; } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 7a6b53e93917..0a6ae4e2f2d9 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -652,6 +652,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { return Integer.toString(lens); } } + + /** + * Hint to window manager that the user has started a navigation action that should + * abort animations that have no timeout, in case they got stuck. + */ + void triggerAnimationFailsafe(); } /** Window has been added to the screen. */ @@ -1429,10 +1435,13 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * @param orientation An orientation constant, such as * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. * @param lastRotation The most recently used rotation. + * @param defaultDisplay Flag indicating whether the rotation is computed for the default + * display. Currently for all non-default displays sensors, docking mode, + * rotation lock and other factors are ignored. * @return The surface rotation to use. */ public int rotationForOrientationLw(@ActivityInfo.ScreenOrientation int orientation, - int lastRotation); + int lastRotation, boolean defaultDisplay); /** * Given an orientation constant and a rotation, returns true if the rotation diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index b3d28fcbc4f1..d252a56ddf6b 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -466,34 +466,32 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } @Override // Binder call - public void setPullingAlarms(long timestampMs, long intervalMs) { - enforceCallingPermission(); - if (DEBUG) - Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms"); - final long callingToken = Binder.clearCallingIdentity(); - try { - // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will - // only fire when it awakens. - // This alarm is inexact, leaving its exactness completely up to the OS optimizations. - // TODO: totally inexact means that stats per bucket could be quite off. Is this okay? - mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, timestampMs, intervalMs, - mPullingAlarmIntent); - } finally { - Binder.restoreCallingIdentity(callingToken); - } + public void setPullingAlarm(long nextPullTimeMs) { + enforceCallingPermission(); + if (DEBUG) + Slog.d(TAG, + "Setting pulling alarm in about " + (nextPullTimeMs - SystemClock.elapsedRealtime())); + final long callingToken = Binder.clearCallingIdentity(); + try { + // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will + // only fire when it awakens. + mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextPullTimeMs, mPullingAlarmIntent); + } finally { + Binder.restoreCallingIdentity(callingToken); + } } @Override // Binder call - public void cancelPullingAlarms() { - enforceCallingPermission(); - if (DEBUG) - Slog.d(TAG, "Cancelling pulling alarm"); - final long callingToken = Binder.clearCallingIdentity(); - try { - mAlarmManager.cancel(mPullingAlarmIntent); - } finally { - Binder.restoreCallingIdentity(callingToken); - } + public void cancelPullingAlarm() { + enforceCallingPermission(); + if (DEBUG) + Slog.d(TAG, "Cancelling pulling alarm"); + final long callingToken = Binder.clearCallingIdentity(); + try { + mAlarmManager.cancel(mPullingAlarmIntent); + } finally { + Binder.restoreCallingIdentity(callingToken); + } } private void addNetworkStats( @@ -1109,7 +1107,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { mContext.unregisterReceiver(mUserUpdateReceiver); mContext.unregisterReceiver(mShutdownEventReceiver); cancelAnomalyAlarm(); - cancelPullingAlarms(); + cancelPullingAlarm(); } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 2ffdbfd4c646..c9ff9e3ba35b 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -909,6 +909,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mRotation; } + @VisibleForTesting void setRotation(int newRotation) { mRotation = newRotation; } @@ -974,7 +975,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final int oldRotation = mRotation; final int lastOrientation = mLastOrientation; final boolean oldAltOrientation = mAltOrientation; - int rotation = mService.mPolicy.rotationForOrientationLw(lastOrientation, oldRotation); + final int rotation = mService.mPolicy.rotationForOrientationLw(lastOrientation, oldRotation, + isDefaultDisplay); + if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Computed rotation=" + rotation + " for display id=" + + mDisplayId + " based on lastOrientation=" + lastOrientation + + " and oldRotation=" + oldRotation); boolean mayRotateSeamlessly = mService.mPolicy.shouldRotateSeamlessly(oldRotation, rotation); @@ -1010,7 +1015,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final boolean altOrientation = !mService.mPolicy.rotationHasCompatibleMetricsLw( lastOrientation, rotation); - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Selected orientation " + lastOrientation + if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId + + " selected orientation " + lastOrientation + ", got rotation " + rotation + " which has " + (altOrientation ? "incompatible" : "compatible") + " metrics"); @@ -1019,7 +1025,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return false; } - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Rotation changed to " + rotation + if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId + + " rotation changed to " + rotation + (altOrientation ? " (alt)" : "") + " from " + oldRotation + (oldAltOrientation ? " (alt)" : "") + ", lastOrientation=" + lastOrientation); @@ -1647,8 +1654,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (mService.mDisplayFrozen) { if (mLastWindowForcedOrientation != SCREEN_ORIENTATION_UNSPECIFIED) { - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, - "Display is frozen, return " + mLastWindowForcedOrientation); + if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId + + " is frozen, return " + mLastWindowForcedOrientation); // If the display is frozen, some activities may be in the middle of restarting, and // thus have removed their old window. If the window has the flag to hide the lock // screen, then the lock screen can re-appear and inflict its own orientation on us. @@ -1660,8 +1667,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // window. We don't want to check the show when locked window directly though as // things aren't stable while the display is frozen, for example the window could be // momentarily unavailable due to activity relaunch. - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display is frozen while keyguard locked, " - + "return " + mLastOrientation); + if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId + + " is frozen while keyguard locked, return " + mLastOrientation); return mLastOrientation; } } else { @@ -3503,19 +3510,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // In a car, you cannot physically rotate the screen, so it doesn't make sense to // allow anything but the default orientation. if (DEBUG_ORIENTATION) Slog.v(TAG_WM, - "Forcing UNSPECIFIED orientation in car. Ignoring " + orientation); + "Forcing UNSPECIFIED orientation in car for display id=" + mDisplayId + + ". Ignoring " + orientation); return SCREEN_ORIENTATION_UNSPECIFIED; } if (orientation != SCREEN_ORIENTATION_UNSET && orientation != SCREEN_ORIENTATION_BEHIND) { if (DEBUG_ORIENTATION) Slog.v(TAG_WM, - "App is requesting an orientation, return " + orientation); + "App is requesting an orientation, return " + orientation + + " for display id=" + mDisplayId); return orientation; } if (DEBUG_ORIENTATION) Slog.v(TAG_WM, - "No app is requesting an orientation, return " + mLastOrientation); + "No app is requesting an orientation, return " + mLastOrientation + + " for display id=" + mDisplayId); // The next app has not been requested to be visible, so we keep the current orientation // to prevent freezing/unfreezing the display too early. return mLastOrientation; @@ -3708,7 +3718,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return SCREEN_ORIENTATION_UNSET; } } - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, win + " forcing orientation to " + req); + if (DEBUG_ORIENTATION) Slog.v(TAG_WM, win + " forcing orientation to " + req + + " for display id=" + mDisplayId); return (mLastWindowForcedOrientation = req); } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 10188487fd9b..7274aee3c987 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -34,6 +34,7 @@ import android.app.WindowConfiguration; import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; +import android.os.IBinder.DeathRecipient; import android.os.RemoteException; import android.os.SystemClock; import android.util.ArraySet; @@ -61,15 +62,17 @@ import java.util.ArrayList; * window manager when the animation is completed. In addition, window manager may also notify the * app if it requires the animation to be canceled at any time (ie. due to timeout, etc.) */ -public class RecentsAnimationController { +public class RecentsAnimationController implements DeathRecipient { private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentsAnimationController" : TAG_WM; private static final boolean DEBUG = false; + private static final long FAILSAFE_DELAY = 1000; private final WindowManagerService mService; private final IRecentsAnimationRunner mRunner; private final RecentsAnimationCallbacks mCallbacks; private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>(); private final int mDisplayId; + private final Runnable mFailsafeRunnable = this::cancelAnimation; // The recents component app token that is shown behind the visibile tasks private AppWindowToken mHomeAppToken; @@ -223,6 +226,13 @@ public class RecentsAnimationController { return; } + try { + mRunner.asBinder().linkToDeath(this, 0); + } catch (RemoteException e) { + cancelAnimation(); + return; + } + // Adjust the wallpaper visibility for the showing home activity final AppWindowToken recentsComponentAppToken = dc.getHomeStack().getTopChild().getTopFullscreenAppToken(); @@ -296,6 +306,7 @@ public class RecentsAnimationController { // We've already canceled the animation return; } + mService.mH.removeCallbacks(mFailsafeRunnable); mCanceled = true; try { mRunner.onAnimationCanceled(); @@ -321,10 +332,21 @@ public class RecentsAnimationController { } mPendingAnimations.clear(); + mRunner.asBinder().unlinkToDeath(this, 0); + mService.mInputMonitor.updateInputWindowsLw(true /*force*/); mService.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION); } + void scheduleFailsafe() { + mService.mH.postDelayed(mFailsafeRunnable, FAILSAFE_DELAY); + } + + @Override + public void binderDied() { + cancelAnimation(); + } + void checkAnimationReady(WallpaperController wallpaperController) { if (mPendingStart) { final boolean wallpaperReady = !isHomeAppOverWallpaper() diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 379a1a1528b4..3be7b23590e5 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -26,6 +26,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; import android.os.Handler; +import android.os.IBinder.DeathRecipient; import android.os.RemoteException; import android.os.SystemClock; import android.util.Slog; @@ -47,7 +48,7 @@ import java.util.ArrayList; /** * Helper class to run app animations in a remote process. */ -class RemoteAnimationController { +class RemoteAnimationController implements DeathRecipient { private static final String TAG = TAG_WITH_CLASS_NAME ? "RemoteAnimationController" : TAG_WM; private static final long TIMEOUT_MS = 2000; @@ -56,12 +57,10 @@ class RemoteAnimationController { private final ArrayList<RemoteAnimationAdapterWrapper> mPendingAnimations = new ArrayList<>(); private final Rect mTmpRect = new Rect(); private final Handler mHandler; - private FinishedCallback mFinishedCallback; + private final Runnable mTimeoutRunnable = this::cancelAnimation; - private final Runnable mTimeoutRunnable = () -> { - onAnimationFinished(); - invokeAnimationCancelled(); - }; + private FinishedCallback mFinishedCallback; + private boolean mCanceled; RemoteAnimationController(WindowManagerService service, RemoteAnimationAdapter remoteAnimationAdapter, Handler handler) { @@ -90,7 +89,7 @@ class RemoteAnimationController { * Called when the transition is ready to be started, and all leashes have been set up. */ void goodToGo() { - if (mPendingAnimations.isEmpty()) { + if (mPendingAnimations.isEmpty() || mCanceled) { onAnimationFinished(); return; } @@ -107,8 +106,8 @@ class RemoteAnimationController { } mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> { try { - mRemoteAnimationAdapter.getRunner().onAnimationStart(animations, - mFinishedCallback); + mRemoteAnimationAdapter.getRunner().asBinder().linkToDeath(this, 0); + mRemoteAnimationAdapter.getRunner().onAnimationStart(animations, mFinishedCallback); } catch (RemoteException e) { Slog.e(TAG, "Failed to start remote animation", e); onAnimationFinished(); @@ -120,6 +119,17 @@ class RemoteAnimationController { } } + private void cancelAnimation() { + synchronized (mService.getWindowManagerLock()) { + if (mCanceled) { + return; + } + mCanceled = true; + } + onAnimationFinished(); + invokeAnimationCancelled(); + } + private void writeStartDebugStatement() { Slog.i(TAG, "Starting remote animation"); final StringWriter sw = new StringWriter(); @@ -154,6 +164,7 @@ class RemoteAnimationController { private void onAnimationFinished() { mHandler.removeCallbacks(mTimeoutRunnable); + mRemoteAnimationAdapter.getRunner().asBinder().unlinkToDeath(this, 0); synchronized (mService.mWindowMap) { releaseFinishedCallback(); mService.openSurfaceTransaction(); @@ -193,6 +204,11 @@ class RemoteAnimationController { mService.sendSetRunningRemoteAnimation(pid, running); } + @Override + public void binderDied() { + cancelAnimation(); + } + private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub { RemoteAnimationController mOuter; diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 6bceda5ae3bc..6686b80d1e18 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -419,4 +419,10 @@ public abstract class WindowManagerInternal { * @see android.view.IWindowManager#lockNow */ public abstract void lockNow(); + + /** + * Return the user that owns the given window, {@link android.os.UserHandle#USER_NULL} if + * the window token is not found. + */ + public abstract int getWindowOwnerUserId(IBinder windowToken); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0b5c0064d40f..f1cd46bc16d0 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -25,12 +25,10 @@ import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.StatusBarManager.DISABLE_MASK; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; -import static android.content.Intent.EXTRA_USER_HANDLE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.SYSTEM_UID; import static android.os.Process.myPid; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; -import static android.os.UserHandle.USER_NULL; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.DOCKED_INVALID; @@ -181,7 +179,6 @@ import android.util.Log; import android.util.MergedConfiguration; import android.util.Pair; import android.util.Slog; -import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.TimeUtils; @@ -2423,8 +2420,8 @@ public class WindowManagerService extends IWindowManager.Stub final int oldRotation = defaultDisplayContent.getRotation(); final boolean oldAltOrientation = defaultDisplayContent.getAltOrientation(); - final int rotation = mPolicy.rotationForOrientationLw(lastOrientation, - oldRotation); + final int rotation = mPolicy.rotationForOrientationLw(lastOrientation, oldRotation, + true /* defaultDisplay */); boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw( lastOrientation, rotation); if (oldRotation == rotation && oldAltOrientation == altOrientation) { @@ -2793,6 +2790,11 @@ public class WindowManagerService extends IWindowManager.Stub mTaskSnapshotController.screenTurningOff(listener); } + @Override + public void triggerAnimationFailsafe() { + mH.sendEmptyMessage(H.ANIMATION_FAILSAFE); + } + /** * Starts deferring layout passes. Useful when doing multiple changes but to optimize * performance, only one layout pass should be done. This can be called multiple times, and @@ -4566,6 +4568,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int NOTIFY_KEYGUARD_TRUSTED_CHANGED = 57; public static final int SET_HAS_OVERLAY_UI = 58; public static final int SET_RUNNING_REMOTE_ANIMATION = 59; + public static final int ANIMATION_FAILSAFE = 60; /** * Used to denote that an integer field in a message will not be used. @@ -4984,6 +4987,14 @@ public class WindowManagerService extends IWindowManager.Stub mAmInternal.setRunningRemoteAnimation(msg.arg1, msg.arg2 == 1); } break; + case ANIMATION_FAILSAFE: { + synchronized (mWindowMap) { + if (mRecentsAnimationController != null) { + mRecentsAnimationController.scheduleFailsafe(); + } + } + } + break; } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG_WM, "handleMessage: exit"); @@ -7351,6 +7362,17 @@ public class WindowManagerService extends IWindowManager.Stub public void lockNow() { WindowManagerService.this.lockNow(null); } + + @Override + public int getWindowOwnerUserId(IBinder token) { + synchronized (mWindowMap) { + WindowState window = mWindowMap.get(token); + if (window != null) { + return UserHandle.getUserId(window.mOwnerUid); + } + return UserHandle.USER_NULL; + } + } } void registerAppFreezeListener(AppFreezeListener listener) { diff --git a/services/core/jni/BroadcastRadio/convert.cpp b/services/core/jni/BroadcastRadio/convert.cpp index 847222ae4ba1..61b48c2e9316 100644 --- a/services/core/jni/BroadcastRadio/convert.cpp +++ b/services/core/jni/BroadcastRadio/convert.cpp @@ -380,6 +380,7 @@ static JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_0::Propert auto jProduct = make_javastr(env, prop10.product); auto jVersion = make_javastr(env, prop10.version); auto jSerial = make_javastr(env, prop10.serial); + constexpr bool isInitializationRequired = true; bool isBgScanSupported = prop11 ? prop11->supportsBackgroundScanning : false; auto jVendorInfo = prop11 ? VendorInfoFromHal(env, prop11->vendorInfo) : nullptr; @@ -394,9 +395,9 @@ static JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_0::Propert return make_javaref(env, env->NewObject(gjni.ModuleProperties.clazz, gjni.ModuleProperties.cstor, moduleId, jServiceName.get(), prop10.classId, jImplementor.get(), jProduct.get(), jVersion.get(), jSerial.get(), prop10.numTuners, - prop10.numAudioSources, prop10.supportsCapture, jBands.get(), isBgScanSupported, - jSupportedProgramTypes.get(), jSupportedIdentifierTypes.get(), nullptr, - jVendorInfo.get())); + prop10.numAudioSources, isInitializationRequired, prop10.supportsCapture, jBands.get(), + isBgScanSupported, jSupportedProgramTypes.get(), jSupportedIdentifierTypes.get(), + nullptr, jVendorInfo.get())); } JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_0::Properties &properties, @@ -712,7 +713,7 @@ void register_android_server_broadcastradio_convert(JNIEnv *env) { gjni.ModuleProperties.clazz = MakeGlobalRefOrDie(env, modulePropertiesClass); gjni.ModuleProperties.cstor = GetMethodIDOrDie(env, modulePropertiesClass, "<init>", "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;" - "Ljava/lang/String;IIZ[Landroid/hardware/radio/RadioManager$BandDescriptor;Z" + "Ljava/lang/String;IIZZ[Landroid/hardware/radio/RadioManager$BandDescriptor;Z" "[I[ILjava/util/Map;Ljava/util/Map;)V"); auto programInfoClass = FindClassOrDie(env, "android/hardware/radio/RadioManager$ProgramInfo"); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 5cfba22d2c66..02cd3b6572ef 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -5533,10 +5533,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .setAttestationChallenge(null) .build(); - final boolean generationResult = keyChain.generateKeyPair(algorithm, + final int generationResult = keyChain.generateKeyPair(algorithm, new ParcelableKeyGenParameterSpec(noAttestationSpec)); - if (!generationResult) { - Log.e(LOG_TAG, "KeyChain failed to generate a keypair."); + if (generationResult != KeyChain.KEY_GEN_SUCCESS) { + Log.e(LOG_TAG, String.format( + "KeyChain failed to generate a keypair, error %d.", generationResult)); return false; } @@ -5549,12 +5550,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final byte[] attestationChallenge = keySpec.getAttestationChallenge(); if (attestationChallenge != null) { - final boolean attestationResult = keyChain.attestKey( + final int attestationResult = keyChain.attestKey( alias, attestationChallenge, attestationUtilsFlags, attestationChain); - if (!attestationResult) { + if (attestationResult != KeyChain.KEY_ATTESTATION_SUCCESS) { Log.e(LOG_TAG, String.format( - "Attestation for %s failed, deleting key.", alias)); + "Attestation for %s failed (rc=%d), deleting key.", + alias, attestationResult)); keyChain.removeKeyPair(alias); + if (attestationResult == KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS) { + throw new UnsupportedOperationException( + "Device does not support Device ID attestation."); + } return false; } } diff --git a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java index f603a09baa37..fa41220dc44c 100644 --- a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java +++ b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java @@ -147,6 +147,15 @@ public class PerformBackupTaskTest { Looper backupLooper = startBackupThreadAndGetLooper(); mShadowBackupLooper = shadowOf(backupLooper); + + Handler mainHandler = new Handler(Looper.getMainLooper()); + BackupAgentTimeoutParameters agentTimeoutParameters = + new BackupAgentTimeoutParameters(mainHandler, application.getContentResolver()); + agentTimeoutParameters.start(); + + // We need to mock BMS timeout parameters before initializing the BackupHandler since + // the constructor of BackupHandler relies on the timeout parameters. + when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters); mBackupHandler = new BackupHandler(mBackupManagerService, backupLooper); mBackupManager = spy(FakeIBackupManager.class); @@ -157,7 +166,8 @@ public class PerformBackupTaskTest { mTransportManager, packageManager, mBackupHandler, - mWakeLock); + mWakeLock, + agentTimeoutParameters); when(mBackupManagerService.getBaseStateDir()).thenReturn(mBaseStateDir); when(mBackupManagerService.getDataDir()).thenReturn(dataDir); when(mBackupManagerService.getBackupManagerBinder()).thenReturn(mBackupManager); diff --git a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java index 03792b1d40ba..92d6bbd54fab 100644 --- a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java +++ b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java @@ -41,12 +41,14 @@ import android.app.backup.IRestoreSession; import android.app.backup.RestoreSet; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import com.android.server.EventLogTags; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; import com.android.server.backup.TransportManager; import com.android.server.backup.internal.BackupHandler; @@ -115,6 +117,15 @@ public class ActiveRestoreSessionTest { Looper backupLooper = startBackupThreadAndGetLooper(); mShadowBackupLooper = shadowOf(backupLooper); + + Handler mainHandler = new Handler(Looper.getMainLooper()); + BackupAgentTimeoutParameters agentTimeoutParameters = + new BackupAgentTimeoutParameters(mainHandler, application.getContentResolver()); + agentTimeoutParameters.start(); + + // We need to mock BMS timeout parameters before initializing the BackupHandler since + // the constructor of BackupHandler relies on it. + when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters); BackupHandler backupHandler = new BackupHandler(mBackupManagerService, backupLooper); mWakeLock = createBackupWakeLock(application); @@ -125,7 +136,8 @@ public class ActiveRestoreSessionTest { mTransportManager, application.getPackageManager(), backupHandler, - mWakeLock); + mWakeLock, + agentTimeoutParameters); when(mBackupManagerService.getPendingRestores()).thenReturn(new ArrayDeque<>()); } diff --git a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java index c210fdea6e89..5a886e33622f 100644 --- a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java +++ b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java @@ -28,6 +28,7 @@ import android.os.Looper; import android.os.PowerManager; import android.util.SparseArray; +import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupManagerService; import com.android.server.backup.TransportManager; import com.android.server.backup.internal.BackupHandler; @@ -43,7 +44,8 @@ public class BackupManagerServiceTestUtils { TransportManager transportManager, PackageManager packageManager, BackupHandler backupHandler, - PowerManager.WakeLock wakeLock) { + PowerManager.WakeLock wakeLock, + BackupAgentTimeoutParameters agentTimeoutParameters) { when(backupManagerService.getContext()).thenReturn(context); when(backupManagerService.getTransportManager()).thenReturn(transportManager); when(backupManagerService.getPackageManager()).thenReturn(packageManager); @@ -53,6 +55,7 @@ public class BackupManagerServiceTestUtils { when(backupManagerService.getCurrentOperations()).thenReturn(new SparseArray<>()); when(backupManagerService.getActivityManager()).thenReturn(mock(IActivityManager.class)); when(backupManagerService.getWakelock()).thenReturn(wakeLock); + when(backupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters); } public static PowerManager.WakeLock createBackupWakeLock(Application application) { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java index 9ae45ea15ca2..81a73efd94ad 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java @@ -38,6 +38,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.os.FileUtils; import android.security.keystore.AndroidKeyStoreSecretKey; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; @@ -49,7 +50,6 @@ import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import android.util.Log; import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb; import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage; @@ -72,6 +72,9 @@ import javax.crypto.SecretKey; @SmallTest @RunWith(AndroidJUnit4.class) public class KeySyncTaskTest { + + private static final String SNAPSHOT_TOP_LEVEL_DIRECTORY = "recoverablekeystore"; + private static final String KEY_ALGORITHM = "AES"; private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore"; private static final String TEST_ROOT_CERT_ALIAS = "trusted_root"; @@ -117,7 +120,7 @@ public class KeySyncTaskTest { TEST_ROOT_CERT_ALIAS); mRecoverableKeyStoreDb.setActiveRootOfTrust(TEST_USER_ID, TEST_RECOVERY_AGENT_UID2, TEST_ROOT_CERT_ALIAS); - mRecoverySnapshotStorage = new RecoverySnapshotStorage(); + mRecoverySnapshotStorage = new RecoverySnapshotStorage(context.getFilesDir()); mKeySyncTask = new KeySyncTask( mRecoverableKeyStoreDb, @@ -139,6 +142,10 @@ public class KeySyncTaskTest { public void tearDown() { mRecoverableKeyStoreDb.close(); mDatabaseFile.delete(); + + File file = new File(InstrumentationRegistry.getTargetContext().getFilesDir(), + SNAPSHOT_TOP_LEVEL_DIRECTORY); + FileUtils.deleteContentsAndDir(file); } @Test diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java index f5f5027da771..18a3885aea6a 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java @@ -189,7 +189,6 @@ public class RecoverableKeyStoreManagerTest { mRecoverableKeyStoreManager = new RecoverableKeyStoreManager( mMockContext, - KeyStore.getInstance(), mRecoverableKeyStoreDb, mRecoverySessionStorage, Executors.newSingleThreadExecutor(), diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java index 6c2958e4f456..2f4da86bf38f 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java @@ -45,6 +45,7 @@ public class KeyChainSnapshotSerializerTest { private static final int MAX_ATTEMPTS = 21; private static final byte[] SERVER_PARAMS = new byte[] { 8, 2, 4 }; private static final byte[] KEY_BLOB = new byte[] { 124, 53, 53, 53 }; + private static final byte[] PUBLIC_KEY_BLOB = new byte[] { 6, 6, 6, 6, 6, 6, 7 }; private static final CertPath CERT_PATH = TestData.CERT_PATH_1; private static final int SECRET_TYPE = KeyChainProtectionParams.TYPE_LOCKSCREEN; private static final int LOCK_SCREEN_UI = KeyChainProtectionParams.UI_FORMAT_PASSWORD; @@ -93,6 +94,11 @@ public class KeyChainSnapshotSerializerTest { } @Test + public void roundTrip_persistsBackendPublicKey() throws Exception { + assertThat(roundTrip().getTrustedHardwarePublicKey()).isEqualTo(PUBLIC_KEY_BLOB); + } + + @Test public void roundTrip_persistsParamsList() throws Exception { assertThat(roundTrip().getKeyChainProtectionParams()).hasSize(1); } @@ -163,6 +169,12 @@ public class KeyChainSnapshotSerializerTest { assertThat(roundTripKeys().get(2).getEncryptedKeyMaterial()).isEqualTo(TEST_KEY_3_BYTES); } + @Test + public void serialize_doesNotThrowForNullPublicKey() throws Exception { + KeyChainSnapshotSerializer.serialize( + createTestKeyChainSnapshotNoPublicKey(), new ByteArrayOutputStream()); + } + private static List<WrappedApplicationKey> roundTripKeys() throws Exception { return roundTrip().getWrappedApplicationKeys(); } @@ -180,6 +192,41 @@ public class KeyChainSnapshotSerializerTest { } private static KeyChainSnapshot createTestKeyChainSnapshot() throws Exception { + return new KeyChainSnapshot.Builder() + .setCounterId(COUNTER_ID) + .setSnapshotVersion(SNAPSHOT_VERSION) + .setServerParams(SERVER_PARAMS) + .setMaxAttempts(MAX_ATTEMPTS) + .setEncryptedRecoveryKeyBlob(KEY_BLOB) + .setKeyChainProtectionParams(createKeyChainProtectionParamsList()) + .setWrappedApplicationKeys(createKeys()) + .setTrustedHardwareCertPath(CERT_PATH) + .setTrustedHardwarePublicKey(PUBLIC_KEY_BLOB) + .build(); + } + + private static KeyChainSnapshot createTestKeyChainSnapshotNoPublicKey() throws Exception { + return new KeyChainSnapshot.Builder() + .setCounterId(COUNTER_ID) + .setSnapshotVersion(SNAPSHOT_VERSION) + .setServerParams(SERVER_PARAMS) + .setMaxAttempts(MAX_ATTEMPTS) + .setEncryptedRecoveryKeyBlob(KEY_BLOB) + .setKeyChainProtectionParams(createKeyChainProtectionParamsList()) + .setWrappedApplicationKeys(createKeys()) + .setTrustedHardwareCertPath(CERT_PATH) + .build(); + } + + private static List<WrappedApplicationKey> createKeys() { + ArrayList<WrappedApplicationKey> keyList = new ArrayList<>(); + keyList.add(createKey(TEST_KEY_1_ALIAS, TEST_KEY_1_BYTES)); + keyList.add(createKey(TEST_KEY_2_ALIAS, TEST_KEY_2_BYTES)); + keyList.add(createKey(TEST_KEY_3_ALIAS, TEST_KEY_3_BYTES)); + return keyList; + } + + private static List<KeyChainProtectionParams> createKeyChainProtectionParamsList() { KeyDerivationParams keyDerivationParams = KeyDerivationParams.createScryptParams(SALT, MEMORY_DIFFICULTY); KeyChainProtectionParams keyChainProtectionParams = new KeyChainProtectionParams.Builder() @@ -191,22 +238,7 @@ public class KeyChainSnapshotSerializerTest { ArrayList<KeyChainProtectionParams> keyChainProtectionParamsList = new ArrayList<>(1); keyChainProtectionParamsList.add(keyChainProtectionParams); - - ArrayList<WrappedApplicationKey> keyList = new ArrayList<>(); - keyList.add(createKey(TEST_KEY_1_ALIAS, TEST_KEY_1_BYTES)); - keyList.add(createKey(TEST_KEY_2_ALIAS, TEST_KEY_2_BYTES)); - keyList.add(createKey(TEST_KEY_3_ALIAS, TEST_KEY_3_BYTES)); - - return new KeyChainSnapshot.Builder() - .setCounterId(COUNTER_ID) - .setSnapshotVersion(SNAPSHOT_VERSION) - .setServerParams(SERVER_PARAMS) - .setMaxAttempts(MAX_ATTEMPTS) - .setEncryptedRecoveryKeyBlob(KEY_BLOB) - .setKeyChainProtectionParams(keyChainProtectionParamsList) - .setWrappedApplicationKeys(keyList) - .setTrustedHardwareCertPath(CERT_PATH) - .build(); + return keyChainProtectionParamsList; } private static WrappedApplicationKey createKey(String alias, byte[] bytes) { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java index c7729566b353..ad14c3a8adef 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java @@ -1,27 +1,82 @@ package com.android.server.locksettings.recoverablekeystore.storage; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import android.content.Context; +import android.os.FileUtils; +import android.security.keystore.recovery.KeyChainProtectionParams; import android.security.keystore.recovery.KeyChainSnapshot; +import android.security.keystore.recovery.KeyDerivationParams; +import android.security.keystore.recovery.WrappedApplicationKey; +import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import com.android.server.locksettings.recoverablekeystore.TestData; +import com.google.common.io.Files; + +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.security.cert.CertPath; import java.security.cert.CertificateException; import java.util.ArrayList; +import java.util.List; @SmallTest @RunWith(AndroidJUnit4.class) public class RecoverySnapshotStorageTest { + private static final int COUNTER_ID = 432546; + private static final int MAX_ATTEMPTS = 10; + private static final byte[] SERVER_PARAMS = new byte[] { 12, 8, 2, 4, 15, 64 }; + private static final byte[] KEY_BLOB = new byte[] { 124, 56, 53, 99, 0, 0, 1 }; + private static final CertPath CERT_PATH = TestData.CERT_PATH_2; + private static final int SECRET_TYPE = KeyChainProtectionParams.TYPE_LOCKSCREEN; + private static final int LOCK_SCREEN_UI = KeyChainProtectionParams.UI_FORMAT_PATTERN; + private static final byte[] SALT = new byte[] { 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1 }; + private static final int MEMORY_DIFFICULTY = 12; + private static final byte[] SECRET = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0 }; + + private static final String TEST_KEY_1_ALIAS = "alias1"; + private static final byte[] TEST_KEY_1_BYTES = new byte[] { 100, 32, 43, 66, 77, 88 }; + + private static final String TEST_KEY_2_ALIAS = "alias11"; + private static final byte[] TEST_KEY_2_BYTES = new byte[] { 100, 0, 0, 99, 33, 11 }; + + private static final String TEST_KEY_3_ALIAS = "alias111"; + private static final byte[] TEST_KEY_3_BYTES = new byte[] { 1, 1, 1, 0, 2, 8, 100 }; + + private static final int TEST_UID = 1000; + private static final String SNAPSHOT_DIRECTORY = "recoverablekeystore/snapshots"; + private static final String SNAPSHOT_FILE_PATH = "1000.xml"; + private static final String SNAPSHOT_TOP_LEVEL_DIRECTORY = "recoverablekeystore"; + private static final KeyChainSnapshot MINIMAL_KEYCHAIN_SNAPSHOT = - createMinimalKeyChainSnapshot(); + createTestKeyChainSnapshot(1); - private final RecoverySnapshotStorage mRecoverySnapshotStorage = new RecoverySnapshotStorage(); + private Context mContext; + private RecoverySnapshotStorage mRecoverySnapshotStorage; + + @Before + public void setUp() { + mContext = InstrumentationRegistry.getTargetContext(); + mRecoverySnapshotStorage = new RecoverySnapshotStorage(mContext.getFilesDir()); + } + + @After + public void tearDown() { + File file = new File(mContext.getFilesDir(), SNAPSHOT_TOP_LEVEL_DIRECTORY); + FileUtils.deleteContentsAndDir(file); + } @Test public void get_isNullForNonExistentSnapshot() { @@ -30,37 +85,153 @@ public class RecoverySnapshotStorageTest { @Test public void get_returnsSetSnapshot() { - int userId = 1000; + mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT); - mRecoverySnapshotStorage.put(userId, MINIMAL_KEYCHAIN_SNAPSHOT); + assertEquals(MINIMAL_KEYCHAIN_SNAPSHOT, mRecoverySnapshotStorage.get(TEST_UID)); + } + + @Test + public void get_readsFromDiskIfNoneInMemory() { + mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT); + RecoverySnapshotStorage storage = new RecoverySnapshotStorage(mContext.getFilesDir()); - assertEquals(MINIMAL_KEYCHAIN_SNAPSHOT, mRecoverySnapshotStorage.get(userId)); + assertKeyChainSnapshotsAreEqual(MINIMAL_KEYCHAIN_SNAPSHOT, storage.get(TEST_UID)); } @Test - public void remove_removesSnapshots() { - int userId = 1000; + public void get_deletesFileIfItIsInvalidSnapshot() throws Exception { + File folder = new File(mContext.getFilesDir(), SNAPSHOT_DIRECTORY); + folder.mkdirs(); + File file = new File(folder, SNAPSHOT_FILE_PATH); + byte[] fileContents = "<keyChainSnapshot></keyChainSnapshot>".getBytes( + StandardCharsets.UTF_8); + Files.write(fileContents, file); + assertTrue(file.exists()); - mRecoverySnapshotStorage.put(userId, MINIMAL_KEYCHAIN_SNAPSHOT); - mRecoverySnapshotStorage.remove(userId); + assertNull(mRecoverySnapshotStorage.get(TEST_UID)); - assertNull(mRecoverySnapshotStorage.get(1000)); + assertFalse(file.exists()); + } + + @Test + public void put_overwritesOldFiles() { + int snapshotVersion = 2; + mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT); + + mRecoverySnapshotStorage.put(TEST_UID, createTestKeyChainSnapshot(snapshotVersion)); + + KeyChainSnapshot snapshot = new RecoverySnapshotStorage(mContext.getFilesDir()) + .get(TEST_UID); + assertEquals(snapshotVersion, snapshot.getSnapshotVersion()); } - private static KeyChainSnapshot createMinimalKeyChainSnapshot() { + @Test + public void put_doesNotThrowIfCannotCreateFiles() throws Exception { + File evilFile = new File(mContext.getFilesDir(), "recoverablekeystore"); + Files.write(new byte[] { 1 }, evilFile); + + mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT); + + assertNull(new RecoverySnapshotStorage(mContext.getFilesDir()).get(TEST_UID)); + } + + @Test + public void remove_removesSnapshotsFromMemory() { + mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT); + mRecoverySnapshotStorage.remove(TEST_UID); + + assertNull(mRecoverySnapshotStorage.get(TEST_UID)); + } + + @Test + public void remove_removesSnapshotsFromDisk() { + mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT); + + new RecoverySnapshotStorage(mContext.getFilesDir()).remove(TEST_UID); + + assertNull(new RecoverySnapshotStorage(mContext.getFilesDir()).get(TEST_UID)); + } + + private void assertKeyChainSnapshotsAreEqual(KeyChainSnapshot a, KeyChainSnapshot b) { + assertEquals(b.getCounterId(), a.getCounterId()); + assertEquals(b.getSnapshotVersion(), a.getSnapshotVersion()); + assertArrayEquals(b.getServerParams(), a.getServerParams()); + assertEquals(b.getMaxAttempts(), a.getMaxAttempts()); + assertArrayEquals(b.getEncryptedRecoveryKeyBlob(), a.getEncryptedRecoveryKeyBlob()); + assertEquals(b.getTrustedHardwareCertPath(), a.getTrustedHardwareCertPath()); + + List<WrappedApplicationKey> aKeys = a.getWrappedApplicationKeys(); + List<WrappedApplicationKey> bKeys = b.getWrappedApplicationKeys(); + assertEquals(bKeys.size(), aKeys.size()); + for (int i = 0; i < aKeys.size(); i++) { + assertWrappedApplicationKeysAreEqual(aKeys.get(i), bKeys.get(i)); + } + + List<KeyChainProtectionParams> aParams = a.getKeyChainProtectionParams(); + List<KeyChainProtectionParams> bParams = b.getKeyChainProtectionParams(); + assertEquals(bParams.size(), aParams.size()); + for (int i = 0; i < aParams.size(); i++) { + assertKeyChainProtectionParamsAreEqual(aParams.get(i), bParams.get(i)); + } + } + + private void assertWrappedApplicationKeysAreEqual( + WrappedApplicationKey a, WrappedApplicationKey b) { + assertEquals(b.getAlias(), a.getAlias()); + assertArrayEquals(b.getEncryptedKeyMaterial(), a.getEncryptedKeyMaterial()); + } + + private void assertKeyChainProtectionParamsAreEqual( + KeyChainProtectionParams a, KeyChainProtectionParams b) { + assertEquals(b.getUserSecretType(), a.getUserSecretType()); + assertEquals(b.getLockScreenUiFormat(), a.getLockScreenUiFormat()); + assertKeyDerivationParamsAreEqual(a.getKeyDerivationParams(), b.getKeyDerivationParams()); + } + + private void assertKeyDerivationParamsAreEqual(KeyDerivationParams a, KeyDerivationParams b) { + assertEquals(b.getAlgorithm(), a.getAlgorithm()); + assertEquals(b.getMemoryDifficulty(), a.getMemoryDifficulty()); + assertArrayEquals(b.getSalt(), a.getSalt()); + } + + private static KeyChainSnapshot createTestKeyChainSnapshot(int snapshotVersion) { + KeyDerivationParams keyDerivationParams = + KeyDerivationParams.createScryptParams(SALT, MEMORY_DIFFICULTY); + KeyChainProtectionParams keyChainProtectionParams = new KeyChainProtectionParams.Builder() + .setKeyDerivationParams(keyDerivationParams) + .setUserSecretType(SECRET_TYPE) + .setLockScreenUiFormat(LOCK_SCREEN_UI) + .setSecret(SECRET) + .build(); + ArrayList<KeyChainProtectionParams> keyChainProtectionParamsList = + new ArrayList<>(1); + keyChainProtectionParamsList.add(keyChainProtectionParams); + + ArrayList<WrappedApplicationKey> keyList = new ArrayList<>(); + keyList.add(createKey(TEST_KEY_1_ALIAS, TEST_KEY_1_BYTES)); + keyList.add(createKey(TEST_KEY_2_ALIAS, TEST_KEY_2_BYTES)); + keyList.add(createKey(TEST_KEY_3_ALIAS, TEST_KEY_3_BYTES)); + try { return new KeyChainSnapshot.Builder() - .setCounterId(1) - .setSnapshotVersion(1) - .setServerParams(new byte[0]) - .setMaxAttempts(10) - .setEncryptedRecoveryKeyBlob(new byte[0]) - .setKeyChainProtectionParams(new ArrayList<>()) - .setWrappedApplicationKeys(new ArrayList<>()) - .setTrustedHardwareCertPath(TestData.CERT_PATH_1) + .setCounterId(COUNTER_ID) + .setSnapshotVersion(snapshotVersion) + .setServerParams(SERVER_PARAMS) + .setMaxAttempts(MAX_ATTEMPTS) + .setEncryptedRecoveryKeyBlob(KEY_BLOB) + .setKeyChainProtectionParams(keyChainProtectionParamsList) + .setWrappedApplicationKeys(keyList) + .setTrustedHardwareCertPath(CERT_PATH) .build(); } catch (CertificateException e) { throw new RuntimeException(e); } } + + private static WrappedApplicationKey createKey(String alias, byte[] bytes) { + return new WrappedApplicationKey.Builder() + .setAlias(alias) + .setEncryptedKeyMaterial(bytes) + .build(); + } } diff --git a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java index 553d65824c54..95361f03fe4b 100644 --- a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java @@ -17,14 +17,20 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; + import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; import android.graphics.Point; import android.graphics.Rect; +import android.os.Binder; +import android.os.IInterface; +import android.platform.test.annotations.Presubmit; import android.support.test.filters.FlakyTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -50,7 +56,7 @@ import org.mockito.MockitoAnnotations; * atest FrameworksServicesTests:com.android.server.wm.RemoteAnimationControllerTest */ @SmallTest -@FlakyTest(detail = "Promote to presubmit if non-flakyness is established") +@Presubmit @RunWith(AndroidJUnit4.class) public class RemoteAnimationControllerTest extends WindowTestsBase { @@ -67,6 +73,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { public void setUp() throws Exception { super.setUp(); MockitoAnnotations.initMocks(this); + when(mMockRunner.asBinder()).thenReturn(new Binder()); mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50); mAdapter.setCallingPid(123); sWm.mH.runWithScissors(() -> { @@ -166,7 +173,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { @Test public void testZeroAnimations() throws Exception { mController.goodToGo(); - verifyZeroInteractions(mMockRunner); + verifyNoMoreInteractionsExceptAsBinder(mMockRunner); } @Test @@ -175,7 +182,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { mController.createAnimationAdapter(win.mAppToken, new Point(50, 100), new Rect(50, 100, 150, 150)); mController.goodToGo(); - verifyZeroInteractions(mMockRunner); + verifyNoMoreInteractionsExceptAsBinder(mMockRunner); } @Test @@ -206,7 +213,12 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); win.mAppToken.removeImmediately(); mController.goodToGo(); - verifyZeroInteractions(mMockRunner); + verifyNoMoreInteractionsExceptAsBinder(mMockRunner); verify(mFinishedCallback).onAnimationFinished(eq(adapter)); } + + private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) { + verify(binder, atLeast(0)).asBinder(); + verifyNoMoreInteractions(binder); + } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java index 6d9167fda585..1af344bb0a89 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -445,8 +445,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public int rotationForOrientationLw(int orientation, - int lastRotation) { + public int rotationForOrientationLw(int orientation, int lastRotation, boolean defaultDisplay) { return rotationToReport; } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java index 09d88fd8c87c..0815876e5915 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java @@ -367,8 +367,8 @@ public class RankingHelperTest extends UiServiceTestCase { mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); - mHelper.createNotificationChannel(PKG, UID, channel1, true); - mHelper.createNotificationChannel(PKG, UID, channel2, false); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); + mHelper.createNotificationChannel(PKG, UID, channel2, false, false); mHelper.setShowBadge(PKG, UID, true); @@ -427,10 +427,10 @@ public class RankingHelperTest extends UiServiceTestCase { mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); - mHelper.createNotificationChannel(PKG, UID, channel1, true); - mHelper.createNotificationChannel(PKG, UID, channel2, false); - mHelper.createNotificationChannel(PKG, UID, channel3, false); - mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); + mHelper.createNotificationChannel(PKG, UID, channel2, false, false); + mHelper.createNotificationChannel(PKG, UID, channel3, false, false); + mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true, false); mHelper.setShowBadge(PKG, UID, true); @@ -481,7 +481,7 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(SOUND_URI, mAudioAttributes); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId()); @@ -507,7 +507,7 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(SOUND_URI, mAudioAttributes); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId()); loadStreamXml(baos, true); @@ -528,7 +528,7 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(SOUND_URI, mAudioAttributes); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId()); loadStreamXml(baos, true); @@ -569,7 +569,7 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel = new NotificationChannel("id", "name", IMPORTANCE_LOW); channel.setSound(null, mAudioAttributes); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId()); loadStreamXml(baos, true); @@ -593,9 +593,9 @@ public class RankingHelperTest extends UiServiceTestCase { mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); - mHelper.createNotificationChannel(PKG, UID, channel1, true); - mHelper.createNotificationChannel(PKG, UID, channel2, false); - mHelper.createNotificationChannel(PKG, UID, channel3, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); + mHelper.createNotificationChannel(PKG, UID, channel2, false, false); + mHelper.createNotificationChannel(PKG, UID, channel3, true, false); mHelper.deleteNotificationChannel(PKG, UID, channel1.getId()); mHelper.deleteNotificationChannelGroup(PKG, UID, ncg.getId()); @@ -701,7 +701,7 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testDeletesDefaultChannelAfterChannelIsCreated() throws Exception { mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas"); @@ -721,7 +721,7 @@ public class RankingHelperTest extends UiServiceTestCase { ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas"); mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false); loadStreamXml(baos, false); @@ -734,36 +734,39 @@ public class RankingHelperTest extends UiServiceTestCase { mHelper.setImportance(PKG, UID, IMPORTANCE_NONE); mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false); } @Test public void testCreateChannel_badImportance() throws Exception { try { mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1), + true, false); fail("Was allowed to create a channel with invalid importance"); } catch (IllegalArgumentException e) { // yay } try { mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED), + true, false); fail("Was allowed to create a channel with invalid importance"); } catch (IllegalArgumentException e) { // yay } try { mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1), + true, false); fail("Was allowed to create a channel with invalid importance"); } catch (IllegalArgumentException e) { // yay } mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true, false); mHelper.createNotificationChannel(PKG, UID, - new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true); + new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false); } @@ -777,7 +780,7 @@ public class RankingHelperTest extends UiServiceTestCase { channel.setBypassDnd(true); channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); - mHelper.createNotificationChannel(PKG, UID, channel, false); + mHelper.createNotificationChannel(PKG, UID, channel, false, false); // same id, try to update all fields final NotificationChannel channel2 = @@ -824,7 +827,7 @@ public class RankingHelperTest extends UiServiceTestCase { public void testUpdate_postUpgrade_noUpdateAppFields() throws Exception { final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG, UID, channel, false); + mHelper.createNotificationChannel(PKG, UID, channel, false, false); assertTrue(mHelper.canShowBadge(PKG, UID)); assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID)); assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, @@ -865,7 +868,7 @@ public class RankingHelperTest extends UiServiceTestCase { } channel.lockFields(lockMask); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); NotificationChannel savedChannel = mHelper.getNotificationChannel(PKG, UID, channel.getId(), false); @@ -894,7 +897,7 @@ public class RankingHelperTest extends UiServiceTestCase { } channel.lockFields(lockMask); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); NotificationChannel savedChannel = mHelper.getNotificationChannel(PKG, UID, channel.getId(), false); @@ -920,7 +923,7 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testLockFields_soundAndVibration() throws Exception { - mHelper.createNotificationChannel(PKG, UID, getChannel(), true); + mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); final NotificationChannel update1 = getChannel(); update1.setSound(new Uri.Builder().scheme("test").build(), @@ -944,7 +947,7 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testLockFields_vibrationAndLights() throws Exception { - mHelper.createNotificationChannel(PKG, UID, getChannel(), true); + mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); final NotificationChannel update1 = getChannel(); update1.setVibrationPattern(new long[]{7945, 46 ,246}); @@ -964,7 +967,7 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testLockFields_lightsAndImportance() throws Exception { - mHelper.createNotificationChannel(PKG, UID, getChannel(), true); + mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); final NotificationChannel update1 = getChannel(); update1.setLightColor(Color.GREEN); @@ -984,7 +987,7 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testLockFields_visibilityAndDndAndBadge() throws Exception { - mHelper.createNotificationChannel(PKG, UID, getChannel(), true); + mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); assertEquals(0, mHelper.getNotificationChannel(PKG, UID, getChannel().getId(), false) .getUserLockedFields()); @@ -1029,7 +1032,7 @@ public class RankingHelperTest extends UiServiceTestCase { channel.enableVibration(true); channel.setVibrationPattern(new long[]{100, 67, 145, 156}); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); // Does not return deleted channel @@ -1058,8 +1061,8 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel2 = new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); channelMap.put(channel2.getId(), channel2); - mHelper.createNotificationChannel(PKG, UID, channel, true); - mHelper.createNotificationChannel(PKG, UID, channel2, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); + mHelper.createNotificationChannel(PKG, UID, channel2, true, false); mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); @@ -1091,9 +1094,9 @@ public class RankingHelperTest extends UiServiceTestCase { new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); NotificationChannel channel3 = new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG, UID, channel, true); - mHelper.createNotificationChannel(PKG, UID, channel2, true); - mHelper.createNotificationChannel(PKG, UID, channel3, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); + mHelper.createNotificationChannel(PKG, UID, channel2, true, false); + mHelper.createNotificationChannel(PKG, UID, channel3, true, false); mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); mHelper.deleteNotificationChannel(PKG, UID, channel3.getId()); @@ -1109,14 +1112,14 @@ public class RankingHelperTest extends UiServiceTestCase { new NotificationChannel("id2", "name2", IMPORTANCE_LOW); channel.setVibrationPattern(vibration); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); NotificationChannel newChannel = new NotificationChannel( channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); newChannel.setVibrationPattern(new long[]{100}); - mHelper.createNotificationChannel(PKG, UID, newChannel, true); + mHelper.createNotificationChannel(PKG, UID, newChannel, true, false); // No long deleted, using old settings compareChannels(channel, @@ -1128,7 +1131,7 @@ public class RankingHelperTest extends UiServiceTestCase { assertTrue(mHelper.onlyHasDefaultChannel(PKG, UID)); assertFalse(mHelper.onlyHasDefaultChannel(UPDATED_PKG, UID2)); - mHelper.createNotificationChannel(PKG, UID, getChannel(), true); + mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); assertFalse(mHelper.onlyHasDefaultChannel(PKG, UID)); } @@ -1136,7 +1139,7 @@ public class RankingHelperTest extends UiServiceTestCase { public void testCreateChannel_defaultChannelId() throws Exception { try { mHelper.createNotificationChannel(PKG, UID, new NotificationChannel( - NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true); + NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true, false); fail("Allowed to create default channel"); } catch (IllegalArgumentException e) { // pass @@ -1150,13 +1153,13 @@ public class RankingHelperTest extends UiServiceTestCase { new NotificationChannel("id2", "name2", IMPORTANCE_LOW); channel.setVibrationPattern(vibration); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); NotificationChannel newChannel = new NotificationChannel( channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); newChannel.setVibrationPattern(new long[]{100}); - mHelper.createNotificationChannel(PKG, UID, newChannel, true); + mHelper.createNotificationChannel(PKG, UID, newChannel, true, false); // Old settings not overridden compareChannels(channel, @@ -1169,7 +1172,7 @@ public class RankingHelperTest extends UiServiceTestCase { final NotificationChannel channel = new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_DEFAULT); channel.setSound(sound, mAudioAttributes); - mHelper.createNotificationChannel(PKG, UID, channel, true); + mHelper.createNotificationChannel(PKG, UID, channel, true, false); assertEquals(sound, mHelper.getNotificationChannel( PKG, UID, channel.getId(), false).getSound()); } @@ -1181,8 +1184,8 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG, UID, channel1, true); - mHelper.createNotificationChannel(PKG, UID, channel2, false); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); + mHelper.createNotificationChannel(PKG, UID, channel2, false, false); mHelper.permanentlyDeleteNotificationChannels(PKG, UID); @@ -1205,9 +1208,9 @@ public class RankingHelperTest extends UiServiceTestCase { mHelper.createNotificationChannelGroup(PKG, UID, notDeleted, true); mHelper.createNotificationChannelGroup(PKG, UID, deleted, true); - mHelper.createNotificationChannel(PKG, UID, nonGroupedNonDeletedChannel, true); - mHelper.createNotificationChannel(PKG, UID, groupedAndDeleted, true); - mHelper.createNotificationChannel(PKG, UID, groupedButNotDeleted, true); + mHelper.createNotificationChannel(PKG, UID, nonGroupedNonDeletedChannel, true, false); + mHelper.createNotificationChannel(PKG, UID, groupedAndDeleted, true, false); + mHelper.createNotificationChannel(PKG, UID, groupedButNotDeleted, true, false); mHelper.deleteNotificationChannelGroup(PKG, UID, deleted.getId()); @@ -1264,14 +1267,14 @@ public class RankingHelperTest extends UiServiceTestCase { // Deleted NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG, UID, channel1, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID}); assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size()); // Not deleted - mHelper.createNotificationChannel(PKG, UID, channel1, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID}); assertEquals(2, mHelper.getNotificationChannels(PKG, UID, false).getList().size()); @@ -1302,7 +1305,7 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testOnPackageChange_downgradeTargetSdk() throws Exception { // create channel as api 26 - mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true); + mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true, false); // install new app version targeting 25 final ApplicationInfo legacy = new ApplicationInfo(); @@ -1338,7 +1341,7 @@ public class RankingHelperTest extends UiServiceTestCase { new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); channel1.setGroup("garbage"); try { - mHelper.createNotificationChannel(PKG, UID, channel1, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); fail("Created a channel with a bad group"); } catch (IllegalArgumentException e) { } @@ -1351,7 +1354,7 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); channel1.setGroup(ncg.getId()); - mHelper.createNotificationChannel(PKG, UID, channel1, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); assertEquals(ncg.getId(), mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false).getGroup()); @@ -1369,20 +1372,20 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); channel1.setGroup(ncg.getId()); - mHelper.createNotificationChannel(PKG, UID, channel1, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); NotificationChannel channel1a = new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH); channel1a.setGroup(ncg.getId()); - mHelper.createNotificationChannel(PKG, UID, channel1a, true); + mHelper.createNotificationChannel(PKG, UID, channel1a, true, false); NotificationChannel channel2 = new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH); channel2.setGroup(ncg2.getId()); - mHelper.createNotificationChannel(PKG, UID, channel2, true); + mHelper.createNotificationChannel(PKG, UID, channel2, true, false); NotificationChannel channel3 = new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG, UID, channel3, true); + mHelper.createNotificationChannel(PKG, UID, channel3, true, false); List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList(); @@ -1416,7 +1419,7 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannel channel1 = new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); channel1.setGroup(ncg.getId()); - mHelper.createNotificationChannel(PKG, UID, channel1, true); + mHelper.createNotificationChannel(PKG, UID, channel1, true, false); mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList(); channel1.setImportance(IMPORTANCE_LOW); @@ -1436,12 +1439,12 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testCreateChannel_updateName() throws Exception { NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG, UID, nc, true); + mHelper.createNotificationChannel(PKG, UID, nc, true, false); NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false); assertEquals("hello", actual.getName()); nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH); - mHelper.createNotificationChannel(PKG, UID, nc, true); + mHelper.createNotificationChannel(PKG, UID, nc, true, false); actual = mHelper.getNotificationChannel(PKG, UID, "id", false); assertEquals("goodbye", actual.getName()); @@ -1455,13 +1458,13 @@ public class RankingHelperTest extends UiServiceTestCase { NotificationChannelGroup group = new NotificationChannelGroup("group", ""); mHelper.createNotificationChannelGroup(PKG, UID, group, true); NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG, UID, nc, true); + mHelper.createNotificationChannel(PKG, UID, nc, true, false); NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false); assertNull(actual.getGroup()); nc = new NotificationChannel("id", "hello", IMPORTANCE_HIGH); nc.setGroup(group.getId()); - mHelper.createNotificationChannel(PKG, UID, nc, true); + mHelper.createNotificationChannel(PKG, UID, nc, true, false); actual = mHelper.getNotificationChannel(PKG, UID, "id", false); assertNotNull(actual.getGroup()); @@ -1486,7 +1489,7 @@ public class RankingHelperTest extends UiServiceTestCase { int numChannels = ThreadLocalRandom.current().nextInt(1, 10); for (int j = 0; j < numChannels; j++) { mHelper.createNotificationChannel(pkgName, UID, - new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true); + new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true, false); } expectedChannels.put(pkgName, numChannels); } @@ -1621,10 +1624,10 @@ public class RankingHelperTest extends UiServiceTestCase { c.setGroup(group.getId()); NotificationChannel d = new NotificationChannel("d", "d", IMPORTANCE_DEFAULT); - mHelper.createNotificationChannel(PKG, UID, a, true); - mHelper.createNotificationChannel(PKG, UID, b, true); - mHelper.createNotificationChannel(PKG, UID, c, true); - mHelper.createNotificationChannel(PKG, UID, d, true); + mHelper.createNotificationChannel(PKG, UID, a, true, false); + mHelper.createNotificationChannel(PKG, UID, b, true, false); + mHelper.createNotificationChannel(PKG, UID, c, true, false); + mHelper.createNotificationChannel(PKG, UID, d, true, false); mHelper.deleteNotificationChannel(PKG, UID, c.getId()); NotificationChannelGroup retrieved = mHelper.getNotificationChannelGroupWithChannels( @@ -1641,22 +1644,31 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testAndroidPkgCanBypassDnd_creation() { - NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); test.setBypassDnd(true); - mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true); + mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false); assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) .canBypassDnd()); } @Test + public void testDndPkgCanBypassDnd_creation() { + NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); + test.setBypassDnd(true); + + mHelper.createNotificationChannel(PKG, UID, test, true, true); + + assertTrue(mHelper.getNotificationChannel(PKG, UID, "A", false).canBypassDnd()); + } + + @Test public void testNormalPkgCannotBypassDnd_creation() { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); test.setBypassDnd(true); - mHelper.createNotificationChannel(PKG, 1000, test, true); + mHelper.createNotificationChannel(PKG, 1000, test, true, false); assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd()); } @@ -1664,11 +1676,11 @@ public class RankingHelperTest extends UiServiceTestCase { @Test public void testAndroidPkgCanBypassDnd_update() throws Exception { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); - mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true); + mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false); NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); update.setBypassDnd(true); - mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true); + mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true, false); assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) .canBypassDnd()); @@ -1678,12 +1690,24 @@ public class RankingHelperTest extends UiServiceTestCase { } @Test + public void testDndPkgCanBypassDnd_update() throws Exception { + NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); + mHelper.createNotificationChannel(PKG, UID, test, true, true); + + NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); + update.setBypassDnd(true); + mHelper.createNotificationChannel(PKG, UID, update, true, true); + + assertTrue(mHelper.getNotificationChannel(PKG, UID, "A", false).canBypassDnd()); + } + + @Test public void testNormalPkgCannotBypassDnd_update() { NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); - mHelper.createNotificationChannel(PKG, 1000, test, true); + mHelper.createNotificationChannel(PKG, 1000, test, true, false); NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); update.setBypassDnd(true); - mHelper.createNotificationChannel(PKG, 1000, update, true); + mHelper.createNotificationChannel(PKG, 1000, update, true, false); assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd()); } } |