diff options
69 files changed, 1461 insertions, 506 deletions
diff --git a/api/current.txt b/api/current.txt index 87aaaa671da3..8db72b951502 100755 --- a/api/current.txt +++ b/api/current.txt @@ -7,6 +7,7 @@ package android { public static final class Manifest.permission { ctor public Manifest.permission(); field public static final java.lang.String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER"; + field public static final java.lang.String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION"; field public static final java.lang.String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES"; field public static final java.lang.String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION"; field public static final java.lang.String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION"; diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index d3496ed9798b..e090ed14320c 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -99,6 +99,7 @@ statsd_common_shared_libraries := \ libhidlbase \ libhidltransport \ libhwbinder \ + android.frameworks.stats@1.0 \ android.hardware.health@2.0 \ android.hardware.power@1.0 \ android.hardware.power@1.1 \ diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 2ef1169851ff..8da2d447a163 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -992,6 +992,60 @@ Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) { return Status::ok(); } +hardware::Return<void> StatsService::reportSpeakerImpedance( + const SpeakerImpedance& speakerImpedance) { + LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), speakerImpedance); + mProcessor->OnLogEvent(&event); + + return hardware::Void(); +} + +hardware::Return<void> StatsService::reportHardwareFailed(const HardwareFailed& hardwareFailed) { + LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), hardwareFailed); + mProcessor->OnLogEvent(&event); + + return hardware::Void(); +} + +hardware::Return<void> StatsService::reportPhysicalDropDetected( + const PhysicalDropDetected& physicalDropDetected) { + LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), physicalDropDetected); + mProcessor->OnLogEvent(&event); + + return hardware::Void(); +} + +hardware::Return<void> StatsService::reportChargeCycles(const ChargeCycles& chargeCycles) { + LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), chargeCycles); + mProcessor->OnLogEvent(&event); + + return hardware::Void(); +} + +hardware::Return<void> StatsService::reportBatteryHealthSnapshot( + const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) { + LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), + batteryHealthSnapshotArgs); + mProcessor->OnLogEvent(&event); + + return hardware::Void(); +} + +hardware::Return<void> StatsService::reportSlowIo(const SlowIo& slowIo) { + LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), slowIo); + mProcessor->OnLogEvent(&event); + + return hardware::Void(); +} + +hardware::Return<void> StatsService::reportBatteryCausedShutdown( + const BatteryCausedShutdown& batteryCausedShutdown) { + LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), batteryCausedShutdown); + mProcessor->OnLogEvent(&event); + + return hardware::Void(); +} + void StatsService::binderDied(const wp <IBinder>& who) { ALOGW("statscompanion service died"); StatsdStats::getInstance().noteSystemServerRestart(getWallClockSec()); diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 06189278abce..1f1d782af235 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -27,6 +27,8 @@ #include "shell/ShellSubscriber.h" #include "statscompanion_util.h" +#include <android/frameworks/stats/1.0/IStats.h> +#include <android/frameworks/stats/1.0/types.h> #include <android/os/BnStatsManager.h> #include <android/os/IStatsCompanionService.h> #include <binder/IResultReceiver.h> @@ -38,6 +40,7 @@ using namespace android; using namespace android::base; using namespace android::binder; +using namespace android::frameworks::stats::V1_0; using namespace android::os; using namespace std; @@ -45,7 +48,12 @@ namespace android { namespace os { namespace statsd { -class StatsService : public BnStatsManager, public LogListener, public IBinder::DeathRecipient { +using android::hardware::Return; + +class StatsService : public BnStatsManager, + public LogListener, + public IStats, + public IBinder::DeathRecipient { public: StatsService(const sp<Looper>& handlerLooper); virtual ~StatsService(); @@ -146,6 +154,44 @@ public: */ virtual Status sendAppBreadcrumbAtom(int32_t label, int32_t state) override; + /** + * Binder call to get SpeakerImpedance atom. + */ + virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override; + + /** + * Binder call to get HardwareFailed atom. + */ + virtual Return<void> reportHardwareFailed(const HardwareFailed& hardwareFailed) override; + + /** + * Binder call to get PhysicalDropDetected atom. + */ + virtual Return<void> reportPhysicalDropDetected( + const PhysicalDropDetected& physicalDropDetected) override; + + /** + * Binder call to get ChargeCyclesReported atom. + */ + virtual Return<void> reportChargeCycles(const ChargeCycles& chargeCycles) override; + + /** + * Binder call to get BatteryHealthSnapshot atom. + */ + virtual Return<void> reportBatteryHealthSnapshot( + const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) override; + + /** + * Binder call to get SlowIo atom. + */ + virtual Return<void> reportSlowIo(const SlowIo& slowIo) override; + + /** + * Binder call to get BatteryCausedShutdown atom. + */ + virtual Return<void> reportBatteryCausedShutdown( + const BatteryCausedShutdown& batteryCausedShutdown) override; + /** IBinder::DeathRecipient */ virtual void binderDied(const wp<IBinder>& who) override; diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 85141caf194d..30d8bfce5d2a 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -138,6 +138,9 @@ message Atom { FingerprintAuthenticated fingerprint_authenticated = 88; FingerprintErrorOccurred fingerprint_error_occurred = 89; Notification notification = 90; + BatteryHealthSnapshot battery_health_snapshot = 91; + SlowIo slow_io = 92; + BatteryCausedShutdown battery_caused_shutdown = 93; } // Pulled events will start at field 10000. @@ -200,9 +203,10 @@ message AttributionNode { message KeyValuePair { optional int32 key = 1; oneof value { - int64 value_int = 2; - string value_str = 3; - float value_float = 4; + int32 value_int = 2; + int64 value_long = 3; + string value_str = 4; + float value_float = 5; } } @@ -1312,6 +1316,68 @@ message ChargeCyclesReported { } /** + * Log battery health snapshot. + * + * Resistance, Voltage, Open Circuit Voltage, Temperature, and Charge Level + * are snapshotted periodically over 24hrs. + */ +message BatteryHealthSnapshot { + enum BatterySnapshotType { + UNKNOWN = 0; + MIN_TEMP = 1; // Snapshot at min batt temp over 24hrs. + MAX_TEMP = 2; // Snapshot at max batt temp over 24hrs. + MIN_RESISTANCE = 3; // Snapshot at min batt resistance over 24hrs. + MAX_RESISTANCE = 4; // Snapshot at max batt resistance over 24hrs. + MIN_VOLTAGE = 5; // Snapshot at min batt voltage over 24hrs. + MAX_VOLTAGE = 6; // Snapshot at max batt voltage over 24hrs. + MIN_CURRENT = 7; // Snapshot at min batt current over 24hrs. + MAX_CURRENT = 8; // Snapshot at max batt current over 24hrs. + MIN_BATT_LEVEL = 9; // Snapshot at min battery level (SoC) over 24hrs. + MAX_BATT_LEVEL = 10; // Snapshot at max battery level (SoC) over 24hrs. + AVG_RESISTANCE = 11; // Snapshot at average battery resistance over 24hrs. + } + optional BatterySnapshotType type = 1; + // Temperature, in 1/10ths of degree C. + optional int32 temperature_deci_celcius = 2; + // Voltage Battery Voltage, in microVolts. + optional int32 voltage_micro_volt = 3; + // Current Battery current, in microAmps. + optional int32 current_micro_amps = 4; + // OpenCircuitVoltage Battery Open Circuit Voltage, in microVolts. + optional int32 open_circuit_micro_volt = 5; + // Resistance Battery Resistance, in microOhms. + optional int32 resistance_micro_ohm = 6; + // Level Battery Level, as % of full. + optional int32 level_percent = 7; +} + +/** + * Log slow I/O operations on the primary storage. + */ +message SlowIo { + // Classifications of IO Operations. + enum IoOperation { + UNKNOWN = 0; + READ = 1; + WRITE = 2; + UNMAP = 3; + SYNC = 4; + } + optional IoOperation operation = 1; + + // The number of slow IO operations of this type over 24 hours. + optional int32 count = 2; +} + +/** + * Log battery caused shutdown with the last recorded voltage. + */ +message BatteryCausedShutdown { + // The last recorded battery voltage prior to shutdown. + optional int32 last_recorded_micro_volt = 1; +} + +/** * Logs the duration of a davey (jank of >=700ms) when it occurs * * Logged from: diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index f9f1b387279a..4bbcfd593366 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -92,7 +92,8 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, int32_t uid, - const std::map<int32_t, int64_t>& int_map, + const std::map<int32_t, int32_t>& int_map, + const std::map<int32_t, int64_t>& long_map, const std::map<int32_t, std::string>& string_map, const std::map<int32_t, float>& float_map) { mLogdTimestampNs = wallClockTimestampNs; @@ -113,7 +114,7 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT pos[1]++; } - for (const auto&itr : string_map) { + for (const auto&itr : long_map) { pos[2] = 1; mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first))); pos[2] = 3; @@ -122,7 +123,7 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT pos[1]++; } - for (const auto&itr : float_map) { + for (const auto&itr : string_map) { pos[2] = 1; mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first))); pos[2] = 4; @@ -130,12 +131,142 @@ LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedT mValues.back().mField.decorateLastPos(2); pos[1]++; } + + for (const auto&itr : float_map) { + pos[2] = 1; + mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first))); + pos[2] = 5; + mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.second))); + mValues.back().mField.decorateLastPos(2); + pos[1]++; + } if (!mValues.empty()) { mValues.back().mField.decorateLastPos(1); mValues.at(mValues.size() - 2).mField.decorateLastPos(1); } } +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, + const SpeakerImpedance& speakerImpedance) { + mLogdTimestampNs = wallClockTimestampNs; + mElapsedTimestampNs = elapsedTimestampNs; + mTagId = android::util::SPEAKER_IMPEDANCE_REPORTED; + + mValues.push_back( + FieldValue(Field(mTagId, getSimpleField(1)), Value(speakerImpedance.speakerLocation))); + mValues.push_back( + FieldValue(Field(mTagId, getSimpleField(2)), Value(speakerImpedance.milliOhms))); + if (!mValues.empty()) { + mValues.back().mField.decorateLastPos(1); + } +} + +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, + const HardwareFailed& hardwareFailed) { + mLogdTimestampNs = wallClockTimestampNs; + mElapsedTimestampNs = elapsedTimestampNs; + mTagId = android::util::HARDWARE_FAILED; + + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), + Value(int32_t(hardwareFailed.hardwareType)))); + mValues.push_back( + FieldValue(Field(mTagId, getSimpleField(2)), Value(hardwareFailed.hardwareLocation))); + mValues.push_back( + FieldValue(Field(mTagId, getSimpleField(3)), Value(int32_t(hardwareFailed.errorCode)))); + if (!mValues.empty()) { + mValues.back().mField.decorateLastPos(1); + } +} + +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, + const PhysicalDropDetected& physicalDropDetected) { + mLogdTimestampNs = wallClockTimestampNs; + mElapsedTimestampNs = elapsedTimestampNs; + mTagId = android::util::PHYSICAL_DROP_DETECTED; + + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), + Value(int32_t(physicalDropDetected.confidencePctg)))); + mValues.push_back( + FieldValue(Field(mTagId, getSimpleField(2)), Value(physicalDropDetected.accelPeak))); + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), + Value(physicalDropDetected.freefallDuration))); + if (!mValues.empty()) { + mValues.back().mField.decorateLastPos(1); + } +} + +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, + const ChargeCycles& chargeCycles) { + mLogdTimestampNs = wallClockTimestampNs; + mElapsedTimestampNs = elapsedTimestampNs; + mTagId = android::util::CHARGE_CYCLES_REPORTED; + + for (size_t i = 0; i < chargeCycles.cycleBucket.size(); i++) { + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 1)), + Value(chargeCycles.cycleBucket[i]))); + } + + if (!mValues.empty()) { + mValues.back().mField.decorateLastPos(1); + } +} + +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, + const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs) { + mLogdTimestampNs = wallClockTimestampNs; + mElapsedTimestampNs = elapsedTimestampNs; + mTagId = android::util::BATTERY_HEALTH_SNAPSHOT; + + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), + Value(int32_t(batteryHealthSnapshotArgs.type)))); + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), + Value(batteryHealthSnapshotArgs.temperatureDeciC))); + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), + Value(batteryHealthSnapshotArgs.voltageMicroV))); + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), + Value(batteryHealthSnapshotArgs.currentMicroA))); + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(5)), + Value(batteryHealthSnapshotArgs.openCircuitVoltageMicroV))); + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(6)), + Value(batteryHealthSnapshotArgs.resistanceMicroOhm))); + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(7)), + Value(batteryHealthSnapshotArgs.levelPercent))); + + if (!mValues.empty()) { + mValues.back().mField.decorateLastPos(1); + } +} + +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, const SlowIo& slowIo) { + mLogdTimestampNs = wallClockTimestampNs; + mElapsedTimestampNs = elapsedTimestampNs; + mTagId = android::util::SLOW_IO; + + int pos[] = {1}; + mValues.push_back( + FieldValue(Field(mTagId, getSimpleField(1)), Value(int32_t(slowIo.operation)))); + pos[0]++; + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(slowIo.count))); + + if (!mValues.empty()) { + mValues.back().mField.decorateLastPos(1); + } +} + +LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, + const BatteryCausedShutdown& batteryCausedShutdown) { + mLogdTimestampNs = wallClockTimestampNs; + mElapsedTimestampNs = elapsedTimestampNs; + mTagId = android::util::BATTERY_CAUSED_SHUTDOWN; + + mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), + Value(batteryCausedShutdown.voltageMicroV))); + + if (!mValues.empty()) { + mValues.back().mField.decorateLastPos(1); + } +} + LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) { mLogdTimestampNs = timestampNs; mTagId = tagId; @@ -213,9 +344,8 @@ bool LogEvent::write(float value) { return false; } - - -bool LogEvent::writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map, +bool LogEvent::writeKeyValuePairs(const std::map<int32_t, int32_t>& int_map, + const std::map<int32_t, int64_t>& long_map, const std::map<int32_t, std::string>& string_map, const std::map<int32_t, float>& float_map) { if (mContext) { @@ -233,6 +363,17 @@ bool LogEvent::writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map, } } + for (const auto& itr : long_map) { + if (android_log_write_list_begin(mContext) < 0) { + return false; + } + write(itr.first); + write(itr.second); + if (android_log_write_list_end(mContext) < 0) { + return false; + } + } + for (const auto& itr : string_map) { if (android_log_write_list_begin(mContext) < 0) { return false; diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h index 9ef0bf469c14..c7e2a8c5ca21 100644 --- a/cmds/statsd/src/logd/LogEvent.h +++ b/cmds/statsd/src/logd/LogEvent.h @@ -18,6 +18,7 @@ #include "FieldValue.h" +#include <android/frameworks/stats/1.0/types.h> #include <android/os/StatsLogEventWrapper.h> #include <android/util/ProtoOutputStream.h> #include <log/log_event_list.h> @@ -28,6 +29,8 @@ #include <string> #include <vector> +using namespace android::frameworks::stats::V1_0; + namespace android { namespace os { namespace statsd { @@ -77,10 +80,32 @@ public: */ explicit LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, int32_t uid, - const std::map<int32_t, int64_t>& int_map, + const std::map<int32_t, int32_t>& int_map, + const std::map<int32_t, int64_t>& long_map, const std::map<int32_t, std::string>& string_map, const std::map<int32_t, float>& float_map); + explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, + const SpeakerImpedance& speakerImpedance); + + explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, + const HardwareFailed& hardwareFailed); + + explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, + const PhysicalDropDetected& physicalDropDetected); + + explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, + const ChargeCycles& chargeCycles); + + explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, + const BatteryHealthSnapshotArgs& batteryHealthSnapshotArgs); + + explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, + const SlowIo& slowIo); + + explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, + const BatteryCausedShutdown& batteryCausedShutdown); + ~LogEvent(); /** @@ -122,7 +147,8 @@ public: bool write(float value); bool write(const std::vector<AttributionNodeInternal>& nodes); bool write(const AttributionNodeInternal& node); - bool writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map, + bool writeKeyValuePairs(const std::map<int32_t, int32_t>& int_map, + const std::map<int32_t, int64_t>& long_map, const std::map<int32_t, std::string>& string_map, const std::map<int32_t, float>& float_map); diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp index 9002f0773aaf..a5dac0836238 100644 --- a/cmds/statsd/src/main.cpp +++ b/cmds/statsd/src/main.cpp @@ -25,6 +25,7 @@ #include <binder/IServiceManager.h> #include <binder/ProcessState.h> #include <binder/Status.h> +#include <hidl/HidlTransportSupport.h> #include <utils/Looper.h> #include <utils/StrongPointer.h> @@ -56,12 +57,21 @@ int main(int /*argc*/, char** /*argv*/) { ps->giveThreadPoolName(); IPCThreadState::self()->disableBackgroundScheduling(true); + ::android::hardware::configureRpcThreadpool(1 /*threads*/, false /*willJoin*/); + // Create the service sp<StatsService> service = new StatsService(looper); if (defaultServiceManager()->addService(String16("stats"), service) != 0) { - ALOGE("Failed to add service"); + ALOGE("Failed to add service as AIDL service"); return -1; } + + auto ret = service->registerAsService(); + if (ret != ::android::OK) { + ALOGE("Failed to add service as HIDL service"); + return 1; // or handle error + } + service->sayHiToStatsCompanion(); service->Startup(); diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp index 6e3b04ce6b3b..d4907017dc6d 100644 --- a/cmds/statsd/tests/LogEvent_test.cpp +++ b/cmds/statsd/tests/LogEvent_test.cpp @@ -91,12 +91,16 @@ TEST(LogEventTest, TestLogParsing) { TEST(LogEventTest, TestKeyValuePairsAtomParsing) { LogEvent event1(83, 2000); - std::map<int32_t, int64_t> int_map; + std::map<int32_t, int32_t> int_map; + std::map<int32_t, int64_t> long_map; std::map<int32_t, std::string> string_map; std::map<int32_t, float> float_map; - int_map[11] = 123L; - int_map[22] = 345L; + int_map[11] = 123; + int_map[22] = 345; + + long_map[33] = 678L; + long_map[44] = 890L; string_map[1] = "test2"; string_map[2] = "test1"; @@ -104,12 +108,15 @@ TEST(LogEventTest, TestKeyValuePairsAtomParsing) { float_map[111] = 2.2f; float_map[222] = 1.1f; - EXPECT_TRUE(event1.writeKeyValuePairs(int_map, string_map, float_map)); + EXPECT_TRUE(event1.writeKeyValuePairs(int_map, + long_map, + string_map, + float_map)); event1.init(); EXPECT_EQ(83, event1.GetTagId()); const auto& items = event1.getValues(); - EXPECT_EQ((size_t)12, items.size()); + EXPECT_EQ((size_t)16, items.size()); const FieldValue& item0 = event1.getValues()[0]; EXPECT_EQ(0x2010101, item0.mField.getField()); @@ -118,8 +125,8 @@ TEST(LogEventTest, TestKeyValuePairsAtomParsing) { const FieldValue& item1 = event1.getValues()[1]; EXPECT_EQ(0x2010182, item1.mField.getField()); - EXPECT_EQ(Type::LONG, item1.mValue.getType()); - EXPECT_EQ(123L, item1.mValue.long_value); + EXPECT_EQ(Type::INT, item1.mValue.getType()); + EXPECT_EQ(123, item1.mValue.int_value); const FieldValue& item2 = event1.getValues()[2]; EXPECT_EQ(0x2010201, item2.mField.getField()); @@ -128,48 +135,68 @@ TEST(LogEventTest, TestKeyValuePairsAtomParsing) { const FieldValue& item3 = event1.getValues()[3]; EXPECT_EQ(0x2010282, item3.mField.getField()); - EXPECT_EQ(Type::LONG, item3.mValue.getType()); - EXPECT_EQ(345L, item3.mValue.long_value); + EXPECT_EQ(Type::INT, item3.mValue.getType()); + EXPECT_EQ(345, item3.mValue.int_value); const FieldValue& item4 = event1.getValues()[4]; EXPECT_EQ(0x2010301, item4.mField.getField()); EXPECT_EQ(Type::INT, item4.mValue.getType()); - EXPECT_EQ(1, item4.mValue.int_value); + EXPECT_EQ(33, item4.mValue.int_value); const FieldValue& item5 = event1.getValues()[5]; - EXPECT_EQ(0x2010383, item5.mField.getField()); - EXPECT_EQ(Type::STRING, item5.mValue.getType()); - EXPECT_EQ("test2", item5.mValue.str_value); + EXPECT_EQ(0x2010382, item5.mField.getField()); + EXPECT_EQ(Type::LONG, item5.mValue.getType()); + EXPECT_EQ(678L, item5.mValue.int_value); const FieldValue& item6 = event1.getValues()[6]; EXPECT_EQ(0x2010401, item6.mField.getField()); EXPECT_EQ(Type::INT, item6.mValue.getType()); - EXPECT_EQ(2, item6.mValue.int_value); + EXPECT_EQ(44, item6.mValue.int_value); const FieldValue& item7 = event1.getValues()[7]; - EXPECT_EQ(0x2010483, item7.mField.getField()); - EXPECT_EQ(Type::STRING, item7.mValue.getType()); - EXPECT_EQ("test1", item7.mValue.str_value); + EXPECT_EQ(0x2010482, item7.mField.getField()); + EXPECT_EQ(Type::LONG, item7.mValue.getType()); + EXPECT_EQ(890L, item7.mValue.int_value); const FieldValue& item8 = event1.getValues()[8]; EXPECT_EQ(0x2010501, item8.mField.getField()); EXPECT_EQ(Type::INT, item8.mValue.getType()); - EXPECT_EQ(111, item8.mValue.int_value); + EXPECT_EQ(1, item8.mValue.int_value); const FieldValue& item9 = event1.getValues()[9]; - EXPECT_EQ(0x2010584, item9.mField.getField()); - EXPECT_EQ(Type::FLOAT, item9.mValue.getType()); - EXPECT_EQ(2.2f, item9.mValue.float_value); + EXPECT_EQ(0x2010583, item9.mField.getField()); + EXPECT_EQ(Type::STRING, item9.mValue.getType()); + EXPECT_EQ("test2", item9.mValue.str_value); const FieldValue& item10 = event1.getValues()[10]; - EXPECT_EQ(0x2018601, item10.mField.getField()); + EXPECT_EQ(0x2010601, item10.mField.getField()); EXPECT_EQ(Type::INT, item10.mValue.getType()); - EXPECT_EQ(222, item10.mValue.int_value); + EXPECT_EQ(2, item10.mValue.int_value); const FieldValue& item11 = event1.getValues()[11]; - EXPECT_EQ(0x2018684, item11.mField.getField()); - EXPECT_EQ(Type::FLOAT, item11.mValue.getType()); - EXPECT_EQ(1.1f, item11.mValue.float_value); + EXPECT_EQ(0x2010683, item11.mField.getField()); + EXPECT_EQ(Type::STRING, item11.mValue.getType()); + EXPECT_EQ("test1", item11.mValue.str_value); + + const FieldValue& item12 = event1.getValues()[12]; + EXPECT_EQ(0x2010701, item12.mField.getField()); + EXPECT_EQ(Type::INT, item12.mValue.getType()); + EXPECT_EQ(111, item12.mValue.int_value); + + const FieldValue& item13 = event1.getValues()[13]; + EXPECT_EQ(0x2010784, item13.mField.getField()); + EXPECT_EQ(Type::FLOAT, item13.mValue.getType()); + EXPECT_EQ(2.2f, item13.mValue.float_value); + + const FieldValue& item14 = event1.getValues()[14]; + EXPECT_EQ(0x2018801, item14.mField.getField()); + EXPECT_EQ(Type::INT, item14.mValue.getType()); + EXPECT_EQ(222, item14.mValue.int_value); + + const FieldValue& item15 = event1.getValues()[15]; + EXPECT_EQ(0x2018884, item15.mField.getField()); + EXPECT_EQ(Type::FLOAT, item15.mValue.getType()); + EXPECT_EQ(1.1f, item15.mValue.float_value); } TEST(LogEventTest, TestLogParsing2) { @@ -242,12 +269,16 @@ TEST(LogEventTest, TestLogParsing2) { } TEST(LogEventTest, TestKeyValuePairsEvent) { - std::map<int32_t, int64_t> int_map; + std::map<int32_t, int32_t> int_map; + std::map<int32_t, int64_t> long_map; std::map<int32_t, std::string> string_map; std::map<int32_t, float> float_map; - int_map[11] = 123L; - int_map[22] = 345L; + int_map[11] = 123; + int_map[22] = 345; + + long_map[33] = 678L; + long_map[44] = 890L; string_map[1] = "test2"; string_map[2] = "test1"; @@ -255,7 +286,7 @@ TEST(LogEventTest, TestKeyValuePairsEvent) { float_map[111] = 2.2f; float_map[222] = 1.1f; - LogEvent event1(83, 2000, 2001, 10001, int_map, string_map, float_map); + LogEvent event1(83, 2000, 2001, 10001, int_map, long_map, string_map, float_map); event1.init(); EXPECT_EQ(83, event1.GetTagId()); @@ -263,7 +294,7 @@ TEST(LogEventTest, TestKeyValuePairsEvent) { EXPECT_EQ((int64_t)2001, event1.GetElapsedTimestampNs()); const auto& items = event1.getValues(); - EXPECT_EQ((size_t)13, items.size()); + EXPECT_EQ((size_t)17, items.size()); const FieldValue& item0 = event1.getValues()[0]; EXPECT_EQ(0x00010000, item0.mField.getField()); @@ -277,8 +308,8 @@ TEST(LogEventTest, TestKeyValuePairsEvent) { const FieldValue& item2 = event1.getValues()[2]; EXPECT_EQ(0x2020182, item2.mField.getField()); - EXPECT_EQ(Type::LONG, item2.mValue.getType()); - EXPECT_EQ(123L, item2.mValue.long_value); + EXPECT_EQ(Type::INT, item2.mValue.getType()); + EXPECT_EQ(123, item2.mValue.int_value); const FieldValue& item3 = event1.getValues()[3]; EXPECT_EQ(0x2020201, item3.mField.getField()); @@ -287,48 +318,68 @@ TEST(LogEventTest, TestKeyValuePairsEvent) { const FieldValue& item4 = event1.getValues()[4]; EXPECT_EQ(0x2020282, item4.mField.getField()); - EXPECT_EQ(Type::LONG, item4.mValue.getType()); - EXPECT_EQ(345L, item4.mValue.long_value); + EXPECT_EQ(Type::INT, item4.mValue.getType()); + EXPECT_EQ(345, item4.mValue.int_value); const FieldValue& item5 = event1.getValues()[5]; EXPECT_EQ(0x2020301, item5.mField.getField()); EXPECT_EQ(Type::INT, item5.mValue.getType()); - EXPECT_EQ(1, item5.mValue.int_value); + EXPECT_EQ(33, item5.mValue.int_value); const FieldValue& item6 = event1.getValues()[6]; - EXPECT_EQ(0x2020383, item6.mField.getField()); - EXPECT_EQ(Type::STRING, item6.mValue.getType()); - EXPECT_EQ("test2", item6.mValue.str_value); + EXPECT_EQ(0x2020382, item6.mField.getField()); + EXPECT_EQ(Type::LONG, item6.mValue.getType()); + EXPECT_EQ(678L, item6.mValue.long_value); const FieldValue& item7 = event1.getValues()[7]; EXPECT_EQ(0x2020401, item7.mField.getField()); EXPECT_EQ(Type::INT, item7.mValue.getType()); - EXPECT_EQ(2, item7.mValue.int_value); + EXPECT_EQ(44, item7.mValue.int_value); const FieldValue& item8 = event1.getValues()[8]; - EXPECT_EQ(0x2020483, item8.mField.getField()); - EXPECT_EQ(Type::STRING, item8.mValue.getType()); - EXPECT_EQ("test1", item8.mValue.str_value); + EXPECT_EQ(0x2020482, item8.mField.getField()); + EXPECT_EQ(Type::LONG, item8.mValue.getType()); + EXPECT_EQ(890L, item8.mValue.long_value); const FieldValue& item9 = event1.getValues()[9]; EXPECT_EQ(0x2020501, item9.mField.getField()); EXPECT_EQ(Type::INT, item9.mValue.getType()); - EXPECT_EQ(111, item9.mValue.int_value); + EXPECT_EQ(1, item9.mValue.int_value); const FieldValue& item10 = event1.getValues()[10]; - EXPECT_EQ(0x2020584, item10.mField.getField()); - EXPECT_EQ(Type::FLOAT, item10.mValue.getType()); - EXPECT_EQ(2.2f, item10.mValue.float_value); + EXPECT_EQ(0x2020583, item10.mField.getField()); + EXPECT_EQ(Type::STRING, item10.mValue.getType()); + EXPECT_EQ("test2", item10.mValue.str_value); const FieldValue& item11 = event1.getValues()[11]; - EXPECT_EQ(0x2028601, item11.mField.getField()); + EXPECT_EQ(0x2020601, item11.mField.getField()); EXPECT_EQ(Type::INT, item11.mValue.getType()); - EXPECT_EQ(222, item11.mValue.int_value); + EXPECT_EQ(2, item11.mValue.int_value); const FieldValue& item12 = event1.getValues()[12]; - EXPECT_EQ(0x2028684, item12.mField.getField()); - EXPECT_EQ(Type::FLOAT, item12.mValue.getType()); - EXPECT_EQ(1.1f, item12.mValue.float_value); + EXPECT_EQ(0x2020683, item12.mField.getField()); + EXPECT_EQ(Type::STRING, item12.mValue.getType()); + EXPECT_EQ("test1", item12.mValue.str_value); + + const FieldValue& item13 = event1.getValues()[13]; + EXPECT_EQ(0x2020701, item13.mField.getField()); + EXPECT_EQ(Type::INT, item13.mValue.getType()); + EXPECT_EQ(111, item13.mValue.int_value); + + const FieldValue& item14 = event1.getValues()[14]; + EXPECT_EQ(0x2020784, item14.mField.getField()); + EXPECT_EQ(Type::FLOAT, item14.mValue.getType()); + EXPECT_EQ(2.2f, item14.mValue.float_value); + + const FieldValue& item15 = event1.getValues()[15]; + EXPECT_EQ(0x2028801, item15.mField.getField()); + EXPECT_EQ(Type::INT, item15.mValue.getType()); + EXPECT_EQ(222, item15.mValue.int_value); + + const FieldValue& item16 = event1.getValues()[16]; + EXPECT_EQ(0x2028884, item16.mField.getField()); + EXPECT_EQ(Type::FLOAT, item16.mValue.getType()); + EXPECT_EQ(1.1f, item16.mValue.float_value); } @@ -337,4 +388,4 @@ TEST(LogEventTest, TestKeyValuePairsEvent) { } // namespace android #else GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif
\ No newline at end of file +#endif diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 6fab3c412ae5..0f64c4531bc3 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -483,6 +483,8 @@ public class Process { * @param appDataDir null-ok the data directory of the app. * @param invokeWith null-ok the command to invoke with. * @param packageName null-ok the name of the package this process belongs to. + * @param packagesForUid null-ok all the packages with the same uid as this process. + * @param visibleVols null-ok storage volumes that can be accessed by this process. * @param zygoteArgs Additional arguments to supply to the zygote process. * * @return An object that describes the result of the attempt to start the process. @@ -501,10 +503,13 @@ public class Process { @Nullable String appDataDir, @Nullable String invokeWith, @Nullable String packageName, + @Nullable String[] packagesForUid, + @Nullable String[] visibleVols, @Nullable String[] zygoteArgs) { return zygoteProcess.start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, - abi, instructionSet, appDataDir, invokeWith, packageName, zygoteArgs); + abi, instructionSet, appDataDir, invokeWith, packageName, + packagesForUid, visibleVols, zygoteArgs); } /** @hide */ @@ -519,10 +524,13 @@ public class Process { @Nullable String appDataDir, @Nullable String invokeWith, @Nullable String packageName, + @Nullable String[] packagesForUid, + @Nullable String[] visibleVols, @Nullable String[] zygoteArgs) { return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, - abi, instructionSet, appDataDir, invokeWith, packageName, zygoteArgs); + abi, instructionSet, appDataDir, invokeWith, packageName, + packagesForUid, visibleVols, zygoteArgs); } /** diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 99181acb03c7..7fd0a4b66d66 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -215,6 +215,8 @@ public class ZygoteProcess { * @param appDataDir null-ok the data directory of the app. * @param invokeWith null-ok the command to invoke with. * @param packageName null-ok the name of the package this process belongs to. + * @param packagesForUid null-ok all the packages with the same uid as this process. + * @param visibleVols null-ok storage volumes that can be accessed by this process. * @param zygoteArgs Additional arguments to supply to the zygote process. * * @return An object that describes the result of the attempt to start the process. @@ -231,12 +233,14 @@ public class ZygoteProcess { @Nullable String appDataDir, @Nullable String invokeWith, @Nullable String packageName, + @Nullable String[] packagesForUid, + @Nullable String[] visibleVols, @Nullable String[] zygoteArgs) { try { return startViaZygote(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */, - packageName, zygoteArgs); + packageName, packagesForUid, visibleVols, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); @@ -355,6 +359,8 @@ public class ZygoteProcess { * @param startChildZygote Start a sub-zygote. This creates a new zygote process * that has its state cloned from this zygote process. * @param packageName null-ok the name of the package this process belongs to. + * @param packagesForUid null-ok all the packages with the same uid as this process. + * @param visibleVols null-ok storage volumes that can be accessed by this process. * @param extraArgs Additional arguments to supply to the zygote process. * @return An object that describes the result of the attempt to start the process. * @throws ZygoteStartFailedEx if process start failed for any reason @@ -372,6 +378,8 @@ public class ZygoteProcess { @Nullable String invokeWith, boolean startChildZygote, @Nullable String packageName, + @Nullable String[] packagesForUid, + @Nullable String[] visibleVols, @Nullable String[] extraArgs) throws ZygoteStartFailedEx { ArrayList<String> argsForZygote = new ArrayList<String>(); @@ -439,6 +447,32 @@ public class ZygoteProcess { argsForZygote.add("--package-name=" + packageName); } + if (packagesForUid != null && packagesForUid.length > 0) { + final StringBuilder sb = new StringBuilder(); + sb.append("--packages-for-uid="); + + for (int i = 0; i < packagesForUid.length; ++i) { + if (i != 0) { + sb.append(','); + } + sb.append(packagesForUid[i]); + } + argsForZygote.add(sb.toString()); + } + + if (visibleVols != null && visibleVols.length > 0) { + final StringBuilder sb = new StringBuilder(); + sb.append("--visible-vols="); + + for (int i = 0; i < visibleVols.length; ++i) { + if (i != 0) { + sb.append(','); + } + sb.append(visibleVols[i]); + } + argsForZygote.add(sb.toString()); + } + argsForZygote.add(processClass); if (extraArgs != null) { @@ -746,7 +780,8 @@ public class ZygoteProcess { result = startViaZygote(processClass, niceName, uid, gid, gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo, abi, instructionSet, null /* appDataDir */, null /* invokeWith */, - true /* startChildZygote */, null /* packageName */, extraArgs); + true /* startChildZygote */, null /* packageName */, + null /* packagesForUid */, null /* visibleVolumes */, extraArgs); } catch (ZygoteStartFailedEx ex) { throw new RuntimeException("Starting child-zygote through Zygote failed", ex); } diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index d850e27e913f..1f54ea53facc 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -89,8 +89,13 @@ public abstract class StorageManagerInternal { * @param appId The appId for the given package. * @param sharedUserId The sharedUserId for given package if it specified * {@code android:sharedUserId} in the manifest, otherwise {@code null} - * @param userId + * @param userId The userId in which the storage needs to be mounted. */ public abstract void mountExternalStorageForApp(String packageName, int appId, String sharedUserId, int userId); + + /** + * @return Labels of storage volumes that are visible to the given userId. + */ + public abstract String[] getVisibleVolumesForUser(int userId); } diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java index afd383691300..e55afb69bab9 100644 --- a/core/java/android/os/storage/VolumeInfo.java +++ b/core/java/android/os/storage/VolumeInfo.java @@ -157,7 +157,7 @@ public class VolumeInfo implements Parcelable { public final DiskInfo disk; public final String partGuid; public int mountFlags = 0; - public int mountUserId = -1; + public int mountUserId = UserHandle.USER_NULL; @UnsupportedAppUsage public int state = STATE_UNMOUNTED; public String fsType; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ad8626ce736b..ce59b97819d3 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7267,12 +7267,12 @@ public final class Settings { private static final Validator DOZE_DOUBLE_TAP_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR; /** - * Whether the device should pulse on reach gesture. + * Gesture that wakes up the lock screen. * @hide */ - public static final String DOZE_REACH_GESTURE = "doze_reach_gesture"; + public static final String DOZE_WAKE_LOCK_SCREEN_GESTURE = "doze_wake_lock_screen_gesture"; - private static final Validator DOZE_REACH_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR; + private static final Validator DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR; /** * Gesture that wakes up the display, showing the ambient version of the status bar. @@ -8193,7 +8193,7 @@ public final class Settings { DOZE_ALWAYS_ON, DOZE_PICK_UP_GESTURE, DOZE_DOUBLE_TAP_GESTURE, - DOZE_REACH_GESTURE, + DOZE_WAKE_LOCK_SCREEN_GESTURE, DOZE_WAKE_SCREEN_GESTURE, NFC_PAYMENT_DEFAULT_COMPONENT, AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN, @@ -8341,7 +8341,7 @@ public final class Settings { VALIDATORS.put(DOZE_ALWAYS_ON, DOZE_ALWAYS_ON_VALIDATOR); VALIDATORS.put(DOZE_PICK_UP_GESTURE, DOZE_PICK_UP_GESTURE_VALIDATOR); VALIDATORS.put(DOZE_DOUBLE_TAP_GESTURE, DOZE_DOUBLE_TAP_GESTURE_VALIDATOR); - VALIDATORS.put(DOZE_REACH_GESTURE, DOZE_REACH_GESTURE_VALIDATOR); + VALIDATORS.put(DOZE_WAKE_LOCK_SCREEN_GESTURE, DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR); VALIDATORS.put(DOZE_WAKE_SCREEN_GESTURE, DOZE_WAKE_SCREEN_GESTURE_VALIDATOR); VALIDATORS.put(NFC_PAYMENT_DEFAULT_COMPONENT, NFC_PAYMENT_DEFAULT_COMPONENT_VALIDATOR); VALIDATORS.put(AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN, diff --git a/core/java/android/text/NativeLineBreaker.java b/core/java/android/text/NativeLineBreaker.java index 2bcfa5fe0857..94e10e89acbd 100644 --- a/core/java/android/text/NativeLineBreaker.java +++ b/core/java/android/text/NativeLineBreaker.java @@ -21,6 +21,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.Px; import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; @@ -258,16 +259,91 @@ public class NativeLineBreaker { /** * A result object of a line breaking */ - public static class LineBreaks { - public int breakCount; - private static final int INITIAL_SIZE = 16; - public int[] breaks = new int[INITIAL_SIZE]; - public float[] widths = new float[INITIAL_SIZE]; - public float[] ascents = new float[INITIAL_SIZE]; - public float[] descents = new float[INITIAL_SIZE]; - // TODO: Introduce Hyphenator for explaining the meaning of flags. - public int[] flags = new int[INITIAL_SIZE]; - // breaks, widths, and flags should all have the same length + public static class Result { + // Following two contstant must be synced with minikin's line breaker. + private static final int TAB_MASK = 0x20000000; + private static final int HYPHEN_MASK = 0xFF; + + private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( + Result.class.getClassLoader(), nGetReleaseResultFunc(), 32); + private final long mPtr; + + private Result(long ptr) { + mPtr = ptr; + sRegistry.registerNativeAllocation(this, mPtr); + } + + /** + * Returns a number of line count. + * + * @return number of lines + */ + public @IntRange(from = 0) int getLineCount() { + return nGetLineCount(mPtr); + } + + /** + * Returns a break offset of the line. + * + * @param lineIndex an index of the line. + * @return the break offset. + */ + public @IntRange(from = 0) int getLineBreakOffset(@IntRange(from = 0) int lineIndex) { + return nGetLineBreakOffset(mPtr, lineIndex); + } + + /** + * Returns a width of the line in pixels. + * + * @param lineIndex an index of the line. + * @return a width of the line in pixexls + */ + public @Px float getLineWidth(@IntRange(from = 0) int lineIndex) { + return nGetLineWidth(mPtr, lineIndex); + } + + /** + * Returns an entier font ascent of the line in pixels. + * + * @param lineIndex an index of the line. + * @return an entier font ascent of the line in pixels. + */ + public @Px float getLineAscent(@IntRange(from = 0) int lineIndex) { + return nGetLineAscent(mPtr, lineIndex); + } + + /** + * Returns an entier font descent of the line in pixels. + * + * @param lineIndex an index of the line. + * @return an entier font descent of the line in pixels. + */ + public @Px float getLineDescent(@IntRange(from = 0) int lineIndex) { + return nGetLineDescent(mPtr, lineIndex); + } + + /** + * Returns true if the line has a TAB character. + * + * @param lineIndex an index of the line. + * @return true if the line has a TAB character + */ + public boolean hasLineTab(int lineIndex) { + return (nGetLineFlag(mPtr, lineIndex) & TAB_MASK) != 0; + } + + /** + * Returns a packed packed hyphen edit for the line. + * + * @param lineIndex an index of the line. + * @return a packed hyphen edit for the line. + * @see android.text.Hyphenator#unpackStartHyphenEdit(int) + * @see android.text.Hyphenator#unpackEndHyphenEdit(int) + * @see android.text.Hyphenator#packHyphenEdit(int,int) + */ + public int getLineHyphenEdit(int lineIndex) { + return (nGetLineFlag(mPtr, lineIndex) & HYPHEN_MASK); + } } private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( @@ -294,14 +370,12 @@ public class NativeLineBreaker { * @param measuredPara a result of the text measurement * @param constraints for a single paragraph * @param lineNumber a line number of this paragraph - * @param out object to set line break information for the given paragraph */ - public void computeLineBreaks( + public Result computeLineBreaks( @NonNull NativeMeasuredParagraph measuredPara, @NonNull ParagraphConstraints constraints, - @IntRange(from = 0) int lineNumber, - @NonNull LineBreaks out) { - out.breakCount = nComputeLineBreaks( + @IntRange(from = 0) int lineNumber) { + return new Result(nComputeLineBreaks( mNativePtr, // Inputs @@ -313,17 +387,7 @@ public class NativeLineBreaker { constraints.mWidth, constraints.mVariableTabStops, constraints.mDefaultTabStop, - lineNumber, - - // Outputs - out, - out.breaks.length, - out.breaks, - out.widths, - out.ascents, - out.descents, - out.flags); - + lineNumber)); } @FastNative @@ -341,7 +405,7 @@ public class NativeLineBreaker { // arrays do not have to be resized // The individual character widths will be returned in charWidths. The length of // charWidths must be at least the length of the text. - private static native int nComputeLineBreaks( + private static native long nComputeLineBreaks( /* non zero */ long nativePtr, // Inputs @@ -353,14 +417,21 @@ public class NativeLineBreaker { @FloatRange(from = 0.0f) float restWidth, @Nullable int[] variableTabStops, int defaultTabStop, - @IntRange(from = 0) int indentsOffset, - - // Outputs - @NonNull LineBreaks recycle, - @IntRange(from = 0) int recycleLength, - @NonNull int[] recycleBreaks, - @NonNull float[] recycleWidths, - @NonNull float[] recycleAscents, - @NonNull float[] recycleDescents, - @NonNull int[] recycleFlags); + @IntRange(from = 0) int indentsOffset); + + // Result accessors + @CriticalNative + private static native int nGetLineCount(long ptr); + @CriticalNative + private static native int nGetLineBreakOffset(long ptr, int idx); + @CriticalNative + private static native float nGetLineWidth(long ptr, int idx); + @CriticalNative + private static native float nGetLineAscent(long ptr, int idx); + @CriticalNative + private static native float nGetLineDescent(long ptr, int idx); + @CriticalNative + private static native int nGetLineFlag(long ptr, int idx); + @CriticalNative + private static native long nGetReleaseResultFunc(); } diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index e1ffef01feae..d2f085369448 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -599,7 +599,14 @@ public class StaticLayout extends Layout { float ellipsizedWidth = b.mEllipsizedWidth; TextUtils.TruncateAt ellipsize = b.mEllipsize; final boolean addLastLineSpacing = b.mAddLastLineLineSpacing; - NativeLineBreaker.LineBreaks lineBreaks = new NativeLineBreaker.LineBreaks(); + + int lineBreakCapacity = 0; + int[] breaks = null; + float[] lineWidths = null; + float[] ascents = null; + float[] descents = null; + boolean[] hasTabs = null; + int[] hyphenEdits = null; mLineCount = 0; mEllipsized = false; @@ -732,14 +739,27 @@ public class StaticLayout extends Layout { constraints.setIndent(firstWidth, firstWidthLineCount); constraints.setTabStops(variableTabStops, TAB_INCREMENT); - lineBreaker.computeLineBreaks(measuredPara.getNativeMeasuredParagraph(), - constraints, mLineCount, lineBreaks); - int breakCount = lineBreaks.breakCount; - final int[] breaks = lineBreaks.breaks; - final float[] lineWidths = lineBreaks.widths; - final float[] ascents = lineBreaks.ascents; - final float[] descents = lineBreaks.descents; - final int[] flags = lineBreaks.flags; + NativeLineBreaker.Result res = lineBreaker.computeLineBreaks( + measuredPara.getNativeMeasuredParagraph(), constraints, mLineCount); + int breakCount = res.getLineCount(); + if (lineBreakCapacity < breakCount) { + lineBreakCapacity = breakCount; + breaks = new int[lineBreakCapacity]; + lineWidths = new float[lineBreakCapacity]; + ascents = new float[lineBreakCapacity]; + descents = new float[lineBreakCapacity]; + hasTabs = new boolean[lineBreakCapacity]; + hyphenEdits = new int[lineBreakCapacity]; + } + + for (int i = 0; i < breakCount; ++i) { + breaks[i] = res.getLineBreakOffset(i); + lineWidths[i] = res.getLineWidth(i); + ascents[i] = res.getLineAscent(i); + descents[i] = res.getLineDescent(i); + hasTabs[i] = res.hasLineTab(i); + hyphenEdits[i] = res.getLineHyphenEdit(i); + } final int remainingLineCount = mMaximumVisibleLineCount - mLineCount; final boolean ellipsisMayBeApplied = ellipsize != null @@ -750,7 +770,7 @@ public class StaticLayout extends Layout { && ellipsisMayBeApplied) { // Calculate width float width = 0; - int flag = 0; // XXX May need to also have starting hyphen edit + boolean hasTab = false; // XXX May need to also have starting hyphen edit for (int i = remainingLineCount - 1; i < breakCount; i++) { if (i == breakCount - 1) { width += lineWidths[i]; @@ -759,12 +779,12 @@ public class StaticLayout extends Layout { width += measuredPara.getCharWidthAt(j - paraStart); } } - flag |= flags[i] & TAB_MASK; + hasTab |= hasTabs[i]; } // Treat the last line and overflowed lines as a single line. breaks[remainingLineCount - 1] = breaks[breakCount - 1]; lineWidths[remainingLineCount - 1] = width; - flags[remainingLineCount - 1] = flag; + hasTabs[remainingLineCount - 1] = hasTab; breakCount = remainingLineCount; } @@ -821,8 +841,8 @@ public class StaticLayout extends Layout { v = out(source, here, endPos, ascent, descent, fmTop, fmBottom, v, spacingmult, spacingadd, chooseHt, chooseHtv, fm, - flags[breakIndex], needMultiply, measuredPara, bufEnd, - includepad, trackpad, addLastLineSpacing, chs, + hasTabs[breakIndex], hyphenEdits[breakIndex], needMultiply, + measuredPara, bufEnd, includepad, trackpad, addLastLineSpacing, chs, paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex], paint, moreChars); @@ -860,7 +880,7 @@ public class StaticLayout extends Layout { fm.top, fm.bottom, v, spacingmult, spacingadd, null, - null, fm, 0, + null, fm, false, 0, needMultiply, measuredPara, bufEnd, includepad, trackpad, addLastLineSpacing, null, bufStart, ellipsize, @@ -871,7 +891,8 @@ public class StaticLayout extends Layout { private int out(final CharSequence text, final int start, final int end, int above, int below, int top, int bottom, int v, final float spacingmult, final float spacingadd, final LineHeightSpan[] chooseHt, final int[] chooseHtv, final Paint.FontMetricsInt fm, - final int flags, final boolean needMultiply, @NonNull final MeasuredParagraph measured, + final boolean hasTab, final int hyphenEdit, final boolean needMultiply, + @NonNull final MeasuredParagraph measured, final int bufEnd, final boolean includePad, final boolean trackPad, final boolean addLastLineLineSpacing, final char[] chs, final int widthStart, final TextUtils.TruncateAt ellipsize, final float ellipsisWidth, @@ -1005,8 +1026,8 @@ public class StaticLayout extends Layout { // TODO: could move TAB to share same column as HYPHEN, simplifying this code and gaining // one bit for start field - lines[off + TAB] |= flags & TAB_MASK; - lines[off + HYPHEN] = flags; + lines[off + TAB] |= hasTab ? TAB_MASK : 0; + lines[off + HYPHEN] = hyphenEdit; lines[off + DIR] |= dir << DIR_SHIFT; mLineDirections[j] = measured.getDirections(start - widthStart, end - widthStart); diff --git a/core/java/android/transition/ChangeImageTransform.java b/core/java/android/transition/ChangeImageTransform.java index d7a912057858..9fa9961d21bc 100644 --- a/core/java/android/transition/ChangeImageTransform.java +++ b/core/java/android/transition/ChangeImageTransform.java @@ -97,22 +97,13 @@ public class ChangeImageTransform extends Transition { values.put(PROPNAME_BOUNDS, bounds); Matrix matrix; ImageView.ScaleType scaleType = imageView.getScaleType(); - if (scaleType == ImageView.ScaleType.FIT_XY) { - matrix = imageView.getImageMatrix(); - if (!matrix.isIdentity()) { - matrix = new Matrix(matrix); - } else { - int drawableWidth = drawable.getIntrinsicWidth(); - int drawableHeight = drawable.getIntrinsicHeight(); - if (drawableWidth > 0 && drawableHeight > 0) { - float scaleX = ((float) bounds.width()) / drawableWidth; - float scaleY = ((float) bounds.height()) / drawableHeight; - matrix = new Matrix(); - matrix.setScale(scaleX, scaleY); - } else { - matrix = null; - } - } + int drawableWidth = drawable.getIntrinsicWidth(); + int drawableHeight = drawable.getIntrinsicHeight(); + if (scaleType == ImageView.ScaleType.FIT_XY && drawableWidth > 0 && drawableHeight > 0) { + float scaleX = ((float) bounds.width()) / drawableWidth; + float scaleY = ((float) bounds.height()) / drawableHeight; + matrix = new Matrix(); + matrix.setScale(scaleX, scaleY); } else { matrix = new Matrix(imageView.getImageMatrix()); } @@ -152,17 +143,13 @@ public class ChangeImageTransform extends Transition { } Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS); Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS); - if (startBounds == null || endBounds == null) { - return null; - } - Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX); Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX); + if (startBounds == null || endBounds == null || startMatrix == null || endMatrix == null) { + return null; + } - boolean matricesEqual = (startMatrix == null && endMatrix == null) || - (startMatrix != null && startMatrix.equals(endMatrix)); - - if (startBounds.equals(endBounds) && matricesEqual) { + if (startBounds.equals(endBounds) && startMatrix.equals(endMatrix)) { return null; } @@ -172,15 +159,9 @@ public class ChangeImageTransform extends Transition { int drawableHeight = drawable.getIntrinsicHeight(); ObjectAnimator animator; - if (drawableWidth == 0 || drawableHeight == 0) { + if (drawableWidth <= 0 || drawableHeight <= 0) { animator = createNullAnimator(imageView); } else { - if (startMatrix == null) { - startMatrix = Matrix.IDENTITY_MATRIX; - } - if (endMatrix == null) { - endMatrix = Matrix.IDENTITY_MATRIX; - } ANIMATED_TRANSFORM_PROPERTY.set(imageView, startMatrix); animator = createMatrixAnimator(imageView, startMatrix, endMatrix); } @@ -189,7 +170,7 @@ public class ChangeImageTransform extends Transition { private ObjectAnimator createNullAnimator(ImageView imageView) { return ObjectAnimator.ofObject(imageView, ANIMATED_TRANSFORM_PROPERTY, - NULL_MATRIX_EVALUATOR, null, null); + NULL_MATRIX_EVALUATOR, Matrix.IDENTITY_MATRIX, Matrix.IDENTITY_MATRIX); } private ObjectAnimator createMatrixAnimator(final ImageView imageView, Matrix startMatrix, diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java index c4ef77a3e7ae..4608e205ec7c 100644 --- a/core/java/android/transition/TransitionManager.java +++ b/core/java/android/transition/TransitionManager.java @@ -188,8 +188,12 @@ public class TransitionManager { final ViewGroup sceneRoot = scene.getSceneRoot(); if (!sPendingTransitions.contains(sceneRoot)) { + Scene oldScene = Scene.getCurrentScene(sceneRoot); if (transition == null) { - exitPreviousScene(sceneRoot); + // Notify old scene that it is being exited + if (oldScene != null) { + oldScene.exit(); + } scene.enter(); } else { @@ -198,7 +202,6 @@ public class TransitionManager { Transition transitionClone = transition.clone(); transitionClone.setSceneRoot(sceneRoot); - Scene oldScene = Scene.getCurrentScene(sceneRoot); if (oldScene != null && oldScene.isCreatedFromLayoutResource()) { transitionClone.setCanRemoveViews(true); } @@ -212,14 +215,6 @@ public class TransitionManager { } } - private static void exitPreviousScene(final ViewGroup sceneRoot) { - // Notify previous scene that it is being exited - final Scene previousScene = Scene.getCurrentScene(sceneRoot); - if (previousScene != null) { - previousScene.exit(); - } - } - @UnsupportedAppUsage private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() { WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>> runningTransitions = @@ -349,7 +344,11 @@ public class TransitionManager { transition.captureValues(sceneRoot, true); } - exitPreviousScene(sceneRoot); + // Notify previous scene that it is being exited + Scene previousScene = Scene.getCurrentScene(sceneRoot); + if (previousScene != null) { + previousScene.exit(); + } } /** diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java index e1600c4a92c8..d09323d3f8ad 100644 --- a/core/java/android/view/inputmethod/InputMethod.java +++ b/core/java/android/view/inputmethod/InputMethod.java @@ -124,7 +124,8 @@ public interface InputMethod { * @hide */ @MainThread - public void updateInputMethodDisplay(int displayId); + default void updateInputMethodDisplay(int displayId) { + } /** * Bind a new application environment in to the input method, so that it diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 0fef9a54a2ff..12cc54d7241e 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -1338,7 +1338,9 @@ public class ImageView extends View { return; } if (matrix == null) { - mDrawable.setBounds(0, 0, getWidth(), getHeight()); + final int vwidth = getWidth() - mPaddingLeft - mPaddingRight; + final int vheight = getHeight() - mPaddingTop - mPaddingBottom; + mDrawable.setBounds(0, 0, vwidth, vheight); } else { mDrawable.setBounds(0, 0, mDrawableWidth, mDrawableHeight); if (mDrawMatrix == null) { diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java index cb282b69845c..0080ace230a2 100644 --- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java +++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java @@ -66,13 +66,13 @@ public class AmbientDisplayConfiguration { return !TextUtils.isEmpty(doubleTapSensorType()); } - public boolean reachGestureEnabled(int user) { - return boolSettingDefaultOn(Settings.Secure.DOZE_REACH_GESTURE, user) - && reachGestureAvailable(); + public boolean wakeLockScreenGestureEnabled(int user) { + return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, user) + && wakeLockScreenGestureAvailable(); } - public boolean reachGestureAvailable() { - return !TextUtils.isEmpty(reachSensorType()); + public boolean wakeLockScreenGestureAvailable() { + return !TextUtils.isEmpty(wakeLockScreenSensorType()); } public boolean wakeScreenGestureEnabled(int user) { @@ -92,8 +92,8 @@ public class AmbientDisplayConfiguration { return mContext.getResources().getString(R.string.config_dozeLongPressSensorType); } - public String reachSensorType() { - return mContext.getResources().getString(R.string.config_dozeReachSensorType); + public String wakeLockScreenSensorType() { + return mContext.getResources().getString(R.string.config_dozeWakeLockScreenSensorType); } public String wakeScreenSensorType() { diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 927322e97e28..98b7b5d28779 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -133,15 +133,16 @@ public final class Zygote { * if this is the parent, or -1 on error. */ public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, - int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, - int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, - String packageName) { + int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, + int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, + String packageName, String[] packagesForUid, String[] visibleVolIds) { VM_HOOKS.preFork(); // Resets nice priority for zygote process. resetNicePriority(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, - fdsToIgnore, startChildZygote, instructionSet, appDataDir, packageName); + fdsToIgnore, startChildZygote, instructionSet, appDataDir, packageName, + packagesForUid, visibleVolIds); // Enable tracing as soon as possible for the child process. if (pid == 0) { Trace.setTracingEnabled(true, runtimeFlags); @@ -154,9 +155,9 @@ public final class Zygote { } native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int runtimeFlags, - int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, - int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, - String packageName); + int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, + int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, + String packageName, String[] packagesForUid, String[] visibleVolIds); /** * Called to do any initialization before starting an application. diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 06c41d858f7c..4a94ec4a4071 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -241,7 +241,8 @@ class ZygoteConnection { pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote, - parsedArgs.instructionSet, parsedArgs.appDataDir, parsedArgs.packageName); + parsedArgs.instructionSet, parsedArgs.appDataDir, parsedArgs.packageName, + parsedArgs.packagesForUid, parsedArgs.visibleVolIds); try { if (pid == 0) { @@ -432,6 +433,12 @@ class ZygoteConnection { /** from --package-name */ String packageName; + /** from --packages-for-uid */ + String[] packagesForUid; + + /** from --visible-vols */ + String[] visibleVolIds; + /** * Any args after and including the first non-option arg * (or after a '--') @@ -687,6 +694,10 @@ class ZygoteConnection { throw new IllegalArgumentException("Duplicate arg specified"); } packageName = arg.substring(arg.indexOf('=') + 1); + } else if (arg.startsWith("--packages-for-uid=")) { + packagesForUid = arg.substring(arg.indexOf('=') + 1).split(","); + } else if (arg.startsWith("--visible-vols=")) { + visibleVolIds = arg.substring(arg.indexOf('=') + 1).split(","); } else { break; } diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp index b16359727e40..a45b4933a900 100644 --- a/core/jni/android/opengl/util.cpp +++ b/core/jni/android/opengl/util.cpp @@ -622,13 +622,17 @@ void util_multiplyMV(JNIEnv *env, jclass clazz, // --------------------------------------------------------------------------- +// The internal format is no longer the same as pixel format, per Table 2 in +// https://www.khronos.org/registry/OpenGL-Refpages/es3.1/html/glTexImage2D.xhtml static int checkInternalFormat(SkColorType colorType, int internalformat, int type) { switch(colorType) { case kN32_SkColorType: return (type == GL_UNSIGNED_BYTE && - internalformat == GL_RGBA) ? 0 : -1; + internalformat == GL_RGBA) || + (type == GL_UNSIGNED_BYTE && + internalformat == GL_SRGB8_ALPHA8) ? 0 : -1; case kAlpha_8_SkColorType: return (type == GL_UNSIGNED_BYTE && internalformat == GL_ALPHA) ? 0 : -1; diff --git a/core/jni/android_text_LineBreaker.cpp b/core/jni/android_text_LineBreaker.cpp index dac108ef5497..543910727ffd 100644 --- a/core/jni/android_text_LineBreaker.cpp +++ b/core/jni/android_text_LineBreaker.cpp @@ -41,17 +41,6 @@ namespace android { -struct JLineBreaksID { - jfieldID breaks; - jfieldID widths; - jfieldID ascents; - jfieldID descents; - jfieldID flags; -}; - -static jclass gLineBreaks_class; -static JLineBreaksID gLineBreaks_fieldID; - static inline std::vector<float> jintArrayToFloatVector(JNIEnv* env, jintArray javaArray) { if (javaArray == nullptr) { return std::vector<float>(); @@ -85,34 +74,7 @@ static jlong nGetReleaseFunc() { return reinterpret_cast<jlong>(nFinish); } -static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks, - jfloatArray recycleWidths, jfloatArray recycleAscents, - jfloatArray recycleDescents, jintArray recycleFlags, - 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); - recycleWidths = env->NewFloatArray(nBreaks); - recycleAscents = env->NewFloatArray(nBreaks); - recycleDescents = env->NewFloatArray(nBreaks); - recycleFlags = env->NewIntArray(nBreaks); - - env->SetObjectField(recycle, gLineBreaks_fieldID.breaks, recycleBreaks); - env->SetObjectField(recycle, gLineBreaks_fieldID.widths, recycleWidths); - env->SetObjectField(recycle, gLineBreaks_fieldID.ascents, recycleAscents); - env->SetObjectField(recycle, gLineBreaks_fieldID.descents, recycleDescents); - env->SetObjectField(recycle, gLineBreaks_fieldID.flags, recycleFlags); - } - // copy data - 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, +static jlong nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr, // Inputs jcharArray javaText, jlong measuredTextPtr, @@ -122,18 +84,7 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr, jfloat restWidth, jintArray variableTabStops, jint defaultTabStop, - jint indentsOffset, - - // Outputs - jobject recycle, - jint recycleLength, - jintArray recycleBreaks, - jfloatArray recycleWidths, - jfloatArray recycleAscents, - jfloatArray recycleDescents, - jintArray recycleFlags, - jfloatArray charWidths) { - + jint indentsOffset) { minikin::android::StaticLayoutNative* builder = toNative(nativePtr); ScopedCharArrayRO text(env, javaText); @@ -141,14 +92,44 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr, minikin::U16StringPiece u16Text(text.get(), length); minikin::MeasuredText* measuredText = reinterpret_cast<minikin::MeasuredText*>(measuredTextPtr); - 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, result); + std::unique_ptr<minikin::LineBreakResult> result = + std::make_unique<minikin::LineBreakResult>(builder->computeBreaks( + u16Text, *measuredText, firstWidth, firstWidthLineCount, restWidth, indentsOffset, + tabStops.get(), tabStops.size(), defaultTabStop)); + return reinterpret_cast<jlong>(result.release()); +} + +static jint nGetLineCount(jlong ptr) { + return reinterpret_cast<minikin::LineBreakResult*>(ptr)->breakPoints.size(); +} + +static jint nGetLineBreakOffset(jlong ptr, jint i) { + return reinterpret_cast<minikin::LineBreakResult*>(ptr)->breakPoints[i]; +} + +static jfloat nGetLineWidth(jlong ptr, jint i) { + return reinterpret_cast<minikin::LineBreakResult*>(ptr)->widths[i]; +} - return static_cast<jint>(result.breakPoints.size()); +static jfloat nGetLineAscent(jlong ptr, jint i) { + return reinterpret_cast<minikin::LineBreakResult*>(ptr)->ascents[i]; +} + +static jfloat nGetLineDescent(jlong ptr, jint i) { + return reinterpret_cast<minikin::LineBreakResult*>(ptr)->descents[i]; +} + +static jint nGetLineFlag(jlong ptr, jint i) { + return reinterpret_cast<minikin::LineBreakResult*>(ptr)->flags[i]; +} + +static void nReleaseResult(jlong ptr) { + delete reinterpret_cast<minikin::LineBreakResult*>(ptr); +} + +static jlong nGetReleaseResultFunc() { + return reinterpret_cast<jlong>(nReleaseResult); } static const JNINativeMethod gMethods[] = { @@ -166,8 +147,6 @@ static const JNINativeMethod gMethods[] = { // Regular JNI {"nComputeLineBreaks", "(" "J" // nativePtr - - // Inputs "[C" // text "J" // MeasuredParagraph ptr. "I" // length @@ -177,31 +156,20 @@ static const JNINativeMethod gMethods[] = { "[I" // variableTabStops "I" // defaultTabStop "I" // indentsOffset - - // Outputs - "Landroid/text/NativeLineBreaker$LineBreaks;" // recycle - "I" // recycleLength - "[I" // recycleBreaks - "[F" // recycleWidths - "[F" // recycleAscents - "[F" // recycleDescents - "[I" // recycleFlags - ")I", (void*) nComputeLineBreaks} + ")J", (void*) nComputeLineBreaks}, + + // Result accessors, CriticalNatives + {"nGetLineCount", "(J)I", (void*)nGetLineCount}, + {"nGetLineBreakOffset", "(JI)I", (void*)nGetLineBreakOffset}, + {"nGetLineWidth", "(JI)F", (void*)nGetLineWidth}, + {"nGetLineAscent", "(JI)F", (void*)nGetLineAscent}, + {"nGetLineDescent", "(JI)F", (void*)nGetLineDescent}, + {"nGetLineFlag", "(JI)I", (void*)nGetLineFlag}, + {"nGetReleaseResultFunc", "()J", (void*)nGetReleaseResultFunc}, }; -int register_android_text_LineBreaker(JNIEnv* env) -{ - gLineBreaks_class = MakeGlobalRefOrDie(env, - FindClassOrDie(env, "android/text/NativeLineBreaker$LineBreaks")); - - gLineBreaks_fieldID.breaks = GetFieldIDOrDie(env, gLineBreaks_class, "breaks", "[I"); - gLineBreaks_fieldID.widths = GetFieldIDOrDie(env, gLineBreaks_class, "widths", "[F"); - gLineBreaks_fieldID.ascents = GetFieldIDOrDie(env, gLineBreaks_class, "ascents", "[F"); - gLineBreaks_fieldID.descents = GetFieldIDOrDie(env, gLineBreaks_class, "descents", "[F"); - gLineBreaks_fieldID.flags = GetFieldIDOrDie(env, gLineBreaks_class, "flags", "[I"); - - return RegisterMethodsOrDie(env, "android/text/NativeLineBreaker", - gMethods, NELEM(gMethods)); +int register_android_text_LineBreaker(JNIEnv* env) { + return RegisterMethodsOrDie(env, "android/text/NativeLineBreaker", gMethods, NELEM(gMethods)); } } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index c15b7ee4fe04..109e65c4a1d0 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -285,10 +285,6 @@ static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats, static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path, jint limitUid, jobjectArray limitIfacesObj, jint limitTag, jboolean useBpfStats) { - ScopedUtfChars path8(env, path); - if (path8.c_str() == NULL) { - return -1; - } std::vector<std::string> limitIfaces; if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { @@ -308,6 +304,11 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstr if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0) return -1; } else { + ScopedUtfChars path8(env, path); + if (path8.c_str() == NULL) { + ALOGE("the qtaguid legacy path is invalid: %s", path8.c_str()); + return -1; + } if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid, path8.c_str()) < 0) return -1; diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 364393e1c649..1f958628374d 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -382,11 +382,10 @@ static int UnmountTree(const char* path) { return 0; } -static bool createPkgSandbox(uid_t uid, const char* package_name, std::string& pkg_sandbox_dir, - std::string* error_msg) { +static bool createPkgSandbox(uid_t uid, const std::string& package_name, std::string* error_msg) { // Create /mnt/user/0/package/<package-name> userid_t user_id = multiuser_get_user_id(uid); - StringAppendF(&pkg_sandbox_dir, "/%d", user_id); + std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id); if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0751, AID_ROOT, AID_ROOT) != 0) { *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str()); return false; @@ -396,7 +395,7 @@ static bool createPkgSandbox(uid_t uid, const char* package_name, std::string& p *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str()); return false; } - StringAppendF(&pkg_sandbox_dir, "/%s", package_name); + StringAppendF(&pkg_sandbox_dir, "/%s", package_name.c_str()); if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0755, uid, uid) != 0) { *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str()); return false; @@ -404,10 +403,51 @@ static bool createPkgSandbox(uid_t uid, const char* package_name, std::string& p return true; } +static bool mountPkgSpecificDir(const std::string& mntSourceRoot, + const std::string& mntTargetRoot, const std::string& packageName, + const char* dirName, std::string* error_msg) { + std::string mntSourceDir = StringPrintf("%s/Android/%s/%s", + mntSourceRoot.c_str(), dirName, packageName.c_str()); + std::string mntTargetDir = StringPrintf("%s/Android/%s/%s", + mntTargetRoot.c_str(), dirName, packageName.c_str()); + if (TEMP_FAILURE_RETRY(mount(mntSourceDir.c_str(), mntTargetDir.c_str(), + nullptr, MS_BIND | MS_REC, nullptr)) == -1) { + *error_msg = CREATE_ERROR("Failed to mount %s to %s: %s", + mntSourceDir.c_str(), mntTargetDir.c_str(), strerror(errno)); + return false; + } + if (TEMP_FAILURE_RETRY(mount(nullptr, mntTargetDir.c_str(), + nullptr, MS_SLAVE | MS_REC, nullptr)) == -1) { + *error_msg = CREATE_ERROR("Failed to set MS_SLAVE for %s", mntTargetDir.c_str()); + return false; + } + return true; +} + +static bool preparePkgSpecificDirs(const std::vector<std::string>& packageNames, + const std::vector<std::string>& volumeLabels, userid_t userId, std::string* error_msg) { + for (auto& label : volumeLabels) { + std::string mntSource = StringPrintf("/mnt/runtime/write/%s", label.c_str()); + std::string mntTarget = StringPrintf("/storage/%s", label.c_str()); + if (label == "emulated") { + StringAppendF(&mntSource, "/%d", userId); + StringAppendF(&mntTarget, "/%d", userId); + } + for (auto& package : packageNames) { + mountPkgSpecificDir(mntSource, mntTarget, package, "data", error_msg); + mountPkgSpecificDir(mntSource, mntTarget, package, "media", error_msg); + mountPkgSpecificDir(mntSource, mntTarget, package, "obb", error_msg); + } + } + return true; +} + // Create a private mount namespace and bind mount appropriate emulated // storage for the given user. static bool MountEmulatedStorage(uid_t uid, jint mount_mode, - bool force_mount_namespace, std::string* error_msg, const char* package_name) { + bool force_mount_namespace, std::string* error_msg, const std::string& package_name, + const std::vector<std::string>& packages_for_uid, + const std::vector<std::string>& visible_vol_ids) { // See storage config details at http://source.android.com/tech/storage/ String8 storageSource; @@ -459,12 +499,25 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode, return false; } } else { - if (package_name == nullptr) { + if (package_name.empty()) { return true; } - std::string pkgSandboxDir("/mnt/user"); - if (!createPkgSandbox(uid, package_name, pkgSandboxDir, error_msg)) { - return false; + userid_t user_id = multiuser_get_user_id(uid); + std::string pkgSandboxDir = StringPrintf("/mnt/user/%d/package/%s", + user_id, package_name.c_str()); + struct stat sb; + bool sandboxAlreadyCreated = true; + if (TEMP_FAILURE_RETRY(lstat(pkgSandboxDir.c_str(), &sb)) == -1) { + if (errno == ENOENT) { + ALOGD("Sandbox not yet created for %s", pkgSandboxDir.c_str()); + sandboxAlreadyCreated = false; + if (!createPkgSandbox(uid, package_name, error_msg)) { + return false; + } + } else { + ALOGE("Failed to lstat %s", pkgSandboxDir.c_str()); + return false; + } } if (TEMP_FAILURE_RETRY(mount(pkgSandboxDir.c_str(), "/storage", nullptr, MS_BIND | MS_REC | MS_SLAVE, nullptr)) == -1) { @@ -472,6 +525,15 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode, pkgSandboxDir.c_str(), strerror(errno)); return false; } + // If the sandbox was already created by vold, only then set up the bind mounts for + // pkg specific directories. Otherwise, leave as is and bind mounts will be taken + // care of by vold later. + if (sandboxAlreadyCreated) { + if (!preparePkgSpecificDirs(packages_for_uid, visible_vol_ids, + user_id, error_msg)) { + return false; + } + } } } else { if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage", @@ -611,7 +673,8 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi jlong permittedCapabilities, jlong effectiveCapabilities, jint mount_external, jstring java_se_info, jstring java_se_name, bool is_system_server, bool is_child_zygote, jstring instructionSet, - jstring dataDir, jstring packageName) { + jstring dataDir, jstring packageName, jobjectArray packagesForUid, + jobjectArray visibleVolIds) { std::string error_msg; auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg) @@ -661,17 +724,33 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi ALOGW("Native bridge will not be used because dataDir == NULL."); } - ScopedUtfChars* package_name = nullptr; - const char* package_name_c_str = nullptr; + std::string package_name_str(""); if (packageName != nullptr) { - package_name = new ScopedUtfChars(env, packageName); - package_name_c_str = package_name->c_str(); + ScopedUtfChars package(env, packageName); + package_name_str = package.c_str(); } else if (is_system_server) { - package_name_c_str = "android"; + package_name_str = "android"; + } + std::vector<std::string> packages_for_uid; + if (packagesForUid != nullptr) { + jsize count = env->GetArrayLength(packagesForUid); + for (jsize i = 0; i < count; ++i) { + jstring package_for_uid = (jstring) env->GetObjectArrayElement(packagesForUid, i); + ScopedUtfChars package(env, package_for_uid); + packages_for_uid.push_back(package.c_str()); + } + } + std::vector<std::string> visible_vol_ids; + if (visibleVolIds != nullptr) { + jsize count = env->GetArrayLength(visibleVolIds); + for (jsize i = 0; i < count; ++i) { + jstring visible_vol_id = (jstring) env->GetObjectArrayElement(visibleVolIds, i); + ScopedUtfChars vol(env, visible_vol_id); + visible_vol_ids.push_back(vol.c_str()); + } } bool success = MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg, - package_name_c_str); - delete package_name; + package_name_str, packages_for_uid, visible_vol_ids); if (!success) { ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno)); if (errno == ENOTCONN || errno == EROFS) { @@ -936,7 +1015,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring se_name, jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote, - jstring instructionSet, jstring appDataDir, jstring packageName) { + jstring instructionSet, jstring appDataDir, jstring packageName, + jobjectArray packagesForUid, jobjectArray visibleVolIds) { jlong capabilities = 0; // Grant CAP_WAKE_ALARM to the Bluetooth process. @@ -989,7 +1069,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, mount_external, se_info, se_name, false, - is_child_zygote == JNI_TRUE, instructionSet, appDataDir, packageName); + is_child_zygote == JNI_TRUE, instructionSet, appDataDir, packageName, + packagesForUid, visibleVolIds); } return pid; } @@ -1003,7 +1084,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permittedCapabilities, effectiveCapabilities, MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, - false, NULL, NULL, nullptr); + false, NULL, NULL, nullptr, nullptr, nullptr); } else if (pid > 0) { // The zygote process checks whether the child process has died or not. ALOGI("System server process %d has been created", pid); @@ -1084,7 +1165,7 @@ static const JNINativeMethod gMethods[] = { { "nativeSecurityInit", "()V", (void *) com_android_internal_os_Zygote_nativeSecurityInit }, { "nativeForkAndSpecialize", - "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", + "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)I", (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize }, { "nativeForkSystemServer", "(II[II[[IJJ)I", (void *) com_android_internal_os_Zygote_nativeForkSystemServer }, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 85a52d5f714f..9acb08b25db2 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -941,7 +941,6 @@ Requesting this by itself is not sufficient to give you location access. <p>Protection level: dangerous - @hide --> <permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:permissionGroup="android.permission-group.LOCATION" diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 9aebf6c4597f..0daf5a76562d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2113,8 +2113,8 @@ <!-- Type of the long press sensor. Empty if long press is not supported. --> <string name="config_dozeLongPressSensorType" translatable="false"></string> - <!-- Type of the reach sensor. Empty if reach is not supported. --> - <string name="config_dozeReachSensorType" translatable="false"></string> + <!-- Type of sensor that wakes up the lock screen. Empty if not supported. --> + <string name="config_dozeWakeLockScreenSensorType" translatable="false"></string> <!-- Type of the wake up sensor. Empty if not supported. --> <string name="config_dozeWakeScreenSensorType" translatable="false"></string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 9f2256a6461a..72ae0d61654a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3279,7 +3279,7 @@ <java-symbol type="array" name="config_hideWhenDisabled_packageNames" /> <java-symbol type="string" name="config_dozeLongPressSensorType" /> - <java-symbol type="string" name="config_dozeReachSensorType" /> + <java-symbol type="string" name="config_dozeWakeLockScreenSensorType" /> <java-symbol type="array" name="config_allowedGlobalInstantAppSettings" /> <java-symbol type="array" name="config_allowedSystemInstantAppSettings" /> diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp index 21fbbdca7ad0..0b9d82b105a3 100644 --- a/libs/hwui/DeviceInfo.cpp +++ b/libs/hwui/DeviceInfo.cpp @@ -61,18 +61,6 @@ DisplayInfo QueryDisplayInfo() { return displayInfo; } -void QueryCompositionPreference(ui::Dataspace* dataSpace, - ui::PixelFormat* pixelFormat) { - if (Properties::isolatedProcess) { - *dataSpace = ui::Dataspace::V0_SRGB; - *pixelFormat = ui::PixelFormat::RGBA_8888; - } - - status_t status = - SurfaceComposerClient::getCompositionPreference(dataSpace, pixelFormat); - LOG_ALWAYS_FATAL_IF(status, "Failed to get composition preference, error %d", status); -} - DeviceInfo::DeviceInfo() { #if HWUI_NULL_GPU mMaxTextureSize = NULL_GPU_MAX_TEXTURE_SIZE; @@ -80,7 +68,6 @@ DeviceInfo::DeviceInfo() { mMaxTextureSize = -1; #endif mDisplayInfo = QueryDisplayInfo(); - QueryCompositionPreference(&mTargetDataSpace, &mTargetPixelFormat); } int DeviceInfo::maxTextureSize() const { diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h index 1d7477416077..595621573e6e 100644 --- a/libs/hwui/DeviceInfo.h +++ b/libs/hwui/DeviceInfo.h @@ -17,7 +17,6 @@ #define DEVICEINFO_H #include <ui/DisplayInfo.h> -#include <ui/GraphicTypes.h> #include "utils/Macros.h" @@ -37,9 +36,6 @@ public: // this value is only valid after the GPU has been initialized and there is a valid graphics // context or if you are using the HWUI_NULL_GPU int maxTextureSize() const; - - ui::Dataspace getTargetDataSpace() const { return mTargetDataSpace; } - ui::PixelFormat getTargetPixelFormat() const { return mTargetPixelFormat; } const DisplayInfo& displayInfo() const { return mDisplayInfo; } private: @@ -50,10 +46,6 @@ private: int mMaxTextureSize; DisplayInfo mDisplayInfo; - - // TODO(lpy) Replace below with android_ prefix types. - ui::Dataspace mTargetDataSpace; - ui::PixelFormat mTargetPixelFormat; }; } /* namespace uirenderer */ diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index e8bf4922cd46..d401b385075e 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -167,6 +167,12 @@ bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, mEglSurface = mEglManager.createSurface(surface, colorMode); } + if (colorMode == ColorMode::SRGB) { + mSurfaceColorType = SkColorType::kN32_SkColorType; + } else if (colorMode == ColorMode::WideColorGamut) { + mSurfaceColorType = SkColorType::kRGBA_F16_SkColorType; + } + if (mEglSurface != EGL_NO_SURFACE) { const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer); mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer); @@ -184,14 +190,6 @@ bool SkiaOpenGLPipeline::isContextReady() { return CC_LIKELY(mEglManager.hasEglContext()); } -SkColorType SkiaOpenGLPipeline::getSurfaceColorType() const { - return mEglManager.getSurfaceColorType(); -} - -sk_sp<SkColorSpace> SkiaOpenGLPipeline::getSurfaceColorSpace() { - return mEglManager.getSurfaceColorSpace(); -} - void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) { DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; if (thread.eglManager().hasEglContext()) { diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index 086a76088a75..4ab3541d447b 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -47,8 +47,6 @@ public: void onStop() override; bool isSurfaceReady() override; bool isContextReady() override; - SkColorType getSurfaceColorType() const override; - sk_sp<SkColorSpace> getSurfaceColorSpace() override; static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index ee9158c5ffc1..42a411a6808c 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -48,6 +48,9 @@ public: bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator, ErrorHandler* errorHandler) override; + SkColorType getSurfaceColorType() const { return mSurfaceColorType; } + sk_sp<SkColorSpace> getSurfaceColorSpace() override { return mSurfaceColorSpace; } + void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip, const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect& contentDrawBounds, sk_sp<SkSurface> surface); @@ -106,6 +109,8 @@ protected: void dumpResourceCacheUsage() const; renderthread::RenderThread& mRenderThread; + SkColorType mSurfaceColorType; + sk_sp<SkColorSpace> mSurfaceColorSpace; private: void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip, diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 4ef30fc6bebc..a2d811993f2f 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -137,14 +137,6 @@ bool SkiaVulkanPipeline::isContextReady() { return CC_LIKELY(mVkManager.hasVkContext()); } -SkColorType SkiaVulkanPipeline::getSurfaceColorType() const { - return mVkManager.getSurfaceColorType(); -} - -sk_sp<SkColorSpace> SkiaVulkanPipeline::getSurfaceColorSpace() { - return mVkManager.getSurfaceColorSpace(); -} - void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) { VkFunctorDrawable::vkInvokeFunctor(functor); } diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index 6e723a8373e1..14c0d69dba33 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -43,8 +43,6 @@ public: void onStop() override; bool isSurfaceReady() override; bool isContextReady() override; - SkColorType getSurfaceColorType() const override; - sk_sp<SkColorSpace> getSurfaceColorSpace() override; static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread, diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index c8c394a72541..92a749f3da33 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -144,8 +144,7 @@ void CanvasContext::setSurface(sp<Surface>&& surface) { mNativeSurface = std::move(surface); - // TODO(b/111436479) Introduce a way for app to specify DisplayColorGamut mode. - ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Legacy; + ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB; bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode); mFrameNumber = -1; diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 0cb23e532064..d4ffddde8def 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -126,17 +126,6 @@ void EglManager::initialize() { createContext(); createPBufferSurface(); makeCurrent(mPBufferSurface, nullptr, /* force */ true); - - mSurfaceColorGamut = DataSpaceToColorGamut( - static_cast<android_dataspace>(DeviceInfo::get()->getTargetDataSpace())); - - LOG_ALWAYS_FATAL_IF(mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut && - !EglExtensions.displayP3, "EGL doesn't support Display P3."); - - mSurfaceColorType = PixelFormatToColorType( - static_cast<android_pixel_format>(DeviceInfo::get()->getTargetPixelFormat())); - mSurfaceColorSpace = DataSpaceToColorSpace( - static_cast<android_dataspace>(DeviceInfo::get()->getTargetDataSpace())); } void EglManager::initExtensions() { @@ -309,21 +298,13 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window, ColorMode color if (wideColorGamut) { attribs[1] = EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT; } else { - if (mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut) { - attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_EXT; - } else { - attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR; - } + attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR; } #else if (wideColorGamut) { attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT; } else { - if (mSurfaceColorGamut == SkColorSpace::kDCIP3_D65_Gamut) { - attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_EXT; - } else { - attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; - } + attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; } #endif } diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h index e97228cd0a39..55c81d42d8a0 100644 --- a/libs/hwui/renderthread/EglManager.h +++ b/libs/hwui/renderthread/EglManager.h @@ -78,9 +78,6 @@ public: // Depending on installed extensions, the result is either Android native fence or EGL fence. status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, sp<Fence>& nativeFence); - SkColorType getSurfaceColorType() const { return mSurfaceColorType; } - sk_sp<SkColorSpace> getSurfaceColorSpace() { return mSurfaceColorSpace; } - private: void initExtensions(); @@ -95,9 +92,6 @@ private: EGLContext mEglContext; EGLSurface mPBufferSurface; EGLSurface mCurrentSurface; - SkColorSpace::Gamut mSurfaceColorGamut; - SkColorType mSurfaceColorType; - sk_sp<SkColorSpace> mSurfaceColorSpace; enum class SwapBehavior { Discard, diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index 0297c9c141ff..4972554c65cc 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -43,15 +43,8 @@ namespace renderthread { enum class MakeCurrentResult { AlreadyCurrent, Failed, Succeeded }; enum class ColorMode { - // Legacy means HWUI will produce buffer with whatever platform prefers - // HWUI to produce, however, HWUI doesn't accurately convert color from - // source color space to destination color space, instead HWUI will take - // the pixel value directly and interpret it destination color space. - Legacy, - // DisplayColorGamut means HWUI will produce buffer with whatever platform - // prefers HWUI to produce and accurately convert color from source color - // space to destination color space. - DisplayColorGamut, + // SRGB means HWUI will produce buffer in SRGB color space. + SRGB, // WideColorGamut means HWUI would support rendering scRGB non-linear into // a signed buffer with enough range to support the wide color gamut of the // display. diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h index e54eb6a0c5f1..7c59b6d340d2 100644 --- a/libs/hwui/renderthread/VulkanManager.h +++ b/libs/hwui/renderthread/VulkanManager.h @@ -120,10 +120,6 @@ public: // Creates a fence that is signaled, when all the pending Vulkan commands are flushed. status_t createReleaseFence(sp<Fence>& nativeFence); - // TODO(b/115636873): Handle composition preference. - SkColorType getSurfaceColorType() const { return SkColorType::kN32_SkColorType; } - sk_sp<SkColorSpace> getSurfaceColorSpace() { return SkColorSpace::MakeSRGB(); } - private: friend class RenderThread; diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index 680fcb3a732b..cdf31da37074 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -386,7 +386,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) { RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) { auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); EXPECT_FALSE(pipeline->isSurfaceReady()); - EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::Legacy)); + EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::SRGB)); EXPECT_TRUE(pipeline->isSurfaceReady()); renderThread.destroyGlContext(); EXPECT_FALSE(pipeline->isSurfaceReady()); diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index 9f71e91629fb..3fb6a31a7d97 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -57,21 +57,6 @@ bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace) { return false; } -SkColorType PixelFormatToColorType(android_pixel_format pixelFormat) { - switch (pixelFormat) { - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_BGRA_8888: - return SkColorType::kN32_SkColorType; - case HAL_PIXEL_FORMAT_RGBA_FP16: - return SkColorType::kRGBA_F16_SkColorType; - case HAL_PIXEL_FORMAT_RGBA_1010102: - return SkColorType::kRGBA_1010102_SkColorType; - default: - ALOGW("Unsupported pixel format: %d, return kN32 by default", pixelFormat); - return SkColorType::kN32_SkColorType; - } -} - android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) { switch (colorType) { case kRGBA_8888_SkColorType: @@ -92,30 +77,6 @@ android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) { } } -SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace) { - switch (dataSpace & HAL_DATASPACE_STANDARD_MASK) { - case HAL_DATASPACE_STANDARD_BT709: - return SkColorSpace::kSRGB_Gamut; - case HAL_DATASPACE_STANDARD_BT2020: - return SkColorSpace::kRec2020_Gamut; - case HAL_DATASPACE_STANDARD_DCI_P3: - return SkColorSpace::kDCIP3_D65_Gamut; - case HAL_DATASPACE_STANDARD_ADOBE_RGB: - return SkColorSpace::kAdobeRGB_Gamut; - case HAL_DATASPACE_STANDARD_UNSPECIFIED: - case HAL_DATASPACE_STANDARD_BT601_625: - case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED: - case HAL_DATASPACE_STANDARD_BT601_525: - case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED: - case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE: - case HAL_DATASPACE_STANDARD_BT470M: - case HAL_DATASPACE_STANDARD_FILM: - default: - ALOGW("Unsupported Gamut: %d, return SRGB gamut by default", dataSpace); - return SkColorSpace::kSRGB_Gamut; - } -} - sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) { SkColorSpace::Gamut gamut; diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h index e935a0d5ec8b..4daccda78e23 100644 --- a/libs/hwui/utils/Color.h +++ b/libs/hwui/utils/Color.h @@ -115,12 +115,8 @@ static constexpr float EOCF(float srgb) { // returns true for sRGB, gamma 2.2 and Display P3 for instance bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace); -SkColorType PixelFormatToColorType(android_pixel_format pixelFormat); - android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType); -SkColorSpace::Gamut DataSpaceToColorGamut(android_dataspace dataSpace); - sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace); struct Lab { diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index ed4da22f69e7..340f27950638 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -336,7 +336,7 @@ import java.util.Vector; * * <table border="0" cellspacing="0" cellpadding="0"> * <tr><td>Method Name </p></td> - * <td>Valid Sates </p></td> + * <td>Valid States </p></td> * <td>Invalid States </p></td> * <td>Comments </p></td></tr> * <tr><td>attachAuxEffect </p></td> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 332ced66ef77..508adbd2a121 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1116,4 +1116,6 @@ <!-- time label for event have that happened very recently [CHAR LIMIT=60] --> <string name="time_unit_just_now">Just now</string> - </resources> + <!-- The notice header of Third-party licenses. not translatable --> + <string name="notice_header" translatable="false"></string> +</resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java index 42306f6d46d0..9db4a35c1d78 100644 --- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java +++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java @@ -46,7 +46,7 @@ import java.util.zip.GZIPInputStream; * TODO: Remove duplicate codes once backward support ends. */ class LicenseHtmlGeneratorFromXml { - private static final String TAG = "LicenseHtmlGeneratorFromXml"; + private static final String TAG = "LicenseGeneratorFromXml"; private static final String TAG_ROOT = "licenses"; private static final String TAG_FILE_NAME = "file-name"; @@ -107,12 +107,13 @@ class LicenseHtmlGeneratorFromXml { mXmlFiles = xmlFiles; } - public static boolean generateHtml(List<File> xmlFiles, File outputFile) { + public static boolean generateHtml(List<File> xmlFiles, File outputFile, + String noticeHeader) { LicenseHtmlGeneratorFromXml genertor = new LicenseHtmlGeneratorFromXml(xmlFiles); - return genertor.generateHtml(outputFile); + return genertor.generateHtml(outputFile, noticeHeader); } - private boolean generateHtml(File outputFile) { + private boolean generateHtml(File outputFile, String noticeHeader) { for (File xmlFile : mXmlFiles) { parse(xmlFile); } @@ -125,7 +126,8 @@ class LicenseHtmlGeneratorFromXml { try { writer = new PrintWriter(outputFile); - generateHtml(mFileNameToContentIdMap, mContentIdToFileContentMap, writer); + generateHtml(mFileNameToContentIdMap, mContentIdToFileContentMap, writer, + noticeHeader); writer.flush(); writer.close(); @@ -239,13 +241,18 @@ class LicenseHtmlGeneratorFromXml { @VisibleForTesting static void generateHtml(Map<String, String> fileNameToContentIdMap, - Map<String, String> contentIdToFileContentMap, PrintWriter writer) { + Map<String, String> contentIdToFileContentMap, PrintWriter writer, + String noticeHeader) { List<String> fileNameList = new ArrayList(); fileNameList.addAll(fileNameToContentIdMap.keySet()); Collections.sort(fileNameList); writer.println(HTML_HEAD_STRING); + if (!TextUtils.isEmpty(noticeHeader)) { + writer.println(noticeHeader); + } + int count = 0; Map<String, Integer> contentIdToOrderMap = new HashMap(); List<ContentIdAndFileNames> contentIdAndFileNamesList = new ArrayList(); diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java index 393006940740..78e807cf1a1c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java +++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoader.java @@ -60,7 +60,7 @@ public class LicenseHtmlLoader extends AsyncLoader<File> { File cachedHtmlFile = getCachedHtmlFile(mContext); if (!isCachedHtmlFileOutdated(xmlFiles, cachedHtmlFile) - || generateHtmlFile(xmlFiles, cachedHtmlFile)) { + || generateHtmlFile(mContext, xmlFiles, cachedHtmlFile)) { return cachedHtmlFile; } diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java index 360c19c2b795..ca6248505dc0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java +++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java @@ -19,6 +19,7 @@ package com.android.settingslib.license; import android.content.Context; import android.util.Log; +import com.android.settingslib.R; import com.android.settingslib.utils.AsyncLoaderCompat; import java.io.File; @@ -65,7 +66,7 @@ public class LicenseHtmlLoaderCompat extends AsyncLoaderCompat<File> { File cachedHtmlFile = getCachedHtmlFile(mContext); if (!isCachedHtmlFileOutdated(xmlFiles, cachedHtmlFile) - || generateHtmlFile(xmlFiles, cachedHtmlFile)) { + || generateHtmlFile(mContext, xmlFiles, cachedHtmlFile)) { return cachedHtmlFile; } @@ -101,7 +102,8 @@ public class LicenseHtmlLoaderCompat extends AsyncLoaderCompat<File> { return outdated; } - static boolean generateHtmlFile(List<File> xmlFiles, File htmlFile) { - return LicenseHtmlGeneratorFromXml.generateHtml(xmlFiles, htmlFile); + static boolean generateHtmlFile(Context context, List<File> xmlFiles, File htmlFile) { + return LicenseHtmlGeneratorFromXml.generateHtml(xmlFiles, htmlFile, + context.getString(R.string.notice_header)); } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java index 96b2a1433f53..b00476b24921 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java @@ -50,7 +50,7 @@ public class LicenseHtmlGeneratorFromXmlTest { + "<file-content contentId=\"0\"><![CDATA[license content #0]]></file-content>\n" + "</licenses2>"; - private static final String EXPECTED_HTML_STRING = + private static final String HTML_HEAD_STRING = "<html><head>\n" + "<style type=\"text/css\">\n" + "body { padding: 0; font-family: sans-serif; }\n" @@ -63,8 +63,12 @@ public class LicenseHtmlGeneratorFromXmlTest { + "</head>" + "<body topmargin=\"0\" leftmargin=\"0\" rightmargin=\"0\" bottommargin=\"0\">\n" + "<div class=\"toc\">\n" - + "<ul>\n" - + "<li><a href=\"#id0\">/file0</a></li>\n" + + "<ul>\n"; + + private static final String HTML_CUSTOM_HEADING = "Custom heading"; + + private static final String HTML_BODY_STRING = + "<li><a href=\"#id0\">/file0</a></li>\n" + "<li><a href=\"#id0\">/file1</a></li>\n" + "</ul>\n" + "</div><!-- table of contents -->\n" @@ -81,6 +85,11 @@ public class LicenseHtmlGeneratorFromXmlTest { + "</td></tr><!-- same-license -->\n" + "</table></body></html>\n"; + private static final String EXPECTED_HTML_STRING = HTML_HEAD_STRING + HTML_BODY_STRING; + + private static final String EXPECTED_HTML_STRING_WITH_CUSTOM_HEADING = + HTML_HEAD_STRING + HTML_CUSTOM_HEADING + "\n" + HTML_BODY_STRING; + @Test public void testParseValidXmlStream() throws XmlPullParserException, IOException { Map<String, String> fileNameToContentIdMap = new HashMap<String, String>(); @@ -117,7 +126,23 @@ public class LicenseHtmlGeneratorFromXmlTest { StringWriter output = new StringWriter(); LicenseHtmlGeneratorFromXml.generateHtml( - fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output)); + fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output), ""); assertThat(output.toString()).isEqualTo(EXPECTED_HTML_STRING); } + + @Test + public void testGenerateHtmlWithCustomHeading() { + Map<String, String> fileNameToContentIdMap = new HashMap<String, String>(); + Map<String, String> contentIdToFileContentMap = new HashMap<String, String>(); + + fileNameToContentIdMap.put("/file0", "0"); + fileNameToContentIdMap.put("/file1", "0"); + contentIdToFileContentMap.put("0", "license content #0"); + + StringWriter output = new StringWriter(); + LicenseHtmlGeneratorFromXml.generateHtml( + fileNameToContentIdMap, contentIdToFileContentMap, new PrintWriter(output), + HTML_CUSTOM_HEADING); + assertThat(output.toString()).isEqualTo(EXPECTED_HTML_STRING_WITH_CUSTOM_HEADING); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java index 12a4e699fb76..c32cc99daf96 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java @@ -142,7 +142,7 @@ public class LicenseHtmlLoaderCompatTest { } @Implementation - static boolean generateHtmlFile(List<File> xmlFiles, File htmlFile) { + static boolean generateHtmlFile(Context context, List<File> xmlFiles, File htmlFile) { return sGenerateHtmlFileSucceeded; } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java index 36fb3a7b4307..7154f5396fbd 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java @@ -21,6 +21,8 @@ import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LE import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import android.app.ActivityOptions; +import android.content.Context; +import android.os.Handler; /** * Wrapper around internal ActivityOptions creation. @@ -43,4 +45,17 @@ public abstract class ActivityOptionsCompat { RemoteAnimationAdapterCompat remoteAnimationAdapter) { return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter.getWrapped()); } + + public static ActivityOptions makeCustomAnimation(Context context, int enterResId, + int exitResId, final Runnable callback, final Handler callbackHandler) { + return ActivityOptions.makeCustomAnimation(context, enterResId, exitResId, callbackHandler, + new ActivityOptions.OnAnimationStartedListener() { + @Override + public void onAnimationStarted() { + if (callback != null) { + callbackHandler.post(callback); + } + } + }); + } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index e6026c14cd28..21b21d9f5527 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -44,7 +44,7 @@ public class DozeLog { public static final int PULSE_REASON_SENSOR_PICKUP = 3; public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4; public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5; - public static final int PULSE_REASON_SENSOR_REACH = 6; + public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 6; public static final int REASON_SENSOR_WAKE_UP = 7; private static boolean sRegisterKeyguardCallback = true; @@ -177,9 +177,9 @@ public class DozeLog { log("state " + state); } - public static void traceReachWakeUp() { + public static void traceWakeLockScreenWakeUp() { if (!ENABLED) return; - log("reachWakeUp"); + log("wakeLockScreenWakeUp"); } public static void traceProximityResult(Context context, boolean near, long millis, @@ -199,7 +199,7 @@ public class DozeLog { case PULSE_REASON_SENSOR_PICKUP: return "pickup"; case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap"; case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress"; - case PULSE_REASON_SENSOR_REACH: return "reach"; + case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakeLockScreen"; case REASON_SENSOR_WAKE_UP: return "wakeup"; default: throw new IllegalArgumentException("bad reason: " + pulseReason); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index f9dfb5d10403..701394763fbd 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -113,10 +113,10 @@ public class DozeSensors { true /* reports touch coordinates */, true /* touchscreen */), new TriggerSensor( - findSensorWithType(config.reachSensorType()), - Settings.Secure.DOZE_REACH_GESTURE, + findSensorWithType(config.wakeLockScreenSensorType()), + Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, true /* configured */, - DozeLog.PULSE_REASON_SENSOR_REACH, + DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, false /* reports touch coordinates */, false /* touchscreen */), new WakeScreenSensor(), diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 31548b93ea60..cb91d7815be5 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -128,7 +128,7 @@ public class DozeTriggers implements DozeMachine.Part { boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP; boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP; boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS; - boolean isReach = pulseReason == DozeLog.PULSE_REASON_SENSOR_REACH; + boolean isWakeLockScreen = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN; if (isLongPress) { requestPulse(pulseReason, sensorPerformedProxCheck); @@ -141,7 +141,7 @@ public class DozeTriggers implements DozeMachine.Part { if (isDoubleTap) { mDozeHost.onDoubleTap(screenX, screenY); mMachine.wakeUp(); - } else if (isPickup || isReach) { + } else if (isPickup || isWakeLockScreen) { mMachine.wakeUp(); } else { mDozeHost.extendPulse(); @@ -156,8 +156,8 @@ public class DozeTriggers implements DozeMachine.Part { final boolean withinVibrationThreshold = timeSinceNotification < mDozeParameters.getPickupVibrationThreshold(); DozeLog.tracePickupWakeUp(mContext, withinVibrationThreshold); - } else if (isReach) { - DozeLog.traceReachWakeUp(); + } else if (isWakeLockScreen) { + DozeLog.traceWakeLockScreenWakeUp(); } } diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index 90c10fdcbfde..39472955dfa8 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -6447,7 +6447,7 @@ message MetricsEvent { // OPEN: Settings > System > Input & Gesture > Reach up gesture // OS: Q - SETTINGS_GESTURE_REACH = 1557; + SETTINGS_GESTURE_WAKE_LOCK_SCREEN = 1557; // OPEN: Emergency dialer opened // CLOSE: Emergency dialer closed diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index d505a77c9192..21f54dd33d3e 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -329,6 +329,12 @@ class StorageManagerService extends IStorageManager.Stub @GuardedBy("mPackagesLock") private final SparseArray<String> mSandboxIds = new SparseArray<>(); + /** + * List of volumes visible to any user. + * TODO: may be have a map of userId -> volumes? + */ + private final CopyOnWriteArrayList<VolumeInfo> mVisibleVols = new CopyOnWriteArrayList<>(); + private volatile int mCurrentUserId = UserHandle.USER_SYSTEM; /** Holding lock for AppFuse business */ @@ -623,16 +629,12 @@ class StorageManagerService extends IStorageManager.Stub Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy"); break; } - try { - mVold.mount(vol.id, vol.mountFlags, vol.mountUserId); - } catch (Exception e) { - Slog.wtf(TAG, e); - } + mount(vol); break; } case H_VOLUME_UNMOUNT: { final VolumeInfo vol = (VolumeInfo) msg.obj; - unmount(vol.getId()); + unmount(vol); break; } case H_VOLUME_BROADCAST: { @@ -869,6 +871,8 @@ class StorageManagerService extends IStorageManager.Stub addInternalVolumeLocked(); } + mVisibleVols.clear(); + try { mVold.reset(); @@ -1466,7 +1470,7 @@ class StorageManagerService extends IStorageManager.Stub = mContext.getPackageManager().getInstalledApplicationsAsUser( PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); synchronized (mPackagesLock) { - final ArraySet<String> userPackages = getPackagesForUserPL(userId); + final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId); for (int i = appInfos.size() - 1; i >= 0; --i) { if (appInfos.get(i).isInstantApp()) { continue; @@ -1523,7 +1527,7 @@ class StorageManagerService extends IStorageManager.Stub } @GuardedBy("mPackagesLock") - private ArraySet<String> getPackagesForUserPL(int userId) { + private ArraySet<String> getAvailablePackagesForUserPL(int userId) { ArraySet<String> userPackages = mPackages.get(userId); if (userPackages == null) { userPackages = new ArraySet<>(); @@ -1535,8 +1539,24 @@ class StorageManagerService extends IStorageManager.Stub private String[] getPackagesArrayForUser(int userId) { if (!ENABLE_ISOLATED_STORAGE) return EmptyArray.STRING; + final ArraySet<String> userPackages; synchronized (mPackagesLock) { - return getPackagesForUserPL(userId).toArray(new String[0]); + userPackages = getAvailablePackagesForUserPL(userId); + if (!userPackages.isEmpty()) { + return userPackages.toArray(new String[0]); + } + } + final List<ApplicationInfo> appInfos = + mContext.getPackageManager().getInstalledApplicationsAsUser( + PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); + synchronized (mPackagesLock) { + for (int i = appInfos.size() - 1; i >= 0; --i) { + if (appInfos.get(i).isInstantApp()) { + continue; + } + userPackages.add(appInfos.get(i).packageName); + } + return userPackages.toArray(new String[0]); } } @@ -1747,8 +1767,15 @@ class StorageManagerService extends IStorageManager.Stub if (isMountDisallowed(vol)) { throw new SecurityException("Mounting " + volId + " restricted by policy"); } + mount(vol); + } + + private void mount(VolumeInfo vol) { try { mVold.mount(vol.id, vol.mountFlags, vol.mountUserId); + if ((vol.mountFlags & VolumeInfo.MOUNT_FLAG_VISIBLE) != 0) { + mVisibleVols.add(vol); + } } catch (Exception e) { Slog.wtf(TAG, e); } @@ -1759,8 +1786,15 @@ class StorageManagerService extends IStorageManager.Stub enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); final VolumeInfo vol = findVolumeByIdOrThrow(volId); + unmount(vol); + } + + private void unmount(VolumeInfo vol) { try { mVold.unmount(vol.id); + if ((vol.mountFlags & VolumeInfo.MOUNT_FLAG_VISIBLE) != 0) { + mVisibleVols.remove(vol); + } } catch (Exception e) { Slog.wtf(TAG, e); } @@ -3596,6 +3630,14 @@ class StorageManagerService extends IStorageManager.Stub pw.decreaseIndent(); pw.println(); + pw.println("mVisibleVols:"); + pw.increaseIndent(); + for (int i = 0; i < mVisibleVols.size(); i++) { + mVisibleVols.get(i).dump(pw); + } + pw.decreaseIndent(); + + pw.println(); pw.println("Primary storage UUID: " + mPrimaryStorageUuid); final Pair<String, Long> pair = StorageManager.getPrimaryStoragePathAndSize(); if (pair == null) { @@ -3716,7 +3758,7 @@ class StorageManagerService extends IStorageManager.Stub int userId) { final String sandboxId; synchronized (mPackagesLock) { - final ArraySet<String> userPackages = getPackagesForUserPL(userId); + final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId); // If userPackages is empty, it means the user is not started yet, so no need to // do anything now. if (userPackages.isEmpty() || userPackages.contains(packageName)) { @@ -3734,5 +3776,29 @@ class StorageManagerService extends IStorageManager.Stub Slog.wtf(TAG, e); } } + + @Override + public String[] getVisibleVolumesForUser(int userId) { + final ArrayList<String> visibleVolsForUser = new ArrayList<>(); + for (int i = mVisibleVols.size() - 1; i >= 0; --i) { + final VolumeInfo vol = mVisibleVols.get(i); + if (vol.isVisibleForUser(userId)) { + visibleVolsForUser.add(getVolumeLabel(vol)); + } + } + return visibleVolsForUser.toArray(new String[visibleVolsForUser.size()]); + } + + private String getVolumeLabel(VolumeInfo vol) { + // STOPSHIP: Label needs to part of VolumeInfo and need to be passed on from vold + switch (vol.getType()) { + case VolumeInfo.TYPE_EMULATED: + return "emulated"; + case VolumeInfo.TYPE_PUBLIC: + return vol.fsUuid == null ? vol.id : vol.fsUuid; + default: + return null; + } + } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2fd699e5a829..d670bf1b387c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -368,7 +368,6 @@ import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; import java.io.UnsupportedEncodingException; -import java.lang.ref.WeakReference; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -3538,6 +3537,9 @@ public class ActivityManagerService extends IActivityManager.Stub String seInfo, String requiredAbi, String instructionSet, String invokeWith, long startTime) { try { + final String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); + final String[] visibleVolIds = LocalServices.getService(StorageManagerInternal.class) + .getVisibleVolumesForUser(UserHandle.getUserId(uid)); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " + app.processName); checkTime(startTime, "startProcess: asking zygote to start proc"); @@ -3547,12 +3549,14 @@ public class ActivityManagerService extends IActivityManager.Stub app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, + packageNames, visibleVolIds, new String[] {PROC_START_SEQ_IDENT + app.startSeq}); } else { startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, app.info.packageName, + packageNames, visibleVolIds, new String[] {PROC_START_SEQ_IDENT + app.startSeq}); } checkTime(startTime, "startProcess: returned from zygote!"); diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java index add9f2a7e9d8..36261b505a94 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java @@ -1960,10 +1960,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId); if (task == null) { Slog.d(TAG, "Could not find task for id: "+ taskId); + SafeActivityOptions.abort(options); return; } if (getLockTaskController().isLockTaskModeViolation(task)) { Slog.e(TAG, "moveTaskToFront: Attempt to violate Lock Task Mode"); + SafeActivityOptions.abort(options); return; } ActivityOptions realOptions = options != null @@ -1983,7 +1985,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } finally { Binder.restoreCallingIdentity(origId); } - SafeActivityOptions.abort(options); } boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid, diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e10827bc6101..10980b79f1f4 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -16004,7 +16004,8 @@ public class PackageManagerService extends IPackageManager.Stub } if (apkPath != null) { final VerityUtils.SetupResult result = - VerityUtils.generateApkVeritySetupData(apkPath); + VerityUtils.generateApkVeritySetupData(apkPath, null /* signaturePath */, + true /* skipSigningBlock */); if (result.isOk()) { if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling apk verity to " + apkPath); FileDescriptor fd = result.getUnownedFileDescriptor(); diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java index 9f69702911c9..37966108fe64 100644 --- a/services/core/java/com/android/server/security/VerityUtils.java +++ b/services/core/java/com/android/server/security/VerityUtils.java @@ -26,42 +26,76 @@ import android.system.Os; import android.util.Pair; import android.util.Slog; import android.util.apk.ApkSignatureVerifier; +import android.util.apk.ApkVerityBuilder; import android.util.apk.ByteBufferFactory; import android.util.apk.SignatureNotFoundException; +import libcore.util.HexEncoding; + import java.io.FileDescriptor; import java.io.IOException; +import java.io.RandomAccessFile; import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.security.DigestException; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import sun.security.pkcs.PKCS7; + /** Provides fsverity related operations. */ abstract public class VerityUtils { private static final String TAG = "VerityUtils"; + /** The maximum size of signature file. This is just to avoid potential abuse. */ + private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192; + private static final boolean DEBUG = false; /** - * Generates Merkle tree and fsverity metadata. + * Generates Merkle tree and fs-verity metadata. * - * @return {@code SetupResult} that contains the {@code EsetupResultCode}, and when success, the + * @return {@code SetupResult} that contains the result code, and when success, the * {@code FileDescriptor} to read all the data from. */ - public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) { - if (DEBUG) Slog.d(TAG, "Trying to install apk verity to " + apkPath); + public static SetupResult generateApkVeritySetupData(@NonNull String apkPath, + String signaturePath, boolean skipSigningBlock) { + if (DEBUG) { + Slog.d(TAG, "Trying to install apk verity to " + apkPath + " with signature file " + + signaturePath); + } SharedMemory shm = null; try { - byte[] signedRootHash = ApkSignatureVerifier.getVerityRootHash(apkPath); - if (signedRootHash == null) { + byte[] signedVerityHash; + if (skipSigningBlock) { + signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath); + } else { + Path path = Paths.get(signaturePath); + if (Files.exists(path)) { + // TODO(112037636): fail early if the signing key is not in .fs-verity keyring. + PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(path)); + signedVerityHash = pkcs7.getContentInfo().getContentBytes(); + if (DEBUG) { + Slog.d(TAG, "fs-verity measurement = " + bytesToString(signedVerityHash)); + } + } else { + signedVerityHash = null; + } + } + + if (signedVerityHash == null) { if (DEBUG) { - Slog.d(TAG, "Skip verity tree generation since there is no root hash"); + Slog.d(TAG, "Skip verity tree generation since there is no signed root hash"); } return SetupResult.skipped(); } - Pair<SharedMemory, Integer> result = generateApkVerityIntoSharedMemory(apkPath, - signedRootHash); + Pair<SharedMemory, Integer> result = generateFsVerityIntoSharedMemory(apkPath, + signaturePath, signedVerityHash, skipSigningBlock); shm = result.first; int contentSize = result.second; FileDescriptor rfd = shm.getFileDescriptor(); @@ -97,22 +131,114 @@ abstract public class VerityUtils { } /** + * Generates fs-verity metadata for {@code filePath} in the buffer created by {@code + * trackedBufferFactory}. The metadata contains the Merkle tree, fs-verity descriptor and + * extensions, including a PKCS#7 signature provided in {@code signaturePath}. + * + * <p>It is worthy to note that {@code trackedBufferFactory} generates a "tracked" {@code + * ByteBuffer}. The data will be used outside this method via the factory itself. + * + * @return fs-verity measurement of {@code filePath}, which is a SHA-256 of fs-verity descriptor + * and authenticated extensions. + */ + private static byte[] generateFsverityMetadata(String filePath, String signaturePath, + @NonNull TrackedShmBufferFactory trackedBufferFactory) + throws IOException, SignatureNotFoundException, SecurityException, DigestException, + NoSuchAlgorithmException { + try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) { + ApkVerityBuilder.ApkVerityResult result = ApkVerityBuilder.generateFsVerityTree( + file, trackedBufferFactory); + + ByteBuffer buffer = result.verityData; + buffer.position(result.merkleTreeSize); + return generateFsverityDescriptorAndMeasurement(file, result.rootHash, signaturePath, + buffer); + } + } + + /** + * Generates fs-verity descriptor including the extensions to the {@code output} and returns the + * fs-verity measurement. + * + * @return fs-verity measurement, which is a SHA-256 of fs-verity descriptor and authenticated + * extensions. + */ + private static byte[] generateFsverityDescriptorAndMeasurement( + @NonNull RandomAccessFile file, @NonNull byte[] rootHash, + @NonNull String pkcs7SignaturePath, @NonNull ByteBuffer output) + throws IOException, NoSuchAlgorithmException, DigestException { + final short kRootHashExtensionId = 1; + final short kPkcs7SignatureExtensionId = 3; + final int origPosition = output.position(); + + // For generating fs-verity file measurement, which consists of the descriptor and + // authenticated extensions (but not unauthenticated extensions and the footer). + MessageDigest md = MessageDigest.getInstance("SHA-256"); + + // 1. Generate fs-verity descriptor. + final byte[] desc = constructFsverityDescriptorNative(file.length()); + output.put(desc); + md.update(desc); + + // 2. Generate authenticated extensions. + final byte[] authExt = + constructFsverityExtensionNative(kRootHashExtensionId, rootHash.length); + output.put(authExt); + output.put(rootHash); + md.update(authExt); + md.update(rootHash); + + // 3. Generate unauthenticated extensions. + ByteBuffer header = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN); + output.putShort((short) 1); // number of unauthenticated extensions below + output.position(output.position() + 6); + + // Generate PKCS#7 extension. NB: We do not verify agaist trusted certificate (should be + // done by the caller if needed). + Path path = Paths.get(pkcs7SignaturePath); + if (Files.size(path) > MAX_SIGNATURE_FILE_SIZE_BYTES) { + throw new IllegalArgumentException("Signature size is unexpectedly large: " + + pkcs7SignaturePath); + } + final byte[] pkcs7Signature = Files.readAllBytes(path); + output.put(constructFsverityExtensionNative(kPkcs7SignatureExtensionId, + pkcs7Signature.length)); + output.put(pkcs7Signature); + + // 4. Generate the footer. + output.put(constructFsverityFooterNative(output.position() - origPosition)); + + return md.digest(); + } + + private static native byte[] constructFsverityDescriptorNative(long fileSize); + private static native byte[] constructFsverityExtensionNative(short extensionId, + int extensionDataSize); + private static native byte[] constructFsverityFooterNative(int offsetToDescriptorHead); + + /** * Returns a pair of {@code SharedMemory} and {@code Integer}. The {@code SharedMemory} contains * Merkle tree and fsverity headers for the given apk, in the form that can immediately be used * for fsverity setup. The data is aligned to the beginning of {@code SharedMemory}, and has * length equals to the returned {@code Integer}. */ - private static Pair<SharedMemory, Integer> generateApkVerityIntoSharedMemory( - String apkPath, byte[] expectedRootHash) + private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory( + String apkPath, String signaturePath, @NonNull byte[] expectedRootHash, + boolean skipSigningBlock) throws IOException, SecurityException, DigestException, NoSuchAlgorithmException, SignatureNotFoundException { TrackedShmBufferFactory shmBufferFactory = new TrackedShmBufferFactory(); - byte[] generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, - shmBufferFactory); + byte[] generatedRootHash; + if (skipSigningBlock) { + generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory); + } else { + generatedRootHash = generateFsverityMetadata(apkPath, signaturePath, shmBufferFactory); + } // We only generate Merkle tree once here, so it's important to make sure the root hash // matches the signed one in the apk. if (!Arrays.equals(expectedRootHash, generatedRootHash)) { - throw new SecurityException("Locally generated verity root hash does not match"); + throw new SecurityException("verity hash mismatch: " + + bytesToString(generatedRootHash) + " != " + bytesToString(expectedRootHash)); } int contentSize = shmBufferFactory.getBufferLimit(); @@ -126,11 +252,15 @@ abstract public class VerityUtils { return Pair.create(shm, contentSize); } + private static String bytesToString(byte[] bytes) { + return HexEncoding.encodeToString(bytes); + } + public static class SetupResult { /** Result code if verity is set up correctly. */ private static final int RESULT_OK = 1; - /** Result code if the apk does not contain a verity root hash. */ + /** Result code if signature is not provided. */ private static final int RESULT_SKIPPED = 2; /** Result code if the setup failed. */ diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index becde7311607..061f8e2ba0fb 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -37,6 +37,7 @@ cc_library_static { "com_android_server_locksettings_SyntheticPasswordManager.cpp", "com_android_server_net_NetworkStatsService.cpp", "com_android_server_power_PowerManagerService.cpp", + "com_android_server_security_VerityUtils.cpp", "com_android_server_SerialService.cpp", "com_android_server_storage_AppFuseBridge.cpp", "com_android_server_SystemServer.cpp", diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp new file mode 100644 index 000000000000..d0f173b572c8 --- /dev/null +++ b/services/core/jni/com_android_server_security_VerityUtils.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "VerityUtils" + +#include <nativehelper/JNIHelp.h> +#include "jni.h" +#include <utils/Log.h> + +#include <string.h> + +// TODO(112037636): Always include once fsverity.h is upstreamed and backported. +#define HAS_FSVERITY 0 + +#if HAS_FSVERITY +#include <linux/fsverity.h> +#endif + +namespace android { + +namespace { + +class JavaByteArrayHolder { + public: + static JavaByteArrayHolder* newArray(JNIEnv* env, jsize size) { + return new JavaByteArrayHolder(env, size); + } + + jbyte* getRaw() { + return mElements; + } + + jbyteArray release() { + mEnv->ReleaseByteArrayElements(mBytes, mElements, 0); + mElements = nullptr; + return mBytes; + } + + private: + JavaByteArrayHolder(JNIEnv* env, jsize size) { + mEnv = env; + mBytes = mEnv->NewByteArray(size); + mElements = mEnv->GetByteArrayElements(mBytes, nullptr); + memset(mElements, 0, size); + } + + virtual ~JavaByteArrayHolder() { + LOG_ALWAYS_FATAL_IF(mElements == nullptr, "Elements are not released"); + } + + JNIEnv* mEnv; + jbyteArray mBytes; + jbyte* mElements; +}; + +jbyteArray constructFsverityDescriptor(JNIEnv* env, jobject /* clazz */, jlong fileSize) { +#if HAS_FSVERITY + auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_descriptor)); + fsverity_descriptor* desc = reinterpret_cast<fsverity_descriptor*>(raii->getRaw()); + + memcpy(desc->magic, FS_VERITY_MAGIC, sizeof(desc->magic)); + desc->major_version = 1; + desc->minor_version = 0; + desc->log_data_blocksize = 12; + desc->log_tree_blocksize = 12; + desc->data_algorithm = FS_VERITY_ALG_SHA256; + desc->tree_algorithm = FS_VERITY_ALG_SHA256; + desc->flags = 0; + desc->orig_file_size = fileSize; + desc->auth_ext_count = 1; + + return raii->release(); +#else + LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); + return 0; +#endif // HAS_FSVERITY +} + +jbyteArray constructFsverityExtension(JNIEnv* env, jobject /* clazz */, jshort extensionId, + jint extensionDataSize) { +#if HAS_FSVERITY + auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_extension)); + fsverity_extension* ext = reinterpret_cast<fsverity_extension*>(raii->getRaw()); + + ext->length = sizeof(fsverity_extension) + extensionDataSize; + ext->type = extensionId; + + return raii->release(); +#else + LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); + return 0; +#endif // HAS_FSVERITY +} + +jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */, + jint offsetToDescriptorHead) { +#if HAS_FSVERITY + auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_footer)); + fsverity_footer* footer = reinterpret_cast<fsverity_footer*>(raii->getRaw()); + + footer->desc_reverse_offset = offsetToDescriptorHead + sizeof(fsverity_footer); + memcpy(footer->magic, FS_VERITY_MAGIC, sizeof(footer->magic)); + + return raii->release(); +#else + LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); + return 0; +#endif // HAS_FSVERITY +} + +const JNINativeMethod sMethods[] = { + { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor }, + { "constructFsverityExtensionNative", "(SI)[B", (void *)constructFsverityExtension }, + { "constructFsverityFooterNative", "(I)[B", (void *)constructFsverityFooter }, +}; + +} // namespace + +int register_android_server_security_VerityUtils(JNIEnv* env) { + return jniRegisterNativeMethods(env, + "com/android/server/security/VerityUtils", sMethods, NELEM(sMethods)); +} + +} // namespace android diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index bb6e6840f3b4..918f57e2945e 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -54,6 +54,7 @@ int register_android_server_SyntheticPasswordManager(JNIEnv* env); int register_android_server_GraphicsStatsService(JNIEnv* env); int register_android_hardware_display_DisplayViewport(JNIEnv* env); int register_android_server_net_NetworkStatsService(JNIEnv* env); +int register_android_server_security_VerityUtils(JNIEnv* env); }; using namespace android; @@ -101,5 +102,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_GraphicsStatsService(env); register_android_hardware_display_DisplayViewport(env); register_android_server_net_NetworkStatsService(env); + register_android_server_security_VerityUtils(env); return JNI_VERSION_1_4; } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 38ee79f06690..d1091f489f14 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2153,7 +2153,12 @@ public class SubscriptionManager { /** * Set preferred default data. - * Set on which slot default data will be on. + * Set on which slot most cellular data will be on. + * It's also usually what we set up internet connection on. + * + * PreferredData overwrites user setting of default data subscription. And it's used + * by ANAS or carrier apps to switch primary and CBRS subscription dynamically in multi-SIM + * devices. * * @param slotId which slot is preferred to for cellular data. * @hide diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index 934847f6eec2..91cd1cba964d 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -492,6 +492,7 @@ def verify_parcelable(clazz): def verify_protected(clazz): """Verify that no protected methods or fields are allowed.""" for m in clazz.methods: + if m.name == "finalize": continue if "protected" in m.split: error(clazz, m, "M7", "Protected methods not allowed; must be public") for f in clazz.fields: @@ -1025,6 +1026,10 @@ def verify_resource_names(clazz): # Resources defined by files are foo_bar_baz if clazz.name in ["anim","animator","color","dimen","drawable","interpolator","layout","transition","menu","mipmap","string","plurals","raw","xml"]: for f in clazz.fields: + if re.match("config_[a-z][a-zA-Z1-9]*$", f.name): continue + if f.name.startswith("config_"): + error(clazz, f, None, "Expected config name to be config_fooBarBaz style") + if re.match("[a-z1-9_]+$", f.name): continue error(clazz, f, None, "Expected resource name in this class to be foo_bar_baz style") @@ -1361,6 +1366,60 @@ def verify_clone(clazz): error(clazz, m, None, "Provide an explicit copy constructor instead of implementing clone()") +def verify_pfd(clazz): + """Verify that android APIs use PFD over FD.""" + examine = clazz.ctors + clazz.methods + for m in examine: + if m.typ == "java.io.FileDescriptor": + error(clazz, m, "FW11", "Must use ParcelFileDescriptor") + if m.typ == "int": + if "Fd" in m.name or "FD" in m.name or "FileDescriptor" in m.name: + error(clazz, m, "FW11", "Must use ParcelFileDescriptor") + for arg in m.args: + if arg == "java.io.FileDescriptor": + error(clazz, m, "FW11", "Must use ParcelFileDescriptor") + + for f in clazz.fields: + if f.typ == "java.io.FileDescriptor": + error(clazz, f, "FW11", "Must use ParcelFileDescriptor") + + +def verify_numbers(clazz): + """Discourage small numbers types like short and byte.""" + + discouraged = ["short","byte"] + + for c in clazz.ctors: + for arg in c.args: + if arg in discouraged: + warn(clazz, c, "FW12", "Should avoid odd sized primitives; use int instead") + + for f in clazz.fields: + if f.typ in discouraged: + warn(clazz, f, "FW12", "Should avoid odd sized primitives; use int instead") + + for m in clazz.methods: + if m.typ in discouraged: + warn(clazz, m, "FW12", "Should avoid odd sized primitives; use int instead") + for arg in m.args: + if arg in discouraged: + warn(clazz, m, "FW12", "Should avoid odd sized primitives; use int instead") + + +def verify_singleton(clazz): + """Catch singleton objects with constructors.""" + + singleton = False + for m in clazz.methods: + if m.name.startswith("get") and m.name.endswith("Instance") and " static " in m.raw: + singleton = True + + if singleton: + for c in clazz.ctors: + error(clazz, c, None, "Singleton classes should use getInstance() methods") + + + def is_interesting(clazz): """Test if given class is interesting from an Android PoV.""" @@ -1431,6 +1490,9 @@ def examine_clazz(clazz): verify_tense(clazz) verify_icu(clazz) verify_clone(clazz) + verify_pfd(clazz) + verify_numbers(clazz) + verify_singleton(clazz) def examine_stream(stream): diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index 991547916919..56c842805190 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -234,9 +234,11 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, } } } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", const std::map<int, int64_t>& arg%d_1, " - "const std::map<int, char const*>& arg%d_2, " - "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex); + fprintf(out, ", const std::map<int, int32_t>& arg%d_1, " + "const std::map<int, int64_t>& arg%d_2, " + "const std::map<int, char const*>& arg%d_3, " + "const std::map<int, float>& arg%d_4", + argIndex, argIndex, argIndex, argIndex); } else { fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); } @@ -302,6 +304,13 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, " event.end();\n"); fprintf(out, " }\n"); + fprintf(out, " for (const auto& it : arg%d_4) {\n", argIndex); + fprintf(out, " event.begin();\n"); + fprintf(out, " event << it.first;\n"); + fprintf(out, " event << it.second;\n"); + fprintf(out, " event.end();\n"); + fprintf(out, " }\n"); + fprintf(out, " event.end();\n\n"); } else { if (*arg == JAVA_TYPE_STRING) { @@ -344,9 +353,11 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, } } } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", const std::map<int, int64_t>& arg%d_1, " - "const std::map<int, char const*>& arg%d_2, " - "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex); + fprintf(out, ", const std::map<int, int32_t>& arg%d_1, " + "const std::map<int, int64_t>& arg%d_2, " + "const std::map<int, char const*>& arg%d_3, " + "const std::map<int, float>& arg%d_4", + argIndex, argIndex, argIndex, argIndex); } else { fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); } @@ -374,7 +385,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, } } } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", arg%d_1, arg%d_2, arg%d_3", argIndex, argIndex, argIndex); + fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", + argIndex, argIndex, argIndex, argIndex); } else { fprintf(out, ", arg%d", argIndex); } @@ -529,10 +541,14 @@ static void write_cpp_usage( } } } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", const std::map<int, int64_t>& %s_int" + fprintf(out, ", const std::map<int, int32_t>& %s_int" + ", const std::map<int, int64_t>& %s_long" ", const std::map<int, char const*>& %s_str" ", const std::map<int, float>& %s_float", - field->name.c_str(), field->name.c_str(), field->name.c_str()); + field->name.c_str(), + field->name.c_str(), + field->name.c_str(), + field->name.c_str()); } else { fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str()); } @@ -561,9 +577,11 @@ static void write_cpp_method_header( } } } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", const std::map<int, int64_t>& arg%d_1, " - "const std::map<int, char const*>& arg%d_2, " - "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex); + fprintf(out, ", const std::map<int, int32_t>& arg%d_1, " + "const std::map<int, int64_t>& arg%d_2, " + "const std::map<int, char const*>& arg%d_3, " + "const std::map<int, float>& arg%d_4", + argIndex, argIndex, argIndex, argIndex); } else { fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); } @@ -976,6 +994,7 @@ jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &att } static void write_key_value_map_jni(FILE* out) { + fprintf(out, " std::map<int, int32_t> int32_t_map;\n"); fprintf(out, " std::map<int, int64_t> int64_t_map;\n"); fprintf(out, " std::map<int, float> float_map;\n"); fprintf(out, " std::map<int, char const*> string_map;\n\n"); @@ -989,9 +1008,11 @@ static void write_key_value_map_jni(FILE* out) { fprintf(out, " std::vector<std::unique_ptr<ScopedUtfChars>> scoped_ufs;\n\n"); + fprintf(out, " jclass jint_class = env->FindClass(\"java/lang/Integer\");\n"); fprintf(out, " jclass jlong_class = env->FindClass(\"java/lang/Long\");\n"); fprintf(out, " jclass jfloat_class = env->FindClass(\"java/lang/Float\");\n"); fprintf(out, " jclass jstring_class = env->FindClass(\"java/lang/String\");\n"); + fprintf(out, " jmethodID jget_int_method = env->GetMethodID(jint_class, \"intValue\", \"()I\");\n"); fprintf(out, " jmethodID jget_long_method = env->GetMethodID(jlong_class, \"longValue\", \"()J\");\n"); fprintf(out, " jmethodID jget_float_method = env->GetMethodID(jfloat_class, \"floatValue\", \"()F\");\n\n"); @@ -1000,7 +1021,9 @@ static void write_key_value_map_jni(FILE* out) { fprintf(out, " jint key = env->CallIntMethod(value_map, jget_key_method, i);\n"); fprintf(out, " jobject jvalue_obj = env->CallObjectMethod(value_map, jget_value_method, i);\n"); fprintf(out, " if (jvalue_obj == NULL) { continue; }\n"); - fprintf(out, " if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n"); + fprintf(out, " if (env->IsInstanceOf(jvalue_obj, jint_class)) {\n"); + fprintf(out, " int32_t_map[key] = env->CallIntMethod(jvalue_obj, jget_int_method);\n"); + fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n"); fprintf(out, " int64_t_map[key] = env->CallLongMethod(jvalue_obj, jget_long_method);\n"); fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jfloat_class)) {\n"); fprintf(out, " float_map[key] = env->CallFloatMethod(jvalue_obj, jget_float_method);\n"); @@ -1129,7 +1152,7 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp } } } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", int64_t_map, string_map, float_map"); + fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map"); } else { const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg"; fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 7a91347102fe..59ba8e7a6177 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1698,9 +1698,7 @@ public class WifiManager { * @return the list of access points found in the most recent scan. An app must hold * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission - * in order to get valid results. If there is a remote exception (e.g., either a communication - * problem with the system service or an exception within the framework) an empty list will be - * returned. + * in order to get valid results. */ public List<ScanResult> getScanResults() { try { |