diff options
63 files changed, 1426 insertions, 481 deletions
diff --git a/Android.mk b/Android.mk index 06f64f1f1601..a69170f4db66 100644 --- a/Android.mk +++ b/Android.mk @@ -529,11 +529,13 @@ LOCAL_SRC_FILES += \ telephony/java/com/android/ims/internal/IImsService.aidl \ telephony/java/com/android/ims/internal/IImsServiceController.aidl \ telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl \ + telephony/java/com/android/ims/internal/IImsSmsFeature.aidl \ telephony/java/com/android/ims/internal/IImsStreamMediaSession.aidl \ telephony/java/com/android/ims/internal/IImsUt.aidl \ telephony/java/com/android/ims/internal/IImsUtListener.aidl \ telephony/java/com/android/ims/internal/IImsVideoCallCallback.aidl \ telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl \ + telephony/java/com/android/ims/internal/ISmsListener.aidl \ telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl \ telephony/java/com/android/ims/internal/uce/uceservice/IUceListener.aidl \ telephony/java/com/android/ims/internal/uce/options/IOptionsService.aidl \ @@ -1116,7 +1118,7 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS += \ -federate SupportLib https://developer.android.com \ -federationapi SupportLib prebuilts/sdk/current/support-api.txt -# ==== the api diff =========================== +# ==== Public API diff =========================== include $(CLEAR_VARS) LOCAL_SRC_FILES := $(framework_docs_LOCAL_API_CHECK_SRC_FILES) @@ -1141,6 +1143,31 @@ LOCAL_APIDIFF_NEWAPI := $(LOCAL_PATH)/../../$(basename $(INTERNAL_PLATFORM_API_F include $(BUILD_APIDIFF) +# ==== System API diff =========================== +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(framework_docs_LOCAL_API_CHECK_SRC_FILES) +LOCAL_INTERMEDIATE_SOURCES := $(framework_docs_LOCAL_INTERMEDIATE_SOURCES) +LOCAL_JAVA_LIBRARIES := $(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES) +LOCAL_MODULE_CLASS := $(framework_docs_LOCAL_MODULE_CLASS) +LOCAL_ADDITIONAL_JAVA_DIR := $(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR) +LOCAL_ADDITIONAL_DEPENDENCIES := \ + $(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES) \ + $(INTERNAL_PLATFORM_SYSTEM_API_FILE) + +LOCAL_MODULE := offline-system-sdk-referenceonly + +last_released_sdk_version := $(lastword $(call numerically_sort, \ + $(filter-out current, \ + $(patsubst $(SRC_SYSTEM_API_DIR)/%.txt,%, $(wildcard $(SRC_SYSTEM_API_DIR)/*.txt)) \ + )\ + )) + +LOCAL_APIDIFF_OLDAPI := $(LOCAL_PATH)/../../$(SRC_SYSTEM_API_DIR)/$(last_released_sdk_version) +LOCAL_APIDIFF_NEWAPI := $(LOCAL_PATH)/../../$(basename $(INTERNAL_PLATFORM_SYSTEM_API_FILE)) + +include $(BUILD_APIDIFF) + # ==== the api stubs and current.xml =========================== include $(CLEAR_VARS) @@ -1317,7 +1344,7 @@ $(full_target): $(static_doc_index_redirect) $(full_target): $(framework_built) -# ==== static html in the sdk ================================== +# ==== Public API static reference docs ================================== include $(CLEAR_VARS) LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES) @@ -1359,6 +1386,50 @@ $(full_target): $(static_doc_properties) $(full_target): $(framework_built) +# ==== System API static reference docs ================================== +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES) +LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES) +LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES) +LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS) +LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH) +LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR) +LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR) +LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES) + +LOCAL_MODULE := offline-system-sdk-referenceonly + +LOCAL_DROIDDOC_OPTIONS:=\ + $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \ + -hide 101 -hide 104 -hide 108 \ + -showAnnotation android.annotation.SystemApi \ + -offlinemode \ + -title "Android System SDK" \ + -proofread $(OUT_DOCS)/$(LOCAL_MODULE)-proofread.txt \ + -sdkvalues $(OUT_DOCS) \ + -hdf android.whichdoc offline \ + -referenceonly + +LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=external/doclava/res/assets/templates-sdk + +include $(BUILD_DROIDDOC) + +static_doc_index_redirect := $(out_dir)/index.html +$(static_doc_index_redirect): $(LOCAL_PATH)/docs/docs-documentation-redirect.html + $(copy-file-to-target) + +static_doc_properties := $(out_dir)/source.properties +$(static_doc_properties): \ + $(LOCAL_PATH)/docs/source.properties | $(ACP) + $(hide) mkdir -p $(dir $@) + $(hide) $(ACP) $< $@ + +$(full_target): $(static_doc_index_redirect) +$(full_target): $(static_doc_properties) +$(full_target): $(framework_built) + + # ==== docs for the web (on the androiddevdocs app engine server) ======================= include $(CLEAR_VARS) diff --git a/api/current.txt b/api/current.txt index 2f3fc26abbbf..182dd3a33bfe 100644 --- a/api/current.txt +++ b/api/current.txt @@ -22033,6 +22033,7 @@ package android.media { 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(); @@ -33139,6 +33140,7 @@ package android.provider { public final class AlarmClock { ctor public AlarmClock(); field public static final java.lang.String ACTION_DISMISS_ALARM = "android.intent.action.DISMISS_ALARM"; + field public static final java.lang.String ACTION_DISMISS_TIMER = "android.intent.action.DISMISS_TIMER"; field public static final java.lang.String ACTION_SET_ALARM = "android.intent.action.SET_ALARM"; field public static final java.lang.String ACTION_SET_TIMER = "android.intent.action.SET_TIMER"; field public static final java.lang.String ACTION_SHOW_ALARMS = "android.intent.action.SHOW_ALARMS"; @@ -49092,15 +49094,19 @@ package android.view.textclassifier { 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 +49122,9 @@ package android.view.textclassifier { } 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 57b4fc1e24b3..2fd794777cb6 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -220,7 +220,7 @@ void StatsLogProcessor::flushIfNecessary(uint64_t timestampNs, 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 c019d5d31443..7eca5aa21201 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -480,7 +480,7 @@ status_t StatsService::cmd_print_stats(FILE* out, const Vector<String8>& args) { 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/atoms.proto b/cmds/statsd/src/atoms.proto index 20e7c600938e..e0d9ce7d8802 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -91,6 +91,8 @@ message Atom { CpuTimePerFreqPulled cpu_time_per_freq_pulled = 1008; CpuTimePerUidPulled cpu_time_per_uid_pulled = 1009; CpuTimePerUidFreqPulled cpu_time_per_uid_freq_pulled = 1010; + WifiActivityEnergyInfoPulled wifi_activity_energy_info_pulled = 1011; + ModemActivityInfoPulled modem_activity_info_pulled = 1012; } } @@ -699,7 +701,7 @@ message SettingChanged { optional int32 user = 7; } -/* +/** * Logs activity going to foreground or background * * Logged from: @@ -839,7 +841,7 @@ message KernelWakelockPulled { optional int64 time = 4; } -/* +/** * Pulls PowerStatePlatformSleepState. * * Definition here: @@ -899,7 +901,7 @@ message IsolatedUidChanged { optional int32 is_create = 3; } -/* +/** * Pulls Cpu time per frequency. * Note: this should be pulled for gauge metric only, without condition. * The puller keeps internal state of last values. It should not be pulled by @@ -916,7 +918,7 @@ message CpuTimePerFreqPulled { optional uint64 time = 3; } -/* +/** * Pulls Cpu Time Per Uid. * Note that isolated process uid time should be attributed to host uids. */ @@ -965,3 +967,56 @@ message PacketWakeupOccurred { // The destination port if this was a TCP or UDP packet. optional int32 destination_port = 9; } + +/** + * Pulls Wifi Controller Activity Energy Info + */ +message WifiActivityEnergyInfoPulled { + // timestamp(wall clock) of record creation + optional uint64 timestamp_ms = 1; + // stack reported state + // TODO: replace this with proto enum + optional int32 stack_state = 2; + // tx time in ms + optional uint64 controller_tx_time_ms = 3; + // rx time in ms + optional uint64 controller_rx_time_ms = 4; + // idle time in ms + optional uint64 controller_idle_time_ms = 5; + // product of current(mA), voltage(V) and time(ms) + optional uint64 controller_energy_used = 6; +} + +/** + * Pulls Modem Activity Energy Info + */ +message ModemActivityInfoPulled { + // timestamp(wall clock) of record creation + optional uint64 timestamp_ms = 1; + // sleep time in ms. + optional uint64 sleep_time_ms = 2; + // idle time in ms + optional uint64 controller_idle_time_ms = 3; + /** + * Tx power index + * index 0 = tx_power < 0dBm + * index 1 = 0dBm < tx_power < 5dBm + * index 2 = 5dBm < tx_power < 15dBm + * index 3 = 15dBm < tx_power < 20dBm + * index 4 = tx_power > 20dBm + */ + // tx time in ms at power level 0 + optional uint64 controller_tx_time_pl0_ms = 4; + // tx time in ms at power level 1 + optional uint64 controller_tx_time_pl1_ms = 5; + // tx time in ms at power level 2 + optional uint64 controller_tx_time_pl2_ms = 6; + // tx time in ms at power level 3 + optional uint64 controller_tx_time_pl3_ms = 7; + // tx time in ms at power level 4 + optional uint64 controller_tx_time_pl4_ms = 8; + // rx time in ms at power level 5 + optional uint64 controller_rx_time_ms = 9; + // product of current(mA), voltage(V) and time(ms) + optional uint64 energy_used = 10; +} diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp index 2bd36126d340..29574579b2a0 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.cpp +++ b/cmds/statsd/src/guardrail/StatsdStats.cpp @@ -45,6 +45,7 @@ const int FIELD_ID_MATCHER_STATS = 4; 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 @@ void StatsdStats::noteMetricsReportSent(const ConfigKey& key, int32_t timeSec) { 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 @@ void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) { } } + 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 451144f80bbf..d6f6566cbc33 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -45,6 +45,10 @@ public: 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 @@ public: 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 @@ private: 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 6c32d3e1b11e..db592e2c5841 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 android { 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 @@ void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid, 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 @@ void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const i 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 @@ void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const i 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 @@ void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const i 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 @@ void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const i 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 @@ void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const i 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 @@ int UidMap::getParentUidOrSelf(int uid) { 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 @@ void UidMap::clearOutput() { 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 @@ int64_t UidMap::getMinimumTimestampNs() { 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 @@ UidMapping UidMap::getOutput(const int64_t& timestamp, const ConfigKey& key) { } } } + 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::printUidMap(FILE* out) { 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 24eb96619527..d2971c9b8a8d 100644 --- a/cmds/statsd/src/packages/UidMap.h +++ b/cmds/statsd/src/packages/UidMap.h @@ -50,15 +50,16 @@ struct AppData { // 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 @@ public: // 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 @@ private: // 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 e7e1d43974af..cc8a26de1a8d 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -220,4 +220,13 @@ message StatsdStatsReport { } 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 0c194683884c..aa194e625060 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 @@ const string kApp2 = "app2.sharing.1"; 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 @@ TEST(UidMapTest, TestClearingOutput) { 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 @@ TEST(UidMapTest, TestClearingOutput) { 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/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java index 5b59c21fcd45..fe3d86d4cd6a 100644 --- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java +++ b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java @@ -110,113 +110,7 @@ public class DisplayProtoUtils { log.getEventMetrics(); for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) { sb.append(getDateStr(event.getTimestampNanos())).append(": "); - switch (event.getAtom().getPushedCase()) { - case SETTING_CHANGED: - sb.append("SETTING_CHANGED\n"); - break; - case SYNC_STATE_CHANGED: - sb.append("SYNC_STATE_CHANGED\n"); - break; - case AUDIO_STATE_CHANGED: - sb.append("AUDIO_STATE_CHANGED\n"); - break; - case CAMERA_STATE_CHANGED: - sb.append("CAMERA_STATE_CHANGED\n"); - break; - case ISOLATED_UID_CHANGED: - sb.append("ISOLATED_UID_CHANGED\n"); - break; - case SCREEN_STATE_CHANGED: - sb.append("SCREEN_STATE_CHANGED\n"); - break; - case SENSOR_STATE_CHANGED: - sb.append("SENSOR_STATE_CHANGED\n"); - break; - case BATTERY_LEVEL_CHANGED: - sb.append("BATTERY_LEVEL_CHANGED\n"); - break; - case PLUGGED_STATE_CHANGED: - sb.append("PLUGGED_STATE_CHANGED\n"); - break; - case WAKEUP_ALARM_OCCURRED: - sb.append("WAKEUP_ALARM_OCCURRED\n"); - break; - case BLE_SCAN_STATE_CHANGED: - sb.append("BLE_SCAN_STATE_CHANGED\n"); - break; - case CHARGING_STATE_CHANGED: - sb.append("CHARGING_STATE_CHANGED\n"); - break; - case GPS_SCAN_STATE_CHANGED: - sb.append("GPS_SCAN_STATE_CHANGED\n"); - break; - case KERNEL_WAKEUP_REPORTED: - sb.append("KERNEL_WAKEUP_REPORTED\n"); - break; - case WAKELOCK_STATE_CHANGED: - sb.append("WAKELOCK_STATE_CHANGED\n"); - break; - case WIFI_LOCK_STATE_CHANGED: - sb.append("WIFI_LOCK_STATE_CHANGED\n"); - break; - case WIFI_SCAN_STATE_CHANGED: - sb.append("WIFI_SCAN_STATE_CHANGED\n"); - break; - case BLE_SCAN_RESULT_RECEIVED: - sb.append("BLE_SCAN_RESULT_RECEIVED\n"); - break; - case DEVICE_ON_STATUS_CHANGED: - sb.append("DEVICE_ON_STATUS_CHANGED\n"); - break; - case FLASHLIGHT_STATE_CHANGED: - sb.append("FLASHLIGHT_STATE_CHANGED\n"); - break; - case SCREEN_BRIGHTNESS_CHANGED: - sb.append("SCREEN_BRIGHTNESS_CHANGED\n"); - break; - case UID_PROCESS_STATE_CHANGED: - sb.append("UID_PROCESS_STATE_CHANGED\n"); - break; - case UID_WAKELOCK_STATE_CHANGED: - sb.append("UID_WAKELOCK_STATE_CHANGED\n"); - break; - case DEVICE_TEMPERATURE_REPORTED: - sb.append("DEVICE_TEMPERATURE_REPORTED\n"); - break; - case SCHEDULED_JOB_STATE_CHANGED: - sb.append("SCHEDULED_JOB_STATE_CHANGED\n"); - break; - case MEDIA_CODEC_ACTIVITY_CHANGED: - sb.append("MEDIA_CODEC_ACTIVITY_CHANGED\n"); - break; - case WIFI_SIGNAL_STRENGTH_CHANGED: - sb.append("WIFI_SIGNAL_STRENGTH_CHANGED\n"); - break; - case PHONE_SIGNAL_STRENGTH_CHANGED: - sb.append("PHONE_SIGNAL_STRENGTH_CHANGED\n"); - break; - case DEVICE_IDLE_MODE_STATE_CHANGED: - sb.append("DEVICE_IDLE_MODE_STATE_CHANGED\n"); - break; - case BATTERY_SAVER_MODE_STATE_CHANGED: - sb.append("BATTERY_SAVER_MODE_STATE_CHANGED\n"); - break; - case PROCESS_LIFE_CYCLE_STATE_CHANGED: - sb.append("PROCESS_LIFE_CYCLE_STATE_CHANGED\n"); - break; - case ACTIVITY_FOREGROUND_STATE_CHANGED: - sb.append("ACTIVITY_FOREGROUND_STATE_CHANGED\n"); - break; - case BLE_UNOPTIMIZED_SCAN_STATE_CHANGED: - sb.append("BLE_UNOPTIMIZED_SCAN_STATE_CHANGED\n"); - break; - case LONG_PARTIAL_WAKELOCK_STATE_CHANGED: - sb.append("LONG_PARTIAL_WAKELOCK_STATE_CHANGED\n"); - break; - case PUSHED_NOT_SET: - sb.append("PUSHED_NOT_SET\n"); - break; - } + sb.append(event.getAtom().getPushedCase().toString()).append("\n"); } } diff --git a/core/java/Android.bp b/core/java/Android.bp index d8c79293f9ba..b43cf277aa57 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -4,16 +4,16 @@ filegroup { } // 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 @@ cc_library_static { "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 3314f604f940..1d2a40850454 100644 --- a/core/java/android/os/IStatsCompanionService.aidl +++ b/core/java/android/os/IStatsCompanionService.aidl @@ -56,4 +56,7 @@ interface IStatsCompanionService { /** 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/provider/AlarmClock.java b/core/java/android/provider/AlarmClock.java index f9030124cc63..21694575631a 100644 --- a/core/java/android/provider/AlarmClock.java +++ b/core/java/android/provider/AlarmClock.java @@ -158,7 +158,6 @@ public final class AlarmClock { * <p> * Dismiss all currently expired timers. If there are no expired timers, then this is a no-op. * </p> - * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_DISMISS_TIMER = "android.intent.action.DISMISS_TIMER"; diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java index cd233b831522..df0842f7fb0d 100644 --- a/core/java/android/service/euicc/EuiccService.java +++ b/core/java/android/service/euicc/EuiccService.java @@ -105,6 +105,13 @@ public abstract class EuiccService extends Service { 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 2779aa2db93a..f675c355638c 100644 --- a/core/java/android/view/textclassifier/TextClassification.java +++ b/core/java/android/view/textclassifier/TextClassification.java @@ -31,6 +31,7 @@ import com.android.internal.util.Preconditions; 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 @@ import java.util.List; * * <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 @@ import java.util.List; * * <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 @@ public final class TextClassification { @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 @@ public final class TextClassification { } /** - * 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 @@ public final class TextClassification { } /** - * 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 aeb84897b06b..5aaa5ad1eefe 100644 --- a/core/java/android/view/textclassifier/TextClassifier.java +++ b/core/java/android/view/textclassifier/TextClassifier.java @@ -23,6 +23,8 @@ import android.annotation.StringDef; 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 @@ public interface TextClassifier { /** @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 @@ public interface TextClassifier { * * @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 @@ public interface TextClassifier { @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 @@ public interface TextClassifier { @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 @@ public interface TextClassifier { * * @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 @@ public interface TextClassifier { @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 @@ public interface TextClassifier { @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 @@ public interface TextClassifier { * 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 @@ public interface TextClassifier { 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 2ad6e02c4849..df5e35f062b7 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -90,8 +90,8 @@ final class TextClassifierImpl implements TextClassifier { @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 @@ final class TextClassifierImpl implements TextClassifier { } @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 @@ final class TextClassifierImpl implements TextClassifier { } @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 @@ final class TextClassifierImpl implements TextClassifier { } /** - * @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 f3cc827f8889..76748d2b191a 100644 --- a/core/java/android/view/textclassifier/TextLinks.java +++ b/core/java/android/view/textclassifier/TextLinks.java @@ -161,39 +161,28 @@ public final class TextLinks { * 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; /** - * Builder to construct Options. + * @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 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); - } + public Options setDefaultLocales(@Nullable LocaleList defaultLocales) { + mDefaultLocales = defaultLocales; + return this; } - public @Nullable LocaleList getDefaultLocales() { - return mLocaleList; + + /** + * @return ordered list of locale preferences that can be used to disambiguate + * the provided text. + */ + @Nullable + public LocaleList getDefaultLocales() { + return mDefaultLocales; } - }; + } /** * A function to create spans from TextLinks. @@ -204,13 +193,10 @@ public final class TextLinks { * @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 0a67954a2e33..480b27a73fc1 100644 --- a/core/java/android/view/textclassifier/TextSelection.java +++ b/core/java/android/view/textclassifier/TextSelection.java @@ -26,6 +26,7 @@ import android.view.textclassifier.TextClassifier.EntityType; 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 @@ public final class TextSelection { @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 @@ public final class TextSelection { } /** - * TextSelection optional input parameters. + * Optional input parameters for generating TextSelection. */ public static final class Options { diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java index 517ad07c8323..46c39834060b 100644 --- a/core/java/android/webkit/WebViewClient.java +++ b/core/java/android/webkit/WebViewClient.java @@ -364,13 +364,13 @@ public class WebViewClient { } /** - * Notify the host application to handle a SSL client certificate - * request. The host application is responsible for showing the UI - * if desired and providing the keys. There are three ways to - * respond: proceed(), cancel() or ignore(). Webview stores the response - * in memory (for the life of the application) if proceed() or cancel() is - * called and does not call {@code onReceivedClientCertRequest()} again for the - * same host and port pair. Webview does not store the response if ignore() + * Notify the host application to handle a SSL client certificate request. The host application + * is responsible for showing the UI if desired and providing the keys. There are three ways to + * respond: {@link ClientCertRequest#proceed}, {@link ClientCertRequest#cancel}, or {@link + * ClientCertRequest#ignore}. Webview stores the response in memory (for the life of the + * application) if {@link ClientCertRequest#proceed} or {@link ClientCertRequest#cancel} is + * called and does not call {@code onReceivedClientCertRequest()} again for the same host and + * port pair. Webview does not store the response if {@link ClientCertRequest#ignore} * is called. Note that, multiple layers in chromium network stack might be * caching the responses, so the behavior for ignore is only a best case * effort. diff --git a/core/java/com/android/internal/view/TooltipPopup.java b/core/java/com/android/internal/view/TooltipPopup.java index d38ea2c19af4..24f0b0cc91c5 100644 --- a/core/java/com/android/internal/view/TooltipPopup.java +++ b/core/java/com/android/internal/view/TooltipPopup.java @@ -142,7 +142,7 @@ public class TooltipPopup { 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 @@ public class TooltipPopup { 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 d7300c4947d9..601bd989ce42 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 nFinish(jlong nativePtr) { 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 @@ static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks, 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 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr, 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 000000000000..77f4c9d14f07 --- /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/res/res/values/config.xml b/core/res/res/values/config.xml index 171f74f9ead8..5f756fabdb78 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3169,6 +3169,10 @@ classes are instantiated in the order of the array. --> <string-array translatable="false" name="config_deviceSpecificSystemServices"></string-array> + <!-- Class name of the device specific implementation to replace the DevicePolicyManagerService + or empty if the default should be used. --> + <string translatable="false" name="config_deviceSpecificDevicePolicyManagerService"></string> + <!-- Component name of media projection permission dialog --> <string name="config_mediaProjectionPermissionDialogComponent" translateable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index a1158162ee73..ad947b7caad3 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -459,6 +459,7 @@ <java-symbol type="bool" name="config_hasPermanentDpad" /> <java-symbol type="bool" name="config_useDefaultFocusHighlight" /> <java-symbol type="array" name="config_deviceSpecificSystemServices" /> + <java-symbol type="string" name="config_deviceSpecificDevicePolicyManagerService" /> <java-symbol type="color" name="tab_indicator_text_v4" /> diff --git a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java index 5f6f62a67b05..978ea7aa9c00 100644 --- a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java +++ b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java @@ -45,8 +45,9 @@ import java.util.concurrent.TimeUnit; @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 @@ abstract class AbstractCrossUserContentResolverTest { 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 @@ abstract class AbstractCrossUserContentResolverTest { 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 41686fa135e0..9092c852db47 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 @@ public class TextClassificationManagerTest { 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 @@ public class TextClassificationManagerTest { .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 @@ public class TextClassificationManagerTest { 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 @@ public class TextClassificationManagerTest { 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 @@ public class TextClassificationManagerTest { 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 @@ public class TextClassificationManagerTest { 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 @@ public class TextClassificationManagerTest { 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 @@ public class TextClassificationManagerTest { 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 @@ public class TextClassificationManagerTest { } @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 @@ public class TextClassificationManagerTest { 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 682a0021b274..4b197e485ef9 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 @@ public class BstatsCpuTimesValidationTest { @Test public void testCpuFreqTimes() throws Exception { - assumeTrue(sCpuFreqTimesAvailable); + if (!sCpuFreqTimesAvailable) { + return; + } batteryOnScreenOn(); forceStop(); @@ -126,7 +128,9 @@ public class BstatsCpuTimesValidationTest { @Test public void testCpuFreqTimes_screenOff() throws Exception { - assumeTrue(sCpuFreqTimesAvailable); + if (!sCpuFreqTimesAvailable) { + return; + } batteryOnScreenOff(); forceStop(); @@ -154,7 +158,9 @@ public class BstatsCpuTimesValidationTest { @Test public void testCpuFreqTimes_isolatedProcess() throws Exception { - assumeTrue(sCpuFreqTimesAvailable); + if (!sCpuFreqTimesAvailable) { + return; + } batteryOnScreenOn(); forceStop(); diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 5c577aecca28..96e4fcf37fa3 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -417,3 +417,15 @@ cc_benchmark { "tests/microbench/TaskManagerBench.cpp", ], } + +// ---------------------------------------- +// Phony target to build benchmarks for PGO +// ---------------------------------------- + +phony { + name: "pgo-targets-hwui", + required: [ + "hwuimicro", + "hwuimacro", + ] +} diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 508869a0cbdd..eb0d161d71d1 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -738,6 +738,7 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& p // care of all alignment. SkPaint paintCopy(paint); paintCopy.setTextAlign(SkPaint::kLeft_Align); + SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); SkRect bounds = SkRect::MakeLTRB(boundsLeft + x, boundsTop + y, boundsRight + x, boundsBottom + y); diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp index 58c99800875b..6bae80c120ab 100644 --- a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp +++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp @@ -36,6 +36,7 @@ class ListOfFadedTextAnimation : public TestListViewSceneBase { SkPaint textPaint; textPaint.setTextSize(dp(20)); textPaint.setAntiAlias(true); + textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); TestUtils::drawUtf8ToCanvas(&canvas, "not that long long text", textPaint, dp(10), dp(30)); SkPoint pts[2]; diff --git a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp index 75b231dd1052..fee0659fa81d 100644 --- a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp +++ b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp @@ -42,8 +42,10 @@ public: mBluePaint.setColor(SkColorSetARGB(255, 0, 0, 255)); mBluePaint.setTextSize(padding); + mBluePaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); mGreenPaint.setColor(SkColorSetARGB(255, 0, 255, 0)); mGreenPaint.setTextSize(padding); + mGreenPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); // interleave drawText and drawRect with saveLayer ops for (int i = 0; i < regions; i++, top += smallRectHeight) { diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 7afe267f9c15..e0289f0bf336 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -741,7 +741,7 @@ public final class AudioAttributes implements Parcelable { /** * @hide * Same as {@link #setCapturePreset(int)} but authorizes the use of HOTWORD, - * REMOTE_SUBMIX and RADIO_TUNER. + * REMOTE_SUBMIX, RADIO_TUNER, VOICE_DOWNLINK, VOICE_UPLINK and VOICE_CALL. * @param preset * @return the same Builder instance. */ @@ -749,7 +749,10 @@ public final class AudioAttributes implements Parcelable { public Builder setInternalCapturePreset(int preset) { if ((preset == MediaRecorder.AudioSource.HOTWORD) || (preset == MediaRecorder.AudioSource.REMOTE_SUBMIX) - || (preset == MediaRecorder.AudioSource.RADIO_TUNER)) { + || (preset == MediaRecorder.AudioSource.RADIO_TUNER) + || (preset == MediaRecorder.AudioSource.VOICE_DOWNLINK) + || (preset == MediaRecorder.AudioSource.VOICE_UPLINK) + || (preset == MediaRecorder.AudioSource.VOICE_CALL)) { mSource = preset; } else { setCapturePreset(preset); diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java index c78c99f7a228..1019580589ab 100644 --- a/media/java/android/media/ImageReader.java +++ b/media/java/android/media/ImageReader.java @@ -640,7 +640,6 @@ public class ImageReader implements AutoCloseable { * 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 334f4e215d96..37f1e13f7827 100644 --- a/media/mca/filterfw/Android.mk +++ b/media/mca/filterfw/Android.mk @@ -26,6 +26,8 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk 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 af2c83f7d8b3..a017f4167907 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/res/drawable/ic_account_circle.xml b/packages/SystemUI/res/drawable/ic_account_circle.xml new file mode 100644 index 000000000000..3c5f01ba85e1 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_account_circle.xml @@ -0,0 +1,24 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48.0dp" + android:height="48.0dp" + android:viewportWidth="48.0" + android:viewportHeight="48.0"> + <path + android:pathData="M24,0C10.8,0 0,10.8 0,24s10.8,24 24,24s24,-10.8 24,-24S37.200001,0 24,0zM24,7.2c3.96,0 7.2,3.24 7.2,7.2s-3.24,7.2 -7.2,7.2s-7.2,-3.24 -7.2,-7.2S20.040001,7.2 24,7.2zM24,41.279999c-6,0 -11.28,-3.12 -14.4,-7.68c0.12,-4.8 9.6,-7.44 14.4,-7.44s14.28,2.64 14.4,7.44C35.279999,38.16 30,41.279999 24,41.279999z" + android:fillColor="?attr/wallpaperTextColor"/> +</vector> diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 9400fd8a4db5..663f20678299 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 android.view.View.MeasureSpec; 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.AppTransitionAnimationSpecsFutur 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 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // 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 f5c77f267952..64c52ed6d29f 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 @@ class CarNavigationBarController { 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/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java index 5c9446ce8672..34486dbcaf43 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java @@ -250,7 +250,7 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange } break; case STATE_FACE_UNLOCK: - iconRes = com.android.internal.R.drawable.ic_account_circle; + iconRes = R.drawable.ic_account_circle; break; case STATE_FINGERPRINT: // If screen is off and device asleep, use the draw on animation so the first frame diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 32af29d24aa2..bd6af01f841d 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5013,6 +5013,11 @@ message MetricsEvent { // 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 ced8621d7beb..bdfd82f440a6 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 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai 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 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai 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 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai 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 27eb98586e7f..2fc5dda6364e 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 @@ class ActivityStarter { 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 fb6278a43950..20ec9b5efa98 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 @@ public class PackageManagerServiceUtils { 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 @@ public class PackageManagerServiceUtils { // 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 b4300a930cdf..d118c4e58a20 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 6bf725e1a09f..6fb345bcbba8 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 @@ package com.android.server.power; 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.Context; 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.Trace; 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 @@ public final class ShutdownThread extends Thread { 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 @@ public final class ShutdownThread extends Thread { 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 @@ public final class ShutdownThread extends Thread { 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 3772371098d1..00c208d08883 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -15,6 +15,7 @@ */ package com.android.server.stats; +import android.annotation.Nullable; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -25,16 +26,22 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.net.NetworkStats; +import android.net.wifi.IWifiManager; +import android.net.wifi.WifiActivityEnergyInfo; +import android.telephony.ModemActivityInfo; +import android.telephony.TelephonyManager; import android.os.BatteryStatsInternal; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.IStatsCompanionService; import android.os.IStatsManager; +import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.StatsLogEventWrapper; +import android.os.SynchronousResultReceiver; import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; @@ -52,6 +59,7 @@ import com.android.server.SystemService; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeoutException; /** * Helper service for statsd (the native stats management service in cmds/statsd/). @@ -60,6 +68,13 @@ import java.util.Map; * @hide */ public class StatsCompanionService extends IStatsCompanionService.Stub { + /** + * How long to wait on an individual subsystem to return its stats. + */ + private static final long EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS = 2000; + + public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity"; + static final String TAG = "StatsCompanionService"; static final boolean DEBUG = true; public static final String ACTION_TRIGGER_COLLECTION = @@ -79,6 +94,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader(); private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats(); private final KernelCpuSpeedReader[] mKernelCpuSpeedReaders; + private IWifiManager mWifiManager = null; + private TelephonyManager mTelephony = null; public StatsCompanionService(Context context) { super(); @@ -389,6 +406,40 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { return ret; } + /** + * Helper method to extract the Parcelable controller info from a + * SynchronousResultReceiver. + */ + private static <T extends Parcelable> T awaitControllerInfo( + @Nullable SynchronousResultReceiver receiver) { + if (receiver == null) { + return null; + } + + try { + final SynchronousResultReceiver.Result result = + receiver.awaitResult(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS); + if (result.bundle != null) { + // This is the final destination for the Bundle. + result.bundle.setDefusable(true); + + final T data = result.bundle.getParcelable( + RESULT_RECEIVER_CONTROLLER_KEY); + if (data != null) { + return data; + } + } + Slog.e(TAG, "no controller energy info supplied for " + receiver.getName()); + } catch (TimeoutException e) { + Slog.w(TAG, "timeout reading " + receiver.getName() + " stats"); + } + return null; + } + + /** + * + * Pulls wifi controller activity energy info from WiFiManager + */ @Override // Binder call public StatsLogEventWrapper[] pullData(int tagId) { enforceCallingPermission(); @@ -509,6 +560,59 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } return ret.toArray(new StatsLogEventWrapper[ret.size()]); } + case StatsLog.WIFI_ACTIVITY_ENERGY_INFO_PULLED: { + List<StatsLogEventWrapper> ret = new ArrayList(); + long token = Binder.clearCallingIdentity(); + if (mWifiManager == null) { + mWifiManager = IWifiManager.Stub.asInterface(ServiceManager.getService( + Context.WIFI_SERVICE)); + } + if (mWifiManager != null) { + try { + SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi"); + mWifiManager.requestActivityInfo(wifiReceiver); + final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver); + StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6); + e.writeLong(wifiInfo.getTimeStamp()); + e.writeInt(wifiInfo.getStackState()); + e.writeLong(wifiInfo.getControllerTxTimeMillis()); + e.writeLong(wifiInfo.getControllerRxTimeMillis()); + e.writeLong(wifiInfo.getControllerIdleTimeMillis()); + e.writeLong(wifiInfo.getControllerEnergyUsed()); + ret.add(e); + } catch (RemoteException e) { + Slog.e(TAG, "Pulling wifiManager for wifi controller activity energy info has error", e); + } finally { + Binder.restoreCallingIdentity(token); + } + } + break; + } + case StatsLog.MODEM_ACTIVITY_INFO_PULLED: { + List<StatsLogEventWrapper> ret = new ArrayList(); + long token = Binder.clearCallingIdentity(); + if (mTelephony == null) { + mTelephony = TelephonyManager.from(mContext); + } + if (mTelephony != null) { + SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony"); + mTelephony.requestModemActivityInfo(modemReceiver); + final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver); + StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6); + e.writeLong(modemInfo.getTimestamp()); + e.writeLong(modemInfo.getSleepTimeMillis()); + e.writeLong(modemInfo.getIdleTimeMillis()); + e.writeLong(modemInfo.getTxTimeMillis()[0]); + e.writeLong(modemInfo.getTxTimeMillis()[1]); + e.writeLong(modemInfo.getTxTimeMillis()[2]); + e.writeLong(modemInfo.getTxTimeMillis()[3]); + e.writeLong(modemInfo.getTxTimeMillis()[4]); + e.writeLong(modemInfo.getRxTimeMillis()); + e.writeLong(modemInfo.getEnergyUsed()); + ret.add(e); + } + break; + } default: Slog.w(TAG, "No such tagId data as " + tagId); return null; @@ -523,6 +627,18 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { 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 c2a4be55e30a..e7547bf04c08 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 class StackWindowController } } - 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/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java new file mode 100644 index 000000000000..dddff8f3ea06 --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.devicepolicy; + +import android.app.admin.IDevicePolicyManager; + +import com.android.internal.R; +import com.android.server.SystemService; + +/** + * Defines the required interface for IDevicePolicyManager implemenation. + * + * <p>The interface consists of public parts determined by {@link IDevicePolicyManager} and also + * several package private methods required by internal infrastructure. + * + * <p>Whenever adding an AIDL method to {@link IDevicePolicyManager}, an empty override method + * should be added here to avoid build breakage in downstream branches. + */ +abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { + /** + * To be called by {@link DevicePolicyManagerService#Lifecycle} during the various boot phases. + * + * @see {@link SystemService#onBootPhase}. + */ + abstract void systemReady(int phase); + /** + * To be called by {@link DevicePolicyManagerService#Lifecycle} when a new user starts. + * + * @see {@link SystemService#onStartUser} + */ + abstract void handleStartUser(int userId); + /** + * To be called by {@link DevicePolicyManagerService#Lifecycle} when a user is being unlocked. + * + * @see {@link SystemService#onUnlockUser} + */ + abstract void handleUnlockUser(int userId); + /** + * To be called by {@link DevicePolicyManagerService#Lifecycle} when a user is being stopped. + * + * @see {@link SystemService#onStopUser} + */ + abstract void handleStopUser(int userId); +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 60c36d1b7203..223778f80b7c 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -198,6 +198,8 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; +import java.lang.IllegalStateException; +import java.lang.reflect.Constructor; import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.util.ArrayList; @@ -214,7 +216,7 @@ import java.util.concurrent.atomic.AtomicBoolean; /** * Implementation of the device policy APIs. */ -public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { +public class DevicePolicyManagerService extends BaseIDevicePolicyManager { protected static final String LOG_TAG = "DevicePolicyManager"; @@ -451,11 +453,24 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { }; public static final class Lifecycle extends SystemService { - private DevicePolicyManagerService mService; + private BaseIDevicePolicyManager mService; public Lifecycle(Context context) { super(context); - mService = new DevicePolicyManagerService(context); + String dpmsClassName = context.getResources() + .getString(R.string.config_deviceSpecificDevicePolicyManagerService); + if (TextUtils.isEmpty(dpmsClassName)) { + dpmsClassName = DevicePolicyManagerService.class.getName(); + } + try { + Class serviceClass = Class.forName(dpmsClassName); + Constructor constructor = serviceClass.getConstructor(Context.class); + mService = (BaseIDevicePolicyManager) constructor.newInstance(context); + } catch (Exception e) { + throw new IllegalStateException( + "Failed to instantiate DevicePolicyManagerService with class name: " + + dpmsClassName, e); + } } @Override @@ -1551,6 +1566,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mContext = context; } + public boolean hasFeature() { + return getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN); + } + Context createContextAsUser(UserHandle user) throws PackageManager.NameNotFoundException { final String packageName = mContext.getPackageName(); return mContext.createPackageContextAsUser(packageName, 0, user); @@ -1848,8 +1867,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // TODO: why does SecurityLogMonitor need to be created even when mHasFeature == false? mSecurityLogMonitor = new SecurityLogMonitor(this); - mHasFeature = mInjector.getPackageManager() - .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN); + mHasFeature = mInjector.hasFeature(); mIsWatch = mInjector.getPackageManager() .hasSystemFeature(PackageManager.FEATURE_WATCH); mBackgroundHandler = BackgroundThread.getHandler(); @@ -3033,6 +3051,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @VisibleForTesting + @Override void systemReady(int phase) { if (!mHasFeature) { return; @@ -3099,6 +3118,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + @Override void handleStartUser(int userId) { updateScreenCaptureDisabledInWindowManager(userId, getScreenCaptureDisabled(null, userId)); @@ -3107,10 +3127,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { startOwnerService(userId, "start-user"); } + @Override void handleUnlockUser(int userId) { startOwnerService(userId, "unlock-user"); } + @Override void handleStopUser(int userId) { stopOwnerService(userId, "stop-user"); } diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index f093d57bcf48..fbcccf0fec2a 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 com.google.common.util.concurrent.AbstractFuture; 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 @@ import java.util.stream.Collectors; "com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner" * </code></pre> */ +@Ignore @RunWith(AndroidJUnit4.class) @MediumTest public class NetworkPolicyManagerServiceTest { diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index 062858d4d237..ca4a210e30cc 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -188,6 +188,11 @@ public abstract class ImsFeature { } /** + * Called when the feature is ready to use. + */ + public abstract void onFeatureReady(); + + /** * Called when the feature is being removed and must be cleaned up. */ public abstract void onFeatureRemoved(); diff --git a/telephony/java/android/telephony/ims/feature/MMTelFeature.java b/telephony/java/android/telephony/ims/feature/MMTelFeature.java index e790d1460ee0..4e095e3a7003 100644 --- a/telephony/java/android/telephony/ims/feature/MMTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MMTelFeature.java @@ -346,6 +346,11 @@ public class MMTelFeature extends ImsFeature { return null; } + @Override + public void onFeatureReady() { + + } + /** * {@inheritDoc} */ diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java index a82e60860972..40c5181d6bca 100644 --- a/telephony/java/android/telephony/ims/feature/RcsFeature.java +++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java @@ -36,6 +36,11 @@ public class RcsFeature extends ImsFeature { } @Override + public void onFeatureReady() { + + } + + @Override public void onFeatureRemoved() { } diff --git a/telephony/java/android/telephony/ims/feature/SmsFeature.java b/telephony/java/android/telephony/ims/feature/SmsFeature.java new file mode 100644 index 000000000000..c1366db4a8d6 --- /dev/null +++ b/telephony/java/android/telephony/ims/feature/SmsFeature.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.telephony.ims.feature; + +import android.annotation.SystemApi; +import android.os.RemoteException; +import com.android.ims.internal.IImsSmsFeature; +import com.android.ims.internal.ISmsListener; + +/** + * Base implementation of SMS over IMS functionality. + * + * @hide + */ +public class SmsFeature extends ImsFeature { + /** + * SMS over IMS format is 3gpp. + */ + public static final int IMS_SMS_FORMAT_3GPP = 1; + + /** + * SMS over IMS format is 3gpp2. + */ + public static final int IMS_SMS_FORMAT_3GPP2 = 2; + + /** + * Message was sent successfully. + */ + public static final int SEND_STATUS_OK = 1; + + /** + * IMS provider failed to send the message and platform should not retry falling back to sending + * the message using the radio. + */ + public static final int SEND_STATUS_ERROR = 2; + + /** + * IMS provider failed to send the message and platform should retry again after setting TP-RD bit + * to high. + */ + public static final int SEND_STATUS_ERROR_RETRY = 3; + + /** + * IMS provider failed to send the message and platform should retry falling back to sending + * the message using the radio. + */ + public static final int SEND_STATUS_ERROR_FALLBACK = 4; + + /** + * Message was delivered successfully. + */ + public static final int DELIVER_STATUS_OK = 1; + + /** + * Message was not delivered. + */ + public static final int DELIVER_STATUS_ERROR = 2; + + // Lock for feature synchronization + private final Object mLock = new Object(); + private ISmsListener mSmsListener; + + private final IImsSmsFeature mIImsSmsBinder = new IImsSmsFeature.Stub() { + @Override + public void registerSmsListener(ISmsListener listener) { + synchronized (mLock) { + SmsFeature.this.registerSmsListener(listener); + } + } + + @Override + public void sendSms(int format, int messageRef, boolean retry, byte[] pdu) { + synchronized (mLock) { + SmsFeature.this.sendSms(format, messageRef, retry, pdu); + } + } + + @Override + public void acknowledgeSms(int messageRef, int result) { + synchronized (mLock) { + SmsFeature.this.acknowledgeSms(messageRef, result); + } + } + + @Override + public int getSmsFormat() { + synchronized (mLock) { + return SmsFeature.this.getSmsFormat(); + } + } + }; + + /** + * Registers a listener responsible for handling tasks like delivering messages. + + * @param listener listener to register. + * + * @hide + */ + @SystemApi + public final void registerSmsListener(ISmsListener listener) { + synchronized (mLock) { + mSmsListener = listener; + } + } + + /** + * This method will be triggered by the platform when the user attempts to send an SMS. This + * method should be implemented by the IMS providers to provide implementation of sending an SMS + * over IMS. + * + * @param format the format of the message. One of {@link #IMS_SMS_FORMAT_3GPP} or + * {@link #IMS_SMS_FORMAT_3GPP2} + * @param messageRef the message reference. + * @param retry whether it is a retry of an already attempted message or not. + * @param pdu PDUs representing the contents of the message. + */ + public void sendSms(int format, int messageRef, boolean isRetry, byte[] pdu) { + } + + /** + * This method will be triggered by the platform after {@link #deliverSms(int, byte[])} has been + * called to deliver the result to the IMS provider. It will also be triggered after + * {@link #setSentSmsResult(int, int)} has been called to provide the result of the operation. + * + * @param result Should be {@link #DELIVER_STATUS_OK} if the message was delivered successfully, + * {@link #DELIVER_STATUS_ERROR} otherwise. + * @param messageRef the message reference. + */ + public void acknowledgeSms(int messageRef, int result) { + + } + + /** + * This method should be triggered by the IMS providers when there is an incoming message. The + * platform will deliver the message to the messages database and notify the IMS provider of the + * result by calling {@link #acknowledgeSms(int)}. + * + * This method must not be called before {@link #onFeatureReady()} is called. + * + * @param format the format of the message.One of {@link #IMS_SMS_FORMAT_3GPP} or + * {@link #IMS_SMS_FORMAT_3GPP2} + * @param pdu PDUs representing the contents of the message. + * @throws IllegalStateException if called before {@link #onFeatureReady()} + */ + public final void deliverSms(int format, byte[] pdu) throws IllegalStateException { + // TODO: Guard against NPE/ Check if feature is ready and thrown an exception + // otherwise. + try { + mSmsListener.deliverSms(format, pdu); + } catch (RemoteException e) { + } + } + + /** + * This method should be triggered by the IMS providers to pass the result of the sent message + * to the platform. + * + * This method must not be called before {@link #onFeatureReady()} is called. + * + * @param messageRef the message reference. + * @param result One of {@link #SEND_STATUS_OK}, {@link #SEND_STATUS_ERROR}, + * {@link #SEND_STATUS_ERROR_RETRY}, {@link #SEND_STATUS_ERROR_FALLBACK} + * @throws IllegalStateException if called before {@link #onFeatureReady()} + */ + public final void setSentSmsResult(int messageRef, int result) throws IllegalStateException { + // TODO: Guard against NPE/ Check if feature is ready and thrown an exception + // otherwise. + try { + mSmsListener.setSentSmsResult(messageRef, result); + } catch (RemoteException e) { + } + } + + /** + * Sets the status report of the sent message. + * + * @param format Should be {@link #IMS_SMS_FORMAT_3GPP} or {@link #IMS_SMS_FORMAT_3GPP2} + * @param pdu PDUs representing the content of the status report. + * @throws IllegalStateException if called before {@link #onFeatureReady()} + */ + public final void setSentSmsStatusReport(int format, byte[] pdu) { + // TODO: Guard against NPE/ Check if feature is ready and thrown an exception + // otherwise. + try { + mSmsListener.setSentSmsStatusReport(format, pdu); + } catch (RemoteException e) { + } + } + + /** + * Returns the SMS format. Default is {@link #IMS_SMS_FORMAT_3GPP} unless overridden by IMS + * Provider. + * + * @return sms format. + */ + public int getSmsFormat() { + return IMS_SMS_FORMAT_3GPP; + } + + /** + * {@inheritDoc} + */ + public void onFeatureReady() { + + } + + /** + * {@inheritDoc} + */ + @Override + public void onFeatureRemoved() { + + } + + /** + * @hide + */ + @Override + public final IImsSmsFeature getBinder() { + return mIImsSmsBinder; + } +}
\ No newline at end of file diff --git a/telephony/java/com/android/ims/internal/IImsSmsFeature.aidl b/telephony/java/com/android/ims/internal/IImsSmsFeature.aidl new file mode 100644 index 000000000000..506812882ef5 --- /dev/null +++ b/telephony/java/com/android/ims/internal/IImsSmsFeature.aidl @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ims.internal; + +import com.android.ims.internal.ISmsListener; + +/** + * See SmsFeature for more information. + * + * {@hide} + */ +interface IImsSmsFeature { + void registerSmsListener(in ISmsListener listener); + void sendSms(in int format, in int messageRef, in boolean retry, in byte[] pdu); + void acknowledgeSms(in int messageRef, in int result); + int getSmsFormat(); +}
\ No newline at end of file diff --git a/telephony/java/com/android/ims/internal/ISmsListener.aidl b/telephony/java/com/android/ims/internal/ISmsListener.aidl new file mode 100644 index 000000000000..1266f040885a --- /dev/null +++ b/telephony/java/com/android/ims/internal/ISmsListener.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ims.internal; + +/** + * See SmsFeature for more information. + * {@hide} + */ +interface ISmsListener { + void setSentSmsResult(in int messageRef, in int result); + void setSentSmsStatusReport(in int format, in byte[] pdu); + void deliverSms(in int format, in byte[] pdu); +}
\ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java index 5f2e561b687f..d27a75815980 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 @@ package com.android.internal.telephony.cdma.sms; 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 @@ public class CdmaSmsAddress extends SmsAddress { * 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 class CdmaSmsAddress extends SmsAddress { 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/test-base/Android.mk b/test-base/Android.mk index 9fc70f397263..6a1ac9eac3c9 100644 --- a/test-base/Android.mk +++ b/test-base/Android.mk @@ -46,20 +46,6 @@ LOCAL_JAVA_LIBRARIES := core-oj core-libart framework include $(BUILD_JAVA_LIBRARY) -# Build the repackaged-legacy-test library -# ======================================== -# This contains repackaged versions of the classes from legacy-test. -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_MODULE := repackaged-legacy-test -LOCAL_NO_STANDARD_LIBRARIES := true -LOCAL_JAVA_LIBRARIES := core-oj core-libart framework -LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt - -include $(BUILD_STATIC_JAVA_LIBRARY) - # Build the repackaged.android.test.base library # ============================================== # This contains repackaged versions of the classes from legacy-test. diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index de4fb736758c..eaaefd5e099a 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -346,30 +346,15 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, 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 @@ static bool RenameManifestPackage(const StringPiece& package_override, xml::Elem 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 da7f410b8b08..40085eab9707 100644 --- a/tools/aapt2/link/ManifestFixer_test.cpp +++ b/tools/aapt2/link/ManifestFixer_test.cpp @@ -240,6 +240,7 @@ TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) { 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 @@ TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) { 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); + + xml::Element* application_el = manifest_el->FindChild({}, "application"); + ASSERT_NE(nullptr, application_el); - attr = applicationEl->FindAttribute(xml::kSchemaAndroid, "name"); + 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"); |