Merge changes from topic "face-logging" into qt-dev
* changes:
Populate debug value for biometric atoms
Adding debug value to Biometric atoms.
diff --git a/api/system-current.txt b/api/system-current.txt
index c0da879..282f6f7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3499,9 +3499,9 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.audiopolicy.AudioProductStrategies getAudioProductStrategies();
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.audiopolicy.AudioVolumeGroups getAudioVolumeGroups();
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
+ method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
+ method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
+ method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method public boolean isAudioServerRunning();
method public boolean isHdmiSystemAudioSupported();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
diff --git a/api/test-current.txt b/api/test-current.txt
index c3215a6..fcad996 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1365,6 +1365,7 @@
}
public class TestNetworkManager {
+ method public android.net.TestNetworkInterface createTapInterface();
method public android.net.TestNetworkInterface createTunInterface(@NonNull android.net.LinkAddress[]);
method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
method public void teardownTestNetwork(@NonNull android.net.Network);
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index df84b6a..a9f5208e 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -77,7 +77,6 @@
#define NS_PER_HOUR 3600 * NS_PER_SEC
-#define STATS_DATA_DIR "/data/misc/stats-data"
#define STATS_ACTIVE_METRIC_DIR "/data/misc/stats-active-metric"
// Cool down period for writing data to disk to avoid overwriting files.
@@ -106,6 +105,19 @@
StatsLogProcessor::~StatsLogProcessor() {
}
+static void flushProtoToBuffer(ProtoOutputStream& proto, vector<uint8_t>* outData) {
+ outData->clear();
+ outData->resize(proto.size());
+ size_t pos = 0;
+ sp<android::util::ProtoReader> reader = proto.data();
+ while (reader->readBuffer() != NULL) {
+ size_t toRead = reader->currentToRead();
+ std::memcpy(&((*outData)[pos]), reader->readBuffer(), toRead);
+ pos += toRead;
+ reader->move(toRead);
+ }
+}
+
void StatsLogProcessor::onAnomalyAlarmFired(
const int64_t& timestampNs,
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
@@ -366,25 +378,29 @@
proto->end(configKeyToken);
// End of ConfigKey.
+ bool keepFile = false;
+ auto it = mMetricsManagers.find(key);
+ if (it != mMetricsManagers.end() && it->second->shouldPersistLocalHistory()) {
+ keepFile = true;
+ }
+
// Then, check stats-data directory to see there's any file containing
// ConfigMetricsReport from previous shutdowns to concatenate to reports.
- StorageManager::appendConfigMetricsReport(key, proto, erase_data);
+ StorageManager::appendConfigMetricsReport(
+ key, proto, erase_data && !keepFile /* should remove file after appending it */,
+ dumpReportReason == ADB_DUMP /*if caller is adb*/);
- auto it = mMetricsManagers.find(key);
if (it != mMetricsManagers.end()) {
// This allows another broadcast to be sent within the rate-limit period if we get close to
// filling the buffer again soon.
mLastBroadcastTimes.erase(key);
- // Start of ConfigMetricsReport (reports).
- uint64_t reportsToken =
- proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
- onConfigMetricsReportLocked(key, dumpTimeStampNs,
- include_current_partial_bucket,
- erase_data, dumpReportReason,
- dumpLatency, proto);
- proto->end(reportsToken);
- // End of ConfigMetricsReport (reports).
+ vector<uint8_t> buffer;
+ onConfigMetricsReportLocked(key, dumpTimeStampNs, include_current_partial_bucket,
+ erase_data, dumpReportReason, dumpLatency,
+ false /* is this data going to be saved on disk */, &buffer);
+ proto->write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS,
+ reinterpret_cast<char*>(buffer.data()), buffer.size());
} else {
ALOGW("Config source %s does not exist", key.ToString().c_str());
}
@@ -404,16 +420,8 @@
dumpReportReason, dumpLatency, &proto);
if (outData != nullptr) {
- outData->clear();
- outData->resize(proto.size());
- size_t pos = 0;
- sp<android::util::ProtoReader> reader = proto.data();
- while (reader->readBuffer() != NULL) {
- size_t toRead = reader->currentToRead();
- std::memcpy(&((*outData)[pos]), reader->readBuffer(), toRead);
- pos += toRead;
- reader->move(toRead);
- }
+ flushProtoToBuffer(proto, outData);
+ VLOG("output data size %zu", outData->size());
}
StatsdStats::getInstance().noteMetricsReportSent(key, proto.size());
@@ -422,13 +430,11 @@
/*
* onConfigMetricsReportLocked dumps serialized ConfigMetricsReport into outData.
*/
-void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
- const int64_t dumpTimeStampNs,
- const bool include_current_partial_bucket,
- const bool erase_data,
- const DumpReportReason dumpReportReason,
- const DumpLatency dumpLatency,
- ProtoOutputStream* proto) {
+void StatsLogProcessor::onConfigMetricsReportLocked(
+ const ConfigKey& key, const int64_t dumpTimeStampNs,
+ const bool include_current_partial_bucket, const bool erase_data,
+ const DumpReportReason dumpReportReason, const DumpLatency dumpLatency,
+ const bool dataSavedOnDisk, vector<uint8_t>* buffer) {
// We already checked whether key exists in mMetricsManagers in
// WriteDataToDisk.
auto it = mMetricsManagers.find(key);
@@ -440,35 +446,46 @@
std::set<string> str_set;
+ ProtoOutputStream tempProto;
// First, fill in ConfigMetricsReport using current data on memory, which
// starts from filling in StatsLogReport's.
- it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket,
- erase_data, dumpLatency, &str_set, proto);
+ it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
+ dumpLatency, &str_set, &tempProto);
// Fill in UidMap if there is at least one metric to report.
// This skips the uid map if it's an empty config.
if (it->second->getNumMetrics() > 0) {
- uint64_t uidMapToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP);
+ uint64_t uidMapToken = tempProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP);
mUidMap->appendUidMap(
dumpTimeStampNs, key, it->second->hashStringInReport() ? &str_set : nullptr,
- it->second->versionStringsInReport(), it->second->installerInReport(), proto);
- proto->end(uidMapToken);
+ it->second->versionStringsInReport(), it->second->installerInReport(), &tempProto);
+ tempProto.end(uidMapToken);
}
// Fill in the timestamps.
- proto->write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS,
- (long long)lastReportTimeNs);
- proto->write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS,
- (long long)dumpTimeStampNs);
- proto->write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS,
- (long long)lastReportWallClockNs);
- proto->write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS,
- (long long)getWallClockNs());
+ tempProto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS,
+ (long long)lastReportTimeNs);
+ tempProto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS,
+ (long long)dumpTimeStampNs);
+ tempProto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS,
+ (long long)lastReportWallClockNs);
+ tempProto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS,
+ (long long)getWallClockNs());
// Dump report reason
- proto->write(FIELD_TYPE_INT32 | FIELD_ID_DUMP_REPORT_REASON, dumpReportReason);
+ tempProto.write(FIELD_TYPE_INT32 | FIELD_ID_DUMP_REPORT_REASON, dumpReportReason);
for (const auto& str : str_set) {
- proto->write(FIELD_TYPE_STRING | FIELD_COUNT_REPEATED | FIELD_ID_STRINGS, str);
+ tempProto.write(FIELD_TYPE_STRING | FIELD_COUNT_REPEATED | FIELD_ID_STRINGS, str);
+ }
+
+ flushProtoToBuffer(tempProto, buffer);
+
+ // save buffer to disk if needed
+ if (erase_data && !dataSavedOnDisk && it->second->shouldPersistLocalHistory()) {
+ VLOG("save history to disk");
+ string file_name = StorageManager::getDataHistoryFileName((long)getWallClockSec(),
+ key.GetUid(), key.GetId());
+ StorageManager::writeFile(file_name.c_str(), buffer->data(), buffer->size());
}
}
@@ -584,18 +601,14 @@
!mMetricsManagers.find(key)->second->shouldWriteToDisk()) {
return;
}
- ProtoOutputStream proto;
+ vector<uint8_t> buffer;
onConfigMetricsReportLocked(key, timestampNs, true /* include_current_partial_bucket*/,
- true /* erase_data */, dumpReportReason, dumpLatency, &proto);
- string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
- (long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
- android::base::unique_fd fd(open(file_name.c_str(),
- O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR));
- if (fd == -1) {
- ALOGE("Attempt to write %s but failed", file_name.c_str());
- return;
- }
- proto.flush(fd.get());
+ true /* erase_data */, dumpReportReason, dumpLatency, true,
+ &buffer);
+ string file_name =
+ StorageManager::getDataFileName((long)getWallClockSec(), key.GetUid(), key.GetId());
+ StorageManager::writeFile(file_name.c_str(), buffer.data(), buffer.size());
+
// We were able to write the ConfigMetricsReport to disk, so we should trigger collection ASAP.
mOnDiskDataConfigs.insert(key);
}
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 305a4ce..f4db0af 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -164,12 +164,13 @@
const DumpReportReason dumpReportReason,
const DumpLatency dumpLatency);
- void onConfigMetricsReportLocked(const ConfigKey& key, const int64_t dumpTimeStampNs,
- const bool include_current_partial_bucket,
- const bool erase_data,
- const DumpReportReason dumpReportReason,
- const DumpLatency dumpLatency,
- util::ProtoOutputStream* proto);
+ void onConfigMetricsReportLocked(
+ const ConfigKey& key, const int64_t dumpTimeStampNs,
+ const bool include_current_partial_bucket, const bool erase_data,
+ const DumpReportReason dumpReportReason, const DumpLatency dumpLatency,
+ /*if dataSavedToDisk is true, it indicates the caller will write the data to disk
+ (e.g., before reboot). So no need to further persist local history.*/
+ const bool dataSavedToDisk, vector<uint8_t>* proto);
/* Check if we should send a broadcast if approaching memory limits and if we're over, we
* actually delete the data. */
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 53f12ac..4d21a29 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -145,6 +145,9 @@
// Maximum age (30 days) that files on disk can exist in seconds.
static const int kMaxAgeSecond = 60 * 60 * 24 * 30;
+ // Maximum age (2 days) that local history files on disk can exist in seconds.
+ static const int kMaxLocalHistoryAgeSecond = 60 * 60 * 24 * 2;
+
// Maximum number of files (1000) that can be in stats directory on disk.
static const int kMaxFileNumber = 1000;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 095f9dd..6a55289 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -65,7 +65,8 @@
mTtlNs(config.has_ttl_in_seconds() ? config.ttl_in_seconds() * NS_PER_SEC : -1),
mTtlEndNs(-1),
mLastReportTimeNs(currentTimeNs),
- mLastReportWallClockNs(getWallClockNs()) {
+ mLastReportWallClockNs(getWallClockNs()),
+ mShouldPersistHistory(config.persist_locally()) {
// Init the ttl end timestamp.
refreshTtl(timeBaseNs);
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index d317f8e..00ae3b7 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -78,6 +78,10 @@
return mNoReportMetricIds.size() != mAllMetricProducers.size();
}
+ bool shouldPersistLocalHistory() const {
+ return mShouldPersistHistory;
+ }
+
void dumpStates(FILE* out, bool verbose);
inline bool isInTtl(const int64_t timestampNs) const {
@@ -184,6 +188,8 @@
// Contains the annotations passed in with StatsdConfig.
std::list<std::pair<const int64_t, const int32_t>> mAnnotations;
+ const bool mShouldPersistHistory;
+
// To guard access to mAllowedLogSources
mutable std::mutex mAllowedLogSourcesMutex;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 90a4e8b..c44ea8a 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -633,10 +633,17 @@
flushIfNeededLocked(eventTimeNs);
}
- // For pulled data, we already check condition when we decide to pull or
- // in onDataPulled. So take all of them.
- // For pushed data, just check condition.
- if (!(mIsPulled || condition)) {
+ // We should not accumulate the data for pushed metrics when the condition is false.
+ bool shouldSkipForPushMetric = !mIsPulled && !condition;
+ // For pulled metrics, there are two cases:
+ // - to compute diffs, we need to process all the state changes
+ // - for non-diffs metrics, we should ignore the data if the condition wasn't true. If we have a
+ // state change from
+ // + True -> True: we should process the data, it might be a bucket boundary
+ // + True -> False: we als need to process the data.
+ bool shouldSkipForPulledMetric = mIsPulled && !mUseDiff
+ && mCondition != ConditionState::kTrue;
+ if (shouldSkipForPushMetric || shouldSkipForPulledMetric) {
VLOG("ValueMetric skip event because condition is false");
return;
}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 0f56337..8c19995 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -259,6 +259,11 @@
FRIEND_TEST(ValueMetricProducerTest, TestLateOnDataPulledWithoutDiff);
FRIEND_TEST(ValueMetricProducerTest, TestPartialBucketCreated);
FRIEND_TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryFalse);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryTrue);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_withFailure);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_withoutCondition);
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition);
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset);
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset);
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 257e65e..2260b9b 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -439,6 +439,8 @@
optional bool installer_in_metric_report = 19;
+ optional bool persist_locally = 20 [default = false];
+
// Field number 1000 is reserved for later use.
reserved 1000;
}
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index cf8b974..0a9161d 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -56,9 +56,31 @@
using android::base::StringPrintf;
using std::unique_ptr;
-// Returns array of int64_t which contains timestamp in seconds, uid, and
-// configID.
-static void parseFileName(char* name, int64_t* result) {
+struct FileName {
+ int64_t mTimestampSec;
+ int mUid;
+ int64_t mConfigId;
+ bool mIsHistory;
+ string getFullFileName(const char* path) {
+ return StringPrintf("%s/%lld_%d_%lld%s", path, (long long)mTimestampSec, (int)mUid,
+ (long long)mConfigId, (mIsHistory ? "_history" : ""));
+ };
+};
+
+string StorageManager::getDataFileName(long wallClockSec, int uid, int64_t id) {
+ return StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR, wallClockSec, uid,
+ (long long)id);
+}
+
+string StorageManager::getDataHistoryFileName(long wallClockSec, int uid, int64_t id) {
+ return StringPrintf("%s/%ld_%d_%lld_history", STATS_DATA_DIR, wallClockSec, uid,
+ (long long)id);
+}
+
+// Returns array of int64_t which contains timestamp in seconds, uid,
+// configID and whether the file is a local history file.
+static void parseFileName(char* name, FileName* output) {
+ int64_t result[3];
int index = 0;
char* substr = strtok(name, "_");
while (substr != nullptr && index < 3) {
@@ -72,11 +94,12 @@
if (index < 3) {
result[0] = -1;
}
-}
-static string getFilePath(const char* path, int64_t timestamp, int64_t uid, int64_t configID) {
- return StringPrintf("%s/%lld_%d_%lld", path, (long long)timestamp, (int)uid,
- (long long)configID);
+ output->mTimestampSec = result[0];
+ output->mUid = result[1];
+ output->mConfigId = result[2];
+ // check if the file is a local history.
+ output->mIsHistory = (substr != nullptr && strcmp("history", substr) == 0);
}
void StorageManager::writeFile(const char* file, const void* buffer, int numBytes) {
@@ -88,14 +111,13 @@
trimToFit(STATS_SERVICE_DIR);
trimToFit(STATS_DATA_DIR);
- int result = write(fd, buffer, numBytes);
- if (result == numBytes) {
+ if (android::base::WriteFully(fd, buffer, numBytes)) {
VLOG("Successfully wrote %s", file);
} else {
- VLOG("Failed to write %s", file);
+ ALOGE("Failed to write %s", file);
}
- result = fchown(fd, AID_STATSD, AID_STATSD);
+ int result = fchown(fd, AID_STATSD, AID_STATSD);
if (result) {
VLOG("Failed to chown %s to statsd", file);
}
@@ -349,13 +371,10 @@
if (name[0] == '.') continue;
VLOG("file %s", name);
- int64_t result[3];
- parseFileName(name, result);
- if (result[0] == -1) continue;
- int64_t uid = result[1];
- int64_t configID = result[2];
-
- sendBroadcast(ConfigKey((int)uid, configID));
+ FileName output;
+ parseFileName(name, &output);
+ if (output.mTimestampSec == -1 || output.mIsHistory) continue;
+ sendBroadcast(ConfigKey((int)output.mUid, output.mConfigId));
}
}
@@ -378,55 +397,58 @@
if (suffixLen <= nameLen &&
strncmp(name + nameLen - suffixLen, suffix.c_str(), suffixLen) == 0) {
// Check again that the file name is parseable.
- int64_t result[3];
- parseFileName(name, result);
- if (result[0] == -1) continue;
+ FileName output;
+ parseFileName(name, &output);
+ if (output.mTimestampSec == -1 || output.mIsHistory) continue;
return true;
}
}
return false;
}
-void StorageManager::appendConfigMetricsReport(const ConfigKey& key,
- ProtoOutputStream* proto,
- bool erasa_data) {
+void StorageManager::appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto,
+ bool erase_data, bool isAdb) {
unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_DATA_DIR), closedir);
if (dir == NULL) {
VLOG("Path %s does not exist", STATS_DATA_DIR);
return;
}
- string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId());
-
dirent* de;
while ((de = readdir(dir.get()))) {
char* name = de->d_name;
+ string fileName(name);
if (name[0] == '.') continue;
+ FileName output;
+ parseFileName(name, &output);
- size_t nameLen = strlen(name);
- size_t suffixLen = suffix.length();
- if (suffixLen <= nameLen &&
- strncmp(name + nameLen - suffixLen, suffix.c_str(), suffixLen) == 0) {
- int64_t result[3];
- parseFileName(name, result);
- if (result[0] == -1) continue;
- int64_t timestamp = result[0];
- int64_t uid = result[1];
- int64_t configID = result[2];
+ if (output.mTimestampSec == -1 || (output.mIsHistory && !isAdb) ||
+ output.mUid != key.GetUid() || output.mConfigId != key.GetId()) {
+ continue;
+ }
- string file_name = getFilePath(STATS_DATA_DIR, timestamp, uid, configID);
- int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
- if (fd != -1) {
- string content;
- if (android::base::ReadFdToString(fd, &content)) {
- proto->write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS,
- content.c_str(), content.size());
- }
- close(fd);
+ auto fullPathName = StringPrintf("%s/%s", STATS_DATA_DIR, fileName.c_str());
+ int fd = open(fullPathName.c_str(), O_RDONLY | O_CLOEXEC);
+ if (fd != -1) {
+ string content;
+ if (android::base::ReadFdToString(fd, &content)) {
+ proto->write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS,
+ content.c_str(), content.size());
}
+ close(fd);
+ } else {
+ ALOGE("file cannot be opened");
+ }
- if (erasa_data) {
- remove(file_name.c_str());
+ if (erase_data) {
+ remove(fullPathName.c_str());
+ } else if (output.mIsHistory && !isAdb) {
+ // This means a real data owner has called to get this data. But the config says it
+ // wants to keep a local history. So now this file must be renamed as a history file.
+ // So that next time, when owner calls getData() again, this data won't be uploaded
+ // again. rename returns 0 on success
+ if (rename(fullPathName.c_str(), (fullPathName + "_history").c_str())) {
+ ALOGE("Failed to rename file %s", fullPathName.c_str());
}
}
}
@@ -458,23 +480,20 @@
while ((de = readdir(dir.get()))) {
char* name = de->d_name;
if (name[0] == '.') continue;
- VLOG("file %s", name);
- int64_t result[3];
- parseFileName(name, result);
- if (result[0] == -1) continue;
- int64_t timestamp = result[0];
- int64_t uid = result[1];
- int64_t configID = result[2];
- string file_name = getFilePath(STATS_SERVICE_DIR, timestamp, uid, configID);
+ FileName output;
+ parseFileName(name, &output);
+ if (output.mTimestampSec == -1) continue;
+ string file_name = output.getFullFileName(STATS_SERVICE_DIR);
int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
if (fd != -1) {
string content;
if (android::base::ReadFdToString(fd, &content)) {
StatsdConfig config;
if (config.ParseFromString(content)) {
- configsMap[ConfigKey(uid, configID)] = config;
- VLOG("map key uid=%lld|configID=%lld", (long long)uid, (long long)configID);
+ configsMap[ConfigKey(output.mUid, output.mConfigId)] = config;
+ VLOG("map key uid=%lld|configID=%lld", (long long)output.mUid,
+ (long long)output.mConfigId);
}
}
close(fd);
@@ -533,6 +552,30 @@
return false;
}
+void StorageManager::sortFiles(vector<FileInfo>* fileNames) {
+ // Reverse sort to effectively remove from the back (oldest entries).
+ // This will sort files in reverse-chronological order. Local history files have lower
+ // priority than regular data files.
+ sort(fileNames->begin(), fileNames->end(), [](FileInfo& lhs, FileInfo& rhs) {
+ // first consider if the file is a local history
+ if (lhs.mIsHistory && !rhs.mIsHistory) {
+ return false;
+ } else if (rhs.mIsHistory && !lhs.mIsHistory) {
+ return true;
+ }
+
+ // then consider the age.
+ if (lhs.mFileAgeSec < rhs.mFileAgeSec) {
+ return true;
+ } else if (lhs.mFileAgeSec > rhs.mFileAgeSec) {
+ return false;
+ }
+
+ // then good luck.... use string::compare
+ return lhs.mFileName.compare(rhs.mFileName) > 0;
+ });
+}
+
void StorageManager::trimToFit(const char* path) {
unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
if (dir == NULL) {
@@ -541,55 +584,46 @@
}
dirent* de;
int totalFileSize = 0;
- vector<string> fileNames;
+ vector<FileInfo> fileNames;
+ auto nowSec = getWallClockSec();
while ((de = readdir(dir.get()))) {
char* name = de->d_name;
if (name[0] == '.') continue;
- int64_t result[3];
- parseFileName(name, result);
- if (result[0] == -1) continue;
- int64_t timestamp = result[0];
- int64_t uid = result[1];
- int64_t configID = result[2];
- string file_name = getFilePath(path, timestamp, uid, configID);
+ FileName output;
+ parseFileName(name, &output);
+ if (output.mTimestampSec == -1) continue;
+ string file_name = output.getFullFileName(path);
// Check for timestamp and delete if it's too old.
- long fileAge = getWallClockSec() - timestamp;
- if (fileAge > StatsdStats::kMaxAgeSecond) {
+ long fileAge = nowSec - output.mTimestampSec;
+ if (fileAge > StatsdStats::kMaxAgeSecond ||
+ (output.mIsHistory && fileAge > StatsdStats::kMaxLocalHistoryAgeSecond)) {
deleteFile(file_name.c_str());
+ continue;
}
- fileNames.push_back(file_name);
ifstream file(file_name.c_str(), ifstream::in | ifstream::binary);
+ int fileSize = 0;
if (file.is_open()) {
file.seekg(0, ios::end);
- int fileSize = file.tellg();
+ fileSize = file.tellg();
file.close();
totalFileSize += fileSize;
}
+ fileNames.emplace_back(file_name, output.mIsHistory, fileSize, fileAge);
}
if (fileNames.size() > StatsdStats::kMaxFileNumber ||
totalFileSize > StatsdStats::kMaxFileSize) {
- // Reverse sort to effectively remove from the back (oldest entries).
- // This will sort files in reverse-chronological order.
- sort(fileNames.begin(), fileNames.end(), std::greater<std::string>());
+ sortFiles(&fileNames);
}
// Start removing files from oldest to be under the limit.
while (fileNames.size() > 0 && (fileNames.size() > StatsdStats::kMaxFileNumber ||
totalFileSize > StatsdStats::kMaxFileSize)) {
- string file_name = fileNames.at(fileNames.size() - 1);
- ifstream file(file_name.c_str(), ifstream::in | ifstream::binary);
- if (file.is_open()) {
- file.seekg(0, ios::end);
- int fileSize = file.tellg();
- file.close();
- totalFileSize -= fileSize;
- }
-
- deleteFile(file_name.c_str());
+ totalFileSize -= fileNames.at(fileNames.size() - 1).mFileSizeBytes;
+ deleteFile(fileNames.at(fileNames.size() - 1).mFileName.c_str());
fileNames.pop_back();
}
}
@@ -614,15 +648,13 @@
if (name[0] == '.') {
continue;
}
- int64_t result[3];
- parseFileName(name, result);
- if (result[0] == -1) continue;
- int64_t timestamp = result[0];
- int64_t uid = result[1];
- int64_t configID = result[2];
- dprintf(outFd, "\t #%d, Last updated: %lld, UID: %d, Config ID: %lld", fileCount + 1,
- (long long)timestamp, (int)uid, (long long)configID);
- string file_name = getFilePath(path, timestamp, uid, configID);
+ FileName output;
+ parseFileName(name, &output);
+ if (output.mTimestampSec == -1) continue;
+ dprintf(outFd, "\t #%d, Last updated: %lld, UID: %d, Config ID: %lld, %s", fileCount + 1,
+ (long long)output.mTimestampSec, output.mUid, (long long)output.mConfigId,
+ (output.mIsHistory ? "local history" : ""));
+ string file_name = output.getFullFileName(path);
ifstream file(file_name.c_str(), ifstream::in | ifstream::binary);
if (file.is_open()) {
file.seekg(0, ios::end);
diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h
index dfcea65..69b41c2 100644
--- a/cmds/statsd/src/storage/StorageManager.h
+++ b/cmds/statsd/src/storage/StorageManager.h
@@ -31,6 +31,19 @@
class StorageManager : public virtual RefBase {
public:
+ struct FileInfo {
+ FileInfo(std::string name, bool isHistory, int fileSize, long fileAge)
+ : mFileName(name),
+ mIsHistory(isHistory),
+ mFileSizeBytes(fileSize),
+ mFileAgeSec(fileAge) {
+ }
+ std::string mFileName;
+ bool mIsHistory;
+ int mFileSizeBytes;
+ long mFileAgeSec;
+ };
+
/**
* Writes a given byte array as a file to the specified file path.
*/
@@ -81,10 +94,19 @@
/**
* Appends the ConfigMetricsReport found on disk to the specifid proto
* and, if erase_data, deletes it from disk.
+ *
+ * [isAdb]: if the caller is adb dump. This includes local adb dump or dumpsys by
+ * bugreport or incidentd. When true, we will append any local history data too.
+ *
+ * When
+ * erase_data=true, isAdb=true: append history data to output, remove all data after read
+ * erase_data=false, isAdb=true: append history data to output, keep data after read
+ * erase_data=true, isAdb=false: do not append history data, and remove data after read
+ * erase_data=false, isAdb=false: do not append history data and *rename* all data files to
+ * history files.
*/
- static void appendConfigMetricsReport(const ConfigKey& key,
- ProtoOutputStream* proto,
- bool erase_data);
+ static void appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto,
+ bool erase_data, bool isAdb);
/**
* Call to load the saved configs from disk.
@@ -115,6 +137,12 @@
*/
static void printStats(int out);
+ static string getDataFileName(long wallClockSec, int uid, int64_t id);
+
+ static string getDataHistoryFileName(long wallClockSec, int uid, int64_t id);
+
+ static void sortFiles(vector<FileInfo>* fileNames);
+
private:
/**
* Prints disk usage statistics about a directory related to statsd.
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index c12a5900..43a3c7b 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -2964,6 +2964,146 @@
EXPECT_EQ(10, report.value_metrics().data(0).bucket_info(0).condition_true_nanos());
}
+TEST(ValueMetricProducerTest, TestPulledData_noDiff_withoutCondition) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.set_use_diff(false);
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 10));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 30);
+
+ // Bucket should have been completed.
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs});
+}
+
+TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+ metric.set_use_diff(false);
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // condition becomes true
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(
+ bucketStartTimeNs + 30, 10));
+ return true;
+ }))
+ // condition becomes false
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(
+ bucketStartTimeNs + 50, 20));
+ return true;
+ }));
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ valueProducer->mCondition = ConditionState::kFalse;
+
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
+ valueProducer->onConditionChanged(false, bucketStartTimeNs + 50);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(false, curInterval.hasBase);
+ EXPECT_EQ(true, curInterval.hasValue);
+ EXPECT_EQ(20, curInterval.value.long_value);
+
+
+ // Now the alarm is delivered. Condition is off though.
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 110));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {50 - 8});
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(false, curInterval.hasBase);
+ EXPECT_EQ(false, curInterval.hasValue);
+}
+
+TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryTrue) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+ metric.set_use_diff(false);
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // condition becomes true
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(
+ bucketStartTimeNs + 30, 10));
+ return true;
+ }));
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ valueProducer->mCondition = ConditionState::kFalse;
+
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
+
+ // Now the alarm is delivered. Condition is off though.
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 30));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs - 8});
+ ValueMetricProducer::Interval curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(false, curInterval.hasBase);
+ EXPECT_EQ(false, curInterval.hasValue);
+}
+
+TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryFalse) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+ metric.set_use_diff(false);
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ valueProducer->mCondition = ConditionState::kFalse;
+
+ // Now the alarm is delivered. Condition is off though.
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 30));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ // Condition was always false.
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {});
+}
+
+TEST(ValueMetricProducerTest, TestPulledData_noDiff_withFailure) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+ metric.set_use_diff(false);
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // condition becomes true
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(
+ bucketStartTimeNs + 30, 10));
+ return true;
+ }))
+ .WillOnce(Return(false));
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ valueProducer->mCondition = ConditionState::kFalse;
+
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
+ valueProducer->onConditionChanged(false, bucketStartTimeNs + 50);
+
+ // Now the alarm is delivered. Condition is off though.
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 30));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ // No buckets, we had a failure.
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {});
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/storage/StorageManager_test.cpp b/cmds/statsd/tests/storage/StorageManager_test.cpp
index 4564a5d..cae2f30 100644
--- a/cmds/statsd/tests/storage/StorageManager_test.cpp
+++ b/cmds/statsd/tests/storage/StorageManager_test.cpp
@@ -110,6 +110,21 @@
EXPECT_EQ(trainInfo.experimentIds, trainInfoResult.experimentIds);
}
+TEST(StorageManagerTest, SortFileTest) {
+ vector<StorageManager::FileInfo> list;
+ // assume now sec is 500
+ list.emplace_back("200_5000_123454", false, 20, 300);
+ list.emplace_back("300_2000_123454_history", true, 30, 200);
+ list.emplace_back("400_100009_123454_history", true, 40, 100);
+ list.emplace_back("100_2000_123454", false, 50, 400);
+
+ StorageManager::sortFiles(&list);
+ EXPECT_EQ("200_5000_123454", list[0].mFileName);
+ EXPECT_EQ("100_2000_123454", list[1].mFileName);
+ EXPECT_EQ("400_100009_123454_history", list[2].mFileName);
+ EXPECT_EQ("300_2000_123454_history", list[3].mFileName);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index da9ea83..926044b 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -33,7 +33,6 @@
import android.graphics.Bitmap.Config;
import android.graphics.GraphicBuffer;
import android.graphics.Rect;
-import android.hardware.HardwareBuffer;
import android.os.Bundle;
import android.os.Handler;
import android.os.IRemoteCallback;
@@ -925,8 +924,7 @@
// Unpackage the GraphicBuffer from the parceled thumbnail
final GraphicBuffer buffer = opts.getParcelable(KEY_ANIM_THUMBNAIL);
if (buffer != null) {
- mThumbnail = Bitmap.wrapHardwareBuffer(
- HardwareBuffer.createFromGraphicBuffer(buffer), null);
+ mThumbnail = Bitmap.wrapHardwareBuffer(buffer, null);
}
mStartX = opts.getInt(KEY_ANIM_START_X, 0);
mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b37d117..b6e5754 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2121,7 +2121,11 @@
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
- if (ai != null && packageInfo != null && isLoadedApkUpToDate(packageInfo, ai)) {
+ if (ai != null && packageInfo != null) {
+ if (!isLoadedApkResourceDirsUpToDate(packageInfo, ai)) {
+ packageInfo.updateApplicationInfo(ai, null);
+ }
+
if (packageInfo.isSecurityViolation()
&& (flags&Context.CONTEXT_IGNORE_SECURITY) == 0) {
throw new SecurityException(
@@ -2205,9 +2209,11 @@
LoadedApk packageInfo = ref != null ? ref.get() : null;
- boolean isUpToDate = packageInfo != null && isLoadedApkUpToDate(packageInfo, aInfo);
+ if (packageInfo != null) {
+ if (!isLoadedApkResourceDirsUpToDate(packageInfo, aInfo)) {
+ packageInfo.updateApplicationInfo(aInfo, null);
+ }
- if (isUpToDate) {
return packageInfo;
}
@@ -2243,11 +2249,8 @@
}
}
- /**
- * Compares overlay/resource directories for a LoadedApk to determine if it's up to date
- * with the given ApplicationInfo.
- */
- private boolean isLoadedApkUpToDate(LoadedApk loadedApk, ApplicationInfo appInfo) {
+ private static boolean isLoadedApkResourceDirsUpToDate(LoadedApk loadedApk,
+ ApplicationInfo appInfo) {
Resources packageResources = loadedApk.mResources;
String[] overlayDirs = ArrayUtils.defeatNullable(loadedApk.getOverlayDirs());
String[] resourceDirs = ArrayUtils.defeatNullable(appInfo.resourceDirs);
diff --git a/core/java/android/app/AppComponentFactory.java b/core/java/android/app/AppComponentFactory.java
index 2cec7f0..5b02817 100644
--- a/core/java/android/app/AppComponentFactory.java
+++ b/core/java/android/app/AppComponentFactory.java
@@ -35,11 +35,22 @@
public class AppComponentFactory {
/**
- * Allows application to override the creation of the default class loader.
- * This can be used to perform things such as dependency injection or setting up
- * a custom class loader hierarchy.
+ * Selects the class loader which will be used by the platform to instantiate app components.
+ * <p>
+ * The default implementation of this method returns the {@code cl} parameter unchanged.
+ * Applications can override this method to set up a custom class loader or a custom class
+ * loader hierarchy and return it to the platform.
+ * <p>
+ * The method is a hook invoked before any application components are instantiated or the
+ * application Context is initialized. It is intended to allow the application's classes to
+ * be loaded from a different source than the base/split APK(s).
+ * <p>
+ * The default class loader {@code cl} is created by the platform and used to load the
+ * application's base or split APK(s). Its parent is typically the boot class loader, unless
+ * running under instrumentation. Its classname is configurable using the
+ * {@link android.R.attr#classLoader} manifest attribute.
*
- * @param cl The default classloader instantiated by platform.
+ * @param cl The default class loader created by the platform.
* @param aInfo Information about the application being loaded.
*/
public @NonNull ClassLoader instantiateClassLoader(@NonNull ClassLoader cl,
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index af738da..b97ea5f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3820,10 +3820,7 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a {@link
- * android.net.wifi.rtt.WifiRttManager} for ranging devices with wifi
- *
- * Note: this is a replacement for WIFI_RTT_SERVICE above. It will
- * be renamed once final implementation in place.
+ * android.net.wifi.rtt.WifiRttManager} for ranging devices with wifi.
*
* @see #getSystemService(String)
* @see android.net.wifi.rtt.WifiRttManager
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index a71f7d2..6c72a9a 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1222,7 +1222,7 @@
try {
mSession.addChildSessionId(sessionId);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ e.rethrowFromSystemServer();
}
}
@@ -1236,7 +1236,7 @@
try {
mSession.removeChildSessionId(sessionId);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/hardware/biometrics/CryptoObject.java b/core/java/android/hardware/biometrics/CryptoObject.java
index 496d9c5..787dc66 100644
--- a/core/java/android/hardware/biometrics/CryptoObject.java
+++ b/core/java/android/hardware/biometrics/CryptoObject.java
@@ -25,8 +25,8 @@
import javax.crypto.Mac;
/**
- * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
- * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
+ * A wrapper class for the crypto objects supported by BiometricPrompt and FingerprintManager.
+ * Currently the framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
* @hide
*/
public class CryptoObject {
diff --git a/core/java/android/net/ITestNetworkManager.aidl b/core/java/android/net/ITestNetworkManager.aidl
index 119a30c..bab6ae8 100644
--- a/core/java/android/net/ITestNetworkManager.aidl
+++ b/core/java/android/net/ITestNetworkManager.aidl
@@ -29,6 +29,7 @@
interface ITestNetworkManager
{
TestNetworkInterface createTunInterface(in LinkAddress[] linkAddrs);
+ TestNetworkInterface createTapInterface();
void setupTestNetwork(in String iface, in IBinder binder);
diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java
index cd58e66..ba26c1f 100644
--- a/core/java/android/net/TestNetworkManager.java
+++ b/core/java/android/net/TestNetworkManager.java
@@ -88,4 +88,21 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Create a tap interface for testing purposes
+ *
+ * @return A ParcelFileDescriptor of the underlying TAP interface. Close this to tear down the
+ * TAP interface.
+ * @hide
+ */
+ @TestApi
+ public TestNetworkInterface createTapInterface() {
+ try {
+ return mService.createTapInterface();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index e56b6e0..779790c 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -72,6 +72,14 @@
private static final String INTENT_KEY_A4A_TOAST_MESSAGE = "A4A Toast Message";
private static final String GAME_DRIVER_WHITELIST_ALL = "*";
+ // GAME_DRIVER_ALL_APPS
+ // 0: Default (Invalid values fallback to default as well)
+ // 1: All apps use Game Driver
+ // 2: All apps use system graphics driver
+ private static final int GAME_DRIVER_GLOBAL_OPT_IN_DEFAULT = 0;
+ private static final int GAME_DRIVER_GLOBAL_OPT_IN_ALL = 1;
+ private static final int GAME_DRIVER_GLOBAL_OPT_IN_NONE = 2;
+
private ClassLoader mClassLoader;
private String mLayerPath;
private String mDebugLayerPath;
@@ -97,6 +105,65 @@
}
/**
+ * Allow to query whether an application will use Game Driver.
+ */
+ public static boolean shouldUseGameDriver(Context context, Bundle coreSettings,
+ ApplicationInfo applicationInfo) {
+ final String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
+ if (driverPackageName == null || driverPackageName.isEmpty()) {
+ return false;
+ }
+
+ // To minimize risk of driver updates crippling the device beyond user repair, never use an
+ // updated driver for privileged or non-updated system apps. Presumably pre-installed apps
+ // were tested thoroughly with the pre-installed driver.
+ if (applicationInfo.isPrivilegedApp() || (applicationInfo.isSystemApp()
+ && !applicationInfo.isUpdatedSystemApp())) {
+ if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app");
+ return false;
+ }
+ final ContentResolver contentResolver = context.getContentResolver();
+ final String packageName = applicationInfo.packageName;
+ final int globalOptIn;
+ if (coreSettings != null) {
+ globalOptIn = coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0);
+ } else {
+ globalOptIn = Settings.Global.getInt(contentResolver,
+ Settings.Global.GAME_DRIVER_ALL_APPS, 0);
+ }
+ if (globalOptIn == GAME_DRIVER_GLOBAL_OPT_IN_ALL) {
+ return true;
+ }
+ if (globalOptIn == GAME_DRIVER_GLOBAL_OPT_IN_NONE) {
+ return false;
+ }
+
+ // GAME_DRIVER_OPT_OUT_APPS has higher priority than GAME_DRIVER_OPT_IN_APPS
+ if (getGlobalSettingsString(contentResolver, coreSettings,
+ Settings.Global.GAME_DRIVER_OPT_OUT_APPS).contains(packageName)) {
+ return false;
+ }
+ final boolean isOptIn = getGlobalSettingsString(contentResolver, coreSettings,
+ Settings.Global.GAME_DRIVER_OPT_IN_APPS).contains(packageName);
+ final List<String> whitelist = getGlobalSettingsString(contentResolver, coreSettings,
+ Settings.Global.GAME_DRIVER_WHITELIST);
+ if (!isOptIn && whitelist.indexOf(GAME_DRIVER_WHITELIST_ALL) != 0
+ && !whitelist.contains(packageName)) {
+ return false;
+ }
+
+ // If the application is not opted-in, then check whether it's on the blacklist,
+ // terminate early if it's on the blacklist and fallback to system driver.
+ if (!isOptIn
+ && getGlobalSettingsString(contentResolver, coreSettings,
+ Settings.Global.GAME_DRIVER_BLACKLIST)
+ .contains(packageName)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Check whether application is debuggable
*/
private static boolean isDebuggable(Context context) {
@@ -657,59 +724,10 @@
return false;
}
- // To minimize risk of driver updates crippling the device beyond user repair, never use an
- // updated driver for privileged or non-updated system apps. Presumably pre-installed apps
- // were tested thoroughly with the pre-installed driver.
- final ApplicationInfo ai = context.getApplicationInfo();
- if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) {
- if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app");
+ if (!shouldUseGameDriver(context, coreSettings, context.getApplicationInfo())) {
return false;
}
- // GAME_DRIVER_ALL_APPS
- // 0: Default (Invalid values fallback to default as well)
- // 1: All apps use Game Driver
- // 2: All apps use system graphics driver
- final int gameDriverAllApps = coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0);
- if (gameDriverAllApps == 2) {
- if (DEBUG) {
- Log.w(TAG, "Game Driver is turned off on this device");
- }
- return false;
- }
-
- if (gameDriverAllApps != 1) {
- // GAME_DRIVER_OPT_OUT_APPS has higher priority than GAME_DRIVER_OPT_IN_APPS
- if (getGlobalSettingsString(null, coreSettings,
- Settings.Global.GAME_DRIVER_OPT_OUT_APPS).contains(packageName)) {
- if (DEBUG) {
- Log.w(TAG, packageName + " opts out from Game Driver.");
- }
- return false;
- }
- final boolean isOptIn =
- getGlobalSettingsString(null, coreSettings,
- Settings.Global.GAME_DRIVER_OPT_IN_APPS).contains(packageName);
- final List<String> whitelist = getGlobalSettingsString(null, coreSettings,
- Settings.Global.GAME_DRIVER_WHITELIST);
- if (!isOptIn && whitelist.indexOf(GAME_DRIVER_WHITELIST_ALL) != 0
- && !whitelist.contains(packageName)) {
- if (DEBUG) {
- Log.w(TAG, packageName + " is not on the whitelist.");
- }
- return false;
- }
-
- // If the application is not opted-in and check whether it's on the blacklist,
- // terminate early if it's on the blacklist and fallback to system driver.
- if (!isOptIn
- && getGlobalSettingsString(null, coreSettings,
- Settings.Global.GAME_DRIVER_BLACKLIST)
- .contains(ai.packageName)) {
- return false;
- }
- }
-
final String abi = chooseAbi(driverAppInfo);
if (abi == null) {
if (DEBUG) {
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index a7ac7a1..fb35db1 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -513,6 +513,7 @@
* @param packageName null-ok the name of the package this process belongs to.
* @param packagesForUid null-ok all the packages with the same uid as this process.
* @param zygoteArgs Additional arguments to supply to the zygote process.
+ * @param useSystemGraphicsDriver whether the process uses system graphics driver.
*
* @return An object that describes the result of the attempt to start the process.
* @throws RuntimeException on fatal start failure
@@ -532,12 +533,13 @@
@Nullable String packageName,
@Nullable String[] packagesForUid,
@Nullable String sandboxId,
- @Nullable String[] zygoteArgs) {
+ @Nullable String[] zygoteArgs,
+ boolean useSystemGraphicsDriver) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
packagesForUid, sandboxId, /*useUnspecializedAppProcessPool=*/ true,
- zygoteArgs);
+ zygoteArgs, useSystemGraphicsDriver);
}
/** @hide */
@@ -554,12 +556,13 @@
@Nullable String packageName,
@Nullable String[] packagesForUid,
@Nullable String sandboxId,
- @Nullable String[] zygoteArgs) {
+ @Nullable String[] zygoteArgs,
+ boolean useSystemGraphicsDriver) {
return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
packagesForUid, sandboxId, /*useUnspecializedAppProcessPool=*/ false,
- zygoteArgs);
+ zygoteArgs, useSystemGraphicsDriver);
}
/**
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index ab19fd6..b7789c0 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -308,6 +308,7 @@
* @param packageName null-ok the name of the package this process belongs to.
* @param packagesForUid null-ok all the packages with the same uid as this process.
* @param zygoteArgs Additional arguments to supply to the zygote process.
+ * @param useSystemGraphicsDriver whether the process uses system graphics driver.
*
* @return An object that describes the result of the attempt to start the process.
* @throws RuntimeException on fatal start failure
@@ -326,7 +327,8 @@
@Nullable String[] packagesForUid,
@Nullable String sandboxId,
boolean useUsapPool,
- @Nullable String[] zygoteArgs) {
+ @Nullable String[] zygoteArgs,
+ boolean useSystemGraphicsDriver) {
// TODO (chriswailes): Is there a better place to check this value?
if (fetchUsapPoolEnabledPropWithMinInterval()) {
informZygotesOfUsapPoolStatus();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d7bbfe2..0491c73 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1075,6 +1075,22 @@
"android.settings.ADD_ACCOUNT_SETTINGS";
/**
+ * Activity Action: Show settings for enabling or disabling data saver
+ * <p></p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_DATA_SAVER_SETTINGS =
+ "android.settings.DATA_SAVER_SETTINGS";
+
+ /**
* Activity Action: Show settings for selecting the network operator.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
diff --git a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
index 45a8466..55e6141 100644
--- a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
+++ b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
@@ -31,7 +31,6 @@
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.GraphicBuffer;
-import android.hardware.HardwareBuffer;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -67,8 +66,7 @@
Bitmap wrappedBuffer = null;
if (contextImage != null) {
- wrappedBuffer = Bitmap.wrapHardwareBuffer(
- HardwareBuffer.createFromGraphicBuffer(contextImage), null);
+ wrappedBuffer = Bitmap.wrapHardwareBuffer(contextImage, null);
}
mHandler.sendMessage(
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 79363ed..b5ad908 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -41,7 +41,6 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
-import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
import android.os.Build;
@@ -1917,9 +1916,7 @@
Log.w(TAG, "Failed to take screenshot");
return null;
}
- return Bitmap.wrapHardwareBuffer(
- HardwareBuffer.createFromGraphicBuffer(buffer.getGraphicBuffer()),
- buffer.getColorSpace());
+ return Bitmap.wrapHardwareBuffer(buffer.getGraphicBuffer(), buffer.getColorSpace());
}
/**
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 81e9c13..9e914d4 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -87,6 +87,12 @@
/**
* Defines the duration in milliseconds a user needs to hold down the
+ * appropriate buttons (power + volume down) to trigger the screenshot chord.
+ */
+ private static final int SCREENSHOT_CHORD_KEY_TIMEOUT = 500;
+
+ /**
+ * Defines the duration in milliseconds a user needs to hold down the
* appropriate button to bring up the accessibility shortcut for the first time
*/
private static final int A11Y_SHORTCUT_KEY_TIMEOUT = 3000;
@@ -316,6 +322,7 @@
private final float mVerticalScrollFactor;
private final float mHorizontalScrollFactor;
private final boolean mShowMenuShortcutsWhenKeyboardPresent;
+ private final long mScreenshotChordKeyTimeout;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768915)
private boolean sHasPermanentMenuKey;
@@ -353,6 +360,7 @@
mHorizontalScrollFactor = HORIZONTAL_SCROLL_FACTOR;
mVerticalScrollFactor = VERTICAL_SCROLL_FACTOR;
mShowMenuShortcutsWhenKeyboardPresent = false;
+ mScreenshotChordKeyTimeout = SCREENSHOT_CHORD_KEY_TIMEOUT;
// Getter throws if mConstructedWithContext is false so doesn't matter what
// this value is.
@@ -457,6 +465,9 @@
mMinScalingSpan = res.getDimensionPixelSize(
com.android.internal.R.dimen.config_minScalingSpan);
+
+ mScreenshotChordKeyTimeout = res.getInteger(
+ com.android.internal.R.integer.config_screenshotChordKeyTimeout);
}
/**
@@ -890,6 +901,18 @@
}
/**
+ * The amount of time a user needs to press the relevant keys to trigger
+ * the screenshot chord.
+ *
+ * @return how long a user needs to press the relevant keys to trigger
+ * the screenshot chord.
+ * @hide
+ */
+ public long getScreenshotChordKeyTimeout() {
+ return mScreenshotChordKeyTimeout;
+ }
+
+ /**
* The amount of time a user needs to press the relevant keys to activate the accessibility
* shortcut.
*
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 62f54b9..2bfbe4b 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -17,7 +17,6 @@
package android.webkit;
import android.content.pm.PackageInfo;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.ChildZygoteProcess;
import android.os.Process;
@@ -81,17 +80,9 @@
synchronized (sLock) {
sMultiprocessEnabled = enabled;
- // When toggling between multi-process being on/off, start or stop the
- // zygote. If it is enabled and the zygote is not yet started, launch it.
- // Otherwise, kill it. The name may be null if the package information has
- // not yet been resolved.
- if (enabled) {
- // Run on a background thread as this waits for the zygote to start and we don't
- // want to block the caller on this. It's okay if this is delayed as anyone trying
- // to use the zygote will call it first anyway.
- AsyncTask.THREAD_POOL_EXECUTOR.execute(WebViewZygote::getProcess);
- } else {
- // No need to run this in the background, it's very brief.
+ // When multi-process is disabled, kill the zygote. When it is enabled,
+ // the zygote will be started when it is first needed in getProcess().
+ if (!enabled) {
stopZygoteLocked();
}
}
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index ef5178a..65a63a0 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -344,13 +344,21 @@
* {@link #getTimeoutIdleBindMillis() idle timeout} expires.
*/
protected void scheduleUnbind() {
- final long unbindDelay = getTimeoutIdleBindMillis();
+ scheduleUnbind(true);
+ }
- if (unbindDelay <= 0) {
+ private void scheduleUnbind(boolean delay) {
+ long unbindDelay = getTimeoutIdleBindMillis();
+
+ if (unbindDelay <= PERMANENT_BOUND_TIMEOUT_MS) {
if (mVerbose) Slog.v(mTag, "not scheduling unbind when value is " + unbindDelay);
return;
}
+ if (!delay) {
+ unbindDelay = 0;
+ }
+
cancelScheduledUnbind();
// TODO(b/117779333): make sure it's unbound if the service settings changing (right now
// it's not)
@@ -462,9 +470,16 @@
@Override
public void onServiceDisconnected(ComponentName name) {
+ if (mVerbose) Slog.v(mTag, "onServiceDisconnected()");
mBinding = true;
mService = null;
}
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ if (mVerbose) Slog.v(mTag, "onBindingDied()");
+ scheduleUnbind(false);
+ }
}
private boolean checkIfDestroyed() {
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
index 1aef573..b0855f4 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -60,7 +60,7 @@
public static final boolean FW_SYSTEM_USER_SPLIT =
SystemProperties.getBoolean("ro.fw.system_user_split", false);
public static final boolean MULTIUSER_HEADLESS_SYSTEM_USER =
- SystemProperties.getBoolean("ro.fw.multiuser.headless_system_user", true);
+ SystemProperties.getBoolean("ro.fw.multiuser.headless_system_user", false);
// ------ ro.crypto.* -------- //
public static final CryptoProperties.state_values CRYPTO_STATE =
diff --git a/core/res/res/drawable/ic_qs_ui_mode_night.xml b/core/res/res/drawable/ic_qs_ui_mode_night.xml
new file mode 100644
index 0000000..7227827
--- /dev/null
+++ b/core/res/res/drawable/ic_qs_ui_mode_night.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,22C17.52,22 22,17.52 22,12 22,6.48 17.52,2 12,2 6.48,2 2,6.48 2,12 2,17.52 6.48,22 12,22ZM12,3.915c3.889,0 8,4.005 8,8.085 0,4.08 -3.927,7.992 -7.928,7.992z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 58a4c18..58afe33 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2398,9 +2398,14 @@
<!-- Maximum velocity to initiate a fling, as measured in dips per second. -->
<dimen name="config_viewMaxFlingVelocity">8000dp</dimen>
- <!-- Amount of time in ms the user needs to press the relevant key to bring up the global actions dialog -->
+ <!-- Amount of time in ms the user needs to press the relevant key to bring up the
+ global actions dialog -->
<integer name="config_globalActionsKeyTimeout">500</integer>
+ <!-- Amount of time in ms the user needs to press the relevant keys to trigger the
+ screenshot chord -->
+ <integer name="config_screenshotChordKeyTimeout">500</integer>
+
<!-- Default width of a vertical scrollbar and height of a horizontal scrollbar.
Takes effect only if the scrollbar drawables have no intrinsic size. -->
<dimen name="config_scrollbarSize">4dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0304d82..e9ce6ac 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1484,6 +1484,7 @@
<java-symbol type="drawable" name="ic_settings_print" />
<java-symbol type="drawable" name="ic_signal_location" />
<java-symbol type="drawable" name="ic_info_outline_24" />
+ <java-symbol type="drawable" name="ic_qs_ui_mode_night" />
<java-symbol type="drawable" name="stat_notify_mmcc_indication_icn" />
<java-symbol type="drawable" name="autofilled_highlight"/>
@@ -2228,6 +2229,7 @@
<java-symbol type="id" name="button_always" />
<java-symbol type="id" name="button_app_settings" />
<java-symbol type="integer" name="config_globalActionsKeyTimeout" />
+ <java-symbol type="integer" name="config_screenshotChordKeyTimeout" />
<java-symbol type="integer" name="config_maxResolverActivityColumns" />
<java-symbol type="array" name="config_notificationSignalExtractors" />
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 3562a8f..a4337cc8 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -35,6 +35,7 @@
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.MASTER_CLEAR"/>
<permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
+ <permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<permission name="android.permission.OVERRIDE_WIFI_CONFIG"/>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 170dec2..07f81c1 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -763,6 +763,18 @@
}
/**
+ * Utility method to create a hardware backed bitmap using the graphics buffer.
+ * @hide
+ */
+ @Nullable
+ public static Bitmap wrapHardwareBuffer(@NonNull GraphicBuffer graphicBuffer,
+ @Nullable ColorSpace colorSpace) {
+ try (HardwareBuffer hb = HardwareBuffer.createFromGraphicBuffer(graphicBuffer)) {
+ return wrapHardwareBuffer(hb, colorSpace);
+ }
+ }
+
+ /**
* Creates a new bitmap, scaled from an existing bitmap, when possible. If the
* specified width and height are the same as the current width and height of
* the source bitmap, the source bitmap is returned and no new bitmap is
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index c4df274..bd6ce7e 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -22,7 +22,8 @@
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.KeyguardManager;
-import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.BiometricPrompt;
import android.security.GateKeeper;
import android.security.KeyStore;
import android.text.TextUtils;
@@ -670,9 +671,9 @@
}
/**
- * Returns {@code true} if the key is irreversibly invalidated when a new fingerprint is
- * enrolled or all enrolled fingerprints are removed. This has effect only for keys that
- * require fingerprint user authentication for every use.
+ * Returns {@code true} if the key is irreversibly invalidated when a new biometric is
+ * enrolled or all enrolled biometrics are removed. This has effect only for keys that
+ * require biometric user authentication for every use.
*
* @see #isUserAuthenticationRequired()
* @see #getUserAuthenticationValidityDurationSeconds()
@@ -1098,19 +1099,19 @@
* <li>The key can only be generated if secure lock screen is set up (see
* {@link KeyguardManager#isDeviceSecure()}). Additionally, if the key requires that user
* authentication takes place for every use of the key (see
- * {@link #setUserAuthenticationValidityDurationSeconds(int)}), at least one fingerprint
- * must be enrolled (see {@link FingerprintManager#hasEnrolledFingerprints()}).</li>
+ * {@link #setUserAuthenticationValidityDurationSeconds(int)}), at least one biometric
+ * must be enrolled (see {@link BiometricManager#canAuthenticate()}).</li>
* <li>The use of the key must be authorized by the user by authenticating to this Android
* device using a subset of their secure lock screen credentials such as
- * password/PIN/pattern or fingerprint.
+ * password/PIN/pattern or biometric.
* <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
* information</a>.
* <li>The key will become <em>irreversibly invalidated</em> once the secure lock screen is
* disabled (reconfigured to None, Swipe or other mode which does not authenticate the user)
* or when the secure lock screen is forcibly reset (e.g., by a Device Administrator).
* Additionally, if the key requires that user authentication takes place for every use of
- * the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\
- * no more fingerprints are enrolled, unless {@link
+ * the key, it is also irreversibly invalidated once a new biometric is enrolled or once\
+ * no more biometrics are enrolled, unless {@link
* #setInvalidatedByBiometricEnrollment(boolean)} is used to allow validity after
* enrollment. Attempts to initialize cryptographic operations using such keys will throw
* {@link KeyPermanentlyInvalidatedException}.</li>
@@ -1121,7 +1122,7 @@
*
* @see #setUserAuthenticationValidityDurationSeconds(int)
* @see KeyguardManager#isDeviceSecure()
- * @see FingerprintManager#hasEnrolledFingerprints()
+ * @see BiometricManager#canAuthenticate()
*/
@NonNull
public Builder setUserAuthenticationRequired(boolean required) {
@@ -1161,10 +1162,10 @@
* the key.
*
* <p>Cryptographic operations involving keys which require user authentication to take
- * place for every operation can only use fingerprint authentication. This is achieved by
+ * place for every operation can only use biometric authentication. This is achieved by
* initializing a cryptographic operation ({@link Signature}, {@link Cipher}, {@link Mac})
- * with the key, wrapping it into a {@link FingerprintManager.CryptoObject}, invoking
- * {@code FingerprintManager.authenticate} with {@code CryptoObject}, and proceeding with
+ * with the key, wrapping it into a {@link BiometricPrompt.CryptoObject}, invoking
+ * {@code BiometricPrompt.authenticate} with {@code CryptoObject}, and proceeding with
* the cryptographic operation only if the authentication flow succeeds.
*
* <p>Cryptographic operations involving keys which are authorized to be used for a duration
@@ -1183,8 +1184,8 @@
* for every use of the key.
*
* @see #setUserAuthenticationRequired(boolean)
- * @see FingerprintManager
- * @see FingerprintManager.CryptoObject
+ * @see BiometricPrompt
+ * @see BiometricPrompt.CryptoObject
* @see KeyguardManager
*/
@NonNull
@@ -1286,20 +1287,20 @@
}
/**
- * Sets whether this key should be invalidated on fingerprint enrollment. This
+ * Sets whether this key should be invalidated on biometric enrollment. This
* applies only to keys which require user authentication (see {@link
* #setUserAuthenticationRequired(boolean)}) and if no positive validity duration has been
* set (see {@link #setUserAuthenticationValidityDurationSeconds(int)}, meaning the key is
- * valid for fingerprint authentication only.
+ * valid for biometric authentication only.
*
* <p>By default, {@code invalidateKey} is {@code true}, so keys that are valid for
- * fingerprint authentication only are <em>irreversibly invalidated</em> when a new
- * fingerprint is enrolled, or when all existing fingerprints are deleted. That may be
+ * biometric authentication only are <em>irreversibly invalidated</em> when a new
+ * biometric is enrolled, or when all existing biometrics are deleted. That may be
* changed by calling this method with {@code invalidateKey} set to {@code false}.
*
- * <p>Invalidating keys on enrollment of a new finger or unenrollment of all fingers
+ * <p>Invalidating keys on enrollment of a new biometric or unenrollment of all biometrics
* improves security by ensuring that an unauthorized person who obtains the password can't
- * gain the use of fingerprint-authenticated keys by enrolling their own finger. However,
+ * gain the use of biometric-authenticated keys by enrolling their own biometric. However,
* invalidating keys makes key-dependent operations impossible, requiring some fallback
* procedure to authenticate the user and set up a new key.
*/
@@ -1322,7 +1323,7 @@
* Sets whether the keystore requires the screen to be unlocked before allowing decryption
* using this key. If this is set to {@code true}, any attempt to decrypt or sign using this
* key while the screen is locked will fail. A locked device requires a PIN, password,
- * fingerprint, or other trusted factor to access. While the screen is locked, the key can
+ * biometric, or other trusted factor to access. While the screen is locked, the key can
* still be used for encryption or signature verification.
*/
@NonNull
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 3357fdf..26181a6 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -21,12 +21,13 @@
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.app.KeyguardManager;
-import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.BiometricPrompt;
import android.security.GateKeeper;
import java.security.Key;
-import java.security.Signature;
import java.security.KeyStore.ProtectionParameter;
+import java.security.Signature;
import java.security.cert.Certificate;
import java.util.Date;
@@ -479,9 +480,9 @@
}
/**
- * Returns {@code true} if the key is irreversibly invalidated when a new fingerprint is
- * enrolled or all enrolled fingerprints are removed. This has effect only for keys that
- * require fingerprint user authentication for every use.
+ * Returns {@code true} if the key is irreversibly invalidated when a new biometric is
+ * enrolled or all enrolled biometrics are removed. This has effect only for keys that
+ * require biometric user authentication for every use.
*
* @see #isUserAuthenticationRequired()
* @see #getUserAuthenticationValidityDurationSeconds()
@@ -496,7 +497,7 @@
*
* Normally an authentication-bound key is tied to the secure user id of the current user
* (either the root SID from GateKeeper for auth-bound keys with a timeout, or the authenticator
- * id of the current fingerprint set for keys requiring explicit fingerprint authorization).
+ * id of the current biometric set for keys requiring explicit biometric authorization).
* If this parameter is set (this method returning non-zero value), the key should be tied to
* the specified secure user id, overriding the logic above.
*
@@ -762,19 +763,19 @@
* <li>The key can only be import if secure lock screen is set up (see
* {@link KeyguardManager#isDeviceSecure()}). Additionally, if the key requires that user
* authentication takes place for every use of the key (see
- * {@link #setUserAuthenticationValidityDurationSeconds(int)}), at least one fingerprint
- * must be enrolled (see {@link FingerprintManager#hasEnrolledFingerprints()}).</li>
+ * {@link #setUserAuthenticationValidityDurationSeconds(int)}), at least one biometric
+ * must be enrolled (see {@link BiometricManager#canAuthenticate()}).</li>
* <li>The use of the key must be authorized by the user by authenticating to this Android
* device using a subset of their secure lock screen credentials such as
- * password/PIN/pattern or fingerprint.
+ * password/PIN/pattern or biometric.
* <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
* information</a>.
* <li>The key will become <em>irreversibly invalidated</em> once the secure lock screen is
* disabled (reconfigured to None, Swipe or other mode which does not authenticate the user)
* or when the secure lock screen is forcibly reset (e.g., by a Device Administrator).
* Additionally, if the key requires that user authentication takes place for every use of
- * the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\
- * no more fingerprints are enrolled, unless {@link
+ * the key, it is also irreversibly invalidated once a new biometric is enrolled or once\
+ * no more biometrics are enrolled, unless {@link
* #setInvalidatedByBiometricEnrollment(boolean)} is used to allow validity after
* enrollment. Attempts to initialize cryptographic operations using such keys will throw
* {@link KeyPermanentlyInvalidatedException}.</li> </ul>
@@ -784,7 +785,7 @@
*
* @see #setUserAuthenticationValidityDurationSeconds(int)
* @see KeyguardManager#isDeviceSecure()
- * @see FingerprintManager#hasEnrolledFingerprints()
+ * @see BiometricManager#canAuthenticate()
*/
@NonNull
public Builder setUserAuthenticationRequired(boolean required) {
@@ -824,10 +825,10 @@
* the key.
*
* <p>Cryptographic operations involving keys which require user authentication to take
- * place for every operation can only use fingerprint authentication. This is achieved by
+ * place for every operation can only use biometric authentication. This is achieved by
* initializing a cryptographic operation ({@link Signature}, {@link Cipher}, {@link Mac})
- * with the key, wrapping it into a {@link FingerprintManager.CryptoObject}, invoking
- * {@code FingerprintManager.authenticate} with {@code CryptoObject}, and proceeding with
+ * with the key, wrapping it into a {@link BiometricPrompt.CryptoObject}, invoking
+ * {@code BiometricPrompt.authenticate} with {@code CryptoObject}, and proceeding with
* the cryptographic operation only if the authentication flow succeeds.
*
* <p>Cryptographic operations involving keys which are authorized to be used for a duration
@@ -846,8 +847,8 @@
* for every use of the key.
*
* @see #setUserAuthenticationRequired(boolean)
- * @see FingerprintManager
- * @see FingerprintManager.CryptoObject
+ * @see BiometricPrompt
+ * @see BiometricPrompt.CryptoObject
* @see KeyguardManager
*/
@NonNull
@@ -902,20 +903,20 @@
}
/**
- * Sets whether this key should be invalidated on fingerprint enrollment. This
+ * Sets whether this key should be invalidated on biometric enrollment. This
* applies only to keys which require user authentication (see {@link
* #setUserAuthenticationRequired(boolean)}) and if no positive validity duration has been
* set (see {@link #setUserAuthenticationValidityDurationSeconds(int)}, meaning the key is
- * valid for fingerprint authentication only.
+ * valid for biometric authentication only.
*
* <p>By default, {@code invalidateKey} is {@code true}, so keys that are valid for
- * fingerprint authentication only are <em>irreversibly invalidated</em> when a new
- * fingerprint is enrolled, or when all existing fingerprints are deleted. That may be
+ * biometric authentication only are <em>irreversibly invalidated</em> when a new
+ * biometric is enrolled, or when all existing biometrics are deleted. That may be
* changed by calling this method with {@code invalidateKey} set to {@code false}.
*
- * <p>Invalidating keys on enrollment of a new finger or unenrollment of all fingers
+ * <p>Invalidating keys on enrollment of a new biometric or unenrollment of all biometrics
* improves security by ensuring that an unauthorized person who obtains the password can't
- * gain the use of fingerprint-authenticated keys by enrolling their own finger. However,
+ * gain the use of biometric-authenticated keys by enrolling their own biometric. However,
* invalidating keys makes key-dependent operations impossible, requiring some fallback
* procedure to authenticate the user and set up a new key.
*/
@@ -930,7 +931,7 @@
*
* Normally an authentication-bound key is tied to the secure user id of the current user
* (either the root SID from GateKeeper for auth-bound keys with a timeout, or the
- * authenticator id of the current fingerprint set for keys requiring explicit fingerprint
+ * authenticator id of the current biometric set for keys requiring explicit biometric
* authorization). If this parameter is set (this method returning non-zero value), the key
* should be tied to the specified secure user id, overriding the logic above.
*
@@ -964,7 +965,7 @@
* Sets whether the keystore requires the screen to be unlocked before allowing decryption
* using this key. If this is set to {@code true}, any attempt to decrypt or sign using this
* key while the screen is locked will fail. A locked device requires a PIN, password,
- * fingerprint, or other trusted factor to access. While the screen is locked, the key can
+ * biometric, or other trusted factor to access. While the screen is locked, the key can
* still be used for encryption or signature verification.
*/
@NonNull
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index dc5c663..a5a4092 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -1204,6 +1205,7 @@
* @hide
*/
@SystemApi
+ @IntRange(from = 0)
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
Preconditions.checkNotNull(attr, "attr must not be null");
@@ -1224,6 +1226,7 @@
* @hide
*/
@SystemApi
+ @IntRange(from = 0)
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
Preconditions.checkNotNull(attr, "attr must not be null");
@@ -1244,6 +1247,7 @@
* @hide
*/
@SystemApi
+ @IntRange(from = 0)
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
Preconditions.checkNotNull(attr, "attr must not be null");
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index fcf9200..02d826f 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -175,6 +175,9 @@
<!-- Adding Quick Settings tiles -->
<uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
+ <!-- Quick Settings tile: Night Mode / Dark Theme -->
+ <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE" />
+
<!-- Block notifications inline notifications -->
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index d033057..7a43c6d 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -47,6 +47,7 @@
android:layout_height="match_parent"
android:paddingStart="@dimen/status_bar_padding_start"
android:paddingEnd="@dimen/status_bar_padding_end"
+ android:paddingTop="@dimen/status_bar_padding_top"
android:orientation="horizontal"
>
<FrameLayout
diff --git a/packages/SystemUI/res/values-sw372dp/dimens.xml b/packages/SystemUI/res/values-sw372dp/dimens.xml
index 717f18f..e64662e 100644
--- a/packages/SystemUI/res/values-sw372dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw372dp/dimens.xml
@@ -17,6 +17,5 @@
-->
<resources>
<dimen name="nav_content_padding">8dp</dimen>
- <dimen name="rounded_corner_content_padding">8dp</dimen>
<dimen name="qs_header_tile_margin_horizontal">13dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index a067cd2..e02be38 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -114,7 +114,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night
+ wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,dark,saver,work,cast,night
</string>
<!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6dfe701..74924fb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -238,6 +238,9 @@
<!-- the padding on the end of the statusbar -->
<dimen name="status_bar_padding_end">8dp</dimen>
+ <!-- the padding on the top of the statusbar (usually 0) -->
+ <dimen name="status_bar_padding_top">0dp</dimen>
+
<!-- the radius of the overflow dot in the status bar -->
<dimen name="overflow_dot_radius">2dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e098bc5..444cabfc 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -868,6 +868,8 @@
<string name="quick_settings_night_secondary_label_on_at">On at <xliff:g id="time" example="10 pm">%s</xliff:g></string>
<!-- QuickSettings: Secondary text for when the Night Light or some other tile will be on until some user-selected time. [CHAR LIMIT=20] -->
<string name="quick_settings_secondary_label_until">Until <xliff:g id="time" example="7 am">%s</xliff:g></string>
+ <!-- QuickSettings: Label for the toggle to activate Dark theme (A.K.A Dark Mode). [CHAR LIMIT=20] -->
+ <string name="quick_settings_ui_mode_night_label">Dark Theme</string>
<!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] -->
<string name="quick_settings_nfc_label">NFC</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index 1413ac1..98a8110 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -23,7 +23,6 @@
import android.app.ActivityManager.TaskSnapshot;
import android.graphics.Bitmap;
import android.graphics.Rect;
-import android.hardware.HardwareBuffer;
/**
* Data for a single thumbnail.
@@ -53,9 +52,7 @@
}
public ThumbnailData(TaskSnapshot snapshot) {
- thumbnail = Bitmap.wrapHardwareBuffer(
- HardwareBuffer.createFromGraphicBuffer(snapshot.getSnapshot()),
- snapshot.getColorSpace());
+ thumbnail = Bitmap.wrapHardwareBuffer(snapshot.getSnapshot(), snapshot.getColorSpace());
insets = new Rect(snapshot.getContentInsets());
orientation = snapshot.getOrientation();
reducedResolution = snapshot.isReducedResolution();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 89abd35..93effed 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -356,8 +356,10 @@
ensureStackViewCreated();
mStackView.addBubble(notif);
}
+ Bubble bubble = mBubbleData.getBubble(notif.key);
if (shouldAutoExpand(notif)) {
- mStackView.setExpandedBubble(notif);
+ mStackView.setSelectedBubble(bubble);
+ mStackView.setExpanded(true);
}
updateVisibility();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 53e65e6..1f1a3e4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -441,40 +441,15 @@
* Sets the bubble that should be expanded and expands if needed.
*
* @param key the {@link NotificationEntry#key} associated with the bubble to expand.
+ * @deprecated replaced by setSelectedBubble(Bubble) + setExpanded(true)
*/
+ @Deprecated
void setExpandedBubble(String key) {
Bubble bubbleToExpand = mBubbleData.getBubble(key);
- if (mIsExpanded && !bubbleToExpand.equals(mExpandedBubble)) {
- // Previously expanded, notify that this bubble is no longer expanded
- notifyExpansionChanged(mExpandedBubble.entry, false /* expanded */);
- }
- Bubble prevBubble = mExpandedBubble;
- mExpandedBubble = bubbleToExpand;
- if (!mIsExpanded) {
- // If we weren't previously expanded we should animate open.
- animateExpansion(true /* expand */);
- logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
- mExpandedBubble.entry.setShowInShadeWhenBubble(false);
- notifyExpansionChanged(mExpandedBubble.entry, true /* expanded */);
- } else {
- // Make the container of the expanded view transparent before removing the expanded view
- // from it. Otherwise a punch hole created by {@link android.view.SurfaceView} in the
- // expanded view becomes visible on the screen. See b/126856255
- mExpandedViewContainer.setAlpha(0.0f);
-
- mSurfaceSynchronizer.syncSurfaceAndRun(new Runnable() {
- @Override
- public void run() {
- updateExpandedBubble();
- updatePointerPosition();
- requestUpdate();
- logBubbleEvent(prevBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
- logBubbleEvent(mExpandedBubble,
- StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
- mExpandedBubble.entry.setShowInShadeWhenBubble(false);
- notifyExpansionChanged(mExpandedBubble.entry, true /* expanded */);
- }
- });
+ if (bubbleToExpand != null) {
+ setSelectedBubble(bubbleToExpand);
+ bubbleToExpand.entry.setShowInShadeWhenBubble(false);
+ setExpanded(true);
}
}
@@ -492,6 +467,57 @@
}
/**
+ * Changes the currently selected bubble. If the stack is already expanded, the newly selected
+ * bubble will be shown immediately. This does not change the expanded state or change the
+ * position of any bubble.
+ */
+ public void setSelectedBubble(Bubble bubbleToSelect) {
+ if (mExpandedBubble != null && mExpandedBubble.equals(bubbleToSelect)) {
+ return;
+ }
+ final Bubble previouslySelected = mExpandedBubble;
+ mExpandedBubble = bubbleToSelect;
+ if (mIsExpanded) {
+ // Make the container of the expanded view transparent before removing the expanded view
+ // from it. Otherwise a punch hole created by {@link android.view.SurfaceView} in the
+ // expanded view becomes visible on the screen. See b/126856255
+ mExpandedViewContainer.setAlpha(0.0f);
+ mSurfaceSynchronizer.syncSurfaceAndRun(() -> {
+ updateExpandedBubble();
+ updatePointerPosition();
+ requestUpdate();
+ logBubbleEvent(previouslySelected, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
+ logBubbleEvent(bubbleToSelect, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
+ notifyExpansionChanged(previouslySelected.entry, false /* expanded */);
+ notifyExpansionChanged(bubbleToSelect.entry, true /* expanded */);
+ });
+ }
+ }
+
+ /**
+ * Changes the expanded state of the stack.
+ *
+ * @param expanded whether the bubble stack should appear expanded
+ */
+ public void setExpanded(boolean expanded) {
+ if (expanded == mIsExpanded) {
+ return;
+ }
+ if (mIsExpanded) {
+ // Collapse the stack
+ animateExpansion(false /* expand */);
+ logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
+ } else {
+ // Expand the stack
+ animateExpansion(true /* expand */);
+ // TODO: move next line to BubbleData
+ logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
+ logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED);
+ }
+ notifyExpansionChanged(mExpandedBubble.entry, mIsExpanded);
+ }
+
+ /**
* Adds a bubble to the top of the stack.
*
* @param entry the notification to add to the stack of bubbles.
@@ -652,7 +678,10 @@
* Collapses the stack of bubbles.
* <p>
* Must be called from the main thread.
+ *
+ * @deprecated use {@link #setExpanded(boolean)} and {@link #setSelectedBubble(Bubble)}
*/
+ @Deprecated
@MainThread
public void collapseStack() {
if (mIsExpanded) {
@@ -663,6 +692,11 @@
}
}
+ /**
+ * @deprecated use {@link #setExpanded(boolean)} and {@link #setSelectedBubble(Bubble)}
+ */
+ @Deprecated
+ @MainThread
void collapseStack(Runnable endRunnable) {
collapseStack();
// TODO - use the runnable at end of animation
@@ -673,7 +707,10 @@
* Expands the stack of bubbles.
* <p>
* Must be called from the main thread.
+ *
+ * @deprecated use {@link #setExpanded(boolean)} and {@link #setSelectedBubble(Bubble)}
*/
+ @Deprecated
@MainThread
public void expandStack() {
if (!mIsExpanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 2956ad0..daaee4c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -41,6 +41,7 @@
import com.android.systemui.qs.tiles.NfcTile;
import com.android.systemui.qs.tiles.NightDisplayTile;
import com.android.systemui.qs.tiles.RotationLockTile;
+import com.android.systemui.qs.tiles.UiModeNightTile;
import com.android.systemui.qs.tiles.UserTile;
import com.android.systemui.qs.tiles.WifiTile;
import com.android.systemui.qs.tiles.WorkModeTile;
@@ -73,6 +74,7 @@
private final Provider<NightDisplayTile> mNightDisplayTileProvider;
private final Provider<NfcTile> mNfcTileProvider;
private final Provider<GarbageMonitor.MemoryTile> mMemoryTileProvider;
+ private final Provider<UiModeNightTile> mUiModeNightTileProvider;
private QSTileHost mHost;
@@ -94,7 +96,8 @@
Provider<DataSaverTile> dataSaverTileProvider,
Provider<NightDisplayTile> nightDisplayTileProvider,
Provider<NfcTile> nfcTileProvider,
- Provider<GarbageMonitor.MemoryTile> memoryTileProvider) {
+ Provider<GarbageMonitor.MemoryTile> memoryTileProvider,
+ Provider<UiModeNightTile> uiModeNightTileProvider) {
mWifiTileProvider = wifiTileProvider;
mBluetoothTileProvider = bluetoothTileProvider;
mCellularTileProvider = cellularTileProvider;
@@ -113,6 +116,7 @@
mNightDisplayTileProvider = nightDisplayTileProvider;
mNfcTileProvider = nfcTileProvider;
mMemoryTileProvider = memoryTileProvider;
+ mUiModeNightTileProvider = uiModeNightTileProvider;
}
public void setHost(QSTileHost host) {
@@ -164,6 +168,8 @@
return mNightDisplayTileProvider.get();
case "nfc":
return mNfcTileProvider.get();
+ case "dark":
+ return mUiModeNightTileProvider.get();
}
// Intent tiles.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 38962eb..20e002e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -25,6 +25,7 @@
import android.content.res.Resources;
import android.provider.Settings;
import android.service.quicksettings.Tile;
+import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -285,7 +286,13 @@
}
static Intent getCellularSettingIntent() {
- return new Intent(Settings.ACTION_DATA_USAGE_SETTINGS);
+ Intent intent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS);
+ int dataSub = SubscriptionManager.getDefaultDataSubscriptionId();
+ if (dataSub != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ intent.putExtra(Settings.EXTRA_SUB_ID,
+ SubscriptionManager.getDefaultDataSubscriptionId());
+ }
+ return intent;
}
private final class CellularDetailAdapter implements DetailAdapter {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index c6c6f87..79996bc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -16,6 +16,7 @@
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
+import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.widget.Switch;
@@ -54,7 +55,7 @@
@Override
public Intent getLongClickIntent() {
- return CellularTile.getCellularSettingIntent();
+ return new Intent(Settings.ACTION_DATA_SAVER_SETTINGS);
}
@Override
protected void handleClick() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
new file mode 100644
index 0000000..8d2f895
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.app.UiModeManager;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.provider.Settings;
+import android.service.quicksettings.Tile;
+import android.widget.Switch;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+
+import javax.inject.Inject;
+
+/**
+ * Quick Settings tile for: Night Mode / Dark Theme / Dark Mode.
+ *
+ * The string id of this tile is "dark" because "night" was already
+ * taken by {@link NightDisplayTile}.
+ */
+public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements
+ ConfigurationController.ConfigurationListener {
+
+ private final Icon mIcon = ResourceIcon.get(
+ com.android.internal.R.drawable.ic_qs_ui_mode_night);
+ private UiModeManager mUiModeManager;
+
+ @Inject
+ public UiModeNightTile(QSHost host, ConfigurationController configurationController) {
+ super(host);
+ mUiModeManager = mContext.getSystemService(UiModeManager.class);
+ configurationController.observe(getLifecycle(), this);
+ }
+
+ @Override
+ public void onUiModeChanged() {
+ refreshState();
+ }
+
+ @Override
+ public BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ protected void handleClick() {
+ boolean newState = !mState.value;
+ mUiModeManager.setNightMode(newState ? UiModeManager.MODE_NIGHT_YES
+ : UiModeManager.MODE_NIGHT_NO);
+ refreshState(newState);
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ boolean nightMode = (mContext.getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+
+ state.value = nightMode;
+ state.label = mContext.getString(R.string.quick_settings_ui_mode_night_label);
+ state.contentDescription = state.label;
+ state.icon = mIcon;
+ state.expandedAccessibilityClassName = Switch.class.getName();
+ state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsProto.MetricsEvent.QS_UI_MODE_NIGHT;
+ }
+
+ @Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_DISPLAY_SETTINGS);
+ }
+
+ @Override
+ protected void handleSetListening(boolean listening) {
+ }
+
+ @Override
+ public CharSequence getTileLabel() {
+ return getState().label;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 8f135c8..11e5625 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -75,7 +75,8 @@
private SignalStrength mSignalStrength;
private MobileIconGroup mDefaultIcons;
private Config mConfig;
- private boolean mInflateSignalStrengths = false;
+ @VisibleForTesting
+ boolean mInflateSignalStrengths = false;
// Some specific carriers have 5GE network which is special LTE CA network.
private static final int NETWORK_TYPE_LTE_CA_5GE = TelephonyManager.MAX_NETWORK_TYPE + 1;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 4fe18b4..ce5bfce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -428,8 +428,12 @@
IconState iconState = iconArg.getValue();
- int state = SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS,
- cutOut);
+ int numSignalStrengthBins = SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
+ if (mMobileSignalController.mInflateSignalStrengths) {
+ numSignalStrengthBins++;
+ icon++;
+ }
+ int state = SignalDrawable.getState(icon, numSignalStrengthBins, cutOut);
assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
assertEquals("Signal icon in status bar", state, iconState.icon);
assertEquals("Visibility in status bar", visible, iconState.visible);
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index a88ae9e..3babb6d 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7175,6 +7175,13 @@
// Salt generation for the above hashed direct share target
FIELD_HASHED_TARGET_SALT_GEN = 1705;
+ // OPEN: QS dark theme tile shown
+ // ACTION: QS dark theme tile tapped
+ // SUBTYPE: 0 is off, 1 is on
+ // CATEGORY: QUICK_SETTINGS
+ // OS: Q
+ QS_UI_MODE_NIGHT = 1706;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index e64ab78..6f2df3f 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -60,6 +60,7 @@
@NonNull private static final String TAG = TestNetworkService.class.getSimpleName();
@NonNull private static final String TEST_NETWORK_TYPE = "TEST_NETWORK";
@NonNull private static final String TEST_TUN_PREFIX = "testtun";
+ @NonNull private static final String TEST_TAP_PREFIX = "testtap";
@NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
@NonNull private final Context mContext;
@@ -70,7 +71,7 @@
@NonNull private final Handler mHandler;
// Native method stubs
- private static native int jniCreateTun(@NonNull String iface);
+ private static native int jniCreateTunTap(boolean isTun, @NonNull String iface);
@VisibleForTesting
protected TestNetworkService(
@@ -85,23 +86,23 @@
}
/**
- * Create a TUN interface with the given interface name and link addresses
+ * Create a TUN or TAP interface with the given interface name and link addresses
*
- * <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the
- * TUN interface.
+ * <p>This method will return the FileDescriptor to the interface. Close it to tear down the
+ * interface.
*/
- @Override
- public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
+ private TestNetworkInterface createInterface(boolean isTun, LinkAddress[] linkAddrs) {
enforceTestNetworkPermissions(mContext);
checkNotNull(linkAddrs, "missing linkAddrs");
- String iface = TEST_TUN_PREFIX + sTestTunIndex.getAndIncrement();
+ String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX;
+ String iface = ifacePrefix + sTestTunIndex.getAndIncrement();
return Binder.withCleanCallingIdentity(
() -> {
try {
ParcelFileDescriptor tunIntf =
- ParcelFileDescriptor.adoptFd(jniCreateTun(iface));
+ ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface));
for (LinkAddress addr : linkAddrs) {
mNetd.interfaceAddAddress(
iface,
@@ -116,6 +117,28 @@
});
}
+ /**
+ * Create a TUN interface with the given interface name and link addresses
+ *
+ * <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the
+ * TUN interface.
+ */
+ @Override
+ public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
+ return createInterface(true, linkAddrs);
+ }
+
+ /**
+ * Create a TAP interface with the given interface name
+ *
+ * <p>This method will return the FileDescriptor to the TAP interface. Close it to tear down the
+ * TAP interface.
+ */
+ @Override
+ public TestNetworkInterface createTapInterface() {
+ return createInterface(false, new LinkAddress[0]);
+ }
+
// Tracker for TestNetworkAgents
@GuardedBy("mTestNetworkTracker")
@NonNull
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index f1f40d4..9780a7f 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -62,6 +62,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.GraphicsEnvironment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -703,6 +704,13 @@
return prefix + "+" + Integer.toString(diff);
}
+ private static boolean shouldUseSystemGraphicsDriver(Context context, Bundle coreSettings,
+ ApplicationInfo applicationInfo) {
+ final boolean shouldUseGameDriver =
+ GraphicsEnvironment.shouldUseGameDriver(context, coreSettings, applicationInfo);
+ return !shouldUseGameDriver;
+ }
+
public static String makeOomAdjString(int setAdj, boolean compact) {
if (setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
return buildOomTag("cch", "cch", " ", setAdj,
@@ -1783,6 +1791,8 @@
final StorageManagerInternal storageManagerInternal =
LocalServices.getService(StorageManagerInternal.class);
final String sandboxId = storageManagerInternal.getSandboxId(app.info.packageName);
+ final boolean useSystemGraphicsDriver = shouldUseSystemGraphicsDriver(mService.mContext,
+ mService.mCoreSettingsObserver.getCoreSettingsLocked(), app.info);
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkSlow(startTime, "startProcess: asking zygote to start proc");
@@ -1793,7 +1803,8 @@
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
packageNames, sandboxId,
- new String[] {PROC_START_SEQ_IDENT + app.startSeq});
+ new String[] {PROC_START_SEQ_IDENT + app.startSeq},
+ useSystemGraphicsDriver);
} else if (hostingType.equals("app_zygote")) {
final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
@@ -1802,14 +1813,16 @@
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
packageNames, sandboxId, /*useUnspecializedAppProcessPool=*/ false,
- new String[] {PROC_START_SEQ_IDENT + app.startSeq});
+ new String[] {PROC_START_SEQ_IDENT + app.startSeq},
+ useSystemGraphicsDriver);
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName,
packageNames, sandboxId,
- new String[] {PROC_START_SEQ_IDENT + app.startSeq});
+ new String[] {PROC_START_SEQ_IDENT + app.startSeq},
+ useSystemGraphicsDriver);
}
checkSlow(startTime, "startProcess: returned from zygote!");
return startResult;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index a935c65..74fb4b2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -841,6 +841,11 @@
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
+ if (hasParentSessionId()) {
+ throw new IllegalStateException(
+ "Session " + sessionId + " is a child of multi-package session "
+ + mParentSessionId + " and may not be committed directly.");
+ }
if (!markAsCommitted(statusReceiver, forTransfer)) {
return;
}
@@ -2037,6 +2042,11 @@
@Override
public void abandon() {
+ if (hasParentSessionId()) {
+ throw new IllegalStateException(
+ "Session " + sessionId + " is a child of multi-package session "
+ + mParentSessionId + " and may not be abandoned directly.");
+ }
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
@@ -2079,13 +2089,14 @@
}
@Override
- public void addChildSessionId(int childSessionId) throws RemoteException {
+ public void addChildSessionId(int childSessionId) {
final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId);
- if (childSession == null) {
- throw new RemoteException("Unable to add child.",
- new PackageManagerException("Child session " + childSessionId
- + " does not exist"),
- false, true).rethrowAsRuntimeException();
+ if (childSession == null
+ || (childSession.hasParentSessionId() && childSession.mParentSessionId != sessionId)
+ || childSession.mCommitted
+ || childSession.mDestroyed) {
+ throw new IllegalStateException("Unable to add child session " + childSessionId
+ + " as it does not exist or is in an invalid state.");
}
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
@@ -2124,11 +2135,8 @@
synchronized (mLock) {
if (parentSessionId != SessionInfo.INVALID_ID
&& mParentSessionId != SessionInfo.INVALID_ID) {
- throw new RemoteException("Unable to set parent session.",
- new PackageManagerException(
- "The parent of " + sessionId + " is" + " already set to "
- + mParentSessionId), false,
- true).rethrowAsRuntimeException();
+ throw new IllegalStateException("The parent of " + sessionId + " is" + " already"
+ + "set to " + mParentSessionId);
}
this.mParentSessionId = parentSessionId;
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 1908b3f..72d5438 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -487,7 +487,7 @@
}
try {
apkParentSession.addChildSessionId(apkChildSession.sessionId);
- } catch (RemoteException e) {
+ } catch (IllegalStateException e) {
Slog.e(TAG, "Failed to add a child session for installing the APK files", e);
return false;
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 35fa940..108eaf6 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -108,7 +108,10 @@
@PackageManager.PackageInfoFlags
private static final int DEFAULT_PACKAGE_INFO_QUERY_FLAGS =
- PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS;
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+ | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+ | PackageManager.GET_PERMISSIONS;
private static final String AUDIO_MIME_TYPE = "audio/mpeg";
@@ -1353,8 +1356,7 @@
}
private PackageInfo getSystemPackageInfo(String pkg) {
- //TODO not MATCH_SYSTEM_ONLY?
- return getPackageInfo(pkg, PackageManager.MATCH_FACTORY_ONLY);
+ return getPackageInfo(pkg, PackageManager.MATCH_SYSTEM_ONLY);
}
private PackageInfo getPackageInfo(String pkg) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index c75a462..dd63e3c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -18,12 +18,6 @@
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
-import static android.app.AppOpsManager.MODE_ALLOWED;
-import static android.app.AppOpsManager.MODE_ERRORED;
-import static android.app.AppOpsManager.MODE_FOREGROUND;
-import static android.app.AppOpsManager.OP_NONE;
-import static android.app.AppOpsManager.permissionToOp;
-import static android.app.AppOpsManager.permissionToOpCode;
import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
@@ -40,8 +34,6 @@
import static android.content.pm.PackageManager.MASK_PERMISSION_FLAGS_ALL;
import static android.content.pm.PackageManager.RESTRICTED_PERMISSIONS_ENABLED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-import static android.os.UserHandle.getAppId;
-import static android.os.UserHandle.getUid;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
@@ -56,8 +48,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.app.AppOpsManager;
-import android.app.AppOpsManagerInternal;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.PermissionWhitelistFlags;
@@ -1309,9 +1299,6 @@
updatedUserIds);
updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
permissionsState, pkg, updatedUserIds);
-
- // TODO: Move to PermissionPolicyService
- setAppOpsLocked(permissionsState, pkg);
}
// Persist the runtime permissions state for users with changes. If permissions
@@ -1327,23 +1314,6 @@
}
/**
- * Set app op for a app-op related to a permission.
- *
- * @param permission The permission the app-op belongs to
- * @param pkg The package the permission belongs to
- * @param userId The user to be changed
- * @param mode The new mode to set
- */
- private void setAppOpMode(@NonNull String permission, @NonNull PackageParser.Package pkg,
- @UserIdInt int userId, int mode) {
- AppOpsManagerInternal appOpsInternal = LocalServices.getService(
- AppOpsManagerInternal.class);
-
- appOpsInternal.setUidMode(permissionToOpCode(permission),
- getUid(userId, getAppId(pkg.applicationInfo.uid)), mode);
- }
-
- /**
* Revoke permissions that are not implicit anymore and that have
* {@link PackageManager#FLAG_PERMISSION_REVOKE_WHEN_REQUESTED} set.
*
@@ -1357,8 +1327,6 @@
private @NonNull int[] revokePermissionsNoLongerImplicitLocked(
@NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
@NonNull int[] updatedUserIds) {
- AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
-
String pkgName = pkg.packageName;
boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
>= Build.VERSION_CODES.M;
@@ -1390,23 +1358,6 @@
}
flagsToRemove |= USER_PERMISSION_FLAGS;
-
- List<String> fgPerms = mBackgroundPermissions.get(permission);
- if (fgPerms != null) {
- int numFgPerms = fgPerms.size();
- for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
- String fgPerm = fgPerms.get(fgPermNum);
-
- int mode = appOpsManager.unsafeCheckOpRaw(
- permissionToOp(fgPerm),
- getUid(userId, getAppId(pkg.applicationInfo.uid)),
- pkgName);
-
- if (mode == MODE_ALLOWED) {
- setAppOpMode(fgPerm, pkg, userId, MODE_FOREGROUND);
- }
- }
- }
}
ps.updatePermissionFlags(bp, userId, flagsToRemove, 0);
@@ -1438,91 +1389,39 @@
@NonNull ArraySet<String> sourcePerms, @NonNull String newPerm,
@NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
@UserIdInt int userId) {
- AppOpsManagerInternal appOpsManager = LocalServices.getService(AppOpsManagerInternal.class);
String pkgName = pkg.packageName;
+ boolean isGranted = false;
+ int flags = 0;
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
- if (permissionToOp(newPerm) != null) {
- int mostLenientSourceMode = MODE_ERRORED;
- int flags = 0;
-
- // Find most lenient source permission state.
- int numSourcePerms = sourcePerms.size();
- for (int i = 0; i < numSourcePerms; i++) {
- String sourcePerm = sourcePerms.valueAt(i);
-
- if (ps.hasRuntimePermission(sourcePerm, userId)) {
- int sourceOp = permissionToOpCode(sourcePerm);
-
- if (sourceOp != OP_NONE) {
- int mode = appOpsManager.checkOperationUnchecked(sourceOp,
- getUid(userId, getAppId(pkg.applicationInfo.uid)), pkgName);
-
- if (mode == MODE_FOREGROUND || mode == MODE_ERRORED) {
- Log.wtf(TAG, "split permission" + sourcePerm + " has app-op state "
- + AppOpsManager.MODE_NAMES[mode]);
-
- continue;
- }
-
- // Leniency order: allowed < ignored < default
- if (mode < mostLenientSourceMode) {
- mostLenientSourceMode = mode;
- flags = ps.getPermissionFlags(sourcePerm, userId);
- } else if (mode == mostLenientSourceMode) {
- flags |= ps.getPermissionFlags(sourcePerm, userId);
- }
- }
- }
+ int numSourcePerm = sourcePerms.size();
+ for (int i = 0; i < numSourcePerm; i++) {
+ String sourcePerm = sourcePerms.valueAt(i);
+ if ((ps.hasRuntimePermission(sourcePerm, userId))
+ || ps.hasInstallPermission(sourcePerm)) {
+ if (!isGranted) {
+ flags = 0;
}
- if (mostLenientSourceMode != MODE_ERRORED) {
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, newPerm + " inherits app-ops state " + mostLenientSourceMode
- + " from " + sourcePerms + " for " + pkgName);
- }
-
- setAppOpMode(newPerm, pkg, userId, mostLenientSourceMode);
-
- // Add permission flags
- ps.updatePermissionFlags(mSettings.getPermission(newPerm), userId, flags,
- flags);
- }
- }
- } else {
- boolean isGranted = false;
- int flags = 0;
-
- int numSourcePerm = sourcePerms.size();
- for (int i = 0; i < numSourcePerm; i++) {
- String sourcePerm = sourcePerms.valueAt(i);
- if ((ps.hasRuntimePermission(sourcePerm, userId))
- || ps.hasInstallPermission(sourcePerm)) {
- if (!isGranted) {
- flags = 0;
- }
-
- isGranted = true;
+ isGranted = true;
+ flags |= ps.getPermissionFlags(sourcePerm, userId);
+ } else {
+ if (!isGranted) {
flags |= ps.getPermissionFlags(sourcePerm, userId);
- } else {
- if (!isGranted) {
- flags |= ps.getPermissionFlags(sourcePerm, userId);
- }
}
}
-
- if (isGranted) {
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, newPerm + " inherits runtime perm grant from " + sourcePerms
- + " for " + pkgName);
- }
-
- ps.grantRuntimePermission(mSettings.getPermissionLocked(newPerm), userId);
- }
-
- // Add permission flags
- ps.updatePermissionFlags(mSettings.getPermission(newPerm), userId, flags, flags);
}
+
+ if (isGranted) {
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, newPerm + " inherits runtime perm grant from " + sourcePerms
+ + " for " + pkgName);
+ }
+
+ ps.grantRuntimePermission(mSettings.getPermissionLocked(newPerm), userId);
+ }
+
+ // Add permission flags
+ ps.updatePermissionFlags(mSettings.getPermission(newPerm), userId, flags, flags);
}
/**
@@ -1632,48 +1531,6 @@
return updatedUserIds;
}
- /**
- * Fix app-op modes for runtime permissions.
- *
- * @param permsState The state of the permissions of the package
- * @param pkg The package information
- */
- private void setAppOpsLocked(@NonNull PermissionsState permsState,
- @NonNull PackageParser.Package pkg) {
- for (int userId : UserManagerService.getInstance().getUserIds()) {
- int numPerms = pkg.requestedPermissions.size();
- for (int i = 0; i < numPerms; i++) {
- String permission = pkg.requestedPermissions.get(i);
-
- // For pre-M apps the runtime permission do not store the state
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
- continue;
- }
-
- PermissionState state = permsState.getRuntimePermissionState(permission, userId);
- if (state == null) {
- continue;
- }
-
- // Adjust app-op mods for foreground/background permissions. If an package used to
- // have both fg and bg permission granted and it lost the bg permission during an
- // upgrade the app-op mode should get downgraded to foreground.
- if (state.isGranted()) {
- BasePermission bp = mSettings.getPermission(permission);
-
- if (bp != null && bp.perm != null && bp.perm.info != null
- && bp.perm.info.backgroundPermission != null) {
- PermissionState bgState = permsState.getRuntimePermissionState(
- bp.perm.info.backgroundPermission, userId);
-
- setAppOpMode(permission, pkg, userId, bgState != null && bgState.isGranted()
- ? MODE_ALLOWED : MODE_FOREGROUND);
- }
- }
- }
- }
- }
-
private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
boolean allowed = false;
final int NP = PackageParser.NEW_PERMISSIONS.length;
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 67f30dc..1fd8b71 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -17,8 +17,10 @@
package com.android.server.policy;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.content.Context;
@@ -29,6 +31,7 @@
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PackageParser;
import android.content.pm.PermissionInfo;
+import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
import android.permission.PermissionControllerManager;
@@ -158,37 +161,59 @@
});
}
+ private static @Nullable Context getUserContext(@NonNull Context context,
+ @NonNull UserHandle user) {
+ if (context.getUser().equals(user)) {
+ return context;
+ } else {
+ try {
+ return context.createPackageContextAsUser(context.getPackageName(), 0, user);
+ } catch (NameNotFoundException e) {
+ Slog.e(LOG_TAG, "Cannot create context for user " + user, e);
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Synchronize a single package.
+ */
private static void synchronizePackagePermissionsAndAppOpsForUser(@NonNull Context context,
@NonNull String packageName, @UserIdInt int userId) {
final PackageManagerInternal packageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
- final PackageParser.Package pkg = packageManagerInternal.getPackage(packageName);
+ final PackageInfo pkg = packageManagerInternal.getPackageInfo(packageName, 0,
+ Process.SYSTEM_UID, userId);
if (pkg == null) {
return;
}
- final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(context);
- synchroniser.addPackage(context, pkg, userId);
+ final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(
+ getUserContext(context, UserHandle.of(userId)));
+ synchroniser.addPackage(pkg.packageName);
final String[] sharedPkgNames = packageManagerInternal.getPackagesForSharedUserId(
- pkg.mSharedUserId, userId);
+ pkg.sharedUserId, userId);
if (sharedPkgNames != null) {
for (String sharedPkgName : sharedPkgNames) {
final PackageParser.Package sharedPkg = packageManagerInternal
.getPackage(sharedPkgName);
if (sharedPkg != null) {
- synchroniser.addPackage(context, sharedPkg, userId);
+ synchroniser.addPackage(sharedPkg.packageName);
}
}
}
synchroniser.syncPackages();
}
+ /**
+ * Synchronize all packages
+ */
private static void synchronizePermissionsAndAppOpsForUser(@NonNull Context context,
@UserIdInt int userId) {
final PackageManagerInternal packageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
- final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(context);
- packageManagerInternal.forEachPackage((pkg) ->
- synchronizer.addPackage(context, pkg, userId));
+ final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(
+ getUserContext(context, UserHandle.of(userId)));
+ packageManagerInternal.forEachPackage((pkg) -> synchronizer.addPackage(pkg.packageName));
synchronizer.syncPackages();
}
@@ -198,17 +223,47 @@
*/
private static class PermissionToOpSynchroniser {
private final @NonNull Context mContext;
+ private final @NonNull PackageManager mPackageManager;
+ private final @NonNull AppOpsManager mAppOpsManager;
- private final @NonNull SparseIntArray mUids = new SparseIntArray();
- private final @NonNull SparseArray<String> mPackageNames = new SparseArray<>();
- private final @NonNull SparseIntArray mAllowedUidOps = new SparseIntArray();
- private final @NonNull SparseIntArray mDefaultUidOps = new SparseIntArray();
+ /** All uid that need to be synchronized */
+ private final @NonNull SparseIntArray mAllUids = new SparseIntArray();
+
+ /**
+ * All ops that need to be restricted
+ *
+ * @see #syncRestrictedOps
+ */
+ private final @NonNull ArrayList<OpToRestrict> mOpsToRestrict = new ArrayList<>();
+
+ /**
+ * All ops that need to be unrestricted
+ *
+ * @see #syncRestrictedOps
+ */
+ private final @NonNull ArrayList<OpToUnrestrict> mOpsToUnrestrict = new ArrayList<>();
+
+ /**
+ * All foreground permissions
+ *
+ * @see #syncOpsOfFgPermissions()
+ */
+ private final @NonNull ArrayList<FgPermission> mFgPermOps = new ArrayList<>();
PermissionToOpSynchroniser(@NonNull Context context) {
mContext = context;
+ mPackageManager = context.getPackageManager();
+ mAppOpsManager = context.getSystemService(AppOpsManager.class);
}
- void syncPackages() {
+ /**
+ * Set app ops that belong to restricted permissions.
+ *
+ * <p>This processes ops previously added by {@link #addOpIfRestricted}
+ */
+ private void syncRestrictedOps() {
+ final SparseIntArray unprocessedUids = mAllUids.clone();
+
// TRICKY: we set the app op for a restricted permission to allow if the app
// requesting the permission is whitelisted and to deny if the app requesting
// the permission is not whitelisted. However, there is another case where an
@@ -222,52 +277,48 @@
final SparseArray<List<String>> unrequestedRestrictedPermissionsForUid =
new SparseArray<>();
- final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
- final int allowedCount = mAllowedUidOps.size();
- for (int i = 0; i < allowedCount; i++) {
- final int opCode = mAllowedUidOps.keyAt(i);
- final int uid = mAllowedUidOps.valueAt(i);
- final String packageName = mPackageNames.valueAt(i);
- setUidModeAllowed(appOpsManager, opCode, uid, packageName);
+ final int unrestrictCount = mOpsToUnrestrict.size();
+ for (int i = 0; i < unrestrictCount; i++) {
+ final OpToUnrestrict op = mOpsToUnrestrict.get(i);
+ setUidModeAllowed(op.code, op.uid, op.packageName);
// Keep track this permission was requested by the UID.
List<String> unrequestedRestrictedPermissions =
- unrequestedRestrictedPermissionsForUid.get(uid);
+ unrequestedRestrictedPermissionsForUid.get(op.uid);
if (unrequestedRestrictedPermissions == null) {
unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions);
- unrequestedRestrictedPermissionsForUid.put(uid,
+ unrequestedRestrictedPermissionsForUid.put(op.uid,
unrequestedRestrictedPermissions);
}
- unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(opCode));
+ unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code));
- mUids.delete(uid);
+ unprocessedUids.delete(op.uid);
}
- final int defaultCount = mDefaultUidOps.size();
- for (int i = 0; i < defaultCount; i++) {
- final int opCode = mDefaultUidOps.keyAt(i);
- final int uid = mDefaultUidOps.valueAt(i);
- setUidModeDefault(appOpsManager, opCode, uid);
+ final int restrictCount = mOpsToRestrict.size();
+ for (int i = 0; i < restrictCount; i++) {
+ final OpToRestrict op = mOpsToRestrict.get(i);
+ setUidModeDefault(op.code, op.uid);
// Keep track this permission was requested by the UID.
List<String> unrequestedRestrictedPermissions =
- unrequestedRestrictedPermissionsForUid.get(uid);
+ unrequestedRestrictedPermissionsForUid.get(op.uid);
if (unrequestedRestrictedPermissions == null) {
unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions);
- unrequestedRestrictedPermissionsForUid.put(uid,
+ unrequestedRestrictedPermissionsForUid.put(op.uid,
unrequestedRestrictedPermissions);
}
- unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(opCode));
+ unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code));
- mUids.delete(uid);
+ unprocessedUids.delete(op.uid);
}
// Give root access
- mUids.put(Process.ROOT_UID, Process.ROOT_UID);
+ unprocessedUids.put(Process.ROOT_UID, Process.ROOT_UID);
// Add records for UIDs that don't use any restricted permissions.
- final int uidCount = mUids.size();
+ final int uidCount = unprocessedUids.size();
for (int i = 0; i < uidCount; i++) {
- final int uid = mUids.keyAt(i);
+ final int uid = unprocessedUids.keyAt(i);
unrequestedRestrictedPermissionsForUid.put(uid,
new ArrayList<>(sAllRestrictedPermissions));
}
@@ -280,7 +331,7 @@
if (unrequestedRestrictedPermissions != null) {
final int uid = unrequestedRestrictedPermissionsForUid.keyAt(i);
final String[] packageNames = (uid != Process.ROOT_UID)
- ? mContext.getPackageManager().getPackagesForUid(uid)
+ ? mPackageManager.getPackagesForUid(uid)
: new String[] {"root"};
if (packageNames == null) {
continue;
@@ -289,8 +340,7 @@
for (int j = 0; j < permissionCount; j++) {
final String permission = unrequestedRestrictedPermissions.get(j);
for (String packageName : packageNames) {
- setUidModeAllowed(appOpsManager,
- AppOpsManager.permissionToOpCode(permission), uid,
+ setUidModeAllowed(AppOpsManager.permissionToOpCode(permission), uid,
packageName);
}
}
@@ -298,19 +348,115 @@
}
}
- private void addPackage(@NonNull Context context,
- @NonNull PackageParser.Package pkg, @UserIdInt int userId) {
- final PackageManager packageManager = context.getPackageManager();
+ /**
+ * Set app ops that belong to restricted permissions.
+ *
+ * <p>This processed ops previously added by {@link #addOpIfRestricted}
+ */
+ private void syncOpsOfFgPermissions() {
+ int numFgPermOps = mFgPermOps.size();
+ for (int i = 0; i < numFgPermOps; i++) {
+ FgPermission perm = mFgPermOps.get(i);
- final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.applicationInfo.uid));
- final UserHandle userHandle = UserHandle.of(userId);
+ if (mPackageManager.checkPermission(perm.fgPermissionName, perm.packageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ if (mPackageManager.checkPermission(perm.bgPermissionName, perm.packageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ mAppOpsManager.setUidMode(
+ AppOpsManager.permissionToOpCode(perm.fgPermissionName), perm.uid,
+ AppOpsManager.MODE_ALLOWED);
+ } else {
+ mAppOpsManager.setUidMode(
+ AppOpsManager.permissionToOpCode(perm.fgPermissionName), perm.uid,
+ AppOpsManager.MODE_FOREGROUND);
+ }
+ } else {
+ mAppOpsManager.setUidMode(
+ AppOpsManager.permissionToOpCode(perm.fgPermissionName), perm.uid,
+ AppOpsManager.MODE_IGNORED);
+ }
+ }
+ }
- mUids.put(uid, uid);
+ /**
+ * Synchronize all previously {@link #addPackage added} packages.
+ */
+ void syncPackages() {
+ syncRestrictedOps();
+ syncOpsOfFgPermissions();
+ }
- final int permissionCount = pkg.requestedPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- final String permission = pkg.requestedPermissions.get(i);
+ /**
+ * Add op that belong to a restricted permission for later processing in
+ * {@link #syncRestrictedOps}.
+ *
+ * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
+ *
+ * @param permissionInfo The permission that is currently looked at
+ * @param pkg The package looked at
+ */
+ private void addOpIfRestricted(@NonNull PermissionInfo permissionInfo,
+ @NonNull PackageInfo pkg) {
+ final String permission = permissionInfo.name;
+ final int opCode = AppOpsManager.permissionToOpCode(permission);
+ final int uid = pkg.applicationInfo.uid;
+ if (!permissionInfo.isRestricted()) {
+ return;
+ }
+
+ final boolean applyRestriction = PackageManager.RESTRICTED_PERMISSIONS_ENABLED
+ && (mPackageManager.getPermissionFlags(permission, pkg.packageName,
+ mContext.getUser()) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+
+ if (permissionInfo.isHardRestricted()) {
+ if (applyRestriction) {
+ mOpsToRestrict.add(new OpToRestrict(uid, opCode));
+ } else {
+ mOpsToUnrestrict.add(new OpToUnrestrict(uid, pkg.packageName, opCode));
+ }
+ } else if (permissionInfo.isSoftRestricted()) {
+ //TODO: Implement soft restrictions like storage here.
+ }
+ }
+
+ private void addOpIfFgPermissions(@NonNull PermissionInfo permissionInfo,
+ @NonNull PackageInfo pkg) {
+ if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ // Pre-M apps do not store their fg/bg state in the permissions
+ return;
+ }
+
+ if (permissionInfo.backgroundPermission == null) {
+ return;
+ }
+
+ mFgPermOps.add(new FgPermission(pkg.applicationInfo.uid, pkg.packageName,
+ permissionInfo.name, permissionInfo.backgroundPermission));
+ }
+
+ /**
+ * Add a package for {@link #syncPackages() processing} later.
+ *
+ * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
+ *
+ * @param pkgName The package to add for later processing.
+ */
+ void addPackage(@NonNull String pkgName) {
+ final PackageInfo pkg;
+ try {
+ pkg = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS);
+ } catch (NameNotFoundException e) {
+ return;
+ }
+
+ mAllUids.put(pkg.applicationInfo.uid, pkg.applicationInfo.uid);
+
+ if (pkg.requestedPermissions == null) {
+ return;
+ }
+
+ for (String permission : pkg.requestedPermissions) {
final int opCode = AppOpsManager.permissionToOpCode(permission);
if (opCode == AppOpsManager.OP_NONE) {
continue;
@@ -318,44 +464,63 @@
final PermissionInfo permissionInfo;
try {
- permissionInfo = packageManager.getPermissionInfo(permission, 0);
+ permissionInfo = mPackageManager.getPermissionInfo(permission, 0);
} catch (PackageManager.NameNotFoundException e) {
continue;
}
- if (!permissionInfo.isRestricted()) {
- continue;
- }
-
- final boolean applyRestriction = PackageManager.RESTRICTED_PERMISSIONS_ENABLED
- && (packageManager.getPermissionFlags(permission, pkg.packageName,
- userHandle) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
-
- if (permissionInfo.isHardRestricted()) {
- if (applyRestriction) {
- mDefaultUidOps.put(opCode, uid);
- } else {
- mPackageNames.put(opCode, pkg.packageName);
- mAllowedUidOps.put(opCode, uid);
- }
- } else if (permissionInfo.isSoftRestricted()) {
- //TODO: Implement soft restrictions like storage here.
- }
+ addOpIfRestricted(permissionInfo, pkg);
+ addOpIfFgPermissions(permissionInfo, pkg);
}
}
- private static void setUidModeAllowed(@NonNull AppOpsManager appOpsManager,
- int opCode, int uid, @NonNull String packageName) {
- final int currentMode = appOpsManager.unsafeCheckOpRaw(AppOpsManager
+ private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) {
+ final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
.opToPublicName(opCode), uid, packageName);
if (currentMode == AppOpsManager.MODE_DEFAULT) {
- appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED);
+ mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED);
}
}
- private static void setUidModeDefault(@NonNull AppOpsManager appOpsManager,
- int opCode, int uid) {
- appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT);
+ private void setUidModeDefault(int opCode, int uid) {
+ mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT);
+ }
+
+ private class OpToRestrict {
+ final int uid;
+ final int code;
+
+ OpToRestrict(int uid, int code) {
+ this.uid = uid;
+ this.code = code;
+ }
+ }
+
+ private class OpToUnrestrict {
+ final int uid;
+ final @NonNull String packageName;
+ final int code;
+
+ OpToUnrestrict(int uid, @NonNull String packageName, int code) {
+ this.uid = uid;
+ this.packageName = packageName;
+ this.code = code;
+ }
+ }
+
+ private class FgPermission {
+ final int uid;
+ final @NonNull String packageName;
+ final @NonNull String fgPermissionName;
+ final @NonNull String bgPermissionName;
+
+ private FgPermission(int uid, @NonNull String packageName,
+ @NonNull String fgPermissionName, @NonNull String bgPermissionName) {
+ this.uid = uid;
+ this.packageName = packageName;
+ this.fgPermissionName = fgPermissionName;
+ this.bgPermissionName = bgPermissionName;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b3f1c55..d0ca861 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1361,9 +1361,9 @@
if (mKeyguardDelegate.isShowing()) {
// Double the time it takes to take a screenshot from the keyguard
return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
- ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+ ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout());
}
- return ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout();
+ return ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout();
}
private long getRingerToggleChordDelay() {
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 56a6c3c..a9a6b19 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -266,6 +266,11 @@
}
@Override
+ public void ensureZygoteStarted() {
+ WebViewZygote.getProcess();
+ }
+
+ @Override
public boolean isMultiProcessDefaultEnabled() {
// Multiprocess is enabled for all 64-bit devices, since the ability to run the renderer
// process in 32-bit when it's a separate process typically results in a net memory saving.
diff --git a/services/core/java/com/android/server/webkit/SystemInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
index 3fb5279..743740d 100644
--- a/services/core/java/com/android/server/webkit/SystemInterface.java
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -61,5 +61,7 @@
public int getMultiProcessSetting(Context context);
public void setMultiProcessSetting(Context context, int value);
public void notifyZygote(boolean enableMultiProcess);
+ /** Start the zygote if it's not already running. */
+ public void ensureZygoteStarted();
public boolean isMultiProcessDefaultEnabled();
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index f704c30..890456a 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -17,6 +17,7 @@
import android.content.Context;
import android.content.pm.PackageInfo;
+import android.os.AsyncTask;
import android.os.UserHandle;
import android.webkit.WebViewProviderInfo;
import android.webkit.WebViewProviderResponse;
@@ -81,6 +82,14 @@
migrateFallbackStateOnBoot();
mWebViewUpdater.prepareWebViewInSystemServer();
mSystemInterface.notifyZygote(isMultiProcessEnabled());
+ AsyncTask.THREAD_POOL_EXECUTOR.execute(this::startZygoteWhenReady);
+ }
+
+ void startZygoteWhenReady() {
+ // Wait on a background thread for RELRO creation to be done. We ignore the return value
+ // because even if RELRO creation failed we still want to start the zygote.
+ waitForAndGetProvider();
+ mSystemInterface.ensureZygoteStarted();
}
void handleNewUser(int userId) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6cf36d6..ed3ec94 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -87,6 +87,7 @@
import static android.os.Build.VERSION_CODES.HONEYCOMB;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Process.SYSTEM_UID;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
@@ -1948,14 +1949,20 @@
return false;
}
+ // Whether the activity is on the sleeping display.
+ // TODO(b/129750406): This should be applied for the default display, too.
+ final boolean isDisplaySleeping = getDisplay().isSleeping()
+ && getDisplayId() != DEFAULT_DISPLAY;
// Whether this activity is the top activity of this stack.
final boolean isTop = this == stack.getTopActivity();
// Exclude the case where this is the top activity in a pinned stack.
final boolean isTopNotPinnedStack = stack.isAttached()
&& stack.getDisplay().isTopNotPinnedStack(stack);
- // Now check whether it's really visible depending on Keyguard state.
- return stack.checkKeyguardVisibility(this,
+ // Now check whether it's really visible depending on Keyguard state, and update
+ // {@link ActivityStack} internal states.
+ final boolean visibleIgnoringDisplayStatus = stack.checkKeyguardVisibility(this,
visibleIgnoringKeyguard, isTop && isTopNotPinnedStack);
+ return visibleIgnoringDisplayStatus && !isDisplaySleeping;
}
boolean shouldBeVisible() {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index a187bf73..473a875 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1018,11 +1018,11 @@
if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
return false;
}
- // don't abort if the callingPackage is the device owner
- if (mService.isDeviceOwner(callingPackage)) {
+ // don't abort if the callingUid is the device owner
+ if (mService.isDeviceOwner(callingUid)) {
return false;
}
- // don't abort if the callingPackage has companion device
+ // don't abort if the callingUid has companion device
final int callingUserId = UserHandle.getUserId(callingUid);
if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) {
return false;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index b2e5b6a..7d25466 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -507,9 +507,9 @@
public abstract boolean isUidForeground(int uid);
/**
- * Called by DevicePolicyManagerService to set the package name of the device owner.
+ * Called by DevicePolicyManagerService to set the uid of the device owner.
*/
- public abstract void setDeviceOwnerPackageName(String deviceOwnerPkg);
+ public abstract void setDeviceOwnerUid(int uid);
/** Set all associated companion app that belongs to an userId. */
public abstract void setCompanionAppPackages(int userId, Set<String> companionAppPackages);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index e53d9d7..b424904 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -633,7 +633,7 @@
private FontScaleSettingObserver mFontScaleSettingObserver;
- private String mDeviceOwnerPackageName;
+ private int mDeviceOwnerUid = Process.INVALID_UID;
private final class FontScaleSettingObserver extends ContentObserver {
private final Uri mFontScaleUri = Settings.System.getUriFor(FONT_SCALE);
@@ -5876,15 +5876,12 @@
|| mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
}
- boolean isDeviceOwner(String packageName) {
- if (packageName == null) {
- return false;
- }
- return packageName.equals(mDeviceOwnerPackageName);
+ boolean isDeviceOwner(int uid) {
+ return uid >= 0 && mDeviceOwnerUid == uid;
}
- void setDeviceOwnerPackageName(String deviceOwnerPkg) {
- mDeviceOwnerPackageName = deviceOwnerPkg;
+ void setDeviceOwnerUid(int uid) {
+ mDeviceOwnerUid = uid;
}
/**
@@ -7334,9 +7331,9 @@
}
@Override
- public void setDeviceOwnerPackageName(String deviceOwnerPkg) {
+ public void setDeviceOwnerUid(int uid) {
synchronized (mGlobalLock) {
- ActivityTaskManagerService.this.setDeviceOwnerPackageName(deviceOwnerPkg);
+ ActivityTaskManagerService.this.setDeviceOwnerUid(uid);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0f4e123..ee4e33e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -250,8 +250,8 @@
// on the IME target. We mainly have this container grouping so we can keep track of all the IME
// window containers together and move them in-sync if/when needed. We use a subclass of
// WindowContainer which is omitted from screen magnification, as the IME is never magnified.
- private final NonMagnifiableWindowContainers mImeWindowsContainers =
- new NonMagnifiableWindowContainers("mImeWindowsContainers", mWmService);
+ private final NonAppWindowContainers mImeWindowsContainers =
+ new NonAppWindowContainers("mImeWindowsContainers", mWmService);
private WindowState mTmpWindow;
private WindowState mTmpWindow2;
@@ -4642,16 +4642,6 @@
}
}
- private class NonMagnifiableWindowContainers extends NonAppWindowContainers {
- NonMagnifiableWindowContainers(String name, WindowManagerService service) {
- super(name, service);
- }
-
- @Override
- void applyMagnificationSpec(Transaction t, MagnificationSpec spec) {
- }
- };
-
SurfaceControl.Builder makeSurface(SurfaceSession s) {
return mWmService.makeSurfaceBuilder(s)
.setParent(mWindowingLayer);
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 432d75e..363db54 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -294,7 +294,16 @@
/**
* Called when occluded state changed.
*/
- private void handleOccludedChanged() {
+ private void handleOccludedChanged(int displayId) {
+ // TODO(b/113840485): Handle app transition for individual display, and apply occluded
+ // state change to secondary displays.
+ // For now, only default display fully supports occluded change. Other displays only
+ // updates keygaurd sleep token on that display.
+ if (displayId != DEFAULT_DISPLAY) {
+ updateKeyguardSleepToken(displayId);
+ return;
+ }
+
mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY));
if (isKeyguardLocked()) {
mWindowManager.deferSurfaceLayout();
@@ -303,7 +312,7 @@
.prepareAppTransition(resolveOccludeTransit(),
false /* alwaysKeepCurrent */, 0 /* flags */,
true /* forceOverride */);
- updateKeyguardSleepToken();
+ updateKeyguardSleepToken(DEFAULT_DISPLAY);
mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
} finally {
@@ -395,13 +404,16 @@
for (int displayNdx = mRootActivityContainer.getChildCount() - 1;
displayNdx >= 0; displayNdx--) {
final ActivityDisplay display = mRootActivityContainer.getChildAt(displayNdx);
- final int displayId = display.mDisplayId;
- final KeyguardDisplayState state = getDisplay(displayId);
- if (isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken == null) {
- state.acquiredSleepToken();
- } else if (!isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken != null) {
- state.releaseSleepToken();
- }
+ updateKeyguardSleepToken(display.mDisplayId);
+ }
+ }
+
+ private void updateKeyguardSleepToken(int displayId) {
+ final KeyguardDisplayState state = getDisplay(displayId);
+ if (isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken == null) {
+ state.acquiredSleepToken();
+ } else if (!isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken != null) {
+ state.releaseSleepToken();
}
}
@@ -483,11 +495,8 @@
mOccluded |= controller.mWindowManager.isShowingDream();
}
- // TODO(b/113840485): Handle app transition for individual display, and apply occluded
- // state change to secondary displays.
- // For now, only default display can change occluded.
- if (lastOccluded != mOccluded && mDisplayId == DEFAULT_DISPLAY) {
- controller.handleOccludedChanged();
+ if (lastOccluded != mOccluded) {
+ controller.handleOccludedChanged(mDisplayId);
}
if (lastDismissActivity != mDismissingKeyguardActivity && !mOccluded
&& mDismissingKeyguardActivity != null
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 3c9a46b..0b63f48 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -26,7 +26,6 @@
import android.app.ActivityManager.TaskSnapshot;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
-import android.hardware.HardwareBuffer;
import android.os.Process;
import android.os.SystemClock;
import android.util.ArraySet;
@@ -363,8 +362,7 @@
// TODO(b/116112787) TaskSnapshot needs bookkeep the ColorSpace of the
// hardware bitmap when created.
final Bitmap bitmap = Bitmap.wrapHardwareBuffer(
- HardwareBuffer.createFromGraphicBuffer(mSnapshot.getSnapshot()),
- mSnapshot.getColorSpace());
+ mSnapshot.getSnapshot(), mSnapshot.getColorSpace());
if (bitmap == null) {
Slog.e(TAG, "Invalid task snapshot hw bitmap");
return false;
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 166a33d..da873b8 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -35,7 +35,6 @@
import android.graphics.Bitmap;
import android.graphics.Rect;
-import android.hardware.HardwareBuffer;
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
@@ -744,8 +743,7 @@
return null;
}
return Bitmap.wrapHardwareBuffer(
- HardwareBuffer.createFromGraphicBuffer(wallpaperBuffer.getGraphicBuffer()),
- wallpaperBuffer.getColorSpace());
+ wallpaperBuffer.getGraphicBuffer(), wallpaperBuffer.getColorSpace());
}
private WindowState getTopVisibleWallpaper() {
diff --git a/services/core/jni/com_android_server_TestNetworkService.cpp b/services/core/jni/com_android_server_TestNetworkService.cpp
index b90ff23..36a6fde 100644
--- a/services/core/jni/com_android_server_TestNetworkService.cpp
+++ b/services/core/jni/com_android_server_TestNetworkService.cpp
@@ -54,12 +54,12 @@
jniThrowException(env, "java/lang/IllegalStateException", msg.c_str());
}
-static int createTunInterface(JNIEnv* env, const char* iface) {
+static int createTunTapInterface(JNIEnv* env, bool isTun, const char* iface) {
base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK));
ifreq ifr{};
// Allocate interface.
- ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+ ifr.ifr_flags = (isTun ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
if (ioctl(tun.get(), TUNSETIFF, &ifr)) {
throwException(env, errno, "allocating", ifr.ifr_name);
@@ -80,23 +80,23 @@
//------------------------------------------------------------------------------
-static jint create(JNIEnv* env, jobject /* thiz */, jstring jIface) {
+static jint create(JNIEnv* env, jobject /* thiz */, jboolean isTun, jstring jIface) {
ScopedUtfChars iface(env, jIface);
if (!iface.c_str()) {
jniThrowNullPointerException(env, "iface");
return -1;
}
- int tun = createTunInterface(env, iface.c_str());
+ int tun = createTunTapInterface(env, isTun, iface.c_str());
- // Any exceptions will be thrown from the createTunInterface call
+ // Any exceptions will be thrown from the createTunTapInterface call
return tun;
}
//------------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
- {"jniCreateTun", "(Ljava/lang/String;)I", (void*)create},
+ {"jniCreateTunTap", "(ZLjava/lang/String;)I", (void*)create},
};
int register_android_server_TestNetworkService(JNIEnv* env) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 27cd70c..215e46f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -26,6 +26,7 @@
import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Environment;
+import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
@@ -209,8 +210,11 @@
}
private void pushToActivityTaskManagerLocked() {
- mActivityTaskManagerInternal.setDeviceOwnerPackageName(mDeviceOwner != null
- ? mDeviceOwner.packageName : null);
+ final int uid = mDeviceOwner != null ? mPackageManagerInternal.getPackageUid(
+ mDeviceOwner.packageName,
+ PackageManager.MATCH_ALL | PackageManager.MATCH_KNOWN_PACKAGES, mDeviceOwnerUserId)
+ : Process.INVALID_UID;
+ mActivityTaskManagerInternal.setDeviceOwnerUid(uid);
}
String getDeviceOwnerPackageName() {
diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
index 3f687c8..8cde106 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
@@ -185,6 +185,9 @@
public void notifyZygote(boolean enableMultiProcess) {}
@Override
+ public void ensureZygoteStarted() {}
+
+ @Override
public boolean isMultiProcessDefaultEnabled() {
return mMultiProcessDefault;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index d02db7b..44aa55d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -659,7 +659,7 @@
boolean hasForegroundActivities, boolean callerIsRecents,
boolean callerIsTempWhitelisted,
boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
- boolean isCallingPackageNameDeviceOwner, boolean isCallingPackageTempWhitelisted) {
+ boolean isCallingUidDeviceOwner, boolean isCallingPackageTempWhitelisted) {
// window visibility
doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
.isAnyNonToastWindowVisibleForUid(callingUid);
@@ -685,8 +685,8 @@
// caller is instrumenting with background activity starts privileges
callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
callerIsInstrumentingWithBackgroundActivityStartPrivileges);
- // calling package name is the device owner
- doReturn(isCallingPackageNameDeviceOwner).when(mService).isDeviceOwner(any());
+ // callingUid is the device owner
+ doReturn(isCallingUidDeviceOwner).when(mService).isDeviceOwner(callingUid);
// calling package name is temporarily whitelisted
doReturn(isCallingPackageTempWhitelisted).when(mService)
.isPackageNameWhitelistedForBgActivityStarts("com.whatever.dude");
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 9d7319f..95b8f67 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -78,6 +78,7 @@
private static final String KEY_SIMPLEPERF_CMD = "simpleperf_cmd";
private static final String KEY_SIMPLEPERF_APP = "simpleperf_app";
private static final String KEY_CYCLE_CLEAN = "cycle_clean";
+ private static final String KEY_TRACE_ALL = "trace_all";
private static final String KEY_TRACE_ITERATIONS = "trace_iterations";
private static final String KEY_LAUNCH_DIRECTORY = "launch_directory";
private static final String KEY_TRACE_DIRECTORY = "trace_directory";
@@ -111,7 +112,7 @@
private static final String SUCCESS_MESSAGE = "Status: ok";
private static final String TOTAL_TIME_MESSAGE = "TotalTime:";
private static final String COMPILE_SUCCESS = "Success";
- private static final String LAUNCH_ITERATION = "LAUNCH_ITERATION - %d";
+ private static final String LAUNCH_ITERATION = "LAUNCH_ITERATION-%d";
private static final String TRACE_ITERATION = "TRACE_ITERATION-%d";
private static final String LAUNCH_ITERATION_PREFIX = "LAUNCH_ITERATION";
private static final String TRACE_ITERATION_PREFIX = "TRACE_ITERATION";
@@ -142,6 +143,7 @@
private String[] mCompilerFilters = null;
private String mLastAppName = "";
private boolean mCycleCleanUp = false;
+ private boolean mTraceAll = false;
private boolean mIterationCycle = false;
private long mCycleTime = 0;
private StringBuilder mCycleTimes = new StringBuilder();
@@ -296,18 +298,40 @@
// skip if the app has failures while launched first
continue;
}
- // In the "applaunch.txt" file app launches are referenced using
- // "LAUNCH_ITERATION - ITERATION NUM"
- launchResults = startApp(launch.getApp(), launch.getLaunchReason());
- if (launchResults.mLaunchTime < 0) {
- addLaunchResult(launch, new AppLaunchResult());
- // if it fails once, skip the rest of the launches
- continue;
- } else {
- mCycleTime += launchResults.mLaunchTime;
- addLaunchResult(launch, launchResults);
+ AtraceLogger atraceLogger = null;
+ if (mTraceAll) {
+ Log.i(TAG, "Started tracing " + launch.getApp());
+ atraceLogger = AtraceLogger
+ .getAtraceLoggerInstance(getInstrumentation());
}
- sleep(POST_LAUNCH_IDLE_TIMEOUT);
+ try {
+ // Start the trace
+ if (atraceLogger != null) {
+ atraceLogger.atraceStart(traceCategoriesSet, traceBufferSize,
+ traceDumpInterval, rootTraceSubDir,
+ String.format("%s-%s-%s", launch.getApp(),
+ launch.getCompilerFilter(), launch.getLaunchReason()));
+ }
+ // In the "applaunch.txt" file app launches are referenced using
+ // "LAUNCH_ITERATION - ITERATION NUM"
+ launchResults = startApp(launch.getApp(), launch.getLaunchReason());
+ if (launchResults.mLaunchTime < 0) {
+ addLaunchResult(launch, new AppLaunchResult());
+ // if it fails once, skip the rest of the launches
+ continue;
+ } else {
+ mCycleTime += launchResults.mLaunchTime;
+ addLaunchResult(launch, launchResults);
+ }
+ sleep(POST_LAUNCH_IDLE_TIMEOUT);
+ } finally {
+ // Stop the trace
+ if (atraceLogger != null) {
+ Log.i(TAG, "Stopped tracing " + launch.getApp());
+ atraceLogger.atraceStop();
+ }
+ }
+
}
// App launch times for trace launch will not be used for final
@@ -534,6 +558,7 @@
mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC);
mSimplePerfAppOnly = Boolean.parseBoolean(args.getString(KEY_SIMPLEPERF_APP));
mCycleCleanUp = Boolean.parseBoolean(args.getString(KEY_CYCLE_CLEAN));
+ mTraceAll = Boolean.parseBoolean(args.getString(KEY_TRACE_ALL));
mTrialLaunch = mTrialLaunch || Boolean.parseBoolean(args.getString(KEY_TRIAL_LAUNCH));
if (mSimplePerfCmd != null && mSimplePerfAppOnly) {