Merge "null check on qspanel before called method on it." into pi-dev
diff --git a/api/current.txt b/api/current.txt
index 83092f6..607109d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38395,17 +38395,17 @@
package android.se.omapi {
- public class Channel {
+ public final class Channel implements java.nio.channels.Channel {
method public void close();
method public byte[] getSelectResponse();
method public android.se.omapi.Session getSession();
method public boolean isBasicChannel();
- method public boolean isClosed();
+ method public boolean isOpen();
method public boolean selectNext() throws java.io.IOException;
method public byte[] transmit(byte[]) throws java.io.IOException;
}
- public class Reader {
+ public final class Reader {
method public void closeSessions();
method public java.lang.String getName();
method public android.se.omapi.SEService getSEService();
@@ -38413,26 +38413,28 @@
method public android.se.omapi.Session openSession() throws java.io.IOException;
}
- public class SEService {
- ctor public SEService(android.content.Context, android.se.omapi.SEService.SecureElementListener);
+ public final class SEService {
+ ctor public SEService(android.content.Context, java.util.concurrent.Executor, android.se.omapi.SEService.OnConnectedListener);
method public android.se.omapi.Reader[] getReaders();
method public java.lang.String getVersion();
method public boolean isConnected();
method public void shutdown();
}
- public static abstract interface SEService.SecureElementListener {
- method public abstract void onServiceConnected();
+ public static abstract interface SEService.OnConnectedListener {
+ method public abstract void onConnected();
}
- public class Session {
+ public final class Session {
method public void close();
method public void closeChannels();
method public byte[] getATR();
method public android.se.omapi.Reader getReader();
method public boolean isClosed();
method public android.se.omapi.Channel openBasicChannel(byte[], byte) throws java.io.IOException;
+ method public android.se.omapi.Channel openBasicChannel(byte[]) throws java.io.IOException;
method public android.se.omapi.Channel openLogicalChannel(byte[], byte) throws java.io.IOException;
+ method public android.se.omapi.Channel openLogicalChannel(byte[]) throws java.io.IOException;
}
}
@@ -40955,7 +40957,7 @@
method public final void putExtras(android.os.Bundle);
method public final void removeExtras(java.util.List<java.lang.String>);
method public final void removeExtras(java.lang.String...);
- method public void requestBluetoothAudio(java.lang.String);
+ method public void requestBluetoothAudio(android.bluetooth.BluetoothDevice);
method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
method public final void sendRemoteRttRequest();
method public final void sendRttInitiationFailure(int);
@@ -41166,7 +41168,7 @@
method public void onCanAddCallChanged(boolean);
method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onSilenceRinger();
- method public final void requestBluetoothAudio(java.lang.String);
+ method public final void requestBluetoothAudio(android.bluetooth.BluetoothDevice);
method public final void setAudioRoute(int);
method public final void setMuted(boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
diff --git a/cmds/statsd/benchmark/metric_util.cpp b/cmds/statsd/benchmark/metric_util.cpp
index 50b05cd..fae186a 100644
--- a/cmds/statsd/benchmark/metric_util.cpp
+++ b/cmds/statsd/benchmark/metric_util.cpp
@@ -366,7 +366,7 @@
sp<AlarmMonitor> periodicAlarmMonitor;
sp<StatsLogProcessor> processor = new StatsLogProcessor(
uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, [](const ConfigKey&){});
- processor->OnConfigUpdated(key, config);
+ processor->OnConfigUpdated(0, key, config);
return processor;
}
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 13f2679..f00cdb3 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -191,11 +191,12 @@
}
}
-void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) {
+void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
+ const StatsdConfig& config) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
VLOG("Updated configuration for key %s", key.ToString().c_str());
sp<MetricsManager> newMetricsManager =
- new MetricsManager(key, config, mTimeBaseSec, mUidMap,
+ new MetricsManager(key, config, mTimeBaseSec, (timestampNs - 1) / NS_PER_SEC + 1, mUidMap,
mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
if (newMetricsManager->isConfigValid()) {
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 387a929..1c4698f 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -42,7 +42,8 @@
void OnLogEvent(LogEvent* event);
- void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config);
+ void OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
+ const StatsdConfig& config);
void OnConfigRemoved(const ConfigKey& key);
size_t GetMetricsSize(const ConfigKey& key) const;
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp
index 249cb59..70e6e84 100644
--- a/cmds/statsd/src/anomaly/AlarmTracker.cpp
+++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp
@@ -30,7 +30,8 @@
namespace os {
namespace statsd {
-AlarmTracker::AlarmTracker(uint64_t startMillis,
+AlarmTracker::AlarmTracker(const uint64_t startMillis,
+ const uint64_t currentMillis,
const Alarm& alarm, const ConfigKey& configKey,
const sp<AlarmMonitor>& alarmMonitor)
: mAlarmConfig(alarm),
@@ -38,7 +39,11 @@
mAlarmMonitor(alarmMonitor) {
VLOG("AlarmTracker() called");
mAlarmSec = (startMillis + mAlarmConfig.offset_millis()) / MS_PER_SEC;
+ // startMillis is the time statsd is created. We need to find the 1st alarm timestamp after
+ // the config is added to statsd.
+ mAlarmSec = findNextAlarmSec(currentMillis / MS_PER_SEC); // round up
mInternalAlarm = new InternalAlarm{static_cast<uint32_t>(mAlarmSec)};
+ VLOG("AlarmTracker sets the periodic alarm at: %lld", (long long)mAlarmSec);
if (mAlarmMonitor != nullptr) {
mAlarmMonitor->add(mInternalAlarm);
}
@@ -55,9 +60,13 @@
mSubscriptions.push_back(subscription);
}
-uint64_t AlarmTracker::findNextAlarmSec(uint64_t currentTimeSec) {
- int periodsForward = (currentTimeSec - mAlarmSec) * MS_PER_SEC / mAlarmConfig.period_millis();
- return mAlarmSec + (periodsForward + 1) * mAlarmConfig.period_millis() / MS_PER_SEC;
+int64_t AlarmTracker::findNextAlarmSec(int64_t currentTimeSec) {
+ if (currentTimeSec <= mAlarmSec) {
+ return mAlarmSec;
+ }
+ int64_t periodsForward =
+ ((currentTimeSec - mAlarmSec) * MS_PER_SEC - 1) / mAlarmConfig.period_millis() + 1;
+ return mAlarmSec + periodsForward * mAlarmConfig.period_millis() / MS_PER_SEC;
}
void AlarmTracker::informAlarmsFired(
@@ -68,12 +77,14 @@
return;
}
if (!mSubscriptions.empty()) {
+ VLOG("AlarmTracker triggers the subscribers.");
triggerSubscribers(mAlarmConfig.id(), DEFAULT_METRIC_DIMENSION_KEY, mConfigKey,
mSubscriptions);
}
firedAlarms.erase(mInternalAlarm);
mAlarmSec = findNextAlarmSec((timestampNs-1) / NS_PER_SEC + 1); // round up
mInternalAlarm = new InternalAlarm{static_cast<uint32_t>(mAlarmSec)};
+ VLOG("AlarmTracker sets the periodic alarm at: %lld", (long long)mAlarmSec);
if (mAlarmMonitor != nullptr) {
mAlarmMonitor->add(mInternalAlarm);
}
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.h b/cmds/statsd/src/anomaly/AlarmTracker.h
index 13180a5..962a014 100644
--- a/cmds/statsd/src/anomaly/AlarmTracker.h
+++ b/cmds/statsd/src/anomaly/AlarmTracker.h
@@ -34,7 +34,8 @@
class AlarmTracker : public virtual RefBase {
public:
- AlarmTracker(uint64_t startMillis,
+ AlarmTracker(const uint64_t startMillis,
+ const uint64_t currentMillis,
const Alarm& alarm, const ConfigKey& configKey,
const sp<AlarmMonitor>& subscriberAlarmMonitor);
@@ -53,13 +54,13 @@
return mInternalAlarm == nullptr ? 0 : mInternalAlarm->timestampSec;
}
- uint64_t findNextAlarmSec(uint64_t currentTimeMillis);
+ int64_t findNextAlarmSec(int64_t currentTimeMillis);
// statsd_config.proto Alarm message that defines this tracker.
const Alarm mAlarmConfig;
// A reference to the Alarm's config key.
- const ConfigKey& mConfigKey;
+ const ConfigKey mConfigKey;
// The subscriptions that depend on this alarm.
std::vector<Subscription> mSubscriptions;
@@ -68,7 +69,7 @@
sp<AlarmMonitor> mAlarmMonitor;
// The current expected alarm time in seconds.
- uint64_t mAlarmSec;
+ int64_t mAlarmSec;
// The current alarm.
sp<const InternalAlarm> mInternalAlarm;
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index ae0af64..15671a6 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -127,7 +127,7 @@
std::vector<Subscription> mSubscriptions;
// A reference to the Alert's config key.
- const ConfigKey& mConfigKey;
+ const ConfigKey mConfigKey;
// Number of past buckets. One less than the total number of buckets needed
// for the anomaly detection (since the current bucket is not in the past).
diff --git a/cmds/statsd/src/config/ConfigListener.h b/cmds/statsd/src/config/ConfigListener.h
index 19ccfcf..54e7770 100644
--- a/cmds/statsd/src/config/ConfigListener.h
+++ b/cmds/statsd/src/config/ConfigListener.h
@@ -40,7 +40,8 @@
/**
* A configuration was added or updated.
*/
- virtual void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) = 0;
+ virtual void OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
+ const StatsdConfig& config) = 0;
/**
* A configuration was removed.
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index ff25091..f9aaad4 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -21,6 +21,7 @@
#include "storage/StorageManager.h"
#include "guardrail/StatsdStats.h"
+#include "stats_log_util.h"
#include "stats_util.h"
#include <android-base/file.h>
@@ -109,9 +110,10 @@
}
}
+ const int64_t timestampNs = getElapsedRealtimeNs();
// Tell everyone
for (sp<ConfigListener> listener:broadcastList) {
- listener->OnConfigUpdated(key, config);
+ listener->OnConfigUpdated(timestampNs, key, config);
}
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 00188e8..c61fa76 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -49,7 +49,7 @@
const int FIELD_ID_METRICS = 1;
MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
- const long timeBaseSec,
+ const long timeBaseSec, const long currentTimeSec,
const sp<UidMap> &uidMap,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor)
@@ -58,7 +58,7 @@
mLastReportWallClockNs(getWallClockNs()) {
mConfigValid =
initStatsdConfig(key, config, *uidMap, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, mTagIds, mAllAtomMatchers,
+ timeBaseSec, currentTimeSec, mTagIds, mAllAtomMatchers,
mAllConditionTrackers, mAllMetricProducers, mAllAnomalyTrackers,
mAllPeriodicAlarmTrackers, mConditionToMetricMap, mTrackerToMetricMap,
mTrackerToConditionMap, mNoReportMetricIds);
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index da0cd4a..4fd64b7 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -36,7 +36,8 @@
// A MetricsManager is responsible for managing metrics from one single config source.
class MetricsManager : public PackageInfoListener {
public:
- MetricsManager(const ConfigKey& configKey, const StatsdConfig& config, const long timeBaseSec,
+ MetricsManager(const ConfigKey& configKey, const StatsdConfig& config,
+ const long timeBaseSec, const long currentTimeSec,
const sp<UidMap>& uidMap, const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor);
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 50eca05..b7c5795 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -599,10 +599,11 @@
bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
const sp<AlarmMonitor>& periodicAlarmMonitor,
- const long timeBaseSec,
+ const long timeBaseSec, const long currentTimeSec,
vector<sp<AlarmTracker>>& allAlarmTrackers) {
unordered_map<int64_t, int> alarmTrackerMap;
uint64_t startMillis = (uint64_t)timeBaseSec * MS_PER_SEC;
+ uint64_t currentTimeMillis = (uint64_t)currentTimeSec * MS_PER_SEC;
for (int i = 0; i < config.alarm_size(); i++) {
const Alarm& alarm = config.alarm(i);
if (alarm.offset_millis() <= 0) {
@@ -615,7 +616,8 @@
}
alarmTrackerMap.insert(std::make_pair(alarm.id(), allAlarmTrackers.size()));
allAlarmTrackers.push_back(
- new AlarmTracker(startMillis, alarm, key, periodicAlarmMonitor));
+ new AlarmTracker(startMillis, currentTimeMillis,
+ alarm, key, periodicAlarmMonitor));
}
for (int i = 0; i < config.subscription_size(); ++i) {
const Subscription& subscription = config.subscription(i);
@@ -644,7 +646,7 @@
const UidMap& uidMap,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor,
- const long timeBaseSec,
+ const long timeBaseSec, const long currentTimeSec,
set<int>& allTagIds,
vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
@@ -682,7 +684,8 @@
ALOGE("initAlerts failed");
return false;
}
- if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseSec, allPeriodicAlarmTrackers)) {
+ if (!initAlarms(config, key, periodicAlarmMonitor,
+ timeBaseSec, currentTimeSec, allPeriodicAlarmTrackers)) {
ALOGE("initAlarms failed");
return false;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 386de0b..3754ae0 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -98,7 +98,7 @@
const UidMap& uidMap,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor,
- const long timeBaseSec,
+ const long timeBaseSec, const long currentTimeSec,
std::set<int>& allTagIds,
std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
index 838745e..9455304 100644
--- a/cmds/statsd/tests/ConfigManager_test.cpp
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -44,7 +44,8 @@
*/
class MockListener : public ConfigListener {
public:
- MOCK_METHOD2(OnConfigUpdated, void(const ConfigKey& key, const StatsdConfig& config));
+ MOCK_METHOD3(OnConfigUpdated, void(const int64_t timestampNs, const ConfigKey& key,
+ const StatsdConfig& config));
MOCK_METHOD1(OnConfigRemoved, void(const ConfigKey& key));
};
@@ -88,25 +89,25 @@
manager->StartupForTest();
// Add another one
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, StringToId("zzz")),
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")),
StatsdConfigEq(91)))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config91);
// Update It
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, StringToId("zzz")),
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")),
StatsdConfigEq(92)))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config92);
// Add one with the same uid but a different name
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, StringToId("yyy")),
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(1, StringToId("yyy")),
StatsdConfigEq(93)))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, StringToId("yyy")), config93);
// Add one with the same name but a different uid
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(2, StringToId("zzz")),
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(2, StringToId("zzz")),
StatsdConfigEq(94)))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(2, StringToId("zzz")), config94);
@@ -142,7 +143,7 @@
StatsdConfig config;
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _)).Times(5);
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _, _)).Times(5);
EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("xxx"))));
EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("yyy"))));
EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("zzz"))));
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 5d8c3f7..07378db 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -287,7 +287,7 @@
EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
@@ -315,7 +315,7 @@
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
@@ -340,7 +340,7 @@
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
@@ -364,7 +364,7 @@
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
@@ -388,7 +388,7 @@
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
@@ -413,7 +413,7 @@
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
@@ -438,7 +438,7 @@
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 4b9a87d..5a8ba79 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -43,7 +43,7 @@
class MockMetricsManager : public MetricsManager {
public:
MockMetricsManager() : MetricsManager(
- ConfigKey(1, 12345), StatsdConfig(), 1000,
+ ConfigKey(1, 12345), StatsdConfig(), 1000, 1000,
new UidMap(),
new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t){},
[](const sp<IStatsCompanionService>&){}),
@@ -135,7 +135,7 @@
ConfigKey key(3, 4);
StatsdConfig config;
config.add_allowed_log_source("AID_ROOT");
- p.OnConfigUpdated(key, config);
+ p.OnConfigUpdated(0, key, config);
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
diff --git a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
index 3330ee9..5e6de1c 100644
--- a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
@@ -39,25 +39,24 @@
Alarm alarm;
alarm.set_offset_millis(15 * MS_PER_SEC);
alarm.set_period_millis(60 * 60 * MS_PER_SEC); // 1hr
- uint64_t startMillis = 100000000 * MS_PER_SEC;
- AlarmTracker tracker(startMillis, alarm, kConfigKey,
- subscriberAlarmMonitor);
+ int64_t startMillis = 100000000 * MS_PER_SEC;
+ AlarmTracker tracker(startMillis, startMillis, alarm, kConfigKey, subscriberAlarmMonitor);
- EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15);
+ EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15));
uint64_t currentTimeSec = startMillis / MS_PER_SEC + 10;
std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarmSet =
subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
EXPECT_TRUE(firedAlarmSet.empty());
tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
- EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15);
+ EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15));
currentTimeSec = startMillis / MS_PER_SEC + 7000;
firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
EXPECT_EQ(firedAlarmSet.size(), 1u);
tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
EXPECT_TRUE(firedAlarmSet.empty());
- EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15 + 2 * 60 * 60);
+ EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15 + 2 * 60 * 60));
}
} // namespace statsd
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index d0840f0..0acd297 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -455,7 +455,7 @@
[](const sp<IStatsCompanionService>&){});
sp<StatsLogProcessor> processor = new StatsLogProcessor(
uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, [](const ConfigKey&){});
- processor->OnConfigUpdated(key, config);
+ processor->OnConfigUpdated(timeBaseSec, key, config);
return processor;
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 1776eac..95e4f93 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -279,12 +279,12 @@
}});
registerService(Context.IPSEC_SERVICE, IpSecManager.class,
- new StaticServiceFetcher<IpSecManager>() {
+ new CachedServiceFetcher<IpSecManager>() {
@Override
- public IpSecManager createService() {
+ public IpSecManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBinder b = ServiceManager.getService(Context.IPSEC_SERVICE);
IIpSecService service = IIpSecService.Stub.asInterface(b);
- return new IpSecManager(service);
+ return new IpSecManager(ctx, service);
}});
registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 4124536..7ebe0f9 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -43,6 +43,9 @@
import android.util.Log;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
@@ -924,6 +927,37 @@
idCount++;
}
}
+
+ // The sort logic must match the logic in
+ // libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
+ Arrays.sort(cameraIds, new Comparator<String>() {
+ @Override
+ public int compare(String s1, String s2) {
+ int s1Int = 0, s2Int = 0;
+ try {
+ s1Int = Integer.parseInt(s1);
+ } catch (NumberFormatException e) {
+ s1Int = -1;
+ }
+
+ try {
+ s2Int = Integer.parseInt(s2);
+ } catch (NumberFormatException e) {
+ s2Int = -1;
+ }
+
+ // Uint device IDs first
+ if (s1Int >= 0 && s2Int >= 0) {
+ return s1Int - s2Int;
+ } else if (s1Int >= 0) {
+ return -1;
+ } else if (s2Int >= 0) {
+ return 1;
+ } else {
+ // Simple string compare if both id are not uint
+ return s1.compareTo(s2);
+ }
+ }});
return cameraIds;
}
diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl
index 3a3ddcc..d6774d4 100644
--- a/core/java/android/net/IIpSecService.aidl
+++ b/core/java/android/net/IIpSecService.aidl
@@ -45,25 +45,31 @@
in String localAddr,
in String remoteAddr,
in Network underlyingNetwork,
- in IBinder binder);
+ in IBinder binder,
+ in String callingPackage);
void addAddressToTunnelInterface(
int tunnelResourceId,
- in LinkAddress localAddr);
+ in LinkAddress localAddr,
+ in String callingPackage);
void removeAddressFromTunnelInterface(
int tunnelResourceId,
- in LinkAddress localAddr);
+ in LinkAddress localAddr,
+ in String callingPackage);
- void deleteTunnelInterface(int resourceId);
+ void deleteTunnelInterface(int resourceId, in String callingPackage);
- IpSecTransformResponse createTransform(in IpSecConfig c, in IBinder binder);
+ IpSecTransformResponse createTransform(
+ in IpSecConfig c, in IBinder binder, in String callingPackage);
void deleteTransform(int transformId);
- void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId);
+ void applyTransportModeTransform(
+ in ParcelFileDescriptor socket, int direction, int transformId);
- void applyTunnelModeTransform(int tunnelResourceId, int direction, int transformResourceId);
+ void applyTunnelModeTransform(
+ int tunnelResourceId, int direction, int transformResourceId, in String callingPackage);
void removeTransportModeTransforms(in ParcelFileDescriptor socket);
}
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 1525508..e0654fd 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -140,6 +140,7 @@
}
}
+ private final Context mContext;
private final IIpSecService mService;
/**
@@ -661,6 +662,7 @@
*/
@SystemApi
public static final class IpSecTunnelInterface implements AutoCloseable {
+ private final String mOpPackageName;
private final IIpSecService mService;
private final InetAddress mRemoteAddress;
private final InetAddress mLocalAddress;
@@ -688,7 +690,8 @@
@RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
public void addAddress(@NonNull LinkAddress address) throws IOException {
try {
- mService.addAddressToTunnelInterface(mResourceId, address);
+ mService.addAddressToTunnelInterface(
+ mResourceId, address, mOpPackageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -706,16 +709,18 @@
@RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
public void removeAddress(@NonNull LinkAddress address) throws IOException {
try {
- mService.removeAddressFromTunnelInterface(mResourceId, address);
+ mService.removeAddressFromTunnelInterface(
+ mResourceId, address, mOpPackageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- private IpSecTunnelInterface(@NonNull IIpSecService service,
+ private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service,
@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress,
@NonNull Network underlyingNetwork)
throws ResourceUnavailableException, IOException {
+ mOpPackageName = ctx.getOpPackageName();
mService = service;
mLocalAddress = localAddress;
mRemoteAddress = remoteAddress;
@@ -727,7 +732,8 @@
localAddress.getHostAddress(),
remoteAddress.getHostAddress(),
underlyingNetwork,
- new Binder());
+ new Binder(),
+ mOpPackageName);
switch (result.status) {
case Status.OK:
break;
@@ -756,7 +762,7 @@
@Override
public void close() {
try {
- mService.deleteTunnelInterface(mResourceId);
+ mService.deleteTunnelInterface(mResourceId, mOpPackageName);
mResourceId = INVALID_RESOURCE_ID;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -801,7 +807,8 @@
public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
@NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
throws ResourceUnavailableException, IOException {
- return new IpSecTunnelInterface(mService, localAddress, remoteAddress, underlyingNetwork);
+ return new IpSecTunnelInterface(
+ mContext, mService, localAddress, remoteAddress, underlyingNetwork);
}
/**
@@ -827,7 +834,8 @@
@PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
try {
mService.applyTunnelModeTransform(
- tunnel.getResourceId(), direction, transform.getResourceId());
+ tunnel.getResourceId(), direction,
+ transform.getResourceId(), mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -839,7 +847,8 @@
* @param context the application context for this manager
* @hide
*/
- public IpSecManager(IIpSecService service) {
+ public IpSecManager(Context ctx, IIpSecService service) {
+ mContext = ctx;
mService = checkNotNull(service, "missing service");
}
}
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 099fe02..fb5f46c 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -130,7 +130,8 @@
synchronized (this) {
try {
IIpSecService svc = getIpSecService();
- IpSecTransformResponse result = svc.createTransform(mConfig, new Binder());
+ IpSecTransformResponse result = svc.createTransform(
+ mConfig, new Binder(), mContext.getOpPackageName());
int status = result.status;
checkResultStatus(status);
mResourceId = result.resourceId;
diff --git a/core/java/android/se/omapi/Channel.java b/core/java/android/se/omapi/Channel.java
index c8efede..5db3c1a 100644
--- a/core/java/android/se/omapi/Channel.java
+++ b/core/java/android/se/omapi/Channel.java
@@ -39,7 +39,7 @@
*
* @see <a href="http://globalplatform.org">GlobalPlatform Open Mobile API</a>
*/
-public class Channel {
+public final class Channel implements java.nio.channels.Channel {
private static final String TAG = "OMAPI.Channel";
private Session mSession;
@@ -64,7 +64,7 @@
* before closing the channel.
*/
public void close() {
- if (!isClosed()) {
+ if (isOpen()) {
synchronized (mLock) {
try {
mChannel.close();
@@ -76,21 +76,21 @@
}
/**
- * Tells if this channel is closed.
+ * Tells if this channel is open.
*
- * @return <code>true</code> if the channel is closed or in case of an error.
- * <code>false</code> otherwise.
+ * @return <code>false</code> if the channel is closed or in case of an error.
+ * <code>true</code> otherwise.
*/
- public boolean isClosed() {
+ public boolean isOpen() {
if (!mService.isConnected()) {
Log.e(TAG, "service not connected to system");
- return true;
+ return false;
}
try {
- return mChannel.isClosed();
+ return !mChannel.isClosed();
} catch (RemoteException e) {
Log.e(TAG, "Exception in isClosed()");
- return true;
+ return false;
}
}
diff --git a/core/java/android/se/omapi/Reader.java b/core/java/android/se/omapi/Reader.java
index 9be3da6..80262f7 100644
--- a/core/java/android/se/omapi/Reader.java
+++ b/core/java/android/se/omapi/Reader.java
@@ -37,7 +37,7 @@
*
* @see <a href="http://globalplatform.org">GlobalPlatform Open Mobile API</a>
*/
-public class Reader {
+public final class Reader {
private static final String TAG = "OMAPI.Reader";
private final String mName;
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index 311dc4c..14727f0 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -32,6 +32,7 @@
import android.util.Log;
import java.util.HashMap;
+import java.util.concurrent.Executor;
/**
* The SEService realises the communication to available Secure Elements on the
@@ -40,7 +41,7 @@
*
* @see <a href="http://simalliance.org">SIMalliance Open Mobile API v3.0</a>
*/
-public class SEService {
+public final class SEService {
/**
* Error code used with ServiceSpecificException.
@@ -62,11 +63,11 @@
/**
* Interface to send call-backs to the application when the service is connected.
*/
- public interface SecureElementListener {
+ public interface OnConnectedListener {
/**
* Called by the framework when the service is connected.
*/
- void onServiceConnected();
+ void onConnected();
}
/**
@@ -74,16 +75,22 @@
* SEService could be bound to the backend.
*/
private class SEListener extends ISecureElementListener.Stub {
- public SecureElementListener mListener = null;
+ public OnConnectedListener mListener = null;
+ public Executor mExecutor = null;
@Override
public IBinder asBinder() {
return this;
}
- public void onServiceConnected() {
- if (mListener != null) {
- mListener.onServiceConnected();
+ public void onConnected() {
+ if (mListener != null && mExecutor != null) {
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onConnected();
+ }
+ });
}
}
}
@@ -116,22 +123,26 @@
* the specified listener is called or if isConnected() returns
* <code>true</code>. <br>
* The call-back object passed as a parameter will have its
- * onServiceConnected() method called when the connection actually happen.
+ * onConnected() method called when the connection actually happen.
*
* @param context
* the context of the calling application. Cannot be
* <code>null</code>.
* @param listener
- * a SecureElementListener object.
+ * a OnConnectedListener object.
+ * @param executor
+ * an Executor which will be used when invoking the callback.
*/
- public SEService(@NonNull Context context, @NonNull SecureElementListener listener) {
+ public SEService(@NonNull Context context, @NonNull Executor executor,
+ @NonNull OnConnectedListener listener) {
- if (context == null) {
- throw new NullPointerException("context must not be null");
+ if (context == null || listener == null || executor == null) {
+ throw new NullPointerException("Arguments must not be null");
}
mContext = context;
mSEListener.mListener = listener;
+ mSEListener.mExecutor = executor;
mConnection = new ServiceConnection() {
@@ -140,7 +151,7 @@
mSecureElementService = ISecureElementService.Stub.asInterface(service);
if (mSEListener != null) {
- mSEListener.onServiceConnected();
+ mSEListener.onConnected();
}
Log.i(TAG, "Service onServiceConnected");
}
@@ -171,12 +182,12 @@
}
/**
- * Returns the list of available Secure Element readers.
+ * Returns an array of available Secure Element readers.
* There must be no duplicated objects in the returned list.
* All available readers shall be listed even if no card is inserted.
*
- * @return The readers list, as an array of Readers. If there are no
- * readers the returned array is of length 0.
+ * @return An array of Readers. If there are no readers the returned array
+ * is of length 0.
*/
public @NonNull Reader[] getReaders() {
if (mSecureElementService == null) {
@@ -212,7 +223,8 @@
* (including any binding to an underlying service).
* As a result isConnected() will return false after shutdown() was called.
* After this method call, the SEService object is not connected.
- * It is recommended to call this method in the termination method of the calling application
+ * This method should be called when connection to the Secure Element is not needed
+ * or in the termination method of the calling application
* (or part of this application) which is bound to this SEService.
*/
public void shutdown() {
diff --git a/core/java/android/se/omapi/Session.java b/core/java/android/se/omapi/Session.java
index adfeddd..d5f8c82 100644
--- a/core/java/android/se/omapi/Session.java
+++ b/core/java/android/se/omapi/Session.java
@@ -39,7 +39,7 @@
*
* @see <a href="http://simalliance.org">SIMalliance Open Mobile API v3.0</a>
*/
-public class Session {
+public final class Session {
private final Object mLock = new Object();
private final SEService mService;
@@ -225,6 +225,32 @@
}
/**
+ * This method is provided to ease the development of mobile application and for compliancy
+ * with existing applications.
+ * This method is equivalent to openBasicChannel(aid, P2=0x00)
+ *
+ * @param aid the AID of the Applet to be selected on this channel, as a
+ * byte array, or null if no Applet is to be selected.
+ * @throws IOException if there is a communication problem to the reader or
+ * the Secure Element.
+ * @throws IllegalStateException if the Secure Element session is used after
+ * being closed.
+ * @throws IllegalArgumentException if the aid's length is not within 5 to
+ * 16 (inclusive).
+ * @throws SecurityException if the calling application cannot be granted
+ * access to this AID or the default Applet on this
+ * session.
+ * @throws NoSuchElementException if the AID on the Secure Element is not available or cannot be
+ * selected.
+ * @throws UnsupportedOperationException if the given P2 parameter is not
+ * supported by the device
+ * @return an instance of Channel if available or null.
+ */
+ public @Nullable Channel openBasicChannel(@Nullable byte[] aid) throws IOException {
+ return openBasicChannel(aid, (byte) 0x00);
+ }
+
+ /**
* Open a logical channel with the Secure Element, selecting the Applet represented by
* the given AID. If the AID is null, which means no Applet is to be selected on this
* channel, the default Applet is used. It's up to the Secure Element to choose which
@@ -304,4 +330,32 @@
}
}
}
+
+ /**
+ * This method is provided to ease the development of mobile application and for compliancy
+ * with existing applications.
+ * This method is equivalent to openLogicalChannel(aid, P2=0x00)
+ *
+ * @param aid the AID of the Applet to be selected on this channel, as a
+ * byte array.
+ * @throws IOException if there is a communication problem to the reader or
+ * the Secure Element.
+ * @throws IllegalStateException if the Secure Element is used after being
+ * closed.
+ * @throws IllegalArgumentException if the aid's length is not within 5 to
+ * 16 (inclusive).
+ * @throws SecurityException if the calling application cannot be granted
+ * access to this AID or the default Applet on this
+ * session.
+ * @throws NoSuchElementException if the AID on the Secure Element is not
+ * available or cannot be selected or a logical channel is already
+ * open to a non-multiselectable Applet.
+ * @throws UnsupportedOperationException if the given P2 parameter is not
+ * supported by the device.
+ * @return an instance of Channel. Null if the Secure Element is unable to
+ * provide a new logical channel.
+ */
+ public @Nullable Channel openLogicalChannel(@Nullable byte[] aid) throws IOException {
+ return openLogicalChannel(aid, (byte) 0x00);
+ }
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f4715fc..04c4130 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4248,6 +4248,11 @@
android:exported="false">
</receiver>
+ <receiver android:name="com.android.server.stats.StatsCompanionService$PeriodicAlarmReceiver"
+ android:permission="android.permission.STATSCOMPANION"
+ android:exported="false">
+ </receiver>
+
<receiver android:name="com.android.server.am.BatteryStatsService$UsbConnectionReceiver"
android:exported="false">
<intent-filter>
diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml
index a4a1b94..95aff9a 100644
--- a/data/etc/hiddenapi-package-whitelist.xml
+++ b/data/etc/hiddenapi-package-whitelist.xml
@@ -55,6 +55,7 @@
<hidden-api-whitelisted-app package="com.android.companiondevicemanager" />
<hidden-api-whitelisted-app package="com.android.customlocale2" />
<hidden-api-whitelisted-app package="com.android.defcontainer" />
+ <hidden-api-whitelisted-app package="com.android.development" />
<hidden-api-whitelisted-app package="com.android.documentsui" />
<hidden-api-whitelisted-app package="com.android.dreams.basic" />
<hidden-api-whitelisted-app package="com.android.egg" />
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 32d4c77..3ca9295 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -151,7 +151,12 @@
mGrContext->freeGpuResources();
break;
case TrimMemoryMode::UiHidden:
- mGrContext->purgeUnlockedResources(mMaxResourceBytes - mBackgroundResourceBytes, true);
+ // Here we purge all the unlocked scratch resources and then toggle the resources cache
+ // limits between the background and max amounts. This causes the unlocked resources
+ // that have persistent data to be purged in LRU order.
+ mGrContext->purgeUnlockedResources(true);
+ mGrContext->setResourceCacheLimits(mMaxResources, mBackgroundResourceBytes);
+ mGrContext->setResourceCacheLimits(mMaxResources, mMaxResourceBytes);
break;
}
}
@@ -161,7 +166,10 @@
return;
}
mGrContext->flush();
- mGrContext->purgeResourcesNotUsedInMs(std::chrono::seconds(30));
+ // Here we purge all the unlocked scratch resources (leaving those resources w/ persistent data)
+ // and then purge those w/ persistent data based on age.
+ mGrContext->purgeUnlockedResources(true);
+ mGrContext->purgeResourcesNotUsedInMs(std::chrono::seconds(10));
}
sp<skiapipeline::VectorDrawableAtlas> CacheManager::acquireVectorDrawableAtlas() {
diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp
index b1106f0..c235715 100644
--- a/libs/hwui/tests/unit/CacheManagerTests.cpp
+++ b/libs/hwui/tests/unit/CacheManagerTests.cpp
@@ -20,6 +20,8 @@
#include "renderthread/EglManager.h"
#include "tests/common/TestUtils.h"
+#include <SkImagePriv.h>
+
using namespace android;
using namespace android::uirenderer;
using namespace android::uirenderer::renderthread;
@@ -49,7 +51,12 @@
surfaces.push_back(surface);
}
- ASSERT_TRUE(1 < surfaces.size());
+ // create an image and pin it so that we have something with a unique key in the cache
+ sk_sp<Bitmap> bitmap =
+ Bitmap::allocateHeapBitmap(SkImageInfo::MakeA8(displayInfo.w, displayInfo.h));
+ sk_sp<SkColorFilter> filter;
+ sk_sp<SkImage> image = bitmap->makeImage(&filter);
+ ASSERT_TRUE(SkImage_pinAsTexture(image.get(), grContext));
// attempt to trim all memory while we still hold strong refs
renderThread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete);
@@ -61,11 +68,14 @@
surfaces[i].reset();
}
+ // unpin the image which should add a unique purgeable key to the cache
+ SkImage_unpinAsTexture(image.get(), grContext);
+
// verify that we have enough purgeable bytes
const size_t purgeableBytes = grContext->getResourceCachePurgeableBytes();
ASSERT_TRUE(renderThread.cacheManager().getBackgroundCacheSize() < purgeableBytes);
- // UI hidden and make sure only some got purged
+ // UI hidden and make sure only some got purged (unique should remain)
renderThread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden);
ASSERT_TRUE(0 < grContext->getResourceCachePurgeableBytes());
ASSERT_TRUE(renderThread.cacheManager().getBackgroundCacheSize() > getCacheUsage(grContext));
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
index 6f153c1..78304fd 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
@@ -41,16 +41,4 @@
</FrameLayout>
- <com.android.systemui.statusbar.policy.DeadZone
- android:id="@+id/deadzone"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:layout_gravity="top"
- systemui:minSize="@dimen/navigation_bar_deadzone_size"
- systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
- systemui:holdTime="@integer/navigation_bar_deadzone_hold"
- systemui:decayTime="@integer/navigation_bar_deadzone_decay"
- systemui:orientation="horizontal"
- />
-
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
index 3e60794..953abc7 100644
--- a/packages/SystemUI/res/layout/navigation_layout.xml
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -46,16 +46,4 @@
</com.android.systemui.statusbar.phone.NearestTouchFrame>
- <com.android.systemui.statusbar.policy.DeadZone
- android:id="@+id/deadzone"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:layout_gravity="top"
- systemui:minSize="@dimen/navigation_bar_deadzone_size"
- systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
- systemui:holdTime="@integer/navigation_bar_deadzone_hold"
- systemui:decayTime="@integer/navigation_bar_deadzone_decay"
- systemui:orientation="horizontal"
- />
-
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/navigation_layout_rot90.xml b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
index 39cdff4..0e17e5b5 100644
--- a/packages/SystemUI/res/layout/navigation_layout_rot90.xml
+++ b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
@@ -46,16 +46,4 @@
</com.android.systemui.statusbar.phone.NearestTouchFrame>
- <com.android.systemui.statusbar.policy.DeadZone
- android:id="@+id/deadzone"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:layout_gravity="top"
- systemui:minSize="@dimen/navigation_bar_deadzone_size"
- systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
- systemui:holdTime="@integer/navigation_bar_deadzone_hold"
- systemui:decayTime="@integer/navigation_bar_deadzone_decay"
- systemui:orientation="vertical"
- />
-
</FrameLayout>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index f7e2344..63bbe62 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -28,4 +28,7 @@
<!-- We have only space for one notification on phone landscape layouts. -->
<integer name="keyguard_max_notification_count">1</integer>
+
+ <!-- orientation of the dead zone when touches have recently occurred elsewhere on screen -->
+ <integer name="navigation_bar_deadzone_orientation">1</integer>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 67dabdb..f91af03 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -35,4 +35,7 @@
<!-- Animation duration when using long press on recents to dock -->
<integer name="long_press_dock_anim_duration">290</integer>
+ <!-- orientation of the dead zone when touches have recently occurred elsewhere on screen -->
+ <integer name="navigation_bar_deadzone_orientation">0</integer>
+
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 711d550..f49d3de4 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -93,6 +93,9 @@
<integer name="navigation_bar_deadzone_hold">333</integer>
<integer name="navigation_bar_deadzone_decay">333</integer>
+ <!-- orientation of the dead zone when touches have recently occurred elsewhere on screen -->
+ <integer name="navigation_bar_deadzone_orientation">0</integer>
+
<bool name="config_dead_zone_flash">false</bool>
<!-- Whether to enable dimming navigation buttons when wallpaper is not visible, should be
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 8cff56d..8e59842 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Handler;
@@ -39,6 +40,7 @@
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.GraphicBufferCompat;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.CallbackController;
@@ -71,11 +73,13 @@
private final DeviceProvisionedController mDeviceProvisionedController
= Dependency.get(DeviceProvisionedController.class);
private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
+ private final Intent mQuickStepIntent;
private IOverviewProxy mOverviewProxy;
private int mConnectionBackoffAttempts;
private CharSequence mOnboardingText;
private @InteractionType int mInteractionFlags;
+ private boolean mIsEnabled;
private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@@ -130,14 +134,23 @@
});
}
} finally {
+ Prefs.putInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, mInteractionFlags);
Binder.restoreCallingIdentity(token);
}
}
};
- private final BroadcastReceiver mLauncherAddedReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mLauncherStateChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ updateEnabledState();
+
+ // When launcher service is disabled, reset interaction flags because it is inactive
+ if (!isEnabled()) {
+ mInteractionFlags = 0;
+ Prefs.remove(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS);
+ }
+
// Reconnect immediately, instead of waiting for resume to arrive.
startConnectionToCurrentUser();
}
@@ -196,17 +209,21 @@
mConnectionBackoffAttempts = 0;
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
com.android.internal.R.string.config_recentsComponentName));
+ mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
+ .setPackage(mRecentsComponentName.getPackageName());
+ mInteractionFlags = Prefs.getInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, 0);
// Listen for the package update changes.
if (SystemServicesProxy.getInstance(context)
.isSystemUser(mDeviceProvisionedController.getCurrentUser())) {
+ updateEnabledState();
mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addDataScheme("package");
filter.addDataSchemeSpecificPart(mRecentsComponentName.getPackageName(),
PatternMatcher.PATTERN_LITERAL);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- mContext.registerReceiver(mLauncherAddedReceiver, filter);
+ mContext.registerReceiver(mLauncherStateChangedReceiver, filter);
}
}
@@ -222,7 +239,7 @@
disconnectFromLauncherService();
// If user has not setup yet or already connected, do not try to connect
- if (!mDeviceProvisionedController.isCurrentUserSetup()) {
+ if (!mDeviceProvisionedController.isCurrentUserSetup() || !isEnabled()) {
return;
}
mHandler.removeCallbacks(mConnectionRunnable);
@@ -248,6 +265,7 @@
public void addCallback(OverviewProxyListener listener) {
mConnectionCallbacks.add(listener);
listener.onConnectionChanged(mOverviewProxy != null);
+ listener.onInteractionFlagsChanged(mInteractionFlags);
}
@Override
@@ -256,7 +274,11 @@
}
public boolean shouldShowSwipeUpUI() {
- return getProxy() != null && ((mInteractionFlags & FLAG_DISABLE_SWIPE_UP) == 0);
+ return isEnabled() && ((mInteractionFlags & FLAG_DISABLE_SWIPE_UP) == 0);
+ }
+
+ public boolean isEnabled() {
+ return mIsEnabled;
}
public IOverviewProxy getProxy() {
@@ -292,6 +314,11 @@
}
}
+ private void updateEnabledState() {
+ mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent, 0,
+ ActivityManagerWrapper.getInstance().getCurrentUserId()) != null;
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(TAG_OPS + " state:");
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 2a27147..7f7a769 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -54,7 +54,8 @@
Key.HAS_SEEN_RECENTS_ONBOARDING,
Key.SEEN_RINGER_GUIDANCE_COUNT,
Key.QS_HAS_TURNED_OFF_MOBILE_DATA,
- Key.TOUCHED_RINGER_TOGGLE
+ Key.TOUCHED_RINGER_TOGGLE,
+ Key.QUICK_STEP_INTERACTION_FLAGS
})
public @interface Key {
@Deprecated
@@ -93,6 +94,7 @@
String QS_TILE_SPECS_REVEALED = "QsTileSpecsRevealed";
String QS_HAS_TURNED_OFF_MOBILE_DATA = "QsHasTurnedOffMobileData";
String TOUCHED_RINGER_TOGGLE = "TouchedRingerToggle";
+ String QUICK_STEP_INTERACTION_FLAGS = "QuickStepInteractionFlags";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 19da3db..6fcb1c1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -126,7 +126,7 @@
@Override
public void onTaskStackChangedBackground() {
// Skip background preloading recents in SystemUI if the overview services is bound
- if (Dependency.get(OverviewProxyService.class).getProxy() != null) {
+ if (Dependency.get(OverviewProxyService.class).isEnabled()) {
return;
}
@@ -300,7 +300,7 @@
public void onBootCompleted() {
// Skip preloading tasks if we are already bound to the service
- if (Dependency.get(OverviewProxyService.class).getProxy() != null) {
+ if (Dependency.get(OverviewProxyService.class).isEnabled()) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index f216695..4c4eb60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -124,7 +124,7 @@
private TintedKeyButtonDrawable mRotateSuggestionIcon;
private GestureHelper mGestureHelper;
- private DeadZone mDeadZone;
+ private final DeadZone mDeadZone;
private final NavigationBarTransitions mBarTransitions;
private final OverviewProxyService mOverviewProxyService;
@@ -263,6 +263,7 @@
new ButtonDispatcher(R.id.accessibility_button));
mButtonDispatchers.put(R.id.rotate_suggestion,
new ButtonDispatcher(R.id.rotate_suggestion));
+ mDeadZone = new DeadZone(this);
}
public BarTransitions getBarTransitions() {
@@ -297,6 +298,10 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
+ if (mDeadZone.onTouchEvent(event)) {
+ // Consumed the touch event
+ return true;
+ }
switch (event.getActionMasked()) {
case ACTION_DOWN:
int x = (int) event.getX();
@@ -319,6 +324,10 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
+ if (mDeadZone.onTouchEvent(event)) {
+ // Consumed the touch event
+ return true;
+ }
if (mGestureHelper.onTouchEvent(event)) {
return true;
}
@@ -389,7 +398,7 @@
public boolean isQuickScrubEnabled() {
return SystemProperties.getBoolean("persist.quickstep.scrub.enabled", true)
- && mOverviewProxyService.getProxy() != null && isOverviewEnabled()
+ && mOverviewProxyService.isEnabled() && isOverviewEnabled()
&& ((mOverviewProxyService.getInteractionFlags() & FLAG_DISABLE_QUICK_SCRUB) == 0);
}
@@ -587,7 +596,7 @@
// recents buttons when disconnected from launcher service in screen pinning mode,
// as they are used for exiting.
final boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
- if (mOverviewProxyService.getProxy() != null) {
+ if (mOverviewProxyService.isEnabled()) {
// Use interaction flags to show/hide navigation buttons but will be shown if required
// to exit screen pinning.
final int flags = mOverviewProxyService.getInteractionFlags();
@@ -818,6 +827,7 @@
@Override
protected void onDraw(Canvas canvas) {
mGestureHelper.onDraw(canvas);
+ mDeadZone.onDraw(canvas);
super.onDraw(canvas);
}
@@ -889,10 +899,8 @@
public void reorient() {
updateCurrentView();
- mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
-
((NavigationBarFrame) getRootView()).setDeadZone(mDeadZone);
- mDeadZone.setDisplayRotation(mCurrentRotation);
+ mDeadZone.onConfigurationChanged(mCurrentRotation);
// force the low profile & disabled states into compliance
mBarTransitions.init();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 04cb620..304a499 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -488,7 +488,7 @@
mUpdateFlingVelocity = vel;
}
} else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking
- && !mStatusBar.isBouncerShowing()) {
+ && !mStatusBar.isBouncerShowing() && !mStatusBar.isKeyguardFadingAway()) {
long timePassed = SystemClock.uptimeMillis() - mDownTime;
if (timePassed < ViewConfiguration.getLongPressTimeout()) {
// Lets show the user that he can actually expand the panel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index a51cd93..af77804 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -168,8 +168,8 @@
}
private boolean handleTouchEvent(MotionEvent event) {
- if (!mNavigationBarView.isQuickScrubEnabled()
- && !mNavigationBarView.isQuickStepSwipeUpEnabled()) {
+ if (mOverviewEventSender.getProxy() == null || (!mNavigationBarView.isQuickScrubEnabled()
+ && !mNavigationBarView.isQuickStepSwipeUpEnabled())) {
mNavigationBarView.getHomeButton().setDelayTouchFeedback(false /* delay */);
return false;
}
@@ -199,7 +199,7 @@
break;
}
case MotionEvent.ACTION_MOVE: {
- if (mQuickStepStarted || !mAllowGestureDetection){
+ if (mQuickStepStarted || !mAllowGestureDetection || mHomeButtonView == null){
break;
}
int x = (int) event.getX();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index 06040e2..4a11754 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -17,18 +17,16 @@
package com.android.systemui.statusbar.policy;
import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.os.SystemClock;
-import android.util.AttributeSet;
import android.util.Slog;
import android.view.MotionEvent;
import android.view.Surface;
-import android.view.View;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.phone.NavigationBarView;
import com.android.systemui.statusbar.phone.StatusBar;
/**
@@ -38,7 +36,7 @@
* outside the navigation bar (since this is when accidental taps are more likely), then contracts
* back over time (since a later tap might be intended for the top of the bar).
*/
-public class DeadZone extends View {
+public class DeadZone {
public static final String TAG = "DeadZone";
public static final boolean DEBUG = false;
@@ -47,6 +45,7 @@
private static final boolean CHATTY = true; // print to logcat when we eat a click
private final StatusBar mStatusBar;
+ private final NavigationBarView mNavigationBarView;
private boolean mShouldFlash;
private float mFlashFrac = 0f;
@@ -67,31 +66,11 @@
}
};
- public DeadZone(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public DeadZone(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DeadZone,
- defStyle, 0);
-
- mHold = a.getInteger(R.styleable.DeadZone_holdTime, 0);
- mDecay = a.getInteger(R.styleable.DeadZone_decayTime, 0);
-
- mSizeMin = a.getDimensionPixelSize(R.styleable.DeadZone_minSize, 0);
- mSizeMax = a.getDimensionPixelSize(R.styleable.DeadZone_maxSize, 0);
-
- int index = a.getInt(R.styleable.DeadZone_orientation, -1);
- mVertical = (index == VERTICAL);
-
- if (DEBUG)
- Slog.v(TAG, this + " size=[" + mSizeMin + "-" + mSizeMax + "] hold=" + mHold
- + (mVertical ? " vertical" : " horizontal"));
-
- setFlashOnTouchCapture(context.getResources().getBoolean(R.bool.config_dead_zone_flash));
- mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);
+ public DeadZone(NavigationBarView view) {
+ mNavigationBarView = view;
+ mStatusBar = SysUiServiceProvider.getComponent(mNavigationBarView.getContext(),
+ StatusBar.class);
+ onConfigurationChanged(HORIZONTAL);
}
static float lerp(float a, float b, float f) {
@@ -112,11 +91,29 @@
public void setFlashOnTouchCapture(boolean dbg) {
mShouldFlash = dbg;
mFlashFrac = 0f;
- postInvalidate();
+ mNavigationBarView.postInvalidate();
+ }
+
+ public void onConfigurationChanged(int rotation) {
+ mDisplayRotation = rotation;
+
+ final Resources res = mNavigationBarView.getResources();
+ mHold = res.getInteger(R.integer.navigation_bar_deadzone_hold);
+ mDecay = res.getInteger(R.integer.navigation_bar_deadzone_decay);
+
+ mSizeMin = res.getDimensionPixelSize(R.dimen.navigation_bar_deadzone_size);
+ mSizeMax = res.getDimensionPixelSize(R.dimen.navigation_bar_deadzone_size_max);
+ int index = res.getInteger(R.integer.navigation_bar_deadzone_orientation);
+ mVertical = (index == VERTICAL);
+
+ if (DEBUG) {
+ Slog.v(TAG, this + " size=[" + mSizeMin + "-" + mSizeMax + "] hold=" + mHold
+ + (mVertical ? " vertical" : " horizontal"));
+ }
+ setFlashOnTouchCapture(res.getBoolean(R.bool.config_dead_zone_flash));
}
// I made you a touch event...
- @Override
public boolean onTouchEvent(MotionEvent event) {
if (DEBUG) {
Slog.v(TAG, this + " onTouch: " + MotionEvent.actionToString(event.getAction()));
@@ -143,7 +140,7 @@
final boolean consumeEvent;
if (mVertical) {
if (mDisplayRotation == Surface.ROTATION_270) {
- consumeEvent = event.getX() > getWidth() - size;
+ consumeEvent = event.getX() > mNavigationBarView.getWidth() - size;
} else {
consumeEvent = event.getX() < size;
}
@@ -155,8 +152,8 @@
Slog.v(TAG, "consuming errant click: (" + event.getX() + "," + event.getY() + ")");
}
if (mShouldFlash) {
- post(mDebugFlash);
- postInvalidate();
+ mNavigationBarView.post(mDebugFlash);
+ mNavigationBarView.postInvalidate();
}
return true; // ...but I eated it
}
@@ -168,19 +165,18 @@
mLastPokeTime = event.getEventTime();
if (DEBUG)
Slog.v(TAG, "poked! size=" + getSize(mLastPokeTime));
- if (mShouldFlash) postInvalidate();
+ if (mShouldFlash) mNavigationBarView.postInvalidate();
}
public void setFlash(float f) {
mFlashFrac = f;
- postInvalidate();
+ mNavigationBarView.postInvalidate();
}
public float getFlash() {
return mFlashFrac;
}
- @Override
public void onDraw(Canvas can) {
if (!mShouldFlash || mFlashFrac <= 0f) {
return;
@@ -202,10 +198,6 @@
if (DEBUG && size > mSizeMin)
// crazy aggressive redrawing here, for debugging only
- postInvalidateDelayed(100);
- }
-
- public void setDisplayRotation(int rotation) {
- mDisplayRotation = rotation;
+ mNavigationBarView.postInvalidateDelayed(100);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 5d7e938..44c2757 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -200,7 +200,7 @@
}
public boolean onTouchEvent(MotionEvent ev) {
- final boolean isProxyConnected = mOverviewProxyService.getProxy() != null;
+ final boolean showSwipeUI = mOverviewProxyService.shouldShowSwipeUpUI();
final int action = ev.getAction();
int x, y;
if (action == MotionEvent.ACTION_DOWN) {
@@ -226,7 +226,7 @@
// Provide the same haptic feedback that the system offers for virtual keys.
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
}
- if (!isProxyConnected) {
+ if (!showSwipeUI) {
playSoundEffect(SoundEffectConstants.CLICK);
}
removeCallbacks(mCheckLongPress);
@@ -255,7 +255,7 @@
final boolean doIt = isPressed() && !mLongClicked;
setPressed(false);
final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150;
- if (isProxyConnected) {
+ if (showSwipeUI) {
if (doIt) {
if (doHapticFeedback) {
mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index c6878d7..c66c7b0 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5562,6 +5562,16 @@
// OS: P
PREVIOUSLY_CONNECTED_DEVICES = 1370;
+ // ACTION: A Settings Slice is requested
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_SETTINGS_SLICE_REQUESTED = 1371;
+
+ // ACTION: A Settings Slice is updated with new value
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_SETTINGS_SLICE_CHANGED = 1372;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index bde6bd8..cd90e3f 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -24,6 +24,8 @@
import static android.system.OsConstants.SOCK_DGRAM;
import static com.android.internal.util.Preconditions.checkNotNull;
+import android.annotation.NonNull;
+import android.app.AppOpsManager;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.IIpSecService;
@@ -42,6 +44,7 @@
import android.net.TrafficStats;
import android.net.util.NetdService;
import android.os.Binder;
+import android.os.DeadSystemException;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -974,6 +977,13 @@
return service;
}
+ @NonNull
+ private AppOpsManager getAppOpsManager() {
+ AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ if(appOps == null) throw new RuntimeException("System Server couldn't get AppOps");
+ return appOps;
+ }
+
/** @hide */
@VisibleForTesting
public IpSecService(Context context, IpSecServiceConfiguration config) {
@@ -1240,7 +1250,9 @@
*/
@Override
public synchronized IpSecTunnelInterfaceResponse createTunnelInterface(
- String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder) {
+ String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder,
+ String callingPackage) {
+ enforceTunnelPermissions(callingPackage);
checkNotNull(binder, "Null Binder passed to createTunnelInterface");
checkNotNull(underlyingNetwork, "No underlying network was specified");
checkInetAddress(localAddr);
@@ -1320,8 +1332,8 @@
*/
@Override
public synchronized void addAddressToTunnelInterface(
- int tunnelResourceId, LinkAddress localAddr) {
- enforceNetworkStackPermission();
+ int tunnelResourceId, LinkAddress localAddr, String callingPackage) {
+ enforceTunnelPermissions(callingPackage);
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
// Get tunnelInterface record; if no such interface is found, will throw
@@ -1352,10 +1364,10 @@
*/
@Override
public synchronized void removeAddressFromTunnelInterface(
- int tunnelResourceId, LinkAddress localAddr) {
- enforceNetworkStackPermission();
- UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+ int tunnelResourceId, LinkAddress localAddr, String callingPackage) {
+ enforceTunnelPermissions(callingPackage);
+ UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
// Get tunnelInterface record; if no such interface is found, will throw
// IllegalArgumentException
TunnelInterfaceRecord tunnelInterfaceInfo =
@@ -1383,7 +1395,9 @@
* server
*/
@Override
- public synchronized void deleteTunnelInterface(int resourceId) throws RemoteException {
+ public synchronized void deleteTunnelInterface(
+ int resourceId, String callingPackage) throws RemoteException {
+ enforceTunnelPermissions(callingPackage);
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
releaseResource(userRecord.mTunnelInterfaceRecords, resourceId);
}
@@ -1469,7 +1483,6 @@
case IpSecTransform.MODE_TRANSPORT:
break;
case IpSecTransform.MODE_TUNNEL:
- enforceNetworkStackPermission();
break;
default:
throw new IllegalArgumentException(
@@ -1477,9 +1490,20 @@
}
}
- private void enforceNetworkStackPermission() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK,
- "IpSecService");
+ private void enforceTunnelPermissions(String callingPackage) {
+ checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels");
+ switch (getAppOpsManager().noteOp(
+ AppOpsManager.OP_MANAGE_IPSEC_TUNNELS,
+ Binder.getCallingUid(), callingPackage)) {
+ case AppOpsManager.MODE_DEFAULT:
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService");
+ break;
+ case AppOpsManager.MODE_ALLOWED:
+ return;
+ default:
+ throw new SecurityException("Request to ignore AppOps for non-legacy API");
+ }
}
private void createOrUpdateTransform(
@@ -1535,8 +1559,12 @@
* result in all of those sockets becoming unable to send or receive data.
*/
@Override
- public synchronized IpSecTransformResponse createTransform(IpSecConfig c, IBinder binder)
- throws RemoteException {
+ public synchronized IpSecTransformResponse createTransform(
+ IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException {
+ checkNotNull(c);
+ if (c.getMode() == IpSecTransform.MODE_TUNNEL) {
+ enforceTunnelPermissions(callingPackage);
+ }
checkIpSecConfig(c);
checkNotNull(binder, "Null Binder passed to createTransform");
final int resourceId = mNextResourceId++;
@@ -1657,8 +1685,9 @@
*/
@Override
public synchronized void applyTunnelModeTransform(
- int tunnelResourceId, int direction, int transformResourceId) throws RemoteException {
- enforceNetworkStackPermission();
+ int tunnelResourceId, int direction,
+ int transformResourceId, String callingPackage) throws RemoteException {
+ enforceTunnelPermissions(callingPackage);
checkDirection(direction);
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/net/watchlist/ReportEncoder.java b/services/core/java/com/android/server/net/watchlist/ReportEncoder.java
index 2a8f4d5..a482e05 100644
--- a/services/core/java/com/android/server/net/watchlist/ReportEncoder.java
+++ b/services/core/java/com/android/server/net/watchlist/ReportEncoder.java
@@ -49,6 +49,7 @@
* Apply DP on watchlist results, and generate a serialized watchlist report ready to store
* in DropBox.
*/
+ @Nullable
static byte[] encodeWatchlistReport(WatchlistConfig config, byte[] userSecret,
List<String> appDigestList, WatchlistReportDbHelper.AggregatedResult aggregatedResult) {
Map<String, Boolean> resultMap = PrivacyUtils.createDpEncodedReportMap(
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
index d793842..8352ca6 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
@@ -16,6 +16,7 @@
package com.android.server.net.watchlist;
+import android.annotation.Nullable;
import android.os.FileUtils;
import android.util.AtomicFile;
import android.util.Log;
@@ -55,9 +56,6 @@
private static final String NETWORK_WATCHLIST_DB_FOR_TEST_PATH =
"/data/misc/network_watchlist/network_watchlist_for_test.xml";
- // Hash for null / unknown config, a 32 byte array filled with content 0x00
- private static final byte[] UNKNOWN_CONFIG_HASH = new byte[32];
-
private static class XmlTags {
private static final String WATCHLIST_CONFIG = "watchlist-config";
private static final String SHA256_DOMAIN = "sha256-domain";
@@ -228,16 +226,21 @@
return mIsSecureConfig;
}
+ @Nullable
+ /**
+ * Get watchlist config SHA-256 digest.
+ * Return null if watchlist config does not exist.
+ */
public byte[] getWatchlistConfigHash() {
if (!mXmlFile.exists()) {
- return UNKNOWN_CONFIG_HASH;
+ return null;
}
try {
return DigestUtils.getSha256Hash(mXmlFile);
} catch (IOException | NoSuchAlgorithmException e) {
Log.e(TAG, "Unable to get watchlist config hash", e);
}
- return UNKNOWN_CONFIG_HASH;
+ return null;
}
/**
@@ -271,8 +274,10 @@
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("Watchlist config hash: " + HexDump.toHexString(getWatchlistConfigHash()));
+ final byte[] hash = getWatchlistConfigHash();
+ pw.println("Watchlist config hash: " + (hash != null ? HexDump.toHexString(hash) : null));
pw.println("Domain CRC32 digest list:");
+ // mDomainDigests won't go from non-null to null so it's safe
if (mDomainDigests != null) {
mDomainDigests.crc32Digests.dump(fd, pw, args);
}
@@ -281,6 +286,7 @@
mDomainDigests.sha256Digests.dump(fd, pw, args);
}
pw.println("Ip CRC32 digest list:");
+ // mIpDigests won't go from non-null to null so it's safe
if (mIpDigests != null) {
mIpDigests.crc32Digests.dump(fd, pw, args);
}
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
index b331b9c..864ce5d 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
@@ -346,6 +346,7 @@
* @param ipAddresses Ip address that you want to search in watchlist.
* @return Ip address that exists in watchlist, null if it does not match anything.
*/
+ @Nullable
private String searchIpInWatchlist(String[] ipAddresses) {
for (String ipAddress : ipAddresses) {
if (isIpInWatchlist(ipAddress)) {
@@ -377,6 +378,7 @@
* @param host Host that we want to search.
* @return Domain that exists in watchlist, null if it does not match anything.
*/
+ @Nullable
private String searchAllSubDomainsInWatchlist(String host) {
if (host == null) {
return null;
@@ -392,6 +394,7 @@
/** Get all sub-domains in a host */
@VisibleForTesting
+ @Nullable
static String[] getAllSubDomains(String host) {
if (host == null) {
return null;
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
index 632ab81..c69934a 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
@@ -144,6 +144,7 @@
* Aggregate all records in database before input timestamp, and return a
* rappor encoded result.
*/
+ @Nullable
public AggregatedResult getAggregatedRecords(long untilTimestamp) {
final String selectStatement = WhiteListReportContract.TIMESTAMP + " < ?";
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
index e20a510..c2f3ba0 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
@@ -86,7 +86,7 @@
}
}
- public void reloadSettings() {
+ private void reloadSettings() {
if (!mXmlFile.exists()) {
// No settings config
return;
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index fae0b24..d4625e9 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -379,7 +379,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG)
- Slog.d(TAG, "Time to poll something.");
+ Slog.d(TAG, "Time to trigger periodic alarm.");
synchronized (sStatsdLock) {
if (sStatsd == null) {
Slog.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
@@ -455,13 +455,13 @@
public void setAlarmForSubscriberTriggering(long timestampMs) {
enforceCallingPermission();
if (DEBUG)
- Slog.d(TAG, "Setting periodic alarm at " + timestampMs);
+ Slog.d(TAG, "Setting periodic alarm in about " +
+ (timestampMs - SystemClock.elapsedRealtime()));
final long callingToken = Binder.clearCallingIdentity();
try {
// using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
// only fire when it awakens.
- // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, timestampMs, mPeriodicAlarmIntent);
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, mPeriodicAlarmIntent);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
index 654acc2..678f018 100644
--- a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
@@ -114,13 +115,19 @@
}
@Test
- public void testWatchlistConfig_getWatchlistConfigHash() throws Exception {
+ public void testWatchlistConfig_getWatchlistConfigHash_hasConfig() throws Exception {
copyWatchlistConfigXml(mContext, TEST_XML_1, mTestXmlFile);
WatchlistConfig config = new WatchlistConfig(mTestXmlFile);
assertEquals(TEST_XML_1_HASH, HexDump.toHexString(config.getWatchlistConfigHash()));
}
@Test
+ public void testWatchlistConfig_getWatchlistConfigHash_withoutConfig() throws Exception {
+ WatchlistConfig config = new WatchlistConfig(mTestXmlFile);
+ assertNull(config.getWatchlistConfigHash());
+ }
+
+ @Test
public void testWatchlistConfig_testDumpDoesNotCrash() throws Exception {
WatchlistConfig config = new WatchlistConfig(new File("/not_exist_path.xml"));
ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 36333e4..3bf951d 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -2600,7 +2600,6 @@
}
/**
- *
* Request audio routing to a specific bluetooth device. Calling this method may result in
* the device routing audio to a different bluetooth device than the one specified if the
* bluetooth stack is unable to route audio to the requested device.
@@ -2611,13 +2610,13 @@
* Used by self-managed {@link ConnectionService}s which wish to use bluetooth audio for a
* self-managed {@link Connection} (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.)
* <p>
- * See also {@link InCallService#requestBluetoothAudio(String)}
- * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
- * {@link BluetoothDevice#getAddress()}.
+ * See also {@link InCallService#requestBluetoothAudio(BluetoothDevice)}
+ * @param bluetoothDevice The bluetooth device to connect to.
*/
- public void requestBluetoothAudio(@NonNull String bluetoothAddress) {
+ public void requestBluetoothAudio(@NonNull BluetoothDevice bluetoothDevice) {
for (Listener l : mListeners) {
- l.onAudioRouteChanged(this, CallAudioState.ROUTE_BLUETOOTH, bluetoothAddress);
+ l.onAudioRouteChanged(this, CallAudioState.ROUTE_BLUETOOTH,
+ bluetoothDevice.getAddress());
}
}
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index af65c65..bd25ab2 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -428,12 +428,11 @@
* A list of available devices can be obtained via
* {@link CallAudioState#getSupportedBluetoothDevices()}
*
- * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
- * {@link BluetoothDevice#getAddress()}.
+ * @param bluetoothDevice The bluetooth device to connect to.
*/
- public final void requestBluetoothAudio(@NonNull String bluetoothAddress) {
+ public final void requestBluetoothAudio(@NonNull BluetoothDevice bluetoothDevice) {
if (mPhone != null) {
- mPhone.requestBluetoothAudio(bluetoothAddress);
+ mPhone.requestBluetoothAudio(bluetoothDevice.getAddress());
}
}
diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/net/java/android/net/IpSecManagerTest.java
index 970596d..a946e50 100644
--- a/tests/net/java/android/net/IpSecManagerTest.java
+++ b/tests/net/java/android/net/IpSecManagerTest.java
@@ -30,6 +30,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.test.mock.MockContext;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.system.Os;
@@ -69,11 +70,17 @@
private IpSecService mMockIpSecService;
private IpSecManager mIpSecManager;
+ private MockContext mMockContext = new MockContext() {
+ @Override
+ public String getOpPackageName() {
+ return "fooPackage";
+ }
+ };
@Before
public void setUp() throws Exception {
mMockIpSecService = mock(IpSecService.class);
- mIpSecManager = new IpSecManager(mMockIpSecService);
+ mIpSecManager = new IpSecManager(mMockContext, mMockIpSecService);
}
/*
@@ -227,7 +234,7 @@
new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
when(mMockIpSecService.createTunnelInterface(
eq(VTI_LOCAL_ADDRESS.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()),
- anyObject(), anyObject()))
+ anyObject(), anyObject(), anyString()))
.thenReturn(dummyResponse);
IpSecManager.IpSecTunnelInterface tunnelIntf = mIpSecManager.createIpSecTunnelInterface(
@@ -245,7 +252,7 @@
assertEquals(VTI_INTF_NAME, tunnelIntf.getInterfaceName());
tunnelIntf.close();
- verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID));
+ verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID), anyString());
}
@Test
@@ -255,10 +262,12 @@
tunnelIntf.addAddress(VTI_INNER_ADDRESS);
verify(mMockIpSecService)
- .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));
+ .addAddressToTunnelInterface(
+ eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
tunnelIntf.removeAddress(VTI_INNER_ADDRESS);
verify(mMockIpSecService)
- .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));
+ .addAddressToTunnelInterface(
+ eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
}
-}
\ No newline at end of file
+}
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 410f754..e573d35 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -27,6 +27,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AppOpsManager;
import android.content.Context;
import android.net.INetd;
import android.net.IpSecAlgorithm;
@@ -40,6 +41,7 @@
import android.net.NetworkUtils;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
+import android.test.mock.MockContext;
import android.support.test.filters.SmallTest;
import android.system.Os;
@@ -92,7 +94,28 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
};
- Context mMockContext;
+ AppOpsManager mMockAppOps = mock(AppOpsManager.class);
+
+ MockContext mMockContext = new MockContext() {
+ @Override
+ public Object getSystemService(String name) {
+ switch(name) {
+ case Context.APP_OPS_SERVICE:
+ return mMockAppOps;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+ if (permission == android.Manifest.permission.MANAGE_IPSEC_TUNNELS) {
+ return;
+ }
+ throw new SecurityException("Unavailable permission requested");
+ }
+ };
+
INetd mMockNetd;
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
IpSecService mIpSecService;
@@ -114,13 +137,22 @@
@Before
public void setUp() throws Exception {
- mMockContext = mock(Context.class);
mMockNetd = mock(INetd.class);
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
// Injecting mock netd
when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
+ // A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
+ when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("blessedPackage")))
+ .thenReturn(AppOpsManager.MODE_ALLOWED);
+ // A system package will not be granted the app op, so this should fall back to
+ // a permissions check, which should pass.
+ when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("systemPackage")))
+ .thenReturn(AppOpsManager.MODE_DEFAULT);
+ // A mismatch between the package name and the UID will return MODE_IGNORED.
+ when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("badPackage")))
+ .thenReturn(AppOpsManager.MODE_IGNORED);
}
@Test
@@ -232,7 +264,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
verify(mMockNetd)
@@ -267,7 +299,7 @@
ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
verify(mMockNetd)
@@ -301,12 +333,12 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
// Attempting to create transform a second time with the same SPIs should throw an error...
try {
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
fail("IpSecService should have thrown an error for reuse of SPI");
} catch (IllegalStateException expected) {
}
@@ -314,7 +346,7 @@
// ... even if the transform is deleted
mIpSecService.deleteTransform(createTransformResp.resourceId);
try {
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
fail("IpSecService should have thrown an error for reuse of SPI");
} catch (IllegalStateException expected) {
}
@@ -327,7 +359,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
@@ -351,7 +383,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
mIpSecService.deleteTransform(createTransformResp.resourceId);
verify(mMockNetd, times(1))
@@ -398,7 +430,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
@@ -435,7 +467,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
int resourceId = createTransformResp.resourceId;
@@ -460,10 +492,10 @@
}
private IpSecTunnelInterfaceResponse createAndValidateTunnel(
- String localAddr, String remoteAddr) {
+ String localAddr, String remoteAddr, String pkgName) {
IpSecTunnelInterfaceResponse createTunnelResp =
mIpSecService.createTunnelInterface(
- mSourceAddr, mDestinationAddr, fakeNetwork, new Binder());
+ mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName);
assertNotNull(createTunnelResp);
assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
@@ -473,7 +505,7 @@
@Test
public void testCreateTunnelInterface() throws Exception {
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
// Check that we have stored the tracking object, and retrieve it
IpSecService.UserRecord userRecord =
@@ -495,12 +527,12 @@
@Test
public void testDeleteTunnelInterface() throws Exception {
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
- mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId);
+ mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage");
// Verify quota and RefcountedResource objects cleaned up
assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
@@ -516,7 +548,7 @@
@Test
public void testTunnelInterfaceBinderDeath() throws Exception {
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
@@ -539,22 +571,34 @@
@Test
public void testAddRemoveAddressFromTunnelInterface() throws Exception {
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+ for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
+ mIpSecService.addAddressToTunnelInterface(
+ createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
+ verify(mMockNetd, times(1))
+ .interfaceAddAddress(
+ eq(createTunnelResp.interfaceName),
+ eq(mLocalInnerAddress.getAddress().getHostAddress()),
+ eq(mLocalInnerAddress.getPrefixLength()));
+ mIpSecService.removeAddressFromTunnelInterface(
+ createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
+ verify(mMockNetd, times(1))
+ .interfaceDelAddress(
+ eq(createTunnelResp.interfaceName),
+ eq(mLocalInnerAddress.getAddress().getHostAddress()),
+ eq(mLocalInnerAddress.getPrefixLength()));
+ mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, pkgName);
+ }
+ }
- mIpSecService.addAddressToTunnelInterface(createTunnelResp.resourceId, mLocalInnerAddress);
- verify(mMockNetd)
- .interfaceAddAddress(
- eq(createTunnelResp.interfaceName),
- eq(mLocalInnerAddress.getAddress().getHostAddress()),
- eq(mLocalInnerAddress.getPrefixLength()));
-
- mIpSecService.removeAddressFromTunnelInterface(
- createTunnelResp.resourceId, mLocalInnerAddress);
- verify(mMockNetd)
- .interfaceDelAddress(
- eq(createTunnelResp.interfaceName),
- eq(mLocalInnerAddress.getAddress().getHostAddress()),
- eq(mLocalInnerAddress.getPrefixLength()));
+ @Test
+ public void testAddTunnelFailsForBadPackageName() throws Exception {
+ try {
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "badPackage");
+ fail("Expected a SecurityException for badPackage.");
+ } catch (SecurityException expected) {
+ }
}
}