Merge "Modify statsd dogfood app to use toString() of enum"
diff --git a/api/current.txt b/api/current.txt
index 2f3fc26..ed14b0e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22033,6 +22033,7 @@
method public android.media.Image acquireLatestImage();
method public android.media.Image acquireNextImage();
method public void close();
+ method public void discardFreeBuffers();
method public int getHeight();
method public int getImageFormat();
method public int getMaxImages();
@@ -49092,15 +49093,19 @@
public abstract interface TextClassifier {
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options);
+ method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options);
+ method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
+ method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
field public static final android.view.textclassifier.TextClassifier NO_OP;
field public static final java.lang.String TYPE_ADDRESS = "address";
field public static final java.lang.String TYPE_EMAIL = "email";
field public static final java.lang.String TYPE_OTHER = "other";
field public static final java.lang.String TYPE_PHONE = "phone";
+ field public static final java.lang.String TYPE_UNKNOWN = "";
field public static final java.lang.String TYPE_URL = "url";
}
@@ -49116,13 +49121,9 @@
}
public static final class TextLinks.Options {
+ ctor public TextLinks.Options();
method public android.os.LocaleList getDefaultLocales();
- }
-
- public static final class TextLinks.Options.Builder {
- ctor public TextLinks.Options.Builder();
- method public android.view.textclassifier.TextLinks.Options build();
- method public android.view.textclassifier.TextLinks.Options.Builder setLocaleList(android.os.LocaleList);
+ method public android.view.textclassifier.TextLinks.Options setDefaultLocales(android.os.LocaleList);
}
public static final class TextLinks.TextLink {
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 57b4fc1..2fd7947 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -220,7 +220,7 @@
const unique_ptr<MetricsManager>& metricsManager) {
std::lock_guard<std::mutex> lock(mBroadcastTimesMutex);
- size_t totalBytes = metricsManager->byteSize();
+ size_t totalBytes = metricsManager->byteSize() + mUidMap->getBytesUsed();
if (totalBytes > .9 * kMaxSerializedBytes) { // Send broadcast so that receivers can pull data.
auto lastFlushNs = mLastBroadcastTimes.find(key);
if (lastFlushNs != mLastBroadcastTimes.end()) {
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index c019d5d..7eca5aa 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -480,7 +480,7 @@
fprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
mProcessor->GetMetricsSize(key));
}
- fprintf(out, "Detailed statsd stats in logcat...");
+ fprintf(out, "Detailed statsd stats in logcat...\n");
StatsdStats& statsdStats = StatsdStats::getInstance();
bool reset = false;
if (args.size() > 1) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 2bd3612..2957457 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -45,6 +45,7 @@
const int FIELD_ID_CONDITION_STATS = 5;
const int FIELD_ID_METRIC_STATS = 6;
const int FIELD_ID_ATOM_STATS = 7;
+const int FIELD_ID_UIDMAP_STATS = 8;
const int FIELD_ID_MATCHER_STATS_NAME = 1;
const int FIELD_ID_MATCHER_STATS_COUNT = 2;
@@ -173,6 +174,27 @@
it->second.add_dump_report_time_sec(timeSec);
}
+void StatsdStats::noteUidMapDropped(int snapshots, int deltas) {
+ lock_guard<std::mutex> lock(mLock);
+ mUidMapStats.set_dropped_snapshots(mUidMapStats.dropped_snapshots() + snapshots);
+ mUidMapStats.set_dropped_changes(mUidMapStats.dropped_changes() + deltas);
+}
+
+void StatsdStats::setUidMapSnapshots(int snapshots) {
+ lock_guard<std::mutex> lock(mLock);
+ mUidMapStats.set_snapshots(snapshots);
+}
+
+void StatsdStats::setUidMapChanges(int changes) {
+ lock_guard<std::mutex> lock(mLock);
+ mUidMapStats.set_changes(changes);
+}
+
+void StatsdStats::setCurrentUidMapMemory(int bytes) {
+ lock_guard<std::mutex> lock(mLock);
+ mUidMapStats.set_bytes_used(bytes);
+}
+
void StatsdStats::noteConditionDimensionSize(const ConfigKey& key, const string& name, int size) {
lock_guard<std::mutex> lock(mLock);
// if name doesn't exist before, it will create the key with count 0.
@@ -364,6 +386,15 @@
}
}
+ const int numBytes = mUidMapStats.ByteSize();
+ vector<char> buffer(numBytes);
+ mUidMapStats.SerializeToArray(&buffer[0], numBytes);
+ proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UIDMAP_STATS, &buffer[0], buffer.size());
+ VLOG("UID map stats: bytes=%d, snapshots=%d, changes=%d, snapshots lost=%d, changes "
+ "lost=%d",
+ mUidMapStats.bytes_used(), mUidMapStats.snapshots(), mUidMapStats.changes(),
+ mUidMapStats.dropped_snapshots(), mUidMapStats.dropped_changes());
+
output->clear();
size_t bufferSize = proto.size();
output->resize(bufferSize);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 451144f..d6f6566 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -45,6 +45,10 @@
const static int kMaxTimestampCount = 20;
+ // Cap the UID map's memory usage to this. This should be fairly high since the UID information
+ // is critical for understanding the metrics.
+ const static size_t kMaxBytesUsedUidMap = 50 * 1024;
+
/**
* Report a new config has been received and report the static stats about the config.
*
@@ -113,6 +117,18 @@
void noteAtomLogged(int atomId, int32_t timeSec);
/**
+ * Records the number of snapshot and delta entries that are being dropped from the uid map.
+ */
+ void noteUidMapDropped(int snapshots, int deltas);
+
+ /**
+ * Updates the number of snapshots currently stored in the uid map.
+ */
+ void setUidMapSnapshots(int snapshots);
+ void setUidMapChanges(int changes);
+ void setCurrentUidMapMemory(int bytes);
+
+ /**
* Reset the historical stats. Including all stats in icebox, and the tracked stats about
* metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
* to collect stats after reset() has been called.
@@ -133,6 +149,9 @@
int32_t mStartTimeSec;
+ // Track the number of dropped entries used by the uid map.
+ StatsdStatsReport_UidMapStats mUidMapStats;
+
// The stats about the configs that are still in use.
std::map<const ConfigKey, StatsdStatsReport_ConfigStats> mConfigStats;
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 6c32d3e..db592e2 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -13,11 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+#define DEBUG true // STOPSHIP if true
#include "Log.h"
+#include "guardrail/StatsdStats.h"
#include "packages/UidMap.h"
+#include <android/os/IStatsCompanionService.h>
+#include <binder/IServiceManager.h>
#include <utils/Errors.h>
using namespace android;
@@ -26,6 +29,11 @@
namespace os {
namespace statsd {
+UidMap::UidMap() : mBytesUsed(0) {
+}
+UidMap::~UidMap() {
+}
+
bool UidMap::hasApp(int uid, const string& packageName) const {
lock_guard<mutex> lock(mMutex);
@@ -73,6 +81,10 @@
t->set_version(int(versionCode[j]));
t->set_uid(uid[j]);
}
+ mBytesUsed += snapshot->ByteSize();
+ StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+ StatsdStats::getInstance().setUidMapSnapshots(mOutput.snapshots_size());
+ ensureBytesUsedBelowLimit();
}
void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode) {
@@ -96,6 +108,10 @@
log->set_app(app);
log->set_uid(uid);
log->set_version(versionCode);
+ mBytesUsed += log->ByteSize();
+ StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+ StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
+ ensureBytesUsedBelowLimit();
auto range = mMap.equal_range(int(uid));
for (auto it = range.first; it != range.second; ++it) {
@@ -103,7 +119,7 @@
it->second.versionCode = int(versionCode);
return;
}
- ALOGD("updateApp failed to find the app %s with uid %i to update", app.c_str(), uid);
+ VLOG("updateApp failed to find the app %s with uid %i to update", app.c_str(), uid);
return;
}
@@ -111,6 +127,28 @@
mMap.insert(make_pair(uid, AppData(app, int(versionCode))));
}
+void UidMap::ensureBytesUsedBelowLimit() {
+ size_t limit;
+ if (maxBytesOverride <= 0) {
+ limit = StatsdStats::kMaxBytesUsedUidMap;
+ } else {
+ limit = maxBytesOverride;
+ }
+ while (mBytesUsed > limit) {
+ VLOG("Bytes used %zu is above limit %zu, need to delete something", mBytesUsed, limit);
+ if (mOutput.snapshots_size() > 0) {
+ auto snapshots = mOutput.mutable_snapshots();
+ snapshots->erase(snapshots->begin()); // Remove first snapshot.
+ StatsdStats::getInstance().noteUidMapDropped(1, 0);
+ } else if (mOutput.changes_size() > 0) {
+ auto changes = mOutput.mutable_changes();
+ changes->DeleteSubrange(0, 1);
+ StatsdStats::getInstance().noteUidMapDropped(0, 1);
+ }
+ mBytesUsed = mOutput.ByteSize();
+ }
+}
+
void UidMap::removeApp(const String16& app_16, const int32_t& uid) {
removeApp(time(nullptr) * NS_PER_SEC, app_16, uid);
}
@@ -128,6 +166,10 @@
log->set_timestamp_nanos(timestamp);
log->set_app(app);
log->set_uid(uid);
+ mBytesUsed += log->ByteSize();
+ StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+ StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
+ ensureBytesUsedBelowLimit();
auto range = mMap.equal_range(int(uid));
for (auto it = range.first; it != range.second; ++it) {
@@ -136,7 +178,7 @@
return;
}
}
- ALOGD("removeApp failed to find the app %s with uid %i to remove", app.c_str(), uid);
+ VLOG("removeApp failed to find the app %s with uid %i to remove", app.c_str(), uid);
return;
}
@@ -177,7 +219,6 @@
void UidMap::clearOutput() {
mOutput.Clear();
-
// Re-initialize the initial state for the outputs. This results in extra data being uploaded
// but helps ensure we can re-construct the UID->app name, versionCode mapping in server.
auto snapshot = mOutput.add_snapshots();
@@ -187,6 +228,12 @@
t->set_version(it.second.versionCode);
t->set_uid(it.first);
}
+
+ // Also update the guardrail trackers.
+ StatsdStats::getInstance().setUidMapChanges(0);
+ StatsdStats::getInstance().setUidMapSnapshots(1);
+ mBytesUsed = snapshot->ByteSize();
+ StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
}
int64_t UidMap::getMinimumTimestampNs() {
@@ -201,6 +248,10 @@
return m;
}
+size_t UidMap::getBytesUsed() {
+ return mBytesUsed;
+}
+
UidMapping UidMap::getOutput(const ConfigKey& key) {
return getOutput(time(nullptr) * NS_PER_SEC, key);
}
@@ -236,6 +287,10 @@
}
}
}
+ mBytesUsed = mOutput.ByteSize(); // Compute actual size after potential deletions.
+ StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
+ StatsdStats::getInstance().setUidMapChanges(mOutput.changes_size());
+ StatsdStats::getInstance().setUidMapSnapshots(mOutput.snapshots_size());
return ret;
}
@@ -250,6 +305,23 @@
void UidMap::OnConfigUpdated(const ConfigKey& key) {
mLastUpdatePerConfigKey[key] = -1;
+
+ // Ensure there is at least one snapshot available since this configuration also needs to know
+ // what all the uid's represent.
+ if (mOutput.snapshots_size() == 0) {
+ sp<IStatsCompanionService> statsCompanion = nullptr;
+ // Get statscompanion service from service manager
+ const sp<IServiceManager> sm(defaultServiceManager());
+ if (sm != nullptr) {
+ const String16 name("statscompanion");
+ statsCompanion = interface_cast<IStatsCompanionService>(sm->checkService(name));
+ if (statsCompanion == nullptr) {
+ ALOGW("statscompanion service unavailable!");
+ return;
+ }
+ statsCompanion->triggerUidSnapshot();
+ }
+ }
}
void UidMap::OnConfigRemoved(const ConfigKey& key) {
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 24eb966..d2971c9 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -50,15 +50,16 @@
// at any given moment. This map must be updated by StatsCompanionService.
class UidMap : public virtual android::RefBase {
public:
+ UidMap();
+ ~UidMap();
+
/*
* All three inputs must be the same size, and the jth element in each array refers to the same
* tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
*/
- // TODO: Add safeguards to call clearOutput if there's too much data already stored.
void updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
const vector<String16>& packageName);
- // TODO: Add safeguards to call clearOutput if there's too much data already stored.
void updateApp(const String16& packageName, const int32_t& uid, const int32_t& versionCode);
void removeApp(const String16& packageName, const int32_t& uid);
@@ -98,11 +99,13 @@
// in case we lose a previous upload.
void clearOutput();
+ // Get currently cached value of memory used by UID map.
+ size_t getBytesUsed();
+
private:
void updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
const vector<int32_t>& versionCode, const vector<String16>& packageName);
- // TODO: Add safeguards to call clearOutput if there's too much data already stored.
void updateApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid,
const int32_t& versionCode);
void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid);
@@ -135,8 +138,22 @@
// Returns the minimum value from mConfigKeys.
int64_t getMinimumTimestampNs();
+ // If our current used bytes is above the limit, then we clear out the earliest snapshot. If
+ // there are no more snapshots, then we clear out the earliest delta. We repeat the deletions
+ // until the memory consumed by mOutput is below the specified limit.
+ void ensureBytesUsedBelowLimit();
+
+ // Override used for testing the max memory allowed by uid map. -1 means we use the value
+ // specified in StatsdStats.h with the rest of the guardrails.
+ size_t maxBytesOverride = -1;
+
+ // Cache the size of mOutput;
+ size_t mBytesUsed;
+
// Allows unit-test to access private methods.
FRIEND_TEST(UidMapTest, TestClearingOutput);
+ FRIEND_TEST(UidMapTest, TestMemoryComputed);
+ FRIEND_TEST(UidMapTest, TestMemoryGuardrail);
};
} // namespace statsd
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index e7e1d43..cc8a26d 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -220,4 +220,13 @@
}
repeated AtomStats atom_stats = 7;
+
+ message UidMapStats {
+ optional int32 snapshots = 1;
+ optional int32 changes = 2;
+ optional int32 bytes_used = 3;
+ optional int32 dropped_snapshots = 4;
+ optional int32 dropped_changes = 5;
+ }
+ optional UidMapStats uidmap_stats = 8;
}
\ No newline at end of file
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index 0c19468..aa194e6 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -15,6 +15,7 @@
#include "packages/UidMap.h"
#include "StatsLogProcessor.h"
#include "config/ConfigKey.h"
+#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
#include "statslog.h"
@@ -35,7 +36,8 @@
TEST(UidMapTest, TestIsolatedUID) {
sp<UidMap> m = new UidMap();
sp<AnomalyMonitor> anomalyMonitor;
- StatsLogProcessor p(m, anomalyMonitor, nullptr);
+ // Construct the processor with a dummy sendBroadcast function that does nothing.
+ StatsLogProcessor p(m, anomalyMonitor, [](const ConfigKey& key) {});
LogEvent addEvent(android::util::ISOLATED_UID_CHANGED, 1);
addEvent.write(100); // parent UID
addEvent.write(101); // isolated UID
@@ -114,26 +116,34 @@
versions.push_back(4);
versions.push_back(5);
m.updateMap(1, uids, versions, apps);
+ EXPECT_EQ(1, m.mOutput.snapshots_size());
UidMapping results = m.getOutput(2, config1);
EXPECT_EQ(1, results.snapshots_size());
// It should be cleared now
+ EXPECT_EQ(0, m.mOutput.snapshots_size());
results = m.getOutput(3, config1);
EXPECT_EQ(0, results.snapshots_size());
// Now add another configuration.
m.OnConfigUpdated(config2);
m.updateApp(5, String16(kApp1.c_str()), 1000, 40);
+ EXPECT_EQ(1, m.mOutput.changes_size());
results = m.getOutput(6, config1);
EXPECT_EQ(0, results.snapshots_size());
EXPECT_EQ(1, results.changes_size());
+ EXPECT_EQ(1, m.mOutput.changes_size());
- // Now we still haven't been able to delete anything
+ // Add another delta update.
m.updateApp(7, String16(kApp2.c_str()), 1001, 41);
+ EXPECT_EQ(2, m.mOutput.changes_size());
+
+ // We still can't remove anything.
results = m.getOutput(8, config1);
EXPECT_EQ(0, results.snapshots_size());
EXPECT_EQ(2, results.changes_size());
+ EXPECT_EQ(2, m.mOutput.changes_size());
results = m.getOutput(9, config2);
EXPECT_EQ(0, results.snapshots_size());
@@ -142,6 +152,66 @@
EXPECT_EQ(0, m.mOutput.snapshots_size());
EXPECT_EQ(0, m.mOutput.changes_size());
}
+
+TEST(UidMapTest, TestMemoryComputed) {
+ UidMap m;
+
+ ConfigKey config1(1, "config1");
+ m.OnConfigUpdated(config1);
+
+ size_t startBytes = m.mBytesUsed;
+ vector<int32_t> uids;
+ vector<int32_t> versions;
+ vector<String16> apps;
+ uids.push_back(1000);
+ apps.push_back(String16(kApp1.c_str()));
+ versions.push_back(1);
+ m.updateMap(1, uids, versions, apps);
+ size_t snapshot_bytes = m.mBytesUsed;
+ EXPECT_TRUE(snapshot_bytes > startBytes);
+
+ m.updateApp(3, String16(kApp1.c_str()), 1000, 40);
+ EXPECT_TRUE(m.mBytesUsed > snapshot_bytes);
+ size_t bytesWithSnapshotChange = m.mBytesUsed;
+
+ m.getOutput(2, config1);
+ EXPECT_TRUE(m.mBytesUsed < bytesWithSnapshotChange);
+ size_t prevBytes = m.mBytesUsed;
+
+ m.getOutput(4, config1);
+ EXPECT_TRUE(m.mBytesUsed < prevBytes);
+}
+
+TEST(UidMapTest, TestMemoryGuardrail) {
+ UidMap m;
+ string buf;
+
+ ConfigKey config1(1, "config1");
+ m.OnConfigUpdated(config1);
+
+ size_t startBytes = m.mBytesUsed;
+ vector<int32_t> uids;
+ vector<int32_t> versions;
+ vector<String16> apps;
+ for (int i = 0; i < 100; i++) {
+ uids.push_back(1);
+ buf = "EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY." + to_string(i);
+ apps.push_back(String16(buf.c_str()));
+ versions.push_back(1);
+ }
+ m.updateMap(1, uids, versions, apps);
+ EXPECT_EQ(1, m.mOutput.snapshots_size());
+
+ m.updateApp(3, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 2);
+ EXPECT_EQ(1, m.mOutput.snapshots_size());
+ EXPECT_EQ(1, m.mOutput.changes_size());
+
+ // Now force deletion by limiting the memory to hold one delta change.
+ m.maxBytesOverride = 80; // Since the app string alone requires >45 characters.
+ m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4);
+ EXPECT_EQ(0, m.mOutput.snapshots_size());
+ EXPECT_EQ(1, m.mOutput.changes_size());
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/core/java/Android.bp b/core/java/Android.bp
index d8c7929..b43cf27 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -4,16 +4,16 @@
}
// only used by key_store_service
-cc_library_static {
+cc_library_shared {
name: "libkeystore_aidl",
srcs: ["android/security/IKeystoreService.aidl"],
aidl: {
export_aidl_headers: true,
- include_dirs: ["frameworks/base/core/java/"],
+ include_dirs: [
+ "frameworks/base/core/java/",
+ "system/security/keystore/",
+ ],
},
- header_libs: [
- "libkeystore_headers",
- ],
shared_libs: [
"libbinder",
"libcutils",
@@ -22,7 +22,12 @@
"libhidltransport",
"libhwbinder",
"liblog",
+ "libkeystore_parcelables",
"libselinux",
"libutils",
],
+ export_shared_lib_headers: [
+ "libbinder",
+ "libkeystore_parcelables",
+ ],
}
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index 3314f60..1d2a408 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -56,4 +56,7 @@
/** Send a broadcast to the specified pkg and class that it should getData now. */
oneway void sendBroadcast(String pkg, String cls);
+
+ /** Tells StatsCompaionService to grab the uid map snapshot and send it to statsd. */
+ oneway void triggerUidSnapshot();
}
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index cd233b8..df0842f 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -105,6 +105,13 @@
public static final String EXTRA_RESOLUTION_CALLING_PACKAGE =
"android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE";
+ /**
+ * Intent extra set for resolution requests containing a boolean indicating whether to ask the
+ * user to retry another confirmation code.
+ */
+ public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED =
+ "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
+
/** Result code for a successful operation. */
public static final int RESULT_OK = 0;
/** Result code indicating that an active SIM must be deactivated to perform the operation. */
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 2779aa2..f675c35 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -31,6 +31,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
/**
* Information for generating a widget to handle classified text.
@@ -42,7 +43,7 @@
*
* <pre>{@code
* // Called preferably outside the UiThread.
- * TextClassification classification = textClassifier.classifyText(allText, 10, 25, null);
+ * TextClassification classification = textClassifier.classifyText(allText, 10, 25);
*
* // Called on the UiThread.
* Button button = new Button(context);
@@ -55,7 +56,7 @@
*
* <pre>{@code
* // Called preferably outside the UiThread.
- * final TextClassification classification = textClassifier.classifyText(allText, 10, 25, null);
+ * final TextClassification classification = textClassifier.classifyText(allText, 10, 25);
*
* // Called on the UiThread.
* view.startActionMode(new ActionMode.Callback() {
@@ -281,8 +282,8 @@
@Override
public String toString() {
- return String.format("TextClassification {"
- + "text=%s, entities=%s, labels=%s, intents=%s}",
+ return String.format(Locale.US,
+ "TextClassification {text=%s, entities=%s, labels=%s, intents=%s}",
mText, mEntityConfidence, mLabels, mIntents);
}
@@ -421,7 +422,7 @@
}
/**
- * Ensures that we have at we have storage for the default action.
+ * Ensures that we have storage for the default action.
*/
private void ensureDefaultActionAvailable() {
if (mIntents.isEmpty()) mIntents.add(null);
@@ -441,7 +442,7 @@
}
/**
- * TextClassification optional input parameters.
+ * Optional input parameters for generating TextClassification.
*/
public static final class Options {
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index aeb8489..5aaa5ad 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -23,6 +23,8 @@
import android.annotation.WorkerThread;
import android.os.LocaleList;
+import com.android.internal.util.Preconditions;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -37,8 +39,7 @@
/** @hide */
String DEFAULT_LOG_TAG = "TextClassifierImpl";
- /** @hide */
- String TYPE_UNKNOWN = ""; // TODO: Make this public API.
+ String TYPE_UNKNOWN = "";
String TYPE_OTHER = "other";
String TYPE_EMAIL = "email";
String TYPE_PHONE = "phone";
@@ -70,6 +71,8 @@
*
* @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
* selectionEndIndex is greater than text.length() or not greater than selectionStartIndex
+ *
+ * @see #suggestSelection(CharSequence, int, int)
*/
@WorkerThread
@NonNull
@@ -78,13 +81,46 @@
@IntRange(from = 0) int selectionStartIndex,
@IntRange(from = 0) int selectionEndIndex,
@Nullable TextSelection.Options options) {
+ Utils.validateInput(text, selectionStartIndex, selectionEndIndex);
return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
}
/**
+ * Returns suggested text selection start and end indices, recognized entity types, and their
+ * associated confidence scores. The entity types are ordered from highest to lowest scoring.
+ *
+ * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+ * {@link #suggestSelection(CharSequence, int, int, TextSelection.Options)}. If that method
+ * calls this method, a stack overflow error will happen.
+ *
+ * @param text text providing context for the selected text (which is specified
+ * by the sub sequence starting at selectionStartIndex and ending at selectionEndIndex)
+ * @param selectionStartIndex start index of the selected part of text
+ * @param selectionEndIndex end index of the selected part of text
+ *
+ * @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
+ * selectionEndIndex is greater than text.length() or not greater than selectionStartIndex
+ *
* @see #suggestSelection(CharSequence, int, int, TextSelection.Options)
*/
- // TODO: Consider deprecating (b/68846316)
+ @WorkerThread
+ @NonNull
+ default TextSelection suggestSelection(
+ @NonNull CharSequence text,
+ @IntRange(from = 0) int selectionStartIndex,
+ @IntRange(from = 0) int selectionEndIndex) {
+ return suggestSelection(text, selectionStartIndex, selectionEndIndex,
+ (TextSelection.Options) null);
+ }
+
+ /**
+ * See {@link #suggestSelection(CharSequence, int, int)} or
+ * {@link #suggestSelection(CharSequence, int, int, TextSelection.Options)}.
+ *
+ * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+ * {@link #suggestSelection(CharSequence, int, int, TextSelection.Options)}. If that method
+ * calls this method, a stack overflow error will happen.
+ */
@WorkerThread
@NonNull
default TextSelection suggestSelection(
@@ -92,7 +128,10 @@
@IntRange(from = 0) int selectionStartIndex,
@IntRange(from = 0) int selectionEndIndex,
@Nullable LocaleList defaultLocales) {
- return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
+ final TextSelection.Options options = (defaultLocales != null)
+ ? new TextSelection.Options().setDefaultLocales(defaultLocales)
+ : null;
+ return suggestSelection(text, selectionStartIndex, selectionEndIndex, options);
}
/**
@@ -107,6 +146,8 @@
*
* @throws IllegalArgumentException if text is null; startIndex is negative;
* endIndex is greater than text.length() or not greater than startIndex
+ *
+ * @see #classifyText(CharSequence, int, int)
*/
@WorkerThread
@NonNull
@@ -115,13 +156,45 @@
@IntRange(from = 0) int startIndex,
@IntRange(from = 0) int endIndex,
@Nullable TextClassification.Options options) {
+ Utils.validateInput(text, startIndex, endIndex);
return TextClassification.EMPTY;
}
/**
+ * Classifies the specified text and returns a {@link TextClassification} object that can be
+ * used to generate a widget for handling the classified text.
+ *
+ * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+ * {@link #classifyText(CharSequence, int, int, TextClassification.Options)}. If that method
+ * calls this method, a stack overflow error will happen.
+ *
+ * @param text text providing context for the text to classify (which is specified
+ * by the sub sequence starting at startIndex and ending at endIndex)
+ * @param startIndex start index of the text to classify
+ * @param endIndex end index of the text to classify
+ *
+ * @throws IllegalArgumentException if text is null; startIndex is negative;
+ * endIndex is greater than text.length() or not greater than startIndex
+ *
* @see #classifyText(CharSequence, int, int, TextClassification.Options)
*/
- // TODO: Consider deprecating (b/68846316)
+ @WorkerThread
+ @NonNull
+ default TextClassification classifyText(
+ @NonNull CharSequence text,
+ @IntRange(from = 0) int startIndex,
+ @IntRange(from = 0) int endIndex) {
+ return classifyText(text, startIndex, endIndex, (TextClassification.Options) null);
+ }
+
+ /**
+ * See {@link #classifyText(CharSequence, int, int, TextClassification.Options)} or
+ * {@link #classifyText(CharSequence, int, int)}.
+ *
+ * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+ * {@link #classifyText(CharSequence, int, int, TextClassification.Options)}. If that method
+ * calls this method, a stack overflow error will happen.
+ */
@WorkerThread
@NonNull
default TextClassification classifyText(
@@ -129,7 +202,10 @@
@IntRange(from = 0) int startIndex,
@IntRange(from = 0) int endIndex,
@Nullable LocaleList defaultLocales) {
- return TextClassification.EMPTY;
+ final TextClassification.Options options = (defaultLocales != null)
+ ? new TextClassification.Options().setDefaultLocales(defaultLocales)
+ : null;
+ return classifyText(text, startIndex, endIndex, options);
}
/**
@@ -137,17 +213,39 @@
* information.
*
* @param text the text to generate annotations for
- * @param options configuration for link generation. If null, defaults will be used.
+ * @param options configuration for link generation
*
* @throws IllegalArgumentException if text is null
+ *
+ * @see #generateLinks(CharSequence)
*/
@WorkerThread
default TextLinks generateLinks(
@NonNull CharSequence text, @Nullable TextLinks.Options options) {
+ Utils.validateInput(text);
return new TextLinks.Builder(text.toString()).build();
}
/**
+ * Returns a {@link TextLinks} that may be applied to the text to annotate it with links
+ * information.
+ *
+ * <p><b>NOTE:</b> Do not implement. The default implementation of this method calls
+ * {@link #generateLinks(CharSequence, TextLinks.Options)}. If that method calls this method,
+ * a stack overflow error will happen.
+ *
+ * @param text the text to generate annotations for
+ *
+ * @throws IllegalArgumentException if text is null
+ *
+ * @see #generateLinks(CharSequence, TextLinks.Options)
+ */
+ @WorkerThread
+ default TextLinks generateLinks(@NonNull CharSequence text) {
+ return generateLinks(text, null);
+ }
+
+ /**
* Logs a TextClassifier event.
*
* @param source the text classifier used to generate this event
@@ -164,4 +262,38 @@
default TextClassifierConstants getSettings() {
return TextClassifierConstants.DEFAULT;
}
+
+
+ /**
+ * Utility functions for TextClassifier methods.
+ *
+ * <ul>
+ * <li>Provides validation of input parameters to TextClassifier methods
+ * </ul>
+ *
+ * Intended to be used only in this package.
+ * @hide
+ */
+ final class Utils {
+
+ /**
+ * @throws IllegalArgumentException if text is null; startIndex is negative;
+ * endIndex is greater than text.length() or is not greater than startIndex;
+ * options is null
+ */
+ static void validateInput(
+ @NonNull CharSequence text, int startIndex, int endIndex) {
+ Preconditions.checkArgument(text != null);
+ Preconditions.checkArgument(startIndex >= 0);
+ Preconditions.checkArgument(endIndex <= text.length());
+ Preconditions.checkArgument(endIndex > startIndex);
+ }
+
+ /**
+ * @throws IllegalArgumentException if text is null or options is null
+ */
+ static void validateInput(@NonNull CharSequence text) {
+ Preconditions.checkArgument(text != null);
+ }
+ }
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 2ad6e02..df5e35f 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -90,8 +90,8 @@
@Override
public TextSelection suggestSelection(
@NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
- @Nullable TextSelection.Options options) {
- validateInput(text, selectionStartIndex, selectionEndIndex);
+ @NonNull TextSelection.Options options) {
+ Utils.validateInput(text, selectionStartIndex, selectionEndIndex);
try {
if (text.length() > 0) {
final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
@@ -141,18 +141,10 @@
}
@Override
- public TextSelection suggestSelection(
- @NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
- @Nullable LocaleList defaultLocales) {
- return suggestSelection(text, selectionStartIndex, selectionEndIndex,
- new TextSelection.Options().setDefaultLocales(defaultLocales));
- }
-
- @Override
public TextClassification classifyText(
@NonNull CharSequence text, int startIndex, int endIndex,
- @Nullable TextClassification.Options options) {
- validateInput(text, startIndex, endIndex);
+ @NonNull TextClassification.Options options) {
+ Utils.validateInput(text, startIndex, endIndex);
try {
if (text.length() > 0) {
final String string = text.toString();
@@ -176,17 +168,9 @@
}
@Override
- public TextClassification classifyText(
- @NonNull CharSequence text, int startIndex, int endIndex,
- @Nullable LocaleList defaultLocales) {
- return classifyText(text, startIndex, endIndex,
- new TextClassification.Options().setDefaultLocales(defaultLocales));
- }
-
- @Override
public TextLinks generateLinks(
- @NonNull CharSequence text, @Nullable TextLinks.Options options) {
- Preconditions.checkNotNull(text);
+ @NonNull CharSequence text, @NonNull TextLinks.Options options) {
+ Utils.validateInput(text);
final String textString = text.toString();
final TextLinks.Builder builder = new TextLinks.Builder(textString);
try {
@@ -486,17 +470,6 @@
}
/**
- * @throws IllegalArgumentException if text is null; startIndex is negative;
- * endIndex is greater than text.length() or is not greater than startIndex
- */
- private static void validateInput(@NonNull CharSequence text, int startIndex, int endIndex) {
- Preconditions.checkArgument(text != null);
- Preconditions.checkArgument(startIndex >= 0);
- Preconditions.checkArgument(endIndex <= text.length());
- Preconditions.checkArgument(endIndex > startIndex);
- }
-
- /**
* Creates intents based on the classification type.
*/
private static final class IntentFactory {
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index f3cc827..76748d2 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -161,39 +161,28 @@
* Optional input parameters for generating TextLinks.
*/
public static final class Options {
- private final LocaleList mLocaleList;
- private Options(LocaleList localeList) {
- this.mLocaleList = localeList;
+ private LocaleList mDefaultLocales;
+
+ /**
+ * @param defaultLocales ordered list of locale preferences that may be used to disambiguate
+ * the provided text. If no locale preferences exist, set this to null or an empty
+ * locale list.
+ */
+ public Options setDefaultLocales(@Nullable LocaleList defaultLocales) {
+ mDefaultLocales = defaultLocales;
+ return this;
}
/**
- * Builder to construct Options.
+ * @return ordered list of locale preferences that can be used to disambiguate
+ * the provided text.
*/
- public static final class Builder {
- private LocaleList mLocaleList;
-
- /**
- * Sets the LocaleList to use.
- *
- * @return this Builder.
- */
- public Builder setLocaleList(@Nullable LocaleList localeList) {
- this.mLocaleList = localeList;
- return this;
- }
-
- /**
- * Builds the Options object.
- */
- public Options build() {
- return new Options(mLocaleList);
- }
+ @Nullable
+ public LocaleList getDefaultLocales() {
+ return mDefaultLocales;
}
- public @Nullable LocaleList getDefaultLocales() {
- return mLocaleList;
- }
- };
+ }
/**
* A function to create spans from TextLinks.
@@ -204,13 +193,10 @@
* @hide
*/
public static final Function<TextLink, ClickableSpan> DEFAULT_SPAN_FACTORY =
- new Function<TextLink, ClickableSpan>() {
- @Override
- public ClickableSpan apply(TextLink textLink) {
- // TODO: Implement.
- throw new UnsupportedOperationException("Not yet implemented");
- }
- };
+ textLink -> {
+ // TODO: Implement.
+ throw new UnsupportedOperationException("Not yet implemented");
+ };
/**
* A builder to construct a TextLinks instance.
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 0a67954..480b27a 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -26,6 +26,7 @@
import com.android.internal.util.Preconditions;
import java.util.List;
+import java.util.Locale;
/**
* Information about where text selection should be.
@@ -114,8 +115,8 @@
@Override
public String toString() {
- return String.format("TextSelection {%d, %d, %s}",
- mStartIndex, mEndIndex, mEntityConfidence);
+ return String.format(Locale.US,
+ "TextSelection {%d, %d, %s}", mStartIndex, mEndIndex, mEntityConfidence);
}
/**
@@ -185,7 +186,7 @@
}
/**
- * TextSelection optional input parameters.
+ * Optional input parameters for generating TextSelection.
*/
public static final class Options {
diff --git a/core/java/com/android/internal/view/TooltipPopup.java b/core/java/com/android/internal/view/TooltipPopup.java
index d38ea2c..24f0b0c 100644
--- a/core/java/com/android/internal/view/TooltipPopup.java
+++ b/core/java/com/android/internal/view/TooltipPopup.java
@@ -142,7 +142,7 @@
mTmpAnchorPos[1] -= mTmpAppPos[1];
// mTmpAnchorPos is now relative to the main app window.
- outParams.x = mTmpAnchorPos[0] + offsetX - mTmpDisplayFrame.width() / 2;
+ outParams.x = mTmpAnchorPos[0] + offsetX - appView.getWidth() / 2;
final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
mContentView.measure(spec, spec);
@@ -157,6 +157,9 @@
outParams.y = yBelow;
}
} else {
+ // Use mTmpDisplayFrame.height() as the lower boundary instead of appView.getHeight(),
+ // as the latter includes the navigation bar, and tooltips do not look good over
+ // the navigation bar.
if (yBelow + tooltipHeight <= mTmpDisplayFrame.height()) {
outParams.y = yBelow;
} else {
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index d7300c4..601bd98 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -25,6 +25,7 @@
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"
+#include "scoped_nullable_primitive_array.h"
#include <cstdint>
#include <vector>
#include <list>
@@ -87,9 +88,8 @@
static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
jfloatArray recycleWidths, jfloatArray recycleAscents,
jfloatArray recycleDescents, jintArray recycleFlags,
- jint recycleLength, size_t nBreaks, const jint* breaks,
- const jfloat* widths, const jfloat* ascents, const jfloat* descents,
- const jint* flags) {
+ jint recycleLength, const minikin::LineBreakResult& result) {
+ const size_t nBreaks = result.breakPoints.size();
if ((size_t)recycleLength < nBreaks) {
// have to reallocate buffers
recycleBreaks = env->NewIntArray(nBreaks);
@@ -105,11 +105,11 @@
env->SetObjectField(recycle, gLineBreaks_fieldID.flags, recycleFlags);
}
// copy data
- env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, breaks);
- env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, widths);
- env->SetFloatArrayRegion(recycleAscents, 0, nBreaks, ascents);
- env->SetFloatArrayRegion(recycleDescents, 0, nBreaks, descents);
- env->SetIntArrayRegion(recycleFlags, 0, nBreaks, flags);
+ env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, result.breakPoints.data());
+ env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, result.widths.data());
+ env->SetFloatArrayRegion(recycleAscents, 0, nBreaks, result.ascents.data());
+ env->SetFloatArrayRegion(recycleDescents, 0, nBreaks, result.descents.data());
+ env->SetIntArrayRegion(recycleFlags, 0, nBreaks, result.flags.data());
}
static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
@@ -136,34 +136,22 @@
minikin::android::StaticLayoutNative* builder = toNative(nativePtr);
ScopedCharArrayRO text(env, javaText);
+ ScopedNullableIntArrayRO tabStops(env, variableTabStops);
- // TODO: Reorganize minikin APIs.
- minikin::LineBreaker b(minikin::U16StringPiece(text.get(), length));
- if (variableTabStops == nullptr) {
- b.setTabStops(nullptr, 0, defaultTabStop);
- } else {
- ScopedIntArrayRO stops(env, variableTabStops);
- b.setTabStops(stops.get(), stops.size(), defaultTabStop);
- }
- b.setStrategy(builder->getStrategy());
- b.setHyphenationFrequency(builder->getFrequency());
- b.setJustified(builder->isJustified());
- b.setLineWidthDelegate(builder->buildLineWidthDelegate(
- firstWidth, firstWidthLineCount, restWidth, indentsOffset));
-
- builder->addRuns(&b);
-
- size_t nBreaks = b.computeBreaks();
+ minikin::U16StringPiece u16Text(text.get(), length);
+ minikin::MeasuredText measuredText = builder->measureText(u16Text);
+ minikin::LineBreakResult result = builder->computeBreaks(
+ u16Text, measuredText, firstWidth, firstWidthLineCount, restWidth, indentsOffset,
+ tabStops.get(), tabStops.size(), defaultTabStop);
recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleAscents, recycleDescents,
- recycleFlags, recycleLength, nBreaks, b.getBreaks(), b.getWidths(), b.getAscents(),
- b.getDescents(), b.getFlags());
+ recycleFlags, recycleLength, result);
- env->SetFloatArrayRegion(charWidths, 0, b.size(), b.charWidths());
+ env->SetFloatArrayRegion(charWidths, 0, measuredText.widths.size(), measuredText.widths.data());
builder->clearRuns();
- return static_cast<jint>(nBreaks);
+ return static_cast<jint>(result.breakPoints.size());
}
// Basically similar to Paint.getTextRunAdvances but with C++ interface
diff --git a/core/jni/scoped_nullable_primitive_array.h b/core/jni/scoped_nullable_primitive_array.h
new file mode 100644
index 0000000..77f4c9d
--- /dev/null
+++ b/core/jni/scoped_nullable_primitive_array.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SCOPED_NULLABLE_PRIMITIVE_ARRAY_H
+#define SCOPED_NULLABLE_PRIMITIVE_ARRAY_H
+
+#include <jni.h>
+
+namespace android {
+
+#define ARRAY_TRAITS(ARRAY_TYPE, POINTER_TYPE, NAME) \
+class NAME ## ArrayTraits { \
+public: \
+ static constexpr void getArrayRegion(JNIEnv* env, ARRAY_TYPE array, size_t start, \
+ size_t len, POINTER_TYPE out) { \
+ env->Get ## NAME ## ArrayRegion(array, start, len, out); \
+ } \
+ \
+ static constexpr POINTER_TYPE getArrayElements(JNIEnv* env, ARRAY_TYPE array) { \
+ return env->Get ## NAME ## ArrayElements(array, nullptr); \
+ } \
+ \
+ static constexpr void releaseArrayElements(JNIEnv* env, ARRAY_TYPE array, \
+ POINTER_TYPE buffer, jint mode) { \
+ env->Release ## NAME ## ArrayElements(array, buffer, mode); \
+ } \
+}; \
+
+ARRAY_TRAITS(jbooleanArray, jboolean*, Boolean)
+ARRAY_TRAITS(jbyteArray, jbyte*, Byte)
+ARRAY_TRAITS(jcharArray, jchar*, Char)
+ARRAY_TRAITS(jdoubleArray, jdouble*, Double)
+ARRAY_TRAITS(jfloatArray, jfloat*, Float)
+ARRAY_TRAITS(jintArray, jint*, Int)
+ARRAY_TRAITS(jlongArray, jlong*, Long)
+ARRAY_TRAITS(jshortArray, jshort*, Short)
+
+#undef ARRAY_TRAITS
+
+template<typename JavaArrayType, typename PrimitiveType, class Traits, size_t preallocSize = 10>
+class ScopedArrayRO {
+public:
+ ScopedArrayRO(JNIEnv* env, JavaArrayType javaArray) : mEnv(env), mJavaArray(javaArray) {
+ if (mJavaArray == nullptr) {
+ mSize = 0;
+ mRawArray = nullptr;
+ } else {
+ mSize = mEnv->GetArrayLength(mJavaArray);
+ if (mSize <= preallocSize) {
+ Traits::getArrayRegion(mEnv, mJavaArray, 0, mSize, mBuffer);
+ mRawArray = mBuffer;
+ } else {
+ mRawArray = Traits::getArrayElements(mEnv, mJavaArray);
+ }
+ }
+ }
+
+ ~ScopedArrayRO() {
+ if (mRawArray != nullptr && mRawArray != mBuffer) {
+ Traits::releaseArrayElements(mEnv, mJavaArray, mRawArray, JNI_ABORT);
+ }
+ }
+
+ const PrimitiveType* get() const { return mRawArray; }
+ const PrimitiveType& operator[](size_t n) const { return mRawArray[n]; }
+ size_t size() const { return mSize; }
+
+private:
+ JNIEnv* const mEnv;
+ JavaArrayType mJavaArray;
+ PrimitiveType* mRawArray;
+ size_t mSize;
+ PrimitiveType mBuffer[preallocSize];
+ DISALLOW_COPY_AND_ASSIGN(ScopedArrayRO);
+};
+
+// ScopedNullable***ArrayRO provide convenient read-only access to Java array from JNI code.
+// These accept nullptr. In that case, get() returns nullptr and size() returns 0.
+using ScopedNullableBooleanArrayRO = ScopedArrayRO<jbooleanArray, jboolean, BooleanArrayTraits>;
+using ScopedNullableByteArrayRO = ScopedArrayRO<jbyteArray, jbyte, ByteArrayTraits>;
+using ScopedNullableCharArrayRO = ScopedArrayRO<jcharArray, jchar, CharArrayTraits>;
+using ScopedNullableDoubleArrayRO = ScopedArrayRO<jdoubleArray, jdouble, DoubleArrayTraits>;
+using ScopedNullableFloatArrayRO = ScopedArrayRO<jfloatArray, jfloat, FloatArrayTraits>;
+using ScopedNullableIntArrayRO = ScopedArrayRO<jintArray, jint, IntArrayTraits>;
+using ScopedNullableLongArrayRO = ScopedArrayRO<jlongArray, jlong, LongArrayTraits>;
+using ScopedNullableShortArrayRO = ScopedArrayRO<jshortArray, jshort, ShortArrayTraits>;
+
+} // namespace android
+
+#endif // SCOPED_NULLABLE_PRIMITIVE_ARRAY_H
diff --git a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
index 5f6f62a..978ea7a 100644
--- a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
@@ -45,8 +45,9 @@
@LargeTest
@RunWith(AndroidJUnit4.class)
abstract class AbstractCrossUserContentResolverTest {
- private final static int TIMEOUT_SERVICE_CONNECTION_SEC = 4;
- private final static int TIMEOUT_CONTENT_CHANGE_SEC = 4;
+ private static final int TIMEOUT_SERVICE_CONNECTION_SEC = 4;
+ private static final int TIMEOUT_CONTENT_CHANGE_SEC = 4;
+ private static final int TIMEOUT_USER_UNLOCK_SEC = 4;
private Context mContext;
protected UserManager mUm;
@@ -61,7 +62,7 @@
mCrossUserId = userInfo.id;
final PackageManager pm = mContext.getPackageManager();
pm.installExistingPackageAsUser(mContext.getPackageName(), mCrossUserId);
- ActivityManager.getService().startUserInBackground(mCrossUserId);
+ unlockUser();
final CountDownLatch connectionLatch = new CountDownLatch(1);
mServiceConnection = new CrossUserContentServiceConnection(connectionLatch);
@@ -77,6 +78,30 @@
protected abstract UserInfo createUser() throws RemoteException ;
+ private void unlockUser() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)
+ == mCrossUserId) {
+ latch.countDown();
+ }
+ }
+ };
+ mContext.registerReceiverAsUser(receiver, UserHandle.of(mCrossUserId),
+ new IntentFilter(Intent.ACTION_USER_UNLOCKED), null, null);
+ ActivityManager.getService().startUserInBackground(mCrossUserId);
+
+ try {
+ if (!latch.await(TIMEOUT_USER_UNLOCK_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for the u" + mCrossUserId + " to unlock");
+ }
+ } finally {
+ mContext.unregisterReceiver(receiver);
+ }
+ }
+
@After
public void tearDown() throws Exception {
if (mCrossUserId != -1) {
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 41686fa..9092c85 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -45,6 +45,9 @@
private TextClassificationManager mTcm;
private TextClassifier mClassifier;
+ private TextSelection.Options mSelectionOptions;
+ private TextClassification.Options mClassificationOptions;
+ private TextLinks.Options mLinksOptions;
@Before
public void setup() {
@@ -52,6 +55,9 @@
.getSystemService(TextClassificationManager.class);
mTcm.setTextClassifier(null);
mClassifier = mTcm.getTextClassifier();
+ mSelectionOptions = new TextSelection.Options().setDefaultLocales(LOCALES);
+ mClassificationOptions = new TextClassification.Options().setDefaultLocales(LOCALES);
+ mLinksOptions = new TextLinks.Options().setDefaultLocales(LOCALES);
}
@Test
@@ -66,24 +72,9 @@
int smartStartIndex = text.indexOf(suggested);
int smartEndIndex = smartStartIndex + suggested.length();
- assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
- isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL));
- }
-
- @Test
- public void testSmartSelection_nullLocaleList() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Contact me at droid@android.com";
- String selected = "droid";
- String suggested = "droid@android.com";
- int startIndex = text.indexOf(selected);
- int endIndex = startIndex + selected.length();
- int smartStartIndex = text.indexOf(suggested);
- int smartEndIndex = smartStartIndex + suggested.length();
- LocaleList nullLocales = null;
-
- assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, nullLocales),
+ TextSelection selection = mClassifier.suggestSelection(
+ text, startIndex, endIndex, mSelectionOptions);
+ assertThat(selection,
isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL));
}
@@ -99,7 +90,9 @@
int smartStartIndex = text.indexOf(suggested);
int smartEndIndex = smartStartIndex + suggested.length();
- assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
+ TextSelection selection = mClassifier.suggestSelection(
+ text, startIndex, endIndex, mSelectionOptions);
+ assertThat(selection,
isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_URL));
}
@@ -112,7 +105,9 @@
int startIndex = text.indexOf(selected);
int endIndex = startIndex + selected.length();
- assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
+ TextSelection selection = mClassifier.suggestSelection(
+ text, startIndex, endIndex, mSelectionOptions);
+ assertThat(selection,
isTextSelection(startIndex, endIndex, NO_TYPE));
}
@@ -124,7 +119,10 @@
String classifiedText = "droid@android.com";
int startIndex = text.indexOf(classifiedText);
int endIndex = startIndex + classifiedText.length();
- assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
+
+ TextClassification classification = mClassifier.classifyText(
+ text, startIndex, endIndex, mClassificationOptions);
+ assertThat(classification,
isTextClassification(
classifiedText,
TextClassifier.TYPE_EMAIL,
@@ -139,7 +137,10 @@
String classifiedText = "www.android.com";
int startIndex = text.indexOf(classifiedText);
int endIndex = startIndex + classifiedText.length();
- assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
+
+ TextClassification classification = mClassifier.classifyText(
+ text, startIndex, endIndex, mClassificationOptions);
+ assertThat(classification,
isTextClassification(
classifiedText,
TextClassifier.TYPE_URL,
@@ -154,7 +155,10 @@
String classifiedText = "HTTP://ANDROID.COM";
int startIndex = text.indexOf(classifiedText);
int endIndex = startIndex + classifiedText.length();
- assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
+
+ TextClassification classification = mClassifier.classifyText(
+ text, startIndex, endIndex, mClassificationOptions);
+ assertThat(classification,
isTextClassification(
classifiedText,
TextClassifier.TYPE_URL,
@@ -162,22 +166,6 @@
}
@Test
- public void testTextClassifyText_nullLocaleList() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Contact me at droid@android.com";
- String classifiedText = "droid@android.com";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- LocaleList nullLocales = null;
- assertThat(mClassifier.classifyText(text, startIndex, endIndex, nullLocales),
- isTextClassification(
- classifiedText,
- TextClassifier.TYPE_EMAIL,
- "mailto:" + classifiedText));
- }
-
- @Test
public void testGenerateLinks() {
if (isTextClassifierDisabled()) return;
@@ -210,13 +198,14 @@
int startIndex = text.indexOf(classifiedText);
int endIndex = startIndex + classifiedText.length();
- Collection<TextLinks.TextLink> links = mClassifier.generateLinks(text, null).getLinks();
+ Collection<TextLinks.TextLink> links = mClassifier.generateLinks(text, mLinksOptions)
+ .getLinks();
for (TextLinks.TextLink link : links) {
if (text.subSequence(link.getStart(), link.getEnd()).equals(classifiedText)) {
assertEquals(type, link.getEntity(0));
assertEquals(startIndex, link.getStart());
assertEquals(endIndex, link.getEnd());
- assertTrue(link.getConfidenceScore(type) > .9);
+ assertTrue(link.getConfidenceScore(type) > 0);
return;
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index 682a002..4b197e4 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -104,7 +104,9 @@
@Test
public void testCpuFreqTimes() throws Exception {
- assumeTrue(sCpuFreqTimesAvailable);
+ if (!sCpuFreqTimesAvailable) {
+ return;
+ }
batteryOnScreenOn();
forceStop();
@@ -126,7 +128,9 @@
@Test
public void testCpuFreqTimes_screenOff() throws Exception {
- assumeTrue(sCpuFreqTimesAvailable);
+ if (!sCpuFreqTimesAvailable) {
+ return;
+ }
batteryOnScreenOff();
forceStop();
@@ -154,7 +158,9 @@
@Test
public void testCpuFreqTimes_isolatedProcess() throws Exception {
- assumeTrue(sCpuFreqTimesAvailable);
+ if (!sCpuFreqTimesAvailable) {
+ return;
+ }
batteryOnScreenOn();
forceStop();
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index c78c99f..1019580 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -640,7 +640,6 @@
* The ImageReader continues to be usable after this call, but may need to reallocate buffers
* when more buffers are needed for rendering.
* </p>
- * @hide
*/
public void discardFreeBuffers() {
synchronized (mCloseLock) {
diff --git a/media/mca/filterfw/Android.mk b/media/mca/filterfw/Android.mk
index 334f4e2..37f1e13 100644
--- a/media/mca/filterfw/Android.mk
+++ b/media/mca/filterfw/Android.mk
@@ -26,6 +26,8 @@
LOCAL_MODULE := libfilterfw
+LOCAL_CFLAGS := -Wall -Werror
+
LOCAL_MODULE_TAGS := optional
LOCAL_WHOLE_STATIC_LIBRARIES := libfilterfw_jni \
diff --git a/packages/CompanionDeviceManager/res/drawable/dialog_background.xml b/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
index af2c83f..a017f41 100644
--- a/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
+++ b/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
@@ -16,7 +16,7 @@
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape android:shape="rectangle">
- <corners android:radius="2dp" />
+ <corners android:radius="?android:attr/dialogCornerRadius" />
<solid android:color="?android:attr/colorBackground" />
</shape>
</inset>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 9400fd8..663f206 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -23,14 +23,12 @@
import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
import android.app.ActivityManager;
-import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
@@ -89,7 +87,6 @@
import com.android.systemui.shared.recents.view.RecentsTransition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.stackdivider.DividerView;
-import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
import com.android.systemui.statusbar.phone.StatusBar;
import java.util.ArrayList;
@@ -657,13 +654,6 @@
// the resize mode already.
if (ssp.setTaskWindowingModeSplitScreenPrimary(taskId, stackCreateMode, initialBounds)) {
EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds));
- showRecents(
- false /* triggeredFromAltTab */,
- dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS,
- false /* animate */,
- true /* launchedWhileDockingTask*/,
- false /* fromHome */,
- DividerView.INVALID_RECENTS_GROW_TARGET);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index f5c77f2..64c52ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -369,7 +369,7 @@
private void onFacetClicked(Intent intent, int index) {
String packageName = intent.getPackage();
- if (packageName == null) {
+ if (packageName == null && !intent.getCategories().contains(Intent.CATEGORY_HOME)) {
return;
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 32af29d..bd6af01 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5013,6 +5013,11 @@
// OS: P
FIELD_SELECTION_WIDGET_VERSION = 1262;
+ // OPEN: Settings > Battery(version 2)
+ // CATEGORY: SETTINGS
+ // OS: P
+ FUELGAUGE_POWER_USAGE_SUMMARY_V2 = 1263;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ced8621..bdfd82f 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -501,9 +501,11 @@
windowingMode = WINDOWING_MODE_FULLSCREEN;
}
+ final boolean alreadyInSplitScreenMode = display.hasSplitScreenPrimaryStack();
+
// Take any required action due to us not supporting the preferred windowing mode.
if (windowingMode != preferredWindowingMode && isActivityTypeStandardOrUndefined()) {
- if (display.hasSplitScreenPrimaryStack()
+ if (alreadyInSplitScreenMode
&& (preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|| preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)) {
// Looks like we can't launch in split screen mode, go ahead an dismiss split-screen
@@ -577,7 +579,7 @@
resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */);
}
} finally {
- if (mDisplayId == DEFAULT_DISPLAY
+ if (!alreadyInSplitScreenMode && mDisplayId == DEFAULT_DISPLAY
&& windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
// Make sure recents stack exist when creating a dock stack as it normally needs to
// be on the other side of the docked stack and we make visibility decisions based
@@ -1678,12 +1680,6 @@
return true;
}
- /** Returns true if the stack is currently considered visible. */
- boolean isVisible() {
- return mWindowContainerController != null && mWindowContainerController.isVisible()
- && !mForceHidden;
- }
-
boolean isTopStackOnDisplay() {
return getDisplay().isTopStack(this);
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 27eb985..2fc5dda 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -606,21 +606,9 @@
return;
}
- if (startedActivityStack.inSplitScreenPrimaryWindowingMode()) {
- final ActivityStack homeStack = mSupervisor.mHomeStack;
- final boolean homeStackVisible = homeStack != null && homeStack.isVisible();
- if (homeStackVisible) {
- // We launch an activity while being in home stack, which means either launcher or
- // recents into docked stack. We don't want the launched activity to be alone in a
- // docked stack, so we want to immediately launch recents too.
- if (DEBUG_RECENTS) Slog.d(TAG, "Scheduling recents launch.");
- mService.mWindowManager.showRecentApps(true /* fromHome */);
- }
- return;
- }
-
- boolean clearedTask = (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
- == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK) && (mReuseTask != null);
+ final int clearTaskFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK;
+ boolean clearedTask = (mLaunchFlags & clearTaskFlags) == clearTaskFlags
+ && mReuseTask != null;
if (startedActivityStack.inPinnedWindowingMode()
&& (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP
|| clearedTask)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index fb6278a..20ec9b5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -571,7 +571,7 @@
if (!match) {
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"Package " + packageName +
- " signatures don't match previously installed version; ignoring!");
+ " signatures do not match previously installed version; ignoring!");
}
}
// Check for shared user signatures
@@ -579,16 +579,16 @@
// Already existing package. Make sure signatures match
boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
parsedSignatures) == PackageManager.SIGNATURE_MATCH;
- if (!match) {
+ if (!match && compareCompat) {
match = matchSignaturesCompat(
packageName, pkgSetting.sharedUser.signatures, parsedSignatures);
}
- if (!match && compareCompat) {
+ if (!match && compareRecover) {
match = matchSignaturesRecover(
packageName, pkgSetting.sharedUser.signatures.mSignatures, parsedSignatures);
compatMatch |= match;
}
- if (!match && compareRecover) {
+ if (!match) {
throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
"Package " + packageName
+ " has no signatures that match those in shared user "
diff --git a/services/core/java/com/android/server/power/OWNERS b/services/core/java/com/android/server/power/OWNERS
index b4300a9..d118c4e 100644
--- a/services/core/java/com/android/server/power/OWNERS
+++ b/services/core/java/com/android/server/power/OWNERS
@@ -1,3 +1,4 @@
michaelwr@google.com
per-file BatterySaverPolicy.java=omakoto@google.com
+per-file ShutdownThread.java=fkupolov@google.com
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 6bf725e..6fb345b 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -20,10 +20,7 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.IActivityManager;
-import android.app.KeyguardManager;
import android.app.ProgressDialog;
-import android.app.WallpaperColors;
-import android.app.WallpaperManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetoothManager;
import android.content.BroadcastReceiver;
@@ -31,8 +28,6 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
import android.media.AudioAttributes;
import android.os.FileUtils;
import android.os.Handler;
@@ -47,8 +42,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
-import android.os.storage.IStorageManager;
-import android.os.storage.IStorageShutdownObserver;
import android.util.ArrayMap;
import android.util.Log;
import android.util.TimingsTraceLog;
@@ -123,7 +116,6 @@
private static String METRIC_RADIOS = "shutdown_radios";
private static String METRIC_BT = "shutdown_bt";
private static String METRIC_RADIO = "shutdown_radio";
- private static String METRIC_SM = "shutdown_storage_manager";
private final Object mActionDoneSync = new Object();
private boolean mActionDone;
@@ -526,54 +518,6 @@
shutdownTimingLog.traceEnd(); // ShutdownRadios
metricEnded(METRIC_RADIOS);
- // Shutdown StorageManagerService to ensure media is in a safe state
- IStorageShutdownObserver observer = new IStorageShutdownObserver.Stub() {
- public void onShutDownComplete(int statusCode) throws RemoteException {
- Log.w(TAG, "Result code " + statusCode + " from StorageManagerService.shutdown");
- actionDone();
- }
- };
-
- Log.i(TAG, "Shutting down StorageManagerService");
- shutdownTimingLog.traceBegin("ShutdownStorageManager");
- metricStarted(METRIC_SM);
-
- // Set initial variables and time out time.
- mActionDone = false;
- final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
- synchronized (mActionDoneSync) {
- try {
- final IStorageManager storageManager = IStorageManager.Stub.asInterface(
- ServiceManager.checkService("mount"));
- if (storageManager != null) {
- storageManager.shutdown(observer);
- } else {
- Log.w(TAG, "StorageManagerService unavailable for shutdown");
- }
- } catch (Exception e) {
- Log.e(TAG, "Exception during StorageManagerService shutdown", e);
- }
- while (!mActionDone) {
- long delay = endShutTime - SystemClock.elapsedRealtime();
- if (delay <= 0) {
- Log.w(TAG, "StorageManager shutdown wait timed out");
- break;
- } else if (mRebootHasProgressBar) {
- int status = (int)((MAX_SHUTDOWN_WAIT_TIME - delay) * 1.0 *
- (MOUNT_SERVICE_STOP_PERCENT - RADIO_STOP_PERCENT) /
- MAX_SHUTDOWN_WAIT_TIME);
- status += RADIO_STOP_PERCENT;
- sInstance.setRebootProgress(status, null);
- }
- try {
- mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
- } catch (InterruptedException e) {
- }
- }
- }
- shutdownTimingLog.traceEnd(); // ShutdownStorageManager
- metricEnded(METRIC_SM);
-
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
@@ -585,6 +529,7 @@
shutdownTimingLog.traceEnd(); // SystemServerShutdown
metricEnded(METRIC_SYSTEM_SERVER);
saveMetrics(mReboot);
+ // Remaining work will be done by init, including vold shutdown
rebootOrShutdown(mContext, mReboot, mReason);
}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 3772371..e240ec5 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -523,6 +523,18 @@
sayHiToStatsd(); // tell statsd that we're ready too and link to it
}
+ @Override
+ public void triggerUidSnapshot() {
+ enforceCallingPermission();
+ synchronized (sStatsdLock) {
+ try {
+ informAllUidsLocked(mContext);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to trigger uid snapshot.", e);
+ }
+ }
+ }
+
private void enforceCallingPermission() {
if (Binder.getCallingPid() == Process.myPid()) {
return;
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index c2a4be5..e7547bf 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -87,12 +87,6 @@
}
}
- public boolean isVisible() {
- synchronized (mWindowMap) {
- return mContainer != null && mContainer.isVisible();
- }
- }
-
public void reparent(int displayId, Rect outStackBounds, boolean onTop) {
synchronized (mWindowMap) {
if (mContainer == null) {
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index f093d57..fbcccf0 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -126,6 +126,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
@@ -176,6 +177,7 @@
"com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner"
* </code></pre>
*/
+@Ignore
@RunWith(AndroidJUnit4.class)
@MediumTest
public class NetworkPolicyManagerServiceTest {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
index 5f2e561..d27a758 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
@@ -18,6 +18,7 @@
import android.util.SparseBooleanArray;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.SmsAddress;
import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.util.HexDump;
@@ -113,8 +114,8 @@
* share code and logic with GSM. Also, gather all DTMF/BCD
* processing code in one place.
*/
-
- private static byte[] parseToDtmf(String address) {
+ @VisibleForTesting
+ public static byte[] parseToDtmf(String address) {
int digits = address.length();
byte[] result = new byte[digits];
for (int i = 0; i < digits; i++) {
@@ -196,33 +197,46 @@
public static CdmaSmsAddress parse(String address) {
CdmaSmsAddress addr = new CdmaSmsAddress();
addr.address = address;
- addr.ton = CdmaSmsAddress.TON_UNKNOWN;
- byte[] origBytes = null;
+ addr.ton = TON_UNKNOWN;
+ addr.digitMode = DIGIT_MODE_4BIT_DTMF;
+ addr.numberPlan = NUMBERING_PLAN_UNKNOWN;
+ addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
+
+ byte[] origBytes;
String filteredAddr = filterNumericSugar(address);
- if (filteredAddr != null) {
- origBytes = parseToDtmf(filteredAddr);
- }
- if (origBytes != null) {
- addr.digitMode = DIGIT_MODE_4BIT_DTMF;
- addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
- if (address.indexOf('+') != -1) {
- addr.ton = TON_INTERNATIONAL_OR_IP;
- }
- } else {
- filteredAddr = filterWhitespace(address);
- origBytes = UserData.stringToAscii(filteredAddr);
- if (origBytes == null) {
- return null;
- }
+ if (address.contains("+") || filteredAddr == null) {
+ // 3GPP2 C.S0015-B section 3.4.3.3 Address Parameters
+ // NUMBER_MODE should set to 1 for network address and email address.
addr.digitMode = DIGIT_MODE_8BIT_CHAR;
addr.numberMode = NUMBER_MODE_DATA_NETWORK;
- if (address.indexOf('@') != -1) {
+ filteredAddr = filterWhitespace(address);
+
+ if (address.contains("@")) {
+ // This is an email address
addr.ton = TON_NATIONAL_OR_EMAIL;
+ } else if (address.contains("+") && filterNumericSugar(address) != null) {
+ // This is an international number
+ // 3GPP2 C.S0015-B section 3.4.3.3 Address Parameters
+ // digit mode is set to 1 and number mode is set to 0, type of number should set
+ // to the value correspond to the value in 3GPP2 C.S005-D, table2.7.1.3.2.4-2
+ addr.ton = TON_INTERNATIONAL_OR_IP;
+ addr.numberPlan = NUMBERING_PLAN_ISDN_TELEPHONY;
+ addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
+ filteredAddr = filterNumericSugar(address);
}
+
+ origBytes = UserData.stringToAscii(filteredAddr);
+ } else {
+ // The address is not an international number and it only contains digit and *#
+ origBytes = parseToDtmf(filteredAddr);
}
+
+ if (origBytes == null) {
+ return null;
+ }
+
addr.origBytes = origBytes;
addr.numberOfDigits = origBytes.length;
return addr;
}
-
}
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index de4fb73..eaaefd5 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -346,30 +346,15 @@
return true;
}
-class FullyQualifiedClassNameVisitor : public xml::Visitor {
- public:
- using xml::Visitor::Visit;
-
- explicit FullyQualifiedClassNameVisitor(const StringPiece& package) : package_(package) {}
-
- void Visit(xml::Element* el) override {
- for (xml::Attribute& attr : el->attributes) {
- if (attr.namespace_uri == xml::kSchemaAndroid &&
- class_attributes_.find(attr.name) != class_attributes_.end()) {
- if (Maybe<std::string> new_value = util::GetFullyQualifiedClassName(package_, attr.value)) {
- attr.value = std::move(new_value.value());
- }
- }
+static void FullyQualifyClassName(const StringPiece& package, const StringPiece& attr_ns,
+ const StringPiece& attr_name, xml::Element* el) {
+ xml::Attribute* attr = el->FindAttribute(attr_ns, attr_name);
+ if (attr != nullptr) {
+ if (Maybe<std::string> new_value = util::GetFullyQualifiedClassName(package, attr->value)) {
+ attr->value = std::move(new_value.value());
}
-
- // Super implementation to iterate over the children.
- xml::Visitor::Visit(el);
}
-
- private:
- StringPiece package_;
- std::unordered_set<StringPiece> class_attributes_ = {"name"};
-};
+}
static bool RenameManifestPackage(const StringPiece& package_override, xml::Element* manifest_el) {
xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
@@ -381,8 +366,25 @@
std::string original_package = std::move(attr->value);
attr->value = package_override.to_string();
- FullyQualifiedClassNameVisitor visitor(original_package);
- manifest_el->Accept(&visitor);
+ xml::Element* application_el = manifest_el->FindChild({}, "application");
+ if (application_el != nullptr) {
+ FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", application_el);
+ FullyQualifyClassName(original_package, xml::kSchemaAndroid, "backupAgent", application_el);
+
+ for (xml::Element* child_el : application_el->GetChildElements()) {
+ if (child_el->namespace_uri.empty()) {
+ if (child_el->name == "activity" || child_el->name == "activity-alias" ||
+ child_el->name == "provider" || child_el->name == "receiver" ||
+ child_el->name == "service") {
+ FullyQualifyClassName(original_package, xml::kSchemaAndroid, "name", child_el);
+ }
+
+ if (child_el->name == "activity-alias") {
+ FullyQualifyClassName(original_package, xml::kSchemaAndroid, "targetActivity", child_el);
+ }
+ }
+ }
+ }
return true;
}
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index da7f410..40085ea 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -240,6 +240,7 @@
std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android">
+ <uses-split android:name="feature_a" />
<application android:name=".MainApplication" text="hello">
<activity android:name=".activity.Start" />
<receiver android:name="com.google.android.Receiver" />
@@ -248,35 +249,41 @@
options);
ASSERT_NE(nullptr, doc);
- xml::Element* manifestEl = doc->root.get();
- ASSERT_NE(nullptr, manifestEl);
+ xml::Element* manifest_el = doc->root.get();
+ ASSERT_NE(nullptr, manifest_el);
xml::Attribute* attr = nullptr;
- attr = manifestEl->FindAttribute({}, "package");
+ attr = manifest_el->FindAttribute({}, "package");
ASSERT_NE(nullptr, attr);
EXPECT_EQ(std::string("com.android"), attr->value);
- xml::Element* applicationEl = manifestEl->FindChild({}, "application");
- ASSERT_NE(nullptr, applicationEl);
+ xml::Element* uses_split_el = manifest_el->FindChild({}, "uses-split");
+ ASSERT_NE(nullptr, uses_split_el);
+ attr = uses_split_el->FindAttribute(xml::kSchemaAndroid, "name");
+ ASSERT_NE(nullptr, attr);
+ EXPECT_EQ(std::string("feature_a"), attr->value);
- attr = applicationEl->FindAttribute(xml::kSchemaAndroid, "name");
+ xml::Element* application_el = manifest_el->FindChild({}, "application");
+ ASSERT_NE(nullptr, application_el);
+
+ attr = application_el->FindAttribute(xml::kSchemaAndroid, "name");
ASSERT_NE(nullptr, attr);
EXPECT_EQ(std::string("android.MainApplication"), attr->value);
- attr = applicationEl->FindAttribute({}, "text");
+ attr = application_el->FindAttribute({}, "text");
ASSERT_NE(nullptr, attr);
EXPECT_EQ(std::string("hello"), attr->value);
xml::Element* el;
- el = applicationEl->FindChild({}, "activity");
+ el = application_el->FindChild({}, "activity");
ASSERT_NE(nullptr, el);
attr = el->FindAttribute(xml::kSchemaAndroid, "name");
ASSERT_NE(nullptr, el);
EXPECT_EQ(std::string("android.activity.Start"), attr->value);
- el = applicationEl->FindChild({}, "receiver");
+ el = application_el->FindChild({}, "receiver");
ASSERT_NE(nullptr, el);
attr = el->FindAttribute(xml::kSchemaAndroid, "name");