diff options
112 files changed, 2729 insertions, 1626 deletions
diff --git a/Android.bp b/Android.bp index aeb3cebe8a13..cb7f7a2317d3 100644 --- a/Android.bp +++ b/Android.bp @@ -1221,7 +1221,7 @@ metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.x "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " + "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo" -doc_defaults { +stubs_defaults { name: "metalava-api-stubs-default", srcs: [ ":opt-telephony-srcs", @@ -1246,10 +1246,9 @@ doc_defaults { ], local_sourcepaths: frameworks_base_subdirs, installable: false, - metalava_enabled: true, - metalava_annotations_enabled: true, - metalava_previous_api: ":last-released-public-api", - metalava_merge_annotations_dirs: [ + annotations_enabled: true, + previous_api: ":last-released-public-api", + merge_annotations_dirs: [ "metalava-manual", "ojluni-annotated-stubs", ], @@ -1481,7 +1480,7 @@ java_library_static { ], } -droiddoc { +droidstubs { name: "hiddenapi-lists-docs", defaults: ["metalava-api-stubs-default"], arg_files: [ @@ -1540,7 +1539,7 @@ filegroup { ], } -droiddoc { +droidstubs { name: "api-stubs-docs", defaults: ["metalava-api-stubs-default"], api_filename: "public_api.txt", @@ -1562,7 +1561,7 @@ droiddoc { }, } -droiddoc { +droidstubs { name: "system-api-stubs-docs", defaults: ["metalava-api-stubs-default"], api_tag_name: "SYSTEM", @@ -1586,7 +1585,7 @@ droiddoc { }, } -droiddoc { +droidstubs { name: "test-api-stubs-docs", defaults: ["metalava-api-stubs-default"], api_tag_name: "TEST", diff --git a/api/current.txt b/api/current.txt index e31f8a05611d..b9e00f6fc0be 100755 --- a/api/current.txt +++ b/api/current.txt @@ -42654,6 +42654,7 @@ package android.telephony { method public static int[] getSubscriptionIds(int); method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int); method public boolean isNetworkRoaming(int); + method public static boolean isValidSubscriptionId(int); method public void removeOnOpportunisticSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener); method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); method public void setSubscriptionOverrideCongested(int, boolean, long); diff --git a/api/system-current.txt b/api/system-current.txt index 1e1c621a561d..e2c59cb10dd4 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6785,7 +6785,6 @@ package android.webkit { method public static android.content.pm.PackageInfo getLoadedPackageInfo(); method public static int loadWebViewNativeLibraryFromPackage(java.lang.String, java.lang.ClassLoader); method public static void prepareWebViewInZygote(); - field public static final java.lang.String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY = "persist.sys.webview.vmsize"; field public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2; // 0x2 field public static final int LIBLOAD_FAILED_JNI_CALL = 7; // 0x7 field public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4; // 0x4 diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index d117f390705d..2c07431ee38a 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -91,7 +91,7 @@ message Atom { ActivityForegroundStateChanged activity_foreground_state_changed = 42; IsolatedUidChanged isolated_uid_changed = 43; PacketWakeupOccurred packet_wakeup_occurred = 44; - // 45 is available + WallClockTimeShifted wall_clock_time_shifted = 45; AnomalyDetected anomaly_detected = 46; AppBreadcrumbReported app_breadcrumb_reported = 47; AppStartOccurred app_start_occurred = 48; @@ -1479,6 +1479,18 @@ message AppBreadcrumbReported { } /** + * Logs the wall-clock time when a significant wall-clock time shift occurs. + * For example, this could be due to the user manually changing the time. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/AlarmManagerService.java + */ +message WallClockTimeShifted { + // New wall-clock time in milliseconds, according to System.currentTimeMillis(). + optional int64 wall_clock_timestamp_millis = 1; +} + +/** * Logs when statsd detects an anomaly. * * Logged from: diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp index eec90fc8d053..afd8ec2212fe 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.cpp +++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp @@ -49,7 +49,6 @@ const int FIELD_ID_DATA = 1; // for EventMetricData const int FIELD_ID_ELAPSED_TIMESTAMP_NANOS = 1; const int FIELD_ID_ATOMS = 2; -const int FIELD_ID_WALL_CLOCK_TIMESTAMP_NANOS = 3; EventMetricProducer::EventMetricProducer(const ConfigKey& key, const EventMetric& metric, const int conditionIndex, @@ -146,13 +145,9 @@ void EventMetricProducer::onMatchedLogEventInternalLocked( if (truncateTimestamp) { mProto->write(FIELD_TYPE_INT64 | FIELD_ID_ELAPSED_TIMESTAMP_NANOS, (long long)truncateTimestampNsToFiveMinutes(event.GetElapsedTimestampNs())); - mProto->write(FIELD_TYPE_INT64 | FIELD_ID_WALL_CLOCK_TIMESTAMP_NANOS, - (long long)truncateTimestampNsToFiveMinutes(getWallClockNs())); } else { mProto->write(FIELD_TYPE_INT64 | FIELD_ID_ELAPSED_TIMESTAMP_NANOS, (long long)event.GetElapsedTimestampNs()); - mProto->write(FIELD_TYPE_INT64 | FIELD_ID_WALL_CLOCK_TIMESTAMP_NANOS, - (long long)getWallClockNs()); } uint64_t eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOMS); diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index bcfcd7a4f06e..02b97734d3ff 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -63,7 +63,6 @@ const int FIELD_ID_DIMENSION_LEAF_IN_CONDITION = 5; // for GaugeBucketInfo const int FIELD_ID_ATOM = 3; const int FIELD_ID_ELAPSED_ATOM_TIMESTAMP = 4; -const int FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP = 5; const int FIELD_ID_BUCKET_NUM = 6; const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 7; const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 8; @@ -286,16 +285,9 @@ void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, const int64_t elapsedTimestampNs = truncateTimestamp ? truncateTimestampNsToFiveMinutes(atom.mElapsedTimestamps) : atom.mElapsedTimestamps; - const int64_t wallClockNs = truncateTimestamp ? - truncateTimestampNsToFiveMinutes(atom.mWallClockTimestampNs) : - atom.mWallClockTimestampNs; protoOutput->write( FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_ELAPSED_ATOM_TIMESTAMP, (long long)elapsedTimestampNs); - protoOutput->write( - FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | - FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP, - (long long)wallClockNs); } } protoOutput->end(bucketInfoToken); @@ -450,7 +442,7 @@ void GaugeMetricProducer::onMatchedLogEventInternalLocked( if ((*mCurrentSlicedBucket)[eventKey].size() >= mGaugeAtomsPerDimensionLimit) { return; } - GaugeAtom gaugeAtom(getGaugeFields(event), eventTimeNs, getWallClockNs()); + GaugeAtom gaugeAtom(getGaugeFields(event), eventTimeNs); (*mCurrentSlicedBucket)[eventKey].push_back(gaugeAtom); // Anomaly detection on gauge metric only works when there is one numeric // field specified. diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h index e3da5db4b90e..6379389218fd 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.h +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h @@ -33,12 +33,11 @@ namespace os { namespace statsd { struct GaugeAtom { - GaugeAtom(std::shared_ptr<vector<FieldValue>> fields, int64_t elapsedTimeNs, int64_t wallClockNs) - : mFields(fields), mElapsedTimestamps(elapsedTimeNs), mWallClockTimestampNs(wallClockNs) { + GaugeAtom(std::shared_ptr<vector<FieldValue>> fields, int64_t elapsedTimeNs) + : mFields(fields), mElapsedTimestamps(elapsedTimeNs) { } std::shared_ptr<vector<FieldValue>> mFields; int64_t mElapsedTimestamps; - int64_t mWallClockTimestampNs; }; struct GaugeBucket { diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index db7e680f1d37..ab0b23cc009d 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -46,7 +46,7 @@ message EventMetricData { optional Atom atom = 2; - optional int64 wall_clock_timestamp_nanos = 3; + optional int64 wall_clock_timestamp_nanos = 3 [deprecated = true]; } message CountBucketInfo { @@ -142,7 +142,7 @@ message GaugeBucketInfo { repeated int64 elapsed_timestamp_nanos = 4; - repeated int64 wall_clock_timestamp_nanos = 5; + repeated int64 wall_clock_timestamp_nanos = 5 [deprecated = true]; optional int64 bucket_num = 6; diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp index ea6eb3f3d712..5b6f167984dc 100644 --- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp +++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp @@ -148,7 +148,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) { EXPECT_EQ(1, data.bucket_info(0).atom_size()); EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0)); - EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size()); + EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size()); EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty()); @@ -271,7 +271,7 @@ TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents) { EXPECT_EQ(1, data.bucket_info(0).atom_size()); EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0)); - EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size()); + EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size()); EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty()); @@ -375,7 +375,6 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) { EXPECT_EQ(1, data.bucket_info(0).atom_size()); EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0)); - EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size()); EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty()); diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp index 3de8d0da2c3b..5c1ef01dd576 100644 --- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp +++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp @@ -173,7 +173,7 @@ TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) { if (sampling_type == GaugeMetric::ALL_CONDITION_CHANGES) { EXPECT_EQ(2, data.bucket_info(0).atom_size()); EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size()); - EXPECT_EQ(2, data.bucket_info(0).wall_clock_timestamp_nanos_size()); + EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size()); EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); @@ -192,7 +192,6 @@ TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) { EXPECT_EQ(1, data.bucket_info(1).atom_size()); EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size()); - EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size()); EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos()); EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, @@ -206,7 +205,6 @@ TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) { EXPECT_EQ(2, data.bucket_info(2).atom_size()); EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size()); - EXPECT_EQ(2, data.bucket_info(2).wall_clock_timestamp_nanos_size()); EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos()); EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, @@ -226,7 +224,6 @@ TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) { } else { EXPECT_EQ(1, data.bucket_info(0).atom_size()); EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); - EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size()); EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos()); @@ -239,7 +236,6 @@ TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) { EXPECT_EQ(1, data.bucket_info(1).atom_size()); EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size()); - EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size()); EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos()); EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, @@ -253,7 +249,6 @@ TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) { EXPECT_EQ(1, data.bucket_info(2).atom_size()); EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size()); - EXPECT_EQ(1, data.bucket_info(2).wall_clock_timestamp_nanos_size()); EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos()); EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, @@ -276,7 +271,6 @@ TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) { EXPECT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).atom_size()); EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size()); - EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size()); EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index d9d177760243..9e2050327ece 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -234,7 +234,7 @@ public class PackageInfo implements Parcelable { /** * Array of all signatures read from the package file. This is only filled * in if the flag {@link PackageManager#GET_SIGNATURES} was set. A package - * must be singed with at least one certificate which is at position zero. + * must be signed with at least one certificate which is at position zero. * The package can be signed with additional certificates which appear as * subsequent entries. * diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index 1ee3c933b326..cb336597cb8f 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -58,7 +58,7 @@ import java.util.List; * execute in parallel with any {@link Surface} initialization, such as waiting for a * {@link android.view.SurfaceView} to be ready as part of the UI initialization.</li> * - * <li>The third and most complex usage pattern inlvolves surface sharing. Once instantiated an + * <li>The third and most complex usage pattern involves surface sharing. Once instantiated an * OutputConfiguration can be enabled for surface sharing via {@link #enableSurfaceSharing}. This * must be done before creating a new capture session and enables calls to * {@link CameraCaptureSession#updateOutputConfiguration}. An OutputConfiguration with enabled diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java index 6d9ba778d09a..7e52ca331f9f 100644 --- a/core/java/android/hardware/display/BrightnessConfiguration.java +++ b/core/java/android/hardware/display/BrightnessConfiguration.java @@ -141,13 +141,6 @@ public final class BrightnessConfiguration implements Parcelable { private String mDescription; /** - * STOPSHIP remove when app has stopped using this. - * @hide - */ - public Builder() { - } - - /** * Constructs the builder with the control points for the brightness curve. * * Brightness curves must have strictly increasing ambient brightness values in lux and @@ -159,24 +152,6 @@ public final class BrightnessConfiguration implements Parcelable { * @throws IllegalArgumentException if the nit levels are not monotonically increasing. */ public Builder(float[] lux, float[] nits) { - setCurve(lux, nits); - } - - /** - * Sets the control points for the brightness curve. - * - * Brightness curves must have strictly increasing ambient brightness values in lux and - * monotonically increasing display brightness values in nits. In addition, the initial - * control point must be 0 lux. - * - * @throws IllegalArgumentException if the initial control point is not at 0 lux. - * @throws IllegalArgumentException if the lux levels are not strictly increasing. - * @throws IllegalArgumentException if the nit levels are not monotonically increasing. - * - * STOPSHIP remove when app has stopped using this. - * @hide - */ - public Builder setCurve(float[] lux, float[] nits) { Preconditions.checkNotNull(lux); Preconditions.checkNotNull(nits); if (lux.length == 0 || nits.length == 0) { @@ -190,11 +165,10 @@ public final class BrightnessConfiguration implements Parcelable { } Preconditions.checkArrayElementsInRange(lux, 0, Float.MAX_VALUE, "lux"); Preconditions.checkArrayElementsInRange(nits, 0, Float.MAX_VALUE, "nits"); - checkMonotonic(lux, true/*strictly increasing*/, "lux"); + checkMonotonic(lux, true /*strictly increasing*/, "lux"); checkMonotonic(nits, false /*strictly increasing*/, "nits"); mCurveLux = lux; mCurveNits = nits; - return this; } /** diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index 00a1f6feecc5..4080ee625a0f 100644 --- a/core/java/android/inputmethodservice/IInputMethodWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -87,8 +87,8 @@ class IInputMethodWrapper extends IInputMethod.Stub * guarantees that {@link #bindInput(InputBinding)}, * {@link #startInput(IBinder, IInputContext, int, EditorInfo, boolean)}, and * {@link #unbindInput()} are called with the same order as the original calls - * in {@link com.android.server.InputMethodManagerService}. See {@link IBinder#FLAG_ONEWAY} - * for detailed semantics.</p> + * in {@link com.android.server.inputmethod.InputMethodManagerService}. + * See {@link IBinder#FLAG_ONEWAY} for detailed semantics.</p> */ AtomicBoolean mIsUnbindIssued = null; diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index 9bcc6001615f..40465ceafcb8 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -197,7 +197,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { * * <p>Example: "//www.google.com/search?q=android" * - * @return the decoded scheme-specific-part + * @return the encoded scheme-specific-part */ public abstract String getEncodedSchemeSpecificPart(); diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index b5ade2a3b654..0476cf8961a5 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -39,7 +39,6 @@ public class FeatureFlagUtils { private static final Map<String, String> DEFAULT_FLAGS; static { DEFAULT_FLAGS = new HashMap<>(); - DEFAULT_FLAGS.put("settings_battery_display_app_list", "false"); DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false"); DEFAULT_FLAGS.put("settings_audio_switcher", "true"); DEFAULT_FLAGS.put("settings_systemui_theme", "true"); diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java index 61a697282dcb..a7d7a8d67f64 100644 --- a/core/java/android/view/inputmethod/InputMethodSubtype.java +++ b/core/java/android/view/inputmethod/InputMethodSubtype.java @@ -28,7 +28,7 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.Slog; -import com.android.internal.inputmethod.LocaleUtils; +import com.android.internal.inputmethod.InputMethodUtils; import java.util.ArrayList; import java.util.Arrays; @@ -384,7 +384,7 @@ public final class InputMethodSubtype implements Parcelable { if (!TextUtils.isEmpty(mSubtypeLanguageTag)) { mCachedLocaleObj = Locale.forLanguageTag(mSubtypeLanguageTag); } else { - mCachedLocaleObj = LocaleUtils.constructLocaleFromString(mSubtypeLocale); + mCachedLocaleObj = InputMethodUtils.constructLocaleFromString(mSubtypeLocale); } return mCachedLocaleObj; } diff --git a/core/java/android/view/textservice/SpellCheckerSubtype.java b/core/java/android/view/textservice/SpellCheckerSubtype.java index 41b70b61fd4a..026610ecb6f9 100644 --- a/core/java/android/view/textservice/SpellCheckerSubtype.java +++ b/core/java/android/view/textservice/SpellCheckerSubtype.java @@ -25,7 +25,7 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.Slog; -import com.android.internal.inputmethod.LocaleUtils; +import com.android.internal.inputmethod.InputMethodUtils; import java.util.ArrayList; import java.util.Arrays; @@ -228,7 +228,7 @@ public final class SpellCheckerSubtype implements Parcelable { if (!TextUtils.isEmpty(mSubtypeLanguageTag)) { return Locale.forLanguageTag(mSubtypeLanguageTag); } - return LocaleUtils.constructLocaleFromString(mSubtypeLocale); + return InputMethodUtils.constructLocaleFromString(mSubtypeLocale); } /** diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index e9a9e8f80662..46b1f6e6189e 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -51,9 +51,6 @@ public final class WebViewFactory { private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create"; - public static final String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY = - "persist.sys.webview.vmsize"; - private static final String LOGTAG = "WebViewFactory"; private static final boolean DEBUG = false; diff --git a/core/java/android/webkit/WebViewLibraryLoader.java b/core/java/android/webkit/WebViewLibraryLoader.java index cabba06bdff5..5a6aebaaad51 100644 --- a/core/java/android/webkit/WebViewLibraryLoader.java +++ b/core/java/android/webkit/WebViewLibraryLoader.java @@ -17,15 +17,14 @@ package android.webkit; import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.ActivityManagerInternal; -import android.content.pm.ApplicationInfo; +import android.app.ActivityThread; +import android.app.LoadedApk; +import android.content.Context; import android.content.pm.PackageInfo; import android.os.Build; import android.os.Process; import android.os.RemoteException; -import android.os.SystemProperties; -import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -33,11 +32,7 @@ import com.android.server.LocalServices; import dalvik.system.VMRuntime; -import java.io.File; -import java.io.IOException; import java.util.Arrays; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; /** * @hide @@ -50,7 +45,6 @@ public class WebViewLibraryLoader { "/data/misc/shared_relro/libwebviewchromium32.relro"; private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 = "/data/misc/shared_relro/libwebviewchromium64.relro"; - private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024; private static final boolean DEBUG = false; @@ -69,18 +63,26 @@ public class WebViewLibraryLoader { boolean result = false; boolean is64Bit = VMRuntime.getRuntime().is64Bit(); try { - if (args.length != 1 || args[0] == null) { + if (args.length != 2 || args[0] == null || args[1] == null) { Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args)); return; } - Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), lib: " + args[0]); + String packageName = args[0]; + String libraryFileName = args[1]; + Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), package: " + + packageName + " library: " + libraryFileName); if (!sAddressSpaceReserved) { Log.e(LOGTAG, "can't create relro file; address space not reserved"); return; } - result = nativeCreateRelroFile(args[0] /* path */, + LoadedApk apk = ActivityThread.currentActivityThread().getPackageInfo( + packageName, + null, + Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); + result = nativeCreateRelroFile(libraryFileName, is64Bit ? CHROMIUM_WEBVIEW_NATIVE_RELRO_64 : - CHROMIUM_WEBVIEW_NATIVE_RELRO_32); + CHROMIUM_WEBVIEW_NATIVE_RELRO_32, + apk.getClassLoader()); if (result && DEBUG) Log.v(LOGTAG, "created relro file"); } finally { // We must do our best to always notify the update service, even if something fails. @@ -101,7 +103,8 @@ public class WebViewLibraryLoader { /** * Create a single relro file by invoking an isolated process that to do the actual work. */ - static void createRelroFile(final boolean is64Bit, @NonNull WebViewNativeLibrary nativeLib) { + static void createRelroFile(final boolean is64Bit, @NonNull String packageName, + @NonNull String libraryFileName) { final String abi = is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]; @@ -119,13 +122,10 @@ public class WebViewLibraryLoader { }; try { - if (nativeLib == null || nativeLib.path == null) { - throw new IllegalArgumentException( - "Native library paths to the WebView RelRo process must not be null!"); - } boolean success = LocalServices.getService(ActivityManagerInternal.class) .startIsolatedProcess( - RelroFileCreator.class.getName(), new String[] { nativeLib.path }, + RelroFileCreator.class.getName(), + new String[] { packageName, libraryFileName }, "WebViewLoader-" + abi, abi, Process.SHARED_RELRO_UID, crashHandler); if (!success) throw new Exception("Failed to start the relro file creator process"); } catch (Throwable t) { @@ -140,83 +140,50 @@ public class WebViewLibraryLoader { * be called whenever we change WebView provider. * @return the number of relro processes started. */ - static int prepareNativeLibraries(PackageInfo webviewPackageInfo) - throws WebViewFactory.MissingWebViewPackageException { - WebViewNativeLibrary nativeLib32bit = - getWebViewNativeLibrary(webviewPackageInfo, false /* is64bit */); - WebViewNativeLibrary nativeLib64bit = - getWebViewNativeLibrary(webviewPackageInfo, true /* is64bit */); - updateWebViewZygoteVmSize(nativeLib32bit, nativeLib64bit); - - return createRelros(nativeLib32bit, nativeLib64bit); + static int prepareNativeLibraries(@NonNull PackageInfo webViewPackageInfo) { + // TODO(torne): new way of calculating VM size + // updateWebViewZygoteVmSize(nativeLib32bit, nativeLib64bit); + String libraryFileName = WebViewFactory.getWebViewLibrary( + webViewPackageInfo.applicationInfo); + if (libraryFileName == null) { + // Can't do anything with no filename, don't spawn any processes. + return 0; + } + return createRelros(webViewPackageInfo.packageName, libraryFileName); } /** * @return the number of relro processes started. */ - private static int createRelros(@Nullable WebViewNativeLibrary nativeLib32bit, - @Nullable WebViewNativeLibrary nativeLib64bit) { + private static int createRelros(@NonNull String packageName, @NonNull String libraryFileName) { if (DEBUG) Log.v(LOGTAG, "creating relro files"); int numRelros = 0; if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { - if (nativeLib32bit == null) { - Log.e(LOGTAG, "No 32-bit WebView library path, skipping relro creation."); - } else { - if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro"); - createRelroFile(false /* is64Bit */, nativeLib32bit); - numRelros++; - } + if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro"); + createRelroFile(false /* is64Bit */, packageName, libraryFileName); + numRelros++; } if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { - if (nativeLib64bit == null) { - Log.e(LOGTAG, "No 64-bit WebView library path, skipping relro creation."); - } else { - if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro"); - createRelroFile(true /* is64Bit */, nativeLib64bit); - numRelros++; - } + if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro"); + createRelroFile(true /* is64Bit */, packageName, libraryFileName); + numRelros++; } return numRelros; } /** - * - * @return the native WebView libraries in the new WebView APK. - */ - private static void updateWebViewZygoteVmSize( - @Nullable WebViewNativeLibrary nativeLib32bit, - @Nullable WebViewNativeLibrary nativeLib64bit) - throws WebViewFactory.MissingWebViewPackageException { - // Find the native libraries of the new WebView package, to change the size of the - // memory region in the Zygote reserved for the library. - long newVmSize = 0L; - - if (nativeLib32bit != null) newVmSize = Math.max(newVmSize, nativeLib32bit.size); - if (nativeLib64bit != null) newVmSize = Math.max(newVmSize, nativeLib64bit.size); - - if (DEBUG) { - Log.v(LOGTAG, "Based on library size, need " + newVmSize - + " bytes of address space."); - } - // The required memory can be larger than the file on disk (due to .bss), and an - // upgraded version of the library will likely be larger, so always attempt to - // reserve twice as much as we think to allow for the library to grow during this - // boot cycle. - newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES); - Log.d(LOGTAG, "Setting new address space to " + newVmSize); - setWebViewZygoteVmSize(newVmSize); - } - - /** * Reserve space for the native library to be loaded into. */ static void reserveAddressSpaceInZygote() { System.loadLibrary("webviewchromium_loader"); - long addressSpaceToReserve = - SystemProperties.getLong(WebViewFactory.CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY, - CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES); + boolean is64Bit = VMRuntime.getRuntime().is64Bit(); + // On 64-bit address space is really cheap and we can reserve 1GB which is plenty. + // On 32-bit it's fairly scarce and we should keep it to a realistic number that + // permits some future growth but doesn't hog space: we use 100MB which is more than 2x + // the current requirement. + long addressSpaceToReserve = is64Bit ? 1 * 1024 * 1024 * 1024 : 100 * 1024 * 1024; sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve); if (sAddressSpaceReserved) { @@ -253,106 +220,7 @@ public class WebViewLibraryLoader { return result; } - /** - * Fetch WebView's native library paths from {@param packageInfo}. - * @hide - */ - @Nullable - @VisibleForTesting - public static WebViewNativeLibrary getWebViewNativeLibrary(PackageInfo packageInfo, - boolean is64bit) throws WebViewFactory.MissingWebViewPackageException { - ApplicationInfo ai = packageInfo.applicationInfo; - final String nativeLibFileName = WebViewFactory.getWebViewLibrary(ai); - - String dir = getWebViewNativeLibraryDirectory(ai, is64bit /* 64bit */); - - WebViewNativeLibrary lib = findNativeLibrary(ai, nativeLibFileName, - is64bit ? Build.SUPPORTED_64_BIT_ABIS : Build.SUPPORTED_32_BIT_ABIS, dir); - - if (DEBUG) { - Log.v(LOGTAG, String.format("Native %d-bit lib: %s", is64bit ? 64 : 32, lib.path)); - } - return lib; - } - - /** - * @return the directory of the native WebView library with bitness {@param is64bit}. - * @hide - */ - @VisibleForTesting - public static String getWebViewNativeLibraryDirectory(ApplicationInfo ai, boolean is64bit) { - // Primary arch has the same bitness as the library we are looking for. - if (is64bit == VMRuntime.is64BitAbi(ai.primaryCpuAbi)) return ai.nativeLibraryDir; - - // Secondary arch has the same bitness as the library we are looking for. - if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) { - return ai.secondaryNativeLibraryDir; - } - - return ""; - } - - /** - * @return an object describing a native WebView library given the directory path of that - * library, or null if the library couldn't be found. - */ - @Nullable - private static WebViewNativeLibrary findNativeLibrary(ApplicationInfo ai, - String nativeLibFileName, String[] abiList, String libDirectory) - throws WebViewFactory.MissingWebViewPackageException { - if (TextUtils.isEmpty(libDirectory)) return null; - String libPath = libDirectory + "/" + nativeLibFileName; - File f = new File(libPath); - if (f.exists()) { - return new WebViewNativeLibrary(libPath, f.length()); - } else { - return getLoadFromApkPath(ai.sourceDir, abiList, nativeLibFileName); - } - } - - /** - * @hide - */ - @VisibleForTesting - public static class WebViewNativeLibrary { - public final String path; - public final long size; - - WebViewNativeLibrary(String path, long size) { - this.path = path; - this.size = size; - } - } - - private static WebViewNativeLibrary getLoadFromApkPath(String apkPath, - String[] abiList, - String nativeLibFileName) - throws WebViewFactory.MissingWebViewPackageException { - // Search the APK for a native library conforming to a listed ABI. - try (ZipFile z = new ZipFile(apkPath)) { - for (String abi : abiList) { - final String entry = "lib/" + abi + "/" + nativeLibFileName; - ZipEntry e = z.getEntry(entry); - if (e != null && e.getMethod() == ZipEntry.STORED) { - // Return a path formatted for dlopen() load from APK. - return new WebViewNativeLibrary(apkPath + "!/" + entry, e.getSize()); - } - } - } catch (IOException e) { - throw new WebViewFactory.MissingWebViewPackageException(e); - } - return null; - } - - /** - * Sets the size of the memory area in which to store the relro section. - */ - private static void setWebViewZygoteVmSize(long vmSize) { - SystemProperties.set(WebViewFactory.CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY, - Long.toString(vmSize)); - } - static native boolean nativeReserveAddressSpace(long addressSpaceToReserve); - static native boolean nativeCreateRelroFile(String lib, String relro); + static native boolean nativeCreateRelroFile(String lib, String relro, ClassLoader clazzLoader); static native int nativeLoadWithRelroFile(String lib, String relro, ClassLoader clazzLoader); } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 0645a162f377..d9132736232a 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -313,6 +313,7 @@ import java.util.function.Supplier; * @attr ref android.R.styleable#TextView_fallbackLineSpacing * @attr ref android.R.styleable#TextView_letterSpacing * @attr ref android.R.styleable#TextView_fontFeatureSettings + * @attr ref android.R.styleable#TextView_fontVariationSettings * @attr ref android.R.styleable#TextView_breakStrategy * @attr ref android.R.styleable#TextView_hyphenationFrequency * @attr ref android.R.styleable#TextView_autoSizeTextType @@ -4382,6 +4383,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * * @see #getFontVariationSettings() * @see FontVariationAxis + * + * @attr ref android.R.styleable#TextView_fontVariationSettings */ public boolean setFontVariationSettings(@Nullable String fontVariationSettings) { final String existingSettings = mTextPaint.getFontVariationSettings(); diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java index 7b25a0691c40..3fd88dbb8704 100644 --- a/core/java/com/android/internal/colorextraction/types/Tonal.java +++ b/core/java/com/android/internal/colorextraction/types/Tonal.java @@ -51,10 +51,8 @@ public class Tonal implements ExtractionType { private static final boolean DEBUG = true; - public static final int THRESHOLD_COLOR_LIGHT = 0xffe0e0e0; public static final int MAIN_COLOR_LIGHT = 0xffe0e0e0; - public static final int THRESHOLD_COLOR_DARK = 0xff212121; - public static final int MAIN_COLOR_DARK = 0xff000000; + public static final int MAIN_COLOR_DARK = 0xff212121; private final TonalPalette mGreyPalette; private final ArrayList<TonalPalette> mTonalPalettes; @@ -197,12 +195,12 @@ public class Tonal implements ExtractionType { // light fallback or darker than our dark fallback. ColorUtils.colorToHSL(mainColor, mTmpHSL); final float mainLuminosity = mTmpHSL[2]; - ColorUtils.colorToHSL(THRESHOLD_COLOR_LIGHT, mTmpHSL); + ColorUtils.colorToHSL(MAIN_COLOR_LIGHT, mTmpHSL); final float lightLuminosity = mTmpHSL[2]; if (mainLuminosity > lightLuminosity) { return false; } - ColorUtils.colorToHSL(THRESHOLD_COLOR_DARK, mTmpHSL); + ColorUtils.colorToHSL(MAIN_COLOR_DARK, mTmpHSL); final float darkLuminosity = mTmpHSL[2]; if (mainLuminosity < darkLuminosity) { return false; diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java index 1410ff9a0813..1e5b5c80f31b 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java +++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java @@ -334,6 +334,32 @@ public class InputMethodUtils { return getDefaultEnabledImes(context, imis, false /* onlyMinimum */); } + public static Locale constructLocaleFromString(String localeStr) { + if (TextUtils.isEmpty(localeStr)) { + return null; + } + // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}. + String[] localeParams = localeStr.split("_", 3); + if (localeParams.length >= 1 && "tl".equals(localeParams[0])) { + // Convert a locale whose language is "tl" to one whose language is "fil". + // For example, "tl_PH" will get converted to "fil_PH". + // Versions of Android earlier than Lollipop did not support three letter language + // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino). + // On Lollipop and above, the current three letter version must be used. + localeParams[0] = "fil"; + } + // The length of localeStr is guaranteed to always return a 1 <= value <= 3 + // because localeStr is not empty. + if (localeParams.length == 1) { + return new Locale(localeParams[0]); + } else if (localeParams.length == 2) { + return new Locale(localeParams[0], localeParams[1]); + } else if (localeParams.length == 3) { + return new Locale(localeParams[0], localeParams[1], localeParams[2]); + } + return null; + } + public static boolean containsSubtypeOf(final InputMethodInfo imi, @Nullable final Locale locale, final boolean checkCountry, final String mode) { if (locale == null) { @@ -1294,7 +1320,133 @@ public class InputMethodUtils { } } + // For spell checker service manager. + // TODO: Should we have TextServicesUtils.java? + private static final Locale LOCALE_EN_US = new Locale("en", "US"); + private static final Locale LOCALE_EN_GB = new Locale("en", "GB"); + + /** + * Returns a list of {@link Locale} in the order of appropriateness for the default spell + * checker service. + * + * <p>If the system language is English, and the region is also explicitly specified in the + * system locale, the following fallback order will be applied.</p> + * <ul> + * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> + * <li>(system-locale-language, system-locale-region)</li> + * <li>("en", "US")</li> + * <li>("en", "GB")</li> + * <li>("en")</li> + * </ul> + * + * <p>If the system language is English, but no region is specified in the system locale, + * the following fallback order will be applied.</p> + * <ul> + * <li>("en")</li> + * <li>("en", "US")</li> + * <li>("en", "GB")</li> + * </ul> + * + * <p>If the system language is not English, the following fallback order will be applied.</p> + * <ul> + * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> + * <li>(system-locale-language, system-locale-region) (if exists)</li> + * <li>(system-locale-language) (if exists)</li> + * <li>("en", "US")</li> + * <li>("en", "GB")</li> + * <li>("en")</li> + * </ul> + * + * @param systemLocale the current system locale to be taken into consideration. + * @return a list of {@link Locale}. The first one is considered to be most appropriate. + */ @VisibleForTesting + public static ArrayList<Locale> getSuitableLocalesForSpellChecker( + @Nullable final Locale systemLocale) { + final Locale systemLocaleLanguageCountryVariant; + final Locale systemLocaleLanguageCountry; + final Locale systemLocaleLanguage; + if (systemLocale != null) { + final String language = systemLocale.getLanguage(); + final boolean hasLanguage = !TextUtils.isEmpty(language); + final String country = systemLocale.getCountry(); + final boolean hasCountry = !TextUtils.isEmpty(country); + final String variant = systemLocale.getVariant(); + final boolean hasVariant = !TextUtils.isEmpty(variant); + if (hasLanguage && hasCountry && hasVariant) { + systemLocaleLanguageCountryVariant = new Locale(language, country, variant); + } else { + systemLocaleLanguageCountryVariant = null; + } + if (hasLanguage && hasCountry) { + systemLocaleLanguageCountry = new Locale(language, country); + } else { + systemLocaleLanguageCountry = null; + } + if (hasLanguage) { + systemLocaleLanguage = new Locale(language); + } else { + systemLocaleLanguage = null; + } + } else { + systemLocaleLanguageCountryVariant = null; + systemLocaleLanguageCountry = null; + systemLocaleLanguage = null; + } + + final ArrayList<Locale> locales = new ArrayList<>(); + if (systemLocaleLanguageCountryVariant != null) { + locales.add(systemLocaleLanguageCountryVariant); + } + + if (Locale.ENGLISH.equals(systemLocaleLanguage)) { + if (systemLocaleLanguageCountry != null) { + // If the system language is English, and the region is also explicitly specified, + // following fallback order will be applied. + // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null] + // - en_US [if systemLocaleLanguageCountry is non-null and not en_US] + // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB] + // - en + if (systemLocaleLanguageCountry != null) { + locales.add(systemLocaleLanguageCountry); + } + if (!LOCALE_EN_US.equals(systemLocaleLanguageCountry)) { + locales.add(LOCALE_EN_US); + } + if (!LOCALE_EN_GB.equals(systemLocaleLanguageCountry)) { + locales.add(LOCALE_EN_GB); + } + locales.add(Locale.ENGLISH); + } else { + // If the system language is English, but no region is specified, following + // fallback order will be applied. + // - en + // - en_US + // - en_GB + locales.add(Locale.ENGLISH); + locales.add(LOCALE_EN_US); + locales.add(LOCALE_EN_GB); + } + } else { + // If the system language is not English, the fallback order will be + // - systemLocaleLanguageCountry [if non-null] + // - systemLocaleLanguage [if non-null] + // - en_US + // - en_GB + // - en + if (systemLocaleLanguageCountry != null) { + locales.add(systemLocaleLanguageCountry); + } + if (systemLocaleLanguage != null) { + locales.add(systemLocaleLanguage); + } + locales.add(LOCALE_EN_US); + locales.add(LOCALE_EN_GB); + locales.add(Locale.ENGLISH); + } + return locales; + } + public static boolean isSoftInputModeStateVisibleAllowed( int targetSdkVersion, int controlFlags) { if (targetSdkVersion < Build.VERSION_CODES.P) { @@ -1309,4 +1461,5 @@ public class InputMethodUtils { } return true; } + } diff --git a/core/java/com/android/internal/inputmethod/LocaleUtils.java b/core/java/com/android/internal/inputmethod/LocaleUtils.java index f7360eb0fe13..eeb3854bcc55 100644 --- a/core/java/com/android/internal/inputmethod/LocaleUtils.java +++ b/core/java/com/android/internal/inputmethod/LocaleUtils.java @@ -16,6 +16,8 @@ package com.android.internal.inputmethod; +import com.android.internal.annotations.VisibleForTesting; + import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; @@ -23,8 +25,6 @@ import android.icu.util.ULocale; import android.os.LocaleList; import android.text.TextUtils; -import com.android.internal.annotations.VisibleForTesting; - import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -208,151 +208,4 @@ public final class LocaleUtils { dest.add(sources.get(entry.mIndex)); } } - - public static Locale constructLocaleFromString(String localeStr) { - if (TextUtils.isEmpty(localeStr)) { - return null; - } - // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}. - String[] localeParams = localeStr.split("_", 3); - if (localeParams.length >= 1 && "tl".equals(localeParams[0])) { - // Convert a locale whose language is "tl" to one whose language is "fil". - // For example, "tl_PH" will get converted to "fil_PH". - // Versions of Android earlier than Lollipop did not support three letter language - // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino). - // On Lollipop and above, the current three letter version must be used. - localeParams[0] = "fil"; - } - // The length of localeStr is guaranteed to always return a 1 <= value <= 3 - // because localeStr is not empty. - if (localeParams.length == 1) { - return new Locale(localeParams[0]); - } else if (localeParams.length == 2) { - return new Locale(localeParams[0], localeParams[1]); - } else if (localeParams.length == 3) { - return new Locale(localeParams[0], localeParams[1], localeParams[2]); - } - return null; - } - - /** - * Returns a list of {@link Locale} in the order of appropriateness for the default spell - * checker service. - * - * <p>If the system language is English, and the region is also explicitly specified in the - * system locale, the following fallback order will be applied.</p> - * <ul> - * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> - * <li>(system-locale-language, system-locale-region)</li> - * <li>("en", "US")</li> - * <li>("en", "GB")</li> - * <li>("en")</li> - * </ul> - * - * <p>If the system language is English, but no region is specified in the system locale, - * the following fallback order will be applied.</p> - * <ul> - * <li>("en")</li> - * <li>("en", "US")</li> - * <li>("en", "GB")</li> - * </ul> - * - * <p>If the system language is not English, the following fallback order will be applied.</p> - * <ul> - * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> - * <li>(system-locale-language, system-locale-region) (if exists)</li> - * <li>(system-locale-language) (if exists)</li> - * <li>("en", "US")</li> - * <li>("en", "GB")</li> - * <li>("en")</li> - * </ul> - * - * @param systemLocale the current system locale to be taken into consideration. - * @return a list of {@link Locale}. The first one is considered to be most appropriate. - */ - public static ArrayList<Locale> getSuitableLocalesForSpellChecker( - @Nullable final Locale systemLocale) { - final Locale systemLocaleLanguageCountryVariant; - final Locale systemLocaleLanguageCountry; - final Locale systemLocaleLanguage; - if (systemLocale != null) { - final String language = systemLocale.getLanguage(); - final boolean hasLanguage = !TextUtils.isEmpty(language); - final String country = systemLocale.getCountry(); - final boolean hasCountry = !TextUtils.isEmpty(country); - final String variant = systemLocale.getVariant(); - final boolean hasVariant = !TextUtils.isEmpty(variant); - if (hasLanguage && hasCountry && hasVariant) { - systemLocaleLanguageCountryVariant = new Locale(language, country, variant); - } else { - systemLocaleLanguageCountryVariant = null; - } - if (hasLanguage && hasCountry) { - systemLocaleLanguageCountry = new Locale(language, country); - } else { - systemLocaleLanguageCountry = null; - } - if (hasLanguage) { - systemLocaleLanguage = new Locale(language); - } else { - systemLocaleLanguage = null; - } - } else { - systemLocaleLanguageCountryVariant = null; - systemLocaleLanguageCountry = null; - systemLocaleLanguage = null; - } - - final ArrayList<Locale> locales = new ArrayList<>(); - if (systemLocaleLanguageCountryVariant != null) { - locales.add(systemLocaleLanguageCountryVariant); - } - - if (Locale.ENGLISH.equals(systemLocaleLanguage)) { - if (systemLocaleLanguageCountry != null) { - // If the system language is English, and the region is also explicitly specified, - // following fallback order will be applied. - // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null] - // - en_US [if systemLocaleLanguageCountry is non-null and not en_US] - // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB] - // - en - if (systemLocaleLanguageCountry != null) { - locales.add(systemLocaleLanguageCountry); - } - if (!Locale.US.equals(systemLocaleLanguageCountry)) { - locales.add(Locale.US); - } - if (!Locale.UK.equals(systemLocaleLanguageCountry)) { - locales.add(Locale.UK); - } - locales.add(Locale.ENGLISH); - } else { - // If the system language is English, but no region is specified, following - // fallback order will be applied. - // - en - // - en_US - // - en_GB - locales.add(Locale.ENGLISH); - locales.add(Locale.US); - locales.add(Locale.UK); - } - } else { - // If the system language is not English, the fallback order will be - // - systemLocaleLanguageCountry [if non-null] - // - systemLocaleLanguage [if non-null] - // - en_US - // - en_GB - // - en - if (systemLocaleLanguageCountry != null) { - locales.add(systemLocaleLanguageCountry); - } - if (systemLocaleLanguage != null) { - locales.add(systemLocaleLanguage); - } - locales.add(Locale.US); - locales.add(Locale.UK); - locales.add(Locale.ENGLISH); - } - return locales; - } } diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java index 16ca4fcdbe34..1038199cf109 100644 --- a/core/java/com/android/internal/util/ContrastColorUtil.java +++ b/core/java/com/android/internal/util/ContrastColorUtil.java @@ -455,7 +455,7 @@ public class ContrastColorUtil { * Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT} */ public static int resolveColor(Context context, int color, boolean defaultBackgroundIsDark) { - if (color == Notification.COLOR_DEFAULT) { + if (color == Notification.COLOR_DEFAULT || defaultBackgroundIsDark) { int res = defaultBackgroundIsDark ? com.android.internal.R.color.notification_default_color_dark : com.android.internal.R.color.notification_default_color_light; diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS index 21d750c59a4e..e65d11404a4e 100644 --- a/core/java/com/android/internal/util/OWNERS +++ b/core/java/com/android/internal/util/OWNERS @@ -1,24 +1,4 @@ -per-file AsyncChannel*=lorenzo@google.com -per-file AsyncChannel*=satk@google.com -per-file AsyncChannel*=silberst@google.com -per-file BitUtils*=ek@google.com -per-file BitUtils*=lorenzo@google.com -per-file BitUtils*=satk@google.com -per-file MessageUtils*=ek@google.com -per-file MessageUtils*=lorenzo@google.com -per-file MessageUtils*=satk@google.com -per-file Protocol*=ek@google.com -per-file Protocol*=lorenzo@google.com -per-file Protocol*=quiche@google.com -per-file Protocol*=satk@google.com -per-file Protocol*=silberst@google.com -per-file RingBuffer*=ek@google.com -per-file RingBuffer*=lorenzo@google.com -per-file RingBuffer*=satk@google.com -per-file State*=ek@google.com -per-file State*=lorenzo@google.com -per-file State*=quiche@google.com -per-file State*=silberst@google.com -per-file TokenBucket*=ek@google.com -per-file TokenBucket*=lorenzo@google.com -per-file TokenBucket*=satk@google.com +per-file AsyncChannel* = lorenzo@google.com, satk@google.com, etancohen@google.com +per-file BitUtils*, MessageUtils*, Protocol*, RingBuffer*, TokenBucket* = jchalard@google.com, lorenzo@google.com, satk@google.com +per-file Protocol* = etancohen@google.com, lorenzo@google.com +per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java index e03c1f8621be..7548c2257c06 100644 --- a/core/java/com/android/internal/view/InputBindResult.java +++ b/core/java/com/android/internal/view/InputBindResult.java @@ -60,7 +60,7 @@ public final class InputBindResult implements Parcelable { /** * Indicates that this is a temporary binding until the * {@link android.inputmethodservice.InputMethodService} (IMS) establishes a valid session - * to {@link com.android.server.InputMethodManagerService} (IMMS). + * to {@link com.android.server.inputmethod.InputMethodManagerService} (IMMS). * * <p>Note that in this state the IMS is already bound to IMMS but the logical session * is not yet established on top of the IPC channel.</p> @@ -73,7 +73,7 @@ public final class InputBindResult implements Parcelable { /** * Indicates that this is a temporary binding until the * {@link android.inputmethodservice.InputMethodService} (IMS) establishes a valid session - * to {@link com.android.server.InputMethodManagerService} (IMMS). + * to {@link com.android.server.inputmethod.InputMethodManagerService} (IMMS). * * <p>Note that in this state the IMMS has already initiated a connection to the IMS but * the binding process is not completed yet.</p> @@ -91,12 +91,14 @@ public final class InputBindResult implements Parcelable { int SUCCESS_REPORT_WINDOW_FOCUS_ONLY = 3; /** * Indicates somehow - * {@link com.android.server.InputMethodManagerService#startInputOrWindowGainedFocus} is - * trying to return null {@link InputBindResult}, which must never happen. + * {@link + * com.android.server.inputmethod.InputMethodManagerService#startInputOrWindowGainedFocus} + * is trying to return null {@link InputBindResult}, which must never happen. */ int ERROR_NULL = 4; /** - * Indicates that {@link com.android.server.InputMethodManagerService} recognizes no IME. + * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} + * recognizes no IME. */ int ERROR_NO_IME = 5; /** @@ -114,8 +116,8 @@ public final class InputBindResult implements Parcelable { */ int ERROR_SYSTEM_NOT_READY = 7; /** - * Indicates that {@link com.android.server.InputMethodManagerService} tried to connect to - * an {@link android.inputmethodservice.InputMethodService} but failed. + * Indicates that {@link com.android.server.inputmethod.InputMethodManagerService} tried to + * connect to an {@link android.inputmethodservice.InputMethodService} but failed. * * @see android.content.Context#bindServiceAsUser(Intent, ServiceConnection, int, UserHandle) */ @@ -137,7 +139,8 @@ public final class InputBindResult implements Parcelable { * The client should try to restart input when its {@link android.view.Window} is focused * again.</p> * - * @see com.android.server.wm.WindowManagerService#inputMethodClientHasFocus(IInputMethodClient) + * @see com.android.server.wm.WindowManagerInternal#inputMethodClientHasFocus( + * IInputMethodClient) */ int ERROR_NOT_IME_TARGET_WINDOW = 11; /** diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f845bd0e3964..9ab55d62839b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -584,7 +584,7 @@ <protected-broadcast android:name="android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED" /> <protected-broadcast android:name="android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED" /> <protected-broadcast android:name="android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED" /> - <protected-broadcast android:name="com.android.server.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER" /> + <protected-broadcast android:name="com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER" /> <!-- Time zone rules update intents fired by the system server --> <protected-broadcast android:name="com.android.intent.action.timezone.RULES_UPDATE_OPERATION" /> @@ -3352,7 +3352,7 @@ @hide @removed --> <permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT" - android:protectionLevel="signature" /> + android:protectionLevel="signature|privileged" /> <!-- @SystemApi Allows an application to know what content is playing and control its playback. <p>Not for use by third-party applications due to privacy of media consumption</p> --> @@ -4120,11 +4120,6 @@ <permission android:name="android.permission.DISABLE_HIDDEN_API_CHECKS" android:protectionLevel="signature" /> - <!-- Allows an application to read emergency info name. - @hide <p>Not for use by third-party applications. --> - <permission android:name="com.android.emergency.permission.READ_EMERGENCY_INFO_NAME" - android:protectionLevel="signature" /> - <application android:process="system" android:persistent="true" android:hasCode="false" diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 6932be373c0b..e153082045ec 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -284,7 +284,7 @@ <string name="permgrouprequest_sms" msgid="7168124215838204719">"Permettre à <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> d\'envoyer et d\'afficher des SMS ?"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Stockage"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"accéder à des photos, à des contenus multimédias et à des fichiers sur votre appareil"</string> - <string name="permgrouprequest_storage" msgid="7885942926944299560">"Permettre à <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> d\'accéder aux photos, contenus multimédias et fichiers sur votre appareil ?"</string> + <string name="permgrouprequest_storage" msgid="7885942926944299560">"Autoriser <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> à accéder aux photos, contenus multimédias et fichiers sur votre appareil ?"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"Microphone"</string> <string name="permgroupdesc_microphone" msgid="4988812113943554584">"enregistrer des fichiers audio"</string> <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Permettre à <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> d\'enregistrer des contenus audio ?"</string> @@ -1340,7 +1340,7 @@ <string name="ext_media_unmountable_notification_message" msgid="4193858924381066522">"Appuyez sur la notification pour résoudre le problème"</string> <string name="ext_media_unmountable_notification_message" product="tv" msgid="3941179940297874950">"La <xliff:g id="NAME">%s</xliff:g> est corrompue. Sélectionnez cette option pour résoudre le problème."</string> <string name="ext_media_unsupported_notification_title" msgid="3797642322958803257">"<xliff:g id="NAME">%s</xliff:g> non compatible"</string> - <string name="ext_media_unsupported_notification_message" msgid="6121601473787888589">"Cet appareil n\'est pas compatible avec la mémoire de stockage \"<xliff:g id="NAME">%s</xliff:g>\". Appuyez ici pour le configurer dans un format accepté."</string> + <string name="ext_media_unsupported_notification_message" msgid="6121601473787888589">"Cet appareil n\'est pas compatible avec le support \"<xliff:g id="NAME">%s</xliff:g>\". Appuyez ici pour le configurer dans un format accepté."</string> <string name="ext_media_unsupported_notification_message" product="tv" msgid="3725436899820390906">"Cet appareil n\'est pas compatible avec cette <xliff:g id="NAME">%s</xliff:g>. Sélectionnez cette option pour la configurer dans un format accepté."</string> <string name="ext_media_badremoval_notification_title" msgid="3206248947375505416">"Retrait inattendu de mémoire \"<xliff:g id="NAME">%s</xliff:g>\""</string> <string name="ext_media_badremoval_notification_message" msgid="8556885808951260574">"Éjectez le périphérique externe avant de le retirer pour éviter toute perte de contenu"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index d4b800ad2e04..6afe603993ab 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1895,10 +1895,10 @@ <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> को <b><xliff:g id="LABEL">%2$s</xliff:g></b> में सेव करें?"</string> <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> और <xliff:g id="TYPE_1">%2$s</xliff:g> को <b><xliff:g id="LABEL">%3$s</xliff:g></b> में सेव करें?"</string> <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> और <xliff:g id="TYPE_2">%3$s</xliff:g> को <b><xliff:g id="LABEL">%4$s</xliff:g></b> में सेव करें?"</string> - <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b>? में अपडेट करें?"</string> - <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> को to <b><xliff:g id="LABEL">%2$s</xliff:g></b> में अपडेट करें?"</string> + <string name="autofill_update_title" msgid="4879673117448810818">"<b><xliff:g id="LABEL">%1$s</xliff:g></b> में अपडेट करें?"</string> + <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> को <b><xliff:g id="LABEL">%2$s</xliff:g></b> में अपडेट करें?"</string> <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> और <xliff:g id="TYPE_1">%2$s</xliff:g> को <b><xliff:g id="LABEL">%3$s</xliff:g></b> में अपडेट करें?"</string> - <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> और <xliff:g id="TYPE_2">%3$s</xliff:g> को <b><xliff:g id="LABEL">%4$s</xliff:g></b> में अपडेट करें."</string> + <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> और <xliff:g id="TYPE_2">%3$s</xliff:g> को <b><xliff:g id="LABEL">%4$s</xliff:g></b> में अपडेट करें?"</string> <string name="autofill_save_yes" msgid="6398026094049005921">"सेव करें"</string> <string name="autofill_save_no" msgid="2625132258725581787">"नहीं, धन्यवाद"</string> <string name="autofill_update_yes" msgid="310358413273276958">"अपडेट करें"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 8b3f287d08aa..6a5f287d6f68 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -514,7 +514,7 @@ <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Թույլ է տալիս հավելվածին փոփոխել ձեր լուսանկարների հավաքածուն:"</string> <string name="permlab_mediaLocation" msgid="8675148183726247864">"ճանաչել տեղադրության մասին տվյալները մեդիա բովանդակության հավաքածուից"</string> <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Թույլ է տալիս հավելվածին ճանաչել տեղադրության մասին տվյալները ձեր մեդիա բովանդակության հավաքածուից:"</string> - <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Կենսաչափական սարք չի գտնվել"</string> + <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Կենսաչափական սարքը հասանելի չէ"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Մատնահետքը հայտնաբերվել է մասամբ: Փորձեք նորից:"</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Չհաջողվեց մշակել մատնահետքը: Նորից փորձեք:"</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Մատնահետքերի սենսորն աղտոտված է: Մաքրեք այն և փորձեք նորից:"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 4cada6068fe7..4915111c9e07 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -284,7 +284,7 @@ <string name="permgrouprequest_sms" msgid="7168124215838204719">"SMS メッセージの送信と表示を <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> に許可しますか?"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"ストレージ"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"端末内の写真、メディア、ファイルへのアクセス"</string> - <string name="permgrouprequest_storage" msgid="7885942926944299560">"端末内の写真、メディア、ファイルへのアクセスを <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> に許可しますか?"</string> + <string name="permgrouprequest_storage" msgid="7885942926944299560">"端末内の写真、メディア、ファイルへのアクセスを「<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>」に許可しますか?"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"マイク"</string> <string name="permgroupdesc_microphone" msgid="4988812113943554584">"音声の録音"</string> <string name="permgrouprequest_microphone" msgid="9167492350681916038">"音声の録音を <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> に許可しますか?"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index dca94ff526e1..e228d35d7067 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -284,7 +284,7 @@ <string name="permgrouprequest_sms" msgid="7168124215838204719">"ಎಸ್ಎಂಎಸ್ ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು ಮತ್ತು ವೀಕ್ಷಿಸಲು <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"ಸಂಗ್ರಹಣೆ"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"ಸಾಧನದಲ್ಲಿ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಮತ್ತು ಫೈಲ್ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು"</string> - <string name="permgrouprequest_storage" msgid="7885942926944299560">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಮತ್ತು ಫೈಲ್ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string> + <string name="permgrouprequest_storage" msgid="7885942926944299560">"ಸಾಧನದಲ್ಲಿ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ, ಫೈಲ್ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"ಮೈಕ್ರೋಫೋನ್"</string> <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ಆಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string> <string name="permgrouprequest_microphone" msgid="9167492350681916038">"ಆಡಿಯೋ ರೆಕಾರ್ಡ್ ಮಾಡಲು <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string> diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml index 351f8ea8643e..6bbd2587d78d 100644 --- a/core/res/res/values-night/colors.xml +++ b/core/res/res/values-night/colors.xml @@ -27,5 +27,5 @@ <color name="notification_default_color_dark">#ddffffff</color> <!-- The background color of a notification card. --> - <color name="notification_material_background_color">@*android:color/material_grey_900</color> + <color name="notification_material_background_color">@color/black</color> </resources>
\ No newline at end of file diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml index 5e3675ac6c3e..c8d4d05a3507 100644 --- a/core/res/res/values-night/themes_device_defaults.xml +++ b/core/res/res/values-night/themes_device_defaults.xml @@ -51,4 +51,7 @@ easier. --> <!-- DeviceDefault theme for a window that should look like the Settings app. --> <style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault"/> + + <!-- Theme for the dialog shown when an app crashes or ANRs. --> + <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert" /> </resources> diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml index 4eb2ff3b5970..45cf0f0fedb3 100644 --- a/core/res/res/values-night/values.xml +++ b/core/res/res/values-night/values.xml @@ -26,7 +26,7 @@ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> <!-- QS panel background --> - <item name="colorBackgroundFloating">@color/material_grey_900</item> + <item name="colorBackgroundFloating">@color/black</item> <!-- volume background --> <item name="panelColorBackground">@color/material_grey_800</item> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index e31f161b5dd4..c14bce471bda 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -290,7 +290,7 @@ <string name="permgrouprequest_sms" msgid="7168124215838204719">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> отправлять и просматривать SMS?"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Хранилище"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"доступ к фото, мультимедиа и файлам на вашем устройстве"</string> - <string name="permgrouprequest_storage" msgid="7885942926944299560">"Разрешить приложению <b>\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"</b> доступ к фото, мультимедиа и файлам на устройстве?"</string> + <string name="permgrouprequest_storage" msgid="7885942926944299560">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ к фото, мультимедиа и файлам на устройстве?"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string> <string name="permgroupdesc_microphone" msgid="4988812113943554584">"записывать аудио"</string> <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> записывать аудио?"</string> @@ -305,7 +305,7 @@ <string name="permgrouprequest_phone" msgid="9166979577750581037">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> совершать звонки и управлять ими?"</string> <string name="permgrouplab_sensors" msgid="416037179223226722">"Нательные датчики"</string> <string name="permgroupdesc_sensors" msgid="7147968539346634043">"доступ к данным датчиков о состоянии организма"</string> - <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Разрешить приложению <b>\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"</b> доступ к данным датчиков о состоянии организма?"</string> + <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ к данным датчиков о состоянии организма?"</string> <string name="permgrouplab_aural" msgid="965607064083134896">"Музыка"</string> <string name="permgroupdesc_aural" msgid="4870189506255958055">"доступ к музыке"</string> <string name="permgrouprequest_aural" msgid="6787926123071735620">"Разрешить приложению <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> доступ к музыке?"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 8b89a977faac..0f353f28b2f8 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -514,8 +514,7 @@ <string name="permdesc_imagesWrite" msgid="7073662756617474375">"ඔබගේ ඡායාරූප එකතුව වෙනස් කිරීමට යෙදුමට ඉඩ දෙයි."</string> <string name="permlab_mediaLocation" msgid="8675148183726247864">"ඔබගේ මාධ්ය එකතුවෙන් ස්ථාන කියවන්න"</string> <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ඔබගේ මාධ්ය එකතුවෙන් ස්ථාන කියවීමට යෙදුමට ඉඩ දෙයි."</string> - <!-- no translation found for biometric_error_hw_unavailable (645781226537551036) --> - <skip /> + <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ජීවමිතික දෘඪාංග ලබා ගත නොහැකිය"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"ඇඟිලි සලකුණ අඩ වශයෙන් අනාවරණය කර ගැනිණි. කරුණාකර නැවත උත්සාහ කරන්න."</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ඇඟිලි සලකුණ පිරිසැකසීමට නොහැකි විය. කරුණාකර නැවත උත්සාහ කරන්න."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ඇඟිලි සලකුණු සංවේදකය අපිරිසිදුයි. කරුණාකර පිරිසිදු කර නැවත උත්සාහ කරන්න."</string> @@ -523,8 +522,7 @@ <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"ඇඟිල්ල වඩා සෙමෙන් ගෙන යන ලදි. කරුණාකර නැවත උත්සාහ කරන්න."</string> <string-array name="fingerprint_acquired_vendor"> </string-array> - <!-- no translation found for biometric_not_recognized (5770511773560736082) --> - <skip /> + <string name="biometric_not_recognized" msgid="5770511773560736082">"හඳුනා නොගන්නා ලදී"</string> <string name="fingerprint_authenticated" msgid="5309333983002526448">"ඇඟිලි සලකුණ සත්යාපනය කරන ලදී"</string> <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ඇඟිලි සලකුණු දෘඪාංගය ලද නොහැකිය."</string> <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ඇඟිලි සලකුණ ගබඩා කළ නොහැක. දැනට පවතින ඇඟිලි සලකුණක් ඉවත් කරන්න."</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index b175f75acea9..35592a696d68 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -284,7 +284,7 @@ <string name="permgrouprequest_sms" msgid="7168124215838204719">"மெசேஜ்களை அனுப்பவும், பார்க்கவும் <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ஆப்ஸை அனுமதிக்கவா?"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"சேமிப்பிடம்"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"உங்கள் சாதனத்தில் உள்ள படங்கள், மீடியா மற்றும் கோப்புகளை அணுக வேண்டும்"</string> - <string name="permgrouprequest_storage" msgid="7885942926944299560">"உங்கள் சாதனத்திலுள்ள படங்கள், மீடியா, ஃபைல்கள் ஆகியவற்றை அணுகுவதற்கு <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> பயன்பாட்டை அனுமதிக்கவா?"</string> + <string name="permgrouprequest_storage" msgid="7885942926944299560">"உங்கள் சாதனத்திலுள்ள படங்கள், மீடியா, ஃபைல்கள் ஆகியவற்றை அணுகுவதற்கு <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ஆப்ஸை அனுமதிக்கவா?"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"மைக்ரோஃபோன்"</string> <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ஒலிப் பதிவு செய்யலாம்"</string> <string name="permgrouprequest_microphone" msgid="9167492350681916038">"ஆடியோவைப் பதிவு செய்ய <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> பயன்பாட்டை அனுமதிக்கவா?"</string> diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml index 377982a409c9..0712cbcfc024 100644 --- a/core/res/res/values-television/themes.xml +++ b/core/res/res/values-television/themes.xml @@ -15,7 +15,7 @@ --> <resources> <style name="Theme.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" /> - <style name="Theme.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" /> + <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" /> <style name="Theme.Holo.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" /> <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" /> <style name="Theme.Material.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" /> diff --git a/core/res/res/values-watch/themes.xml b/core/res/res/values-watch/themes.xml index 04df1809878a..1be47baf4e7f 100644 --- a/core/res/res/values-watch/themes.xml +++ b/core/res/res/values-watch/themes.xml @@ -15,7 +15,7 @@ --> <resources> <!-- Theme for the dialog shown when an app crashes or ANRs. Override to make it dark. --> - <style name="Theme.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert"> + <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert"> <item name="windowContentTransitions">false</item> <item name="windowActivityTransitions">false</item> <item name="windowCloseOnTouchOutside">false</item> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 0b04e0875718..966a5a53ffd8 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -272,9 +272,9 @@ <string name="permgrouprequest_contacts" msgid="6032805601881764300">"允许<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>访问您的通讯录吗?"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"位置信息"</string> <string name="permgroupdesc_location" msgid="1346617465127855033">"获取此设备的位置信息"</string> - <string name="permgrouprequest_location" msgid="3788275734953323491">"允许<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>获取此设备的位置信息吗?"</string> + <string name="permgrouprequest_location" msgid="3788275734953323491">"要允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”获取此设备的位置信息吗?"</string> <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"只有当您使用该应用时,该应用才有权获取位置信息。"</string> - <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"一律允许<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>获取此设备的位置信息吗?"</string> + <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"一律允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”获取此设备的位置信息吗?"</string> <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"即使您并未使用该应用,该应用也将始终有权获取位置信息。"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"日历"</string> <string name="permgroupdesc_calendar" msgid="3889615280211184106">"访问您的日历"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index bd4ea2a6610e..bd36ed654915 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -514,7 +514,7 @@ <string name="permdesc_imagesWrite" msgid="7073662756617474375">"允許應用程式修改你的相片收藏。"</string> <string name="permlab_mediaLocation" msgid="8675148183726247864">"讀取你的媒體收藏的位置資訊"</string> <string name="permdesc_mediaLocation" msgid="2237023389178865130">"允許應用程式讀取你的媒體收藏的位置資訊。"</string> - <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"找不到生物特徵辨識硬體"</string> + <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"無法使用生物特徵辨識硬體"</string> <string name="fingerprint_acquired_partial" msgid="735082772341716043">"僅偵測到部分指紋,請再試一次。"</string> <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"無法處理指紋,請再試一次。"</string> <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"指紋感應器有髒汙。請清潔感應器,然後再試一次。"</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 92cca72e055a..389278f87fa1 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2099,7 +2099,7 @@ <java-symbol type="string" name="vpn_lockdown_error" /> <java-symbol type="string" name="vpn_lockdown_config" /> <java-symbol type="string" name="wallpaper_binding_label" /> - <java-symbol type="style" name="Theme.Dialog.AppError" /> + <java-symbol type="style" name="Theme.DeviceDefault.Dialog.AppError" /> <java-symbol type="style" name="Theme.Leanback.Dialog.Alert" /> <java-symbol type="style" name="Theme.Toast" /> <java-symbol type="xml" name="storage_list" /> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index 3937af5c933f..a7530cea5d73 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -869,13 +869,6 @@ please see themes_device_defaults.xml. <!-- System themes --> <eat-comment /> - <!-- Theme for the dialog shown when an app crashes or ANRs. --> - <style name="Theme.Dialog.AppError" parent="Theme.DeviceDefault.Light.Dialog.Alert"> - <item name="windowContentTransitions">false</item> - <item name="windowActivityTransitions">false</item> - <item name="windowCloseOnTouchOutside">false</item> - </style> - <!-- Special theme for the recent apps dialog, to allow customization with overlays. --> <style name="Theme.Dialog.RecentApplications" parent="Theme.DeviceDefault.Light.Dialog"> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index 14e5082bdebb..92096abfcfab 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -719,6 +719,13 @@ easier. <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> </style> + <!-- Theme for the dialog shown when an app crashes or ANRs. --> + <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Light.Dialog.Alert"> + <item name="windowContentTransitions">false</item> + <item name="windowActivityTransitions">false</item> + <item name="windowCloseOnTouchOutside">false</item> + </style> + <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar"> <!-- Color palette --> <item name="colorPrimary">@color/primary_device_default_dark</item> diff --git a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java index 5ef30a828cf7..dcc51e121b32 100644 --- a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java +++ b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java @@ -48,8 +48,8 @@ public class BrightnessConfigurationTest { @Test public void testSetCurveIsUnmodified() { - BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(); - builder.setCurve(LUX_LEVELS, NITS_LEVELS); + BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder( + LUX_LEVELS, NITS_LEVELS); BrightnessConfiguration config = builder.build(); Pair<float[], float[]> curve = config.getCurve(); assertArrayEquals(LUX_LEVELS, curve.first, "lux"); @@ -58,45 +58,33 @@ public class BrightnessConfigurationTest { @Test(expected = IllegalArgumentException.class) public void testCurveMustHaveZeroLuxPoint() { - BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(); float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length); lux[0] = 1f; - builder.setCurve(lux, NITS_LEVELS); - } - - @Test(expected = IllegalStateException.class) - public void testCurveMustBeSet() { - BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(); - builder.build(); + new BrightnessConfiguration.Builder(lux, NITS_LEVELS); } @Test(expected = NullPointerException.class) public void testCurveMustNotHaveNullArrays() { - BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(); - builder.setCurve(null, null); + new BrightnessConfiguration.Builder(null, null); } @Test(expected = IllegalArgumentException.class) public void testCurveMustNotHaveEmptyArrays() { - BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(); - builder.setCurve(new float[0], new float[0]); + new BrightnessConfiguration.Builder(new float[0], new float[0]); } @Test public void testCurveMustNotHaveArraysOfDifferentLengths() { assertThrows(IllegalArgumentException.class, () -> { - BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(); float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length + 1); lux[lux.length - 1] = lux[lux.length - 2] + 1; - boolean exceptionThrown = false; - builder.setCurve(lux, NITS_LEVELS); + new BrightnessConfiguration.Builder(lux, NITS_LEVELS); }); assertThrows(IllegalArgumentException.class, () -> { - BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(); float[] nits = Arrays.copyOf(NITS_LEVELS, NITS_LEVELS.length + 1); nits[nits.length - 1] = nits[nits.length - 2] + 1; - builder.setCurve(LUX_LEVELS, nits); + new BrightnessConfiguration.Builder(LUX_LEVELS, nits); }); } @@ -105,23 +93,21 @@ public class BrightnessConfigurationTest { assertThrows(IllegalArgumentException.class, () -> { float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length); lux[lux.length - 1] = Float.NaN; - BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(); - builder.setCurve(lux, NITS_LEVELS); + new BrightnessConfiguration.Builder(lux, NITS_LEVELS); }); assertThrows(IllegalArgumentException.class, () -> { float[] nits = Arrays.copyOf(NITS_LEVELS, NITS_LEVELS.length); nits[nits.length - 1] = Float.NaN; - BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(); - builder.setCurve(LUX_LEVELS, nits); + new BrightnessConfiguration.Builder(LUX_LEVELS, nits); }); } @Test public void testParceledConfigIsEquivalent() { - BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(); - builder.setCurve(LUX_LEVELS, NITS_LEVELS); + BrightnessConfiguration.Builder builder = + new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS); BrightnessConfiguration config = builder.build(); Parcel p = Parcel.obtain(); p.writeParcelable(config, 0 /*flags*/); @@ -133,12 +119,11 @@ public class BrightnessConfigurationTest { @Test public void testEquals() { - BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(); - builder.setCurve(LUX_LEVELS, NITS_LEVELS); + BrightnessConfiguration.Builder builder = + new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS); BrightnessConfiguration baseConfig = builder.build(); - builder = new BrightnessConfiguration.Builder(); - builder.setCurve(LUX_LEVELS, NITS_LEVELS); + builder = new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS); BrightnessConfiguration identicalConfig = builder.build(); assertEquals(baseConfig, identicalConfig); assertEquals("hashCodes must be equal for identical configs", @@ -146,15 +131,13 @@ public class BrightnessConfigurationTest { float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length); lux[lux.length - 1] = lux[lux.length - 1] * 2; - builder = new BrightnessConfiguration.Builder(); - builder.setCurve(lux, NITS_LEVELS); + builder = new BrightnessConfiguration.Builder(lux, NITS_LEVELS); BrightnessConfiguration luxDifferConfig = builder.build(); assertNotEquals(baseConfig, luxDifferConfig); float[] nits = Arrays.copyOf(NITS_LEVELS, NITS_LEVELS.length); nits[nits.length - 1] = nits[nits.length - 1] * 2; - builder = new BrightnessConfiguration.Builder(); - builder.setCurve(LUX_LEVELS, nits); + builder = new BrightnessConfiguration.Builder(LUX_LEVELS, nits); BrightnessConfiguration nitsDifferConfig = builder.build(); assertNotEquals(baseConfig, nitsDifferConfig); } diff --git a/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java b/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java index 920988be2eb3..9e445541ad3a 100644 --- a/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java +++ b/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java @@ -24,7 +24,6 @@ import android.os.Process; import android.provider.Settings; import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.SmallTest; -import android.util.Log; /** * Tests ActivityManager#setPersistentVrThread and ActivityManager#setVrThread's @@ -76,9 +75,11 @@ public class SetPersistentVrThreadTest extends ActivityInstrumentationTestCase2< } private void setPersistentVrModeEnabled(boolean enable) throws Throwable { - mVrManager.setPersistentVrModeEnabled(enable); - // Allow the system time to send out callbacks for persistent VR mode. - Thread.sleep(200); + if (mVrManager != null) { + mVrManager.setPersistentVrModeEnabled(enable); + // Allow the system time to send out callbacks for persistent VR mode. + Thread.sleep(200); + } } @SmallTest diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java index f731a4affb87..3064afaeaab1 100644 --- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java +++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java @@ -71,11 +71,15 @@ public class InputMethodUtilsTest { private static final Locale LOCALE_FR = new Locale("fr"); private static final Locale LOCALE_FR_CA = new Locale("fr", "CA"); private static final Locale LOCALE_HI = new Locale("hi"); + private static final Locale LOCALE_JA = new Locale("ja"); private static final Locale LOCALE_JA_JP = new Locale("ja", "JP"); private static final Locale LOCALE_ZH_CN = new Locale("zh", "CN"); private static final Locale LOCALE_ZH_TW = new Locale("zh", "TW"); private static final Locale LOCALE_IN = new Locale("in"); private static final Locale LOCALE_ID = new Locale("id"); + private static final Locale LOCALE_TH = new Locale("ht"); + private static final Locale LOCALE_TH_TH = new Locale("ht", "TH"); + private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH"); private static final String SUBTYPE_MODE_KEYBOARD = "keyboard"; private static final String SUBTYPE_MODE_VOICE = "voice"; private static final String SUBTYPE_MODE_HANDWRITING = "handwriting"; @@ -1083,6 +1087,122 @@ public class InputMethodUtilsTest { } @Test + public void testGetSuitableLocalesForSpellChecker() throws Exception { + { + final ArrayList<Locale> locales = + InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US); + assertEquals(3, locales.size()); + assertEquals(LOCALE_EN_US, locales.get(0)); + assertEquals(LOCALE_EN_GB, locales.get(1)); + assertEquals(LOCALE_EN, locales.get(2)); + } + + { + final ArrayList<Locale> locales = + InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB); + assertEquals(3, locales.size()); + assertEquals(LOCALE_EN_GB, locales.get(0)); + assertEquals(LOCALE_EN_US, locales.get(1)); + assertEquals(LOCALE_EN, locales.get(2)); + } + + { + final ArrayList<Locale> locales = + InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN); + assertEquals(3, locales.size()); + assertEquals(LOCALE_EN, locales.get(0)); + assertEquals(LOCALE_EN_US, locales.get(1)); + assertEquals(LOCALE_EN_GB, locales.get(2)); + } + + { + final ArrayList<Locale> locales = + InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN); + assertEquals(4, locales.size()); + assertEquals(LOCALE_EN_IN, locales.get(0)); + assertEquals(LOCALE_EN_US, locales.get(1)); + assertEquals(LOCALE_EN_GB, locales.get(2)); + assertEquals(LOCALE_EN, locales.get(3)); + } + + { + final ArrayList<Locale> locales = + InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP); + assertEquals(5, locales.size()); + assertEquals(LOCALE_JA_JP, locales.get(0)); + assertEquals(LOCALE_JA, locales.get(1)); + assertEquals(LOCALE_EN_US, locales.get(2)); + assertEquals(LOCALE_EN_GB, locales.get(3)); + assertEquals(Locale.ENGLISH, locales.get(4)); + } + + // Test 3-letter language code. + { + final ArrayList<Locale> locales = + InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH); + assertEquals(5, locales.size()); + assertEquals(LOCALE_FIL_PH, locales.get(0)); + assertEquals(LOCALE_FIL, locales.get(1)); + assertEquals(LOCALE_EN_US, locales.get(2)); + assertEquals(LOCALE_EN_GB, locales.get(3)); + assertEquals(Locale.ENGLISH, locales.get(4)); + } + + // Test variant. + { + final ArrayList<Locale> locales = + InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH); + assertEquals(6, locales.size()); + assertEquals(LOCALE_TH_TH_TH, locales.get(0)); + assertEquals(LOCALE_TH_TH, locales.get(1)); + assertEquals(LOCALE_TH, locales.get(2)); + assertEquals(LOCALE_EN_US, locales.get(3)); + assertEquals(LOCALE_EN_GB, locales.get(4)); + assertEquals(Locale.ENGLISH, locales.get(5)); + } + + // Test Locale extension. + { + final Locale localeWithoutVariant = LOCALE_JA_JP; + final Locale localeWithVariant = new Locale.Builder() + .setLocale(LOCALE_JA_JP) + .setExtension('x', "android") + .build(); + assertFalse(localeWithoutVariant.equals(localeWithVariant)); + + final ArrayList<Locale> locales = + InputMethodUtils.getSuitableLocalesForSpellChecker(localeWithVariant); + assertEquals(5, locales.size()); + assertEquals(LOCALE_JA_JP, locales.get(0)); + assertEquals(LOCALE_JA, locales.get(1)); + assertEquals(LOCALE_EN_US, locales.get(2)); + assertEquals(LOCALE_EN_GB, locales.get(3)); + assertEquals(Locale.ENGLISH, locales.get(4)); + } + } + + @Test + public void testConstructLocaleFromString() throws Exception { + assertEquals(new Locale("en"), InputMethodUtils.constructLocaleFromString("en")); + assertEquals(new Locale("en", "US"), InputMethodUtils.constructLocaleFromString("en_US")); + assertEquals(new Locale("en", "US", "POSIX"), + InputMethodUtils.constructLocaleFromString("en_US_POSIX")); + + // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not + // support three letter language codes, and used "tl" (Tagalog) as the language string for + // "fil" (Filipino). + assertEquals(new Locale("fil"), InputMethodUtils.constructLocaleFromString("tl")); + assertEquals(new Locale("fil", "PH"), InputMethodUtils.constructLocaleFromString("tl_PH")); + assertEquals(new Locale("fil", "PH", "POSIX"), + InputMethodUtils.constructLocaleFromString("tl_PH_POSIX")); + + // So far rejecting an invalid/unexpected locale string is out of the scope of this method. + assertEquals(new Locale("a"), InputMethodUtils.constructLocaleFromString("a")); + assertEquals(new Locale("a b c"), InputMethodUtils.constructLocaleFromString("a b c")); + assertEquals(new Locale("en-US"), InputMethodUtils.constructLocaleFromString("en-US")); + } + + @Test public void testIsSoftInputModeStateVisibleAllowed() { // On pre-P devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are always // allowed, regardless of the focused view state. diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java index 7d0e646181c0..549511a420eb 100644 --- a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java +++ b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java @@ -17,7 +17,6 @@ package com.android.internal.inputmethod; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import android.os.LocaleList; import android.support.test.filters.SmallTest; @@ -35,18 +34,6 @@ public class LocaleUtilsTest { private static final LocaleUtils.LocaleExtractor<Locale> sIdentityMapper = source -> source; - private static final Locale LOCALE_EN = new Locale("en"); - private static final Locale LOCALE_EN_US = new Locale("en", "US"); - private static final Locale LOCALE_EN_GB = new Locale("en", "GB"); - private static final Locale LOCALE_EN_IN = new Locale("en", "IN"); - private static final Locale LOCALE_FIL = new Locale("fil"); - private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH"); - private static final Locale LOCALE_JA = new Locale("ja"); - private static final Locale LOCALE_JA_JP = new Locale("ja", "JP"); - private static final Locale LOCALE_TH = new Locale("ht"); - private static final Locale LOCALE_TH_TH = new Locale("ht", "TH"); - private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH"); - @Test public void testFilterByLanguageEmptyLanguageList() throws Exception { final ArrayList<Locale> availableLocales = new ArrayList<>(); @@ -398,120 +385,4 @@ public class LocaleUtilsTest { assertEquals(availableLocales.get(3), dest.get(0)); } } - - @Test - public void testGetSuitableLocalesForSpellChecker() throws Exception { - { - final ArrayList<Locale> locales = - LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US); - assertEquals(3, locales.size()); - assertEquals(LOCALE_EN_US, locales.get(0)); - assertEquals(LOCALE_EN_GB, locales.get(1)); - assertEquals(LOCALE_EN, locales.get(2)); - } - - { - final ArrayList<Locale> locales = - LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB); - assertEquals(3, locales.size()); - assertEquals(LOCALE_EN_GB, locales.get(0)); - assertEquals(LOCALE_EN_US, locales.get(1)); - assertEquals(LOCALE_EN, locales.get(2)); - } - - { - final ArrayList<Locale> locales = - LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN); - assertEquals(3, locales.size()); - assertEquals(LOCALE_EN, locales.get(0)); - assertEquals(LOCALE_EN_US, locales.get(1)); - assertEquals(LOCALE_EN_GB, locales.get(2)); - } - - { - final ArrayList<Locale> locales = - LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN); - assertEquals(4, locales.size()); - assertEquals(LOCALE_EN_IN, locales.get(0)); - assertEquals(LOCALE_EN_US, locales.get(1)); - assertEquals(LOCALE_EN_GB, locales.get(2)); - assertEquals(LOCALE_EN, locales.get(3)); - } - - { - final ArrayList<Locale> locales = - LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP); - assertEquals(5, locales.size()); - assertEquals(LOCALE_JA_JP, locales.get(0)); - assertEquals(LOCALE_JA, locales.get(1)); - assertEquals(LOCALE_EN_US, locales.get(2)); - assertEquals(LOCALE_EN_GB, locales.get(3)); - assertEquals(Locale.ENGLISH, locales.get(4)); - } - - // Test 3-letter language code. - { - final ArrayList<Locale> locales = - LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH); - assertEquals(5, locales.size()); - assertEquals(LOCALE_FIL_PH, locales.get(0)); - assertEquals(LOCALE_FIL, locales.get(1)); - assertEquals(LOCALE_EN_US, locales.get(2)); - assertEquals(LOCALE_EN_GB, locales.get(3)); - assertEquals(Locale.ENGLISH, locales.get(4)); - } - - // Test variant. - { - final ArrayList<Locale> locales = - LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH); - assertEquals(6, locales.size()); - assertEquals(LOCALE_TH_TH_TH, locales.get(0)); - assertEquals(LOCALE_TH_TH, locales.get(1)); - assertEquals(LOCALE_TH, locales.get(2)); - assertEquals(LOCALE_EN_US, locales.get(3)); - assertEquals(LOCALE_EN_GB, locales.get(4)); - assertEquals(Locale.ENGLISH, locales.get(5)); - } - - // Test Locale extension. - { - final Locale localeWithoutVariant = LOCALE_JA_JP; - final Locale localeWithVariant = new Locale.Builder() - .setLocale(LOCALE_JA_JP) - .setExtension('x', "android") - .build(); - assertFalse(localeWithoutVariant.equals(localeWithVariant)); - - final ArrayList<Locale> locales = - LocaleUtils.getSuitableLocalesForSpellChecker(localeWithVariant); - assertEquals(5, locales.size()); - assertEquals(LOCALE_JA_JP, locales.get(0)); - assertEquals(LOCALE_JA, locales.get(1)); - assertEquals(LOCALE_EN_US, locales.get(2)); - assertEquals(LOCALE_EN_GB, locales.get(3)); - assertEquals(Locale.ENGLISH, locales.get(4)); - } - } - - @Test - public void testConstructLocaleFromString() throws Exception { - assertEquals(new Locale("en"), LocaleUtils.constructLocaleFromString("en")); - assertEquals(new Locale("en", "US"), LocaleUtils.constructLocaleFromString("en_US")); - assertEquals(new Locale("en", "US", "POSIX"), - LocaleUtils.constructLocaleFromString("en_US_POSIX")); - - // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not - // support three letter language codes, and used "tl" (Tagalog) as the language string for - // "fil" (Filipino). - assertEquals(new Locale("fil"), LocaleUtils.constructLocaleFromString("tl")); - assertEquals(new Locale("fil", "PH"), LocaleUtils.constructLocaleFromString("tl_PH")); - assertEquals(new Locale("fil", "PH", "POSIX"), - LocaleUtils.constructLocaleFromString("tl_PH_POSIX")); - - // So far rejecting an invalid/unexpected locale string is out of the scope of this method. - assertEquals(new Locale("a"), LocaleUtils.constructLocaleFromString("a")); - assertEquals(new Locale("a b c"), LocaleUtils.constructLocaleFromString("a b c")); - assertEquals(new Locale("en-US"), LocaleUtils.constructLocaleFromString("en-US")); - } } diff --git a/core/tests/webkit/Android.mk b/core/tests/webkit/Android.mk deleted file mode 100644 index 45f6957c10e7..000000000000 --- a/core/tests/webkit/Android.mk +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (C) 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -# We only want this apk build for tests. -LOCAL_MODULE_TAGS := tests - -LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) - - -# Include all test java files. -LOCAL_SRC_FILES := \ - $(call all-java-files-under, unit_tests_src) - -LOCAL_JAVA_LIBRARIES := android.test.runner - -LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-test - -LOCAL_PACKAGE_NAME := WebViewLoadingTests -LOCAL_PRIVATE_PLATFORM_APIS := true -LOCAL_CERTIFICATE := platform - -LOCAL_COMPATIBILITY_SUITE := device-tests - -LOCAL_REQUIRED_MODULES := \ - WebViewLoadingOnDiskTestApk \ - WebViewLoadingFromApkTestApk - -include $(BUILD_PACKAGE) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/core/tests/webkit/AndroidManifest.xml b/core/tests/webkit/AndroidManifest.xml deleted file mode 100644 index 42accdf66891..000000000000 --- a/core/tests/webkit/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2017 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.webkit.tests" - android:sharedUserId="android.uid.system"> - - <application> - <uses-library android:name="android.test.runner" /> - </application> - - <instrumentation - android:name="android.support.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.webkit.tests" - android:label="Frameworks WebView Loader Tests" /> - -</manifest> diff --git a/core/tests/webkit/AndroidTest.xml b/core/tests/webkit/AndroidTest.xml deleted file mode 100644 index 4c50b7df3368..000000000000 --- a/core/tests/webkit/AndroidTest.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2017 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<configuration description="Runs Frameworks WebView Loading Tests."> - <option name="test-suite-tag" value="apct" /> - <option name="test-suite-tag" value="apct-instrumentation" /> - <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> - <option name="test-file-name" value="WebViewLoadingTests.apk" /> - <option name="test-file-name" value="WebViewLoadingOnDiskTestApk.apk" /> - <option name="test-file-name" value="WebViewLoadingFromApkTestApk.apk" /> - <option name="cleanup-apks" value="true" /> - <option name="alt-dir" value="out" /> - </target_preparer> - - <test class="com.android.tradefed.testtype.AndroidJUnitTest" > - <option name="package" value="com.android.webkit.tests" /> - </test> -</configuration> diff --git a/core/tests/webkit/OWNERS b/core/tests/webkit/OWNERS deleted file mode 100644 index 00e540a46ab2..000000000000 --- a/core/tests/webkit/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -changwan@google.com -tobiasjs@google.com -torne@google.com diff --git a/core/tests/webkit/apk_with_native_libs/Android.mk b/core/tests/webkit/apk_with_native_libs/Android.mk deleted file mode 100644 index e18a7e0df175..000000000000 --- a/core/tests/webkit/apk_with_native_libs/Android.mk +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright (C) 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH := $(call my-dir) -MY_PATH := $(LOCAL_PATH) - -# Set shared variables -MY_MODULE_TAGS := optional -MY_JNI_SHARED_LIBRARIES := libwebviewtest_jni -MY_MODULE_PATH := $(TARGET_OUT_DATA_APPS) -MY_SRC_FILES := $(call all-java-files-under, src) -MY_CFLAGS := -Wall -Werror -MY_SDK_VERSION := system_current -MY_PROGUARD_ENABLED := disabled -MY_MULTILIB := both - -# Recurse down the file tree. -include $(call all-subdir-makefiles) - - - -# Builds an apk containing native libraries that will be unzipped on the device. -include $(CLEAR_VARS) - -LOCAL_PATH := $(MY_PATH) -LOCAL_PACKAGE_NAME := WebViewLoadingOnDiskTestApk -LOCAL_MANIFEST_FILE := ondisk/AndroidManifest.xml - -LOCAL_MODULE_TAGS := $(MY_MODULE_TAGS) -LOCAL_JNI_SHARED_LIBRARIES := $(MY_JNI_SHARED_LIBRARIES) -LOCAL_MODULE_PATH := $(MY_MODULE_PATH) -LOCAL_SRC_FILES := $(MY_SRC_FILES) -LOCAL_CFLAGS := $(MY_CFLAGS) -LOCAL_SDK_VERSION := $(MY_SDK_VERSION) -LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED) -LOCAL_MULTILIB := $(MY_MULTILIB) -LOCAL_COMPATIBILITY_SUITE := device-tests - -include $(BUILD_PACKAGE) - - -# Builds an apk containing uncompressed native libraries that have to be -# accessed through the APK itself on the device. -include $(CLEAR_VARS) - -LOCAL_PATH := $(MY_PATH) -LOCAL_PACKAGE_NAME := WebViewLoadingFromApkTestApk -LOCAL_MANIFEST_FILE := inapk/AndroidManifest.xml - -LOCAL_MODULE_TAGS := $(MY_MODULE_TAGS) -LOCAL_JNI_SHARED_LIBRARIES := $(MY_JNI_SHARED_LIBRARIES) -LOCAL_MODULE_PATH := $(MY_MODULE_PATH) -LOCAL_SRC_FILES := $(MY_SRC_FILES) -LOCAL_CFLAGS := $(MY_CFLAGS) -LOCAL_SDK_VERSION := $(MY_SDK_VERSION) -LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED) -LOCAL_MULTILIB := $(MY_MULTILIB) -LOCAL_COMPATIBILITY_SUITE := device-tests - -include $(BUILD_PACKAGE) diff --git a/core/tests/webkit/apk_with_native_libs/inapk/AndroidManifest.xml b/core/tests/webkit/apk_with_native_libs/inapk/AndroidManifest.xml deleted file mode 100644 index 868b2388d135..000000000000 --- a/core/tests/webkit/apk_with_native_libs/inapk/AndroidManifest.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - --> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.webviewloading_test_from_apk" - android:versionCode="1" - android:versionName="0.0.0.1"> - - <application android:label="WebView Loading Test APK" - android:multiArch="true" - android:extractNativeLibs="false"> - <meta-data android:name="com.android.webview.WebViewLibrary" - android:value="libwebviewtest_jni.so" /> - </application> -</manifest> diff --git a/core/tests/webkit/apk_with_native_libs/ondisk/AndroidManifest.xml b/core/tests/webkit/apk_with_native_libs/ondisk/AndroidManifest.xml deleted file mode 100644 index ffffeb8e1630..000000000000 --- a/core/tests/webkit/apk_with_native_libs/ondisk/AndroidManifest.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - --> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.webviewloading_test_on_disk" - android:versionCode="1" - android:versionName="0.0.0.1"> - - <application android:label="WebView Loading Test APK" - android:multiArch="true"> - <meta-data android:name="com.android.webview.WebViewLibrary" - android:value="libwebviewtest_jni.so" /> - </application> -</manifest> diff --git a/core/tests/webkit/apk_with_native_libs/src/com/google/android/xts/webview_list/WebViewLoadingTestClass.java b/core/tests/webkit/apk_with_native_libs/src/com/google/android/xts/webview_list/WebViewLoadingTestClass.java deleted file mode 100644 index 0efa4b4ac694..000000000000 --- a/core/tests/webkit/apk_with_native_libs/src/com/google/android/xts/webview_list/WebViewLoadingTestClass.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package com.android.webview.chromium; - -/** - * An empty class for testing purposes. - */ -public class WebViewLoadingTestClass { -} diff --git a/core/tests/webkit/unit_tests_src/com/android/webkit/WebViewLibraryLoaderTest.java b/core/tests/webkit/unit_tests_src/com/android/webkit/WebViewLibraryLoaderTest.java deleted file mode 100644 index e2f2d37a4d68..000000000000 --- a/core/tests/webkit/unit_tests_src/com/android/webkit/WebViewLibraryLoaderTest.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.webkit; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.Bundle; -import android.util.Log; - -import android.support.test.filters.MediumTest; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; -import android.support.test.InstrumentationRegistry; - -import java.io.File; -import java.io.IOException; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Unit tests for {@link WebViewLibraryLoader}. - * Use the following command to run these tests: - * make WebViewLoadingTests \ - * && adb install -r -d \ - * ${ANDROID_PRODUCT_OUT}/data/app/WebViewLoadingTests/WebViewLoadingTests.apk \ - * && adb shell am instrument -e class 'android.webkit.WebViewLibraryLoaderTest' -w \ - * 'com.android.webkit.tests/android.support.test.runner.AndroidJUnitRunner' - */ -@RunWith(AndroidJUnit4.class) -public final class WebViewLibraryLoaderTest { - private static final String WEBVIEW_LIBS_ON_DISK_TEST_APK = - "com.android.webviewloading_test_on_disk"; - private static final String WEBVIEW_LIBS_IN_APK_TEST_APK = - "com.android.webviewloading_test_from_apk"; - private static final String WEBVIEW_LOADING_TEST_NATIVE_LIB = "libwebviewtest_jni.so"; - - private PackageInfo webviewOnDiskPackageInfo; - private PackageInfo webviewFromApkPackageInfo; - - @Before public void setUp() throws PackageManager.NameNotFoundException { - PackageManager pm = InstrumentationRegistry.getContext().getPackageManager(); - webviewOnDiskPackageInfo = - pm.getPackageInfo(WEBVIEW_LIBS_ON_DISK_TEST_APK, PackageManager.GET_META_DATA); - webviewFromApkPackageInfo = - pm.getPackageInfo(WEBVIEW_LIBS_IN_APK_TEST_APK, PackageManager.GET_META_DATA); - } - - private static boolean is64BitDevice() { - return Build.SUPPORTED_64_BIT_ABIS.length > 0; - } - - // We test the getWebViewNativeLibraryDirectory method here because it handled several different - // cases/combinations and it seems unnecessary to create one test-apk for each such combination - // and arch. - - /** - * Ensure we fetch the correct native library directories in the multi-arch case where - * the primary ABI is 64-bit. - */ - @SmallTest - @Test public void testGetWebViewLibDirMultiArchPrimary64bit() { - final String nativeLib = "nativeLib"; - final String secondaryNativeLib = "secondaryNativeLib"; - PackageInfo packageInfo = new PackageInfo(); - ApplicationInfo ai = new ApplicationInfoBuilder(). - // See VMRuntime.ABI_TO_INSTRUCTION_SET_MAP - setPrimaryCpuAbi("arm64-v8a"). - setNativeLibraryDir(nativeLib). - setSecondaryCpuAbi("armeabi"). - setSecondaryNativeLibraryDir(secondaryNativeLib). - create(); - packageInfo.applicationInfo = ai; - String actual32Lib = - WebViewLibraryLoader.getWebViewNativeLibraryDirectory(ai, false /* is64bit */); - String actual64Lib = - WebViewLibraryLoader.getWebViewNativeLibraryDirectory(ai, true /* is64bit */); - assertEquals(nativeLib, actual64Lib); - assertEquals(secondaryNativeLib, actual32Lib); - } - - /** - * Ensure we fetch the correct native library directory in the 64-bit single-arch case. - */ - @SmallTest - @Test public void testGetWebViewLibDirSingleArch64bit() { - final String nativeLib = "nativeLib"; - PackageInfo packageInfo = new PackageInfo(); - ApplicationInfo ai = new ApplicationInfoBuilder(). - // See VMRuntime.ABI_TO_INSTRUCTION_SET_MAP - setPrimaryCpuAbi("arm64-v8a"). - setNativeLibraryDir(nativeLib). - create(); - packageInfo.applicationInfo = ai; - String actual64Lib = - WebViewLibraryLoader.getWebViewNativeLibraryDirectory(ai, true /* is64bit */); - assertEquals(nativeLib, actual64Lib); - } - - /** - * Ensure we fetch the correct native library directory in the 32-bit single-arch case. - */ - @SmallTest - @Test public void testGetWebViewLibDirSingleArch32bit() { - final String nativeLib = "nativeLib"; - PackageInfo packageInfo = new PackageInfo(); - ApplicationInfo ai = new ApplicationInfoBuilder(). - // See VMRuntime.ABI_TO_INSTRUCTION_SET_MAP - setPrimaryCpuAbi("armeabi-v7a"). - setNativeLibraryDir(nativeLib). - create(); - packageInfo.applicationInfo = ai; - String actual32Lib = - WebViewLibraryLoader.getWebViewNativeLibraryDirectory(ai, false /* is64bit */); - assertEquals(nativeLib, actual32Lib); - } - - /** - * Ensure we fetch the correct 32-bit library path from an APK with 32-bit and 64-bit - * libraries unzipped onto disk. - */ - @MediumTest - @Test public void testGetWebViewLibraryPathOnDisk32Bit() - throws WebViewFactory.MissingWebViewPackageException { - WebViewLibraryLoader.WebViewNativeLibrary actualNativeLib = - WebViewLibraryLoader.getWebViewNativeLibrary( - webviewOnDiskPackageInfo, false /* is64bit */); - String expectedLibaryDirectory = is64BitDevice() ? - webviewOnDiskPackageInfo.applicationInfo.secondaryNativeLibraryDir : - webviewOnDiskPackageInfo.applicationInfo.nativeLibraryDir; - String lib32Path = expectedLibaryDirectory + "/" + WEBVIEW_LOADING_TEST_NATIVE_LIB; - assertEquals("Fetched incorrect 32-bit path from WebView library.", - lib32Path, actualNativeLib.path); - } - - /** - * Ensure we fetch the correct 64-bit library path from an APK with 32-bit and 64-bit - * libraries unzipped onto disk. - */ - @MediumTest - @Test public void testGetWebViewLibraryPathOnDisk64Bit() - throws WebViewFactory.MissingWebViewPackageException { - // A 32-bit device will not unpack 64-bit libraries. - if (!is64BitDevice()) return; - - WebViewLibraryLoader.WebViewNativeLibrary actualNativeLib = - WebViewLibraryLoader.getWebViewNativeLibrary( - webviewOnDiskPackageInfo, true /* is64bit */); - String lib64Path = webviewOnDiskPackageInfo.applicationInfo.nativeLibraryDir - + "/" + WEBVIEW_LOADING_TEST_NATIVE_LIB; - assertEquals("Fetched incorrect 64-bit path from WebView library.", - lib64Path, actualNativeLib.path); - } - - /** - * Check the size of the 32-bit library fetched from an APK with both 32-bit and 64-bit - * libraries unzipped onto disk. - */ - @MediumTest - @Test public void testGetWebView32BitLibrarySizeOnDiskIsNonZero() - throws WebViewFactory.MissingWebViewPackageException { - WebViewLibraryLoader.WebViewNativeLibrary actual32BitNativeLib = - WebViewLibraryLoader.getWebViewNativeLibrary( - webviewOnDiskPackageInfo, false /* is64bit */); - assertTrue(actual32BitNativeLib.size > 0); - } - - /** - * Check the size of the 64-bit library fetched from an APK with both 32-bit and 64-bit - * libraries unzipped onto disk. - */ - @MediumTest - @Test public void testGetWebView64BitLibrarySizeOnDiskIsNonZero() - throws WebViewFactory.MissingWebViewPackageException { - // A 32-bit device will not unpack 64-bit libraries. - if (!is64BitDevice()) return; - WebViewLibraryLoader.WebViewNativeLibrary actual64BitNativeLib = - WebViewLibraryLoader.getWebViewNativeLibrary( - webviewOnDiskPackageInfo, true /* is64bit */); - assertTrue(actual64BitNativeLib.size > 0); - } - - /** - * Ensure we fetch the correct 32-bit library path from an APK with both 32-bit and 64-bit - * libraries stored uncompressed in the APK. - */ - @MediumTest - @Test public void testGetWebView32BitLibraryPathFromApk() - throws WebViewFactory.MissingWebViewPackageException, IOException { - WebViewLibraryLoader.WebViewNativeLibrary actualNativeLib = - WebViewLibraryLoader.getWebViewNativeLibrary( - webviewFromApkPackageInfo, false /* is64bit */); - // The device might have ignored the app's request to not extract native libs, so first - // check whether the library paths match those of extracted libraries. - String expectedLibaryDirectory = is64BitDevice() ? - webviewFromApkPackageInfo.applicationInfo.secondaryNativeLibraryDir : - webviewFromApkPackageInfo.applicationInfo.nativeLibraryDir; - String lib32Path = expectedLibaryDirectory + "/" + WEBVIEW_LOADING_TEST_NATIVE_LIB; - if (lib32Path.equals(actualNativeLib.path)) { - // If the libraries were extracted to disk, ensure that they're actually there. - assertTrue("The given WebView library doesn't exist.", - new File(actualNativeLib.path).exists()); - } else { // The libraries were not extracted to disk. - assertIsValidZipEntryPath(actualNativeLib.path, - webviewFromApkPackageInfo.applicationInfo.sourceDir); - } - } - - /** - * Ensure we fetch the correct 32-bit library path from an APK with both 32-bit and 64-bit - * libraries stored uncompressed in the APK. - */ - @MediumTest - @Test public void testGetWebView64BitLibraryPathFromApk() - throws WebViewFactory.MissingWebViewPackageException, IOException { - // A 32-bit device will not unpack 64-bit libraries. - if (!is64BitDevice()) return; - - WebViewLibraryLoader.WebViewNativeLibrary actualNativeLib = - WebViewLibraryLoader.getWebViewNativeLibrary( - webviewFromApkPackageInfo, true /* is64bit */); - assertIsValidZipEntryPath(actualNativeLib.path, - webviewFromApkPackageInfo.applicationInfo.sourceDir); - } - - private static void assertIsValidZipEntryPath(String path, String zipFilePath) - throws IOException { - assertTrue("The path to a zip entry must start with the path to the zip file itself." - + "Expected zip path: " + zipFilePath + ", actual zip entry: " + path, - path.startsWith(zipFilePath + "!/")); - String[] pathSplit = path.split("!/"); - assertEquals("A zip file path should have two parts, the zip path, and the zip entry path.", - 2, pathSplit.length); - ZipFile zipFile = new ZipFile(pathSplit[0]); - assertNotNull("Path doesn't point to a valid zip entry: " + path, - zipFile.getEntry(pathSplit[1])); - } - - - /** - * Check the size of the 32-bit library fetched from an APK with both 32-bit and 64-bit - * libraries stored uncompressed in the APK. - */ - @MediumTest - @Test public void testGetWebView32BitLibrarySizeFromApkIsNonZero() - throws WebViewFactory.MissingWebViewPackageException { - WebViewLibraryLoader.WebViewNativeLibrary actual32BitNativeLib = - WebViewLibraryLoader.getWebViewNativeLibrary( - webviewFromApkPackageInfo, false /* is64bit */); - assertTrue(actual32BitNativeLib.size > 0); - } - - /** - * Check the size of the 64-bit library fetched from an APK with both 32-bit and 64-bit - * libraries stored uncompressed in the APK. - */ - @MediumTest - @Test public void testGetWebView64BitLibrarySizeFromApkIsNonZero() - throws WebViewFactory.MissingWebViewPackageException { - // A 32-bit device will not unpack 64-bit libraries. - if (!is64BitDevice()) return; - - WebViewLibraryLoader.WebViewNativeLibrary actual64BitNativeLib = - WebViewLibraryLoader.getWebViewNativeLibrary( - webviewFromApkPackageInfo, true /* is64bit */); - assertTrue(actual64BitNativeLib.size > 0); - } - - private static class ApplicationInfoBuilder { - ApplicationInfo ai; - - public ApplicationInfoBuilder setPrimaryCpuAbi(String primaryCpuAbi) { - ai.primaryCpuAbi = primaryCpuAbi; - return this; - } - - public ApplicationInfoBuilder setSecondaryCpuAbi(String secondaryCpuAbi) { - ai.secondaryCpuAbi = secondaryCpuAbi; - return this; - } - - public ApplicationInfoBuilder setNativeLibraryDir(String nativeLibraryDir) { - ai.nativeLibraryDir = nativeLibraryDir; - return this; - } - - public ApplicationInfoBuilder setSecondaryNativeLibraryDir( - String secondaryNativeLibraryDir) { - ai.secondaryNativeLibraryDir = secondaryNativeLibraryDir; - return this; - } - - public ApplicationInfoBuilder setMetaData(Bundle metaData) { - ai.metaData = metaData; - return this; - } - - public ApplicationInfoBuilder() { - ai = new android.content.pm.ApplicationInfo(); - } - - public ApplicationInfo create() { - return ai; - } - } -} diff --git a/media/jni/Android.bp b/media/jni/Android.bp index 339a7eef637e..7681cc340069 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -91,6 +91,7 @@ cc_library_shared { "android_media_Media2HTTPConnection.cpp", "android_media_Media2HTTPService.cpp", "android_media_Media2DataSource.cpp", + "android_media_MediaMetricsJNI.cpp", "android_media_MediaPlayer2.cpp", "android_media_SyncParams.cpp", ], @@ -98,7 +99,6 @@ cc_library_shared { shared_libs: [ "android.hardware.cas@1.0", // for CasManager. VNDK??? "android.hardware.cas.native@1.0", // CasManager. VNDK??? - "libandroid_runtime", // ??? "libaudioclient", // for use of AudioTrack, AudioSystem. to be removed "libbinder", "libgui", // for VideoFrameScheduler @@ -120,13 +120,9 @@ cc_library_shared { header_libs: ["libhardware_headers"], static_libs: [ - "libbacktrace", "libbase", - "libc_malloc_debug_backtrace", "libcrypto", "libcutils", - "libdexfile", - "liblzma", "libmedia_helper", "libmedia_player2_util", "libmediadrm", @@ -135,7 +131,7 @@ cc_library_shared { "libmediaplayer2", "libmediaplayer2-protos", "libmediautils", - "libnetd_client", + "libnetd_client", // for setNetworkForUser "libprotobuf-cpp-lite", "libstagefright_esds", "libstagefright_foundation", @@ -146,9 +142,6 @@ cc_library_shared { "libstagefright_player2", "libstagefright_rtsp", "libstagefright_timedtext2", - "libunwindstack", - "libutilscallstack", - "libziparchive", ], group_static_libs: true, diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp new file mode 100644 index 000000000000..3ded8c260512 --- /dev/null +++ b/media/jni/android_media_MediaMetricsJNI.cpp @@ -0,0 +1,90 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <jni.h> +#include <nativehelper/JNIHelp.h> + +#include "android_media_MediaMetricsJNI.h" +#include <media/MediaAnalyticsItem.h> + + +// Copeid from core/jni/ (libandroid_runtime.so) +namespace android { + +// place the attributes into a java PersistableBundle object +jobject MediaMetricsJNI::writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle) { + + jclass clazzBundle = env->FindClass("android/os/PersistableBundle"); + if (clazzBundle==NULL) { + ALOGD("can't find android/os/PersistableBundle"); + return NULL; + } + // sometimes the caller provides one for us to fill + if (mybundle == NULL) { + // create the bundle + jmethodID constructID = env->GetMethodID(clazzBundle, "<init>", "()V"); + mybundle = env->NewObject(clazzBundle, constructID); + if (mybundle == NULL) { + return NULL; + } + } + + // grab methods that we can invoke + jmethodID setIntID = env->GetMethodID(clazzBundle, "putInt", "(Ljava/lang/String;I)V"); + jmethodID setLongID = env->GetMethodID(clazzBundle, "putLong", "(Ljava/lang/String;J)V"); + jmethodID setDoubleID = env->GetMethodID(clazzBundle, "putDouble", "(Ljava/lang/String;D)V"); + jmethodID setStringID = env->GetMethodID(clazzBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V"); + + // env, class, method, {parms} + //env->CallVoidMethod(env, mybundle, setIntID, jstr, jint); + + // iterate through my attributes + // -- get name, get type, get value + // -- insert appropriately into the bundle + for (size_t i = 0 ; i < item->mPropCount; i++ ) { + MediaAnalyticsItem::Prop *prop = &item->mProps[i]; + // build the key parameter from prop->mName + jstring keyName = env->NewStringUTF(prop->mName); + // invoke the appropriate method to insert + switch (prop->mType) { + case MediaAnalyticsItem::kTypeInt32: + env->CallVoidMethod(mybundle, setIntID, + keyName, (jint) prop->u.int32Value); + break; + case MediaAnalyticsItem::kTypeInt64: + env->CallVoidMethod(mybundle, setLongID, + keyName, (jlong) prop->u.int64Value); + break; + case MediaAnalyticsItem::kTypeDouble: + env->CallVoidMethod(mybundle, setDoubleID, + keyName, (jdouble) prop->u.doubleValue); + break; + case MediaAnalyticsItem::kTypeCString: + env->CallVoidMethod(mybundle, setStringID, keyName, + env->NewStringUTF(prop->u.CStringValue)); + break; + default: + ALOGE("to_String bad item type: %d for %s", + prop->mType, prop->mName); + break; + } + } + + return mybundle; +} + +}; // namespace android + diff --git a/core/tests/webkit/apk_with_native_libs/jni/WebViewTestJniOnLoad.cpp b/media/jni/android_media_MediaMetricsJNI.h index 0ced4ee12ac5..fd621ea7261d 100644 --- a/core/tests/webkit/apk_with_native_libs/jni/WebViewTestJniOnLoad.cpp +++ b/media/jni/android_media_MediaMetricsJNI.h @@ -1,11 +1,11 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright 2017, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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, @@ -14,8 +14,21 @@ * limitations under the License. */ +#ifndef _ANDROID_MEDIA_MEDIAMETRICSJNI_H_ +#define _ANDROID_MEDIA_MEDIAMETRICSJNI_H_ + #include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <media/MediaAnalyticsItem.h> + +// Copeid from core/jni/ (libandroid_runtime.so) +namespace android { + +class MediaMetricsJNI { +public: + static jobject writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle); +}; + +}; // namespace android -jint JNI_OnLoad(JavaVM * /*vm*/, void * /*reserved*/) { - return JNI_VERSION_1_4; -} +#endif // _ANDROID_MEDIA_MEDIAMETRICSJNI_H_ diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp index 801dade63268..d4c84b5b6c77 100644 --- a/media/jni/android_media_MediaPlayer2.cpp +++ b/media/jni/android_media_MediaPlayer2.cpp @@ -909,7 +909,7 @@ android_media_MediaPlayer2_getAudioStreamType(JNIEnv *env, jobject thiz) } static jboolean -android_media_MediaPlayer2_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request) +android_media_MediaPlayer2_setParameter(JNIEnv *env, jobject thiz, jint key, jobject) { ALOGV("setParameter: key %d", key); sp<MediaPlayer2> mp = getMediaPlayer(env, thiz); @@ -918,9 +918,11 @@ android_media_MediaPlayer2_setParameter(JNIEnv *env, jobject thiz, jint key, job return false; } - // TODO: parcelForJavaObject() shouldn't be used since it's dependent on - // framework's Parcel implementation. This setParameter() is used - // only with AudioAttribute. Can this be used as jobject with JAudioTrack? + return false; + // TODO: set/getParameter is temporarily disabled to remove android_runtime.so dependency. + // Once JAudioTrack migration is done, the AudioAttribute jobject + // should be directly passed to AudioTrack without native parcel conversion. + /* Parcel *request = parcelForJavaObject(env, java_request); status_t err = mp->setParameter(key, *request); if (err == OK) { @@ -928,6 +930,7 @@ android_media_MediaPlayer2_setParameter(JNIEnv *env, jobject thiz, jint key, job } else { return false; } + */ } static jobject @@ -940,6 +943,11 @@ android_media_MediaPlayer2_getParameter(JNIEnv *env, jobject thiz, jint key) return NULL; } + return NULL; + // TODO: set/getParameter is temporarily disabled to remove android_runtime.so dependency. + // Once JAudioTrack migration is done, the AudioAttribute jobject + // should be directly passed to AudioTrack without native parcel conversion. + /* jobject jParcel = createJavaParcelObject(env); if (jParcel != NULL) { Parcel* nativeParcel = parcelForJavaObject(env, jParcel); @@ -950,6 +958,7 @@ android_media_MediaPlayer2_getParameter(JNIEnv *env, jobject thiz, jint key) } } return jParcel; + */ } static void @@ -1005,7 +1014,11 @@ android_media_MediaPlayer2_invoke(JNIEnv *env, jobject thiz, jbyteArray requestD PlayerMessage response; request.ParseFromArray(pData, pDataLen); - media_player->invoke(request, &response); + process_media_player_call( env, thiz, media_player->invoke(request, &response), + "java.lang.RuntimeException", NULL ); + if (env->ExceptionCheck()) { + return NULL; + } int size = response.ByteSize(); jbyte* temp = new jbyte[size]; @@ -1019,55 +1032,6 @@ android_media_MediaPlayer2_invoke(JNIEnv *env, jobject thiz, jbyteArray requestD return out; } -// Sends the new filter to the client. -static jint -android_media_MediaPlayer2_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request) -{ - sp<MediaPlayer2> media_player = getMediaPlayer(env, thiz); - if (media_player == NULL ) { - jniThrowException(env, "java/lang/IllegalStateException", NULL); - return UNKNOWN_ERROR; - } - - Parcel *filter = parcelForJavaObject(env, request); - - if (filter == NULL ) { - jniThrowException(env, "java/lang/RuntimeException", "Filter is null"); - return UNKNOWN_ERROR; - } - - return (jint) media_player->setMetadataFilter(*filter); -} - -static jboolean -android_media_MediaPlayer2_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only, - jboolean apply_filter, jobject reply) -{ - sp<MediaPlayer2> media_player = getMediaPlayer(env, thiz); - if (media_player == NULL ) { - jniThrowException(env, "java/lang/IllegalStateException", NULL); - return JNI_FALSE; - } - - Parcel *metadata = parcelForJavaObject(env, reply); - - if (metadata == NULL ) { - jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null"); - return JNI_FALSE; - } - - metadata->freeData(); - // On return metadata is positioned at the beginning of the - // metadata. Note however that the parcel actually starts with the - // return code so you should not rewind the parcel using - // setDataPosition(0). - if (media_player->getMetadata(update_only, apply_filter, metadata) == OK) { - return JNI_TRUE; - } else { - return JNI_FALSE; - } -} - // This function gets some field IDs, which in turn causes class initialization. // It is called from a static block in MediaPlayer2, which won't run until the // first time an instance of this class is used. @@ -1532,8 +1496,6 @@ static const JNINativeMethod gMethods[] = { {"isLooping", "()Z", (void *)android_media_MediaPlayer2_isLooping}, {"_setVolume", "(FF)V", (void *)android_media_MediaPlayer2_setVolume}, {"_invoke", "([B)[B", (void *)android_media_MediaPlayer2_invoke}, - {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer2_setMetadataFilter}, - {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer2_getMetadata}, {"native_init", "()V", (void *)android_media_MediaPlayer2_native_init}, {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer2_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaPlayer2_native_finalize}, diff --git a/native/webview/loader/loader.cpp b/native/webview/loader/loader.cpp index adb371dde0fc..fee2a259cb54 100644 --- a/native/webview/loader/loader.cpp +++ b/native/webview/loader/loader.cpp @@ -64,7 +64,8 @@ jboolean DoReserveAddressSpace(jlong size) { return JNI_TRUE; } -jboolean DoCreateRelroFile(const char* lib, const char* relro) { +jboolean DoCreateRelroFile(JNIEnv* env, const char* lib, const char* relro, + jobject clazzLoader) { // Try to unlink the old file, since if this is being called, the old one is // obsolete. if (unlink(relro) != 0 && errno != ENOENT) { @@ -82,11 +83,19 @@ jboolean DoCreateRelroFile(const char* lib, const char* relro) { ALOGE("Failed to create temporary file %s: %s", relro_tmp, strerror(errno)); return JNI_FALSE; } + android_namespace_t* ns = + android::FindNamespaceByClassLoader(env, clazzLoader); + if (ns == NULL) { + ALOGE("Failed to find classloader namespace"); + return JNI_FALSE; + } android_dlextinfo extinfo; - extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_WRITE_RELRO; + extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_WRITE_RELRO | + ANDROID_DLEXT_USE_NAMESPACE; extinfo.reserved_addr = gReservedAddress; extinfo.reserved_size = gReservedSize; extinfo.relro_fd = tmp_fd; + extinfo.library_namespace = ns; void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo); int close_result = close(tmp_fd); if (handle == NULL) { @@ -143,13 +152,14 @@ jboolean ReserveAddressSpace(JNIEnv*, jclass, jlong size) { return DoReserveAddressSpace(size); } -jboolean CreateRelroFile(JNIEnv* env, jclass, jstring lib, jstring relro) { +jboolean CreateRelroFile(JNIEnv* env, jclass, jstring lib, jstring relro, + jobject clazzLoader) { jboolean ret = JNI_FALSE; const char* lib_utf8 = env->GetStringUTFChars(lib, NULL); if (lib_utf8 != NULL) { const char* relro_utf8 = env->GetStringUTFChars(relro, NULL); if (relro_utf8 != NULL) { - ret = DoCreateRelroFile(lib_utf8, relro_utf8); + ret = DoCreateRelroFile(env, lib_utf8, relro_utf8, clazzLoader); env->ReleaseStringUTFChars(relro, relro_utf8); } env->ReleaseStringUTFChars(lib, lib_utf8); @@ -179,7 +189,7 @@ const JNINativeMethod kJniMethods[] = { { "nativeReserveAddressSpace", "(J)Z", reinterpret_cast<void*>(ReserveAddressSpace) }, { "nativeCreateRelroFile", - "(Ljava/lang/String;Ljava/lang/String;)Z", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)Z", reinterpret_cast<void*>(CreateRelroFile) }, { "nativeLoadWithRelroFile", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)I", diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp index f908595c7da1..86f90327ce4f 100644 --- a/packages/CarSystemUI/Android.bp +++ b/packages/CarSystemUI/Android.bp @@ -51,6 +51,7 @@ android_app { libs: [ "telephony-common", "android.car", + "android.car.user", ], manifest: "AndroidManifest.xml", diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java index 0c4e02b59bec..e13e566ec901 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java @@ -33,7 +33,6 @@ import java.util.List; final class A2dpSinkProfile implements LocalBluetoothProfile { private static final String TAG = "A2dpSinkProfile"; - private static boolean V = true; private BluetoothA2dpSink mService; private boolean mIsProfileReady; @@ -56,7 +55,7 @@ final class A2dpSinkProfile implements LocalBluetoothProfile { implements BluetoothProfile.ServiceListener { public void onServiceConnected(int profile, BluetoothProfile proxy) { - if (V) Log.d(TAG,"Bluetooth service connected"); + Log.d(TAG, "Bluetooth service connected"); mService = (BluetoothA2dpSink) proxy; // We just bound to the service, so refresh the UI for any connected A2DP devices. List<BluetoothDevice> deviceList = mService.getConnectedDevices(); @@ -75,7 +74,7 @@ final class A2dpSinkProfile implements LocalBluetoothProfile { } public void onServiceDisconnected(int profile) { - if (V) Log.d(TAG,"Bluetooth service disconnected"); + Log.d(TAG, "Bluetooth service disconnected"); mIsProfileReady=false; } } @@ -106,7 +105,9 @@ final class A2dpSinkProfile implements LocalBluetoothProfile { } public List<BluetoothDevice> getConnectedDevices() { - if (mService == null) return new ArrayList<BluetoothDevice>(0); + if (mService == null) { + return new ArrayList<BluetoothDevice>(0); + } return mService.getDevicesMatchingConnectionStates( new int[] {BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING, @@ -114,24 +115,18 @@ final class A2dpSinkProfile implements LocalBluetoothProfile { } public boolean connect(BluetoothDevice device) { - if (mService == null) return false; - List<BluetoothDevice> srcs = getConnectedDevices(); - if (srcs != null) { - for (BluetoothDevice src : srcs) { - if (src.equals(device)) { - // Connect to same device, Ignore it - Log.d(TAG,"Ignoring Connect"); - return true; - } - } + if (mService == null) { + return false; } return mService.connect(device); } public boolean disconnect(BluetoothDevice device) { - if (mService == null) return false; + if (mService == null) { + return false; + } // Downgrade priority as user is disconnecting the headset. - if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ + if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { mService.setPriority(device, BluetoothProfile.PRIORITY_ON); } return mService.disconnect(device); @@ -145,17 +140,23 @@ final class A2dpSinkProfile implements LocalBluetoothProfile { } public boolean isPreferred(BluetoothDevice device) { - if (mService == null) return false; + if (mService == null) { + return false; + } return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; } public int getPreferred(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.PRIORITY_OFF; + if (mService == null) { + return BluetoothProfile.PRIORITY_OFF; + } return mService.getPriority(device); } public void setPreferred(BluetoothDevice device, boolean preferred) { - if (mService == null) return; + if (mService == null) { + return; + } if (preferred) { if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { mService.setPriority(device, BluetoothProfile.PRIORITY_ON); @@ -166,7 +167,9 @@ final class A2dpSinkProfile implements LocalBluetoothProfile { } boolean isA2dpPlaying() { - if (mService == null) return false; + if (mService == null) { + return false; + } List<BluetoothDevice> srcs = mService.getConnectedDevices(); if (!srcs.isEmpty()) { if (mService.isA2dpPlaying(srcs.get(0))) { @@ -208,7 +211,7 @@ final class A2dpSinkProfile implements LocalBluetoothProfile { } protected void finalize() { - if (V) Log.d(TAG, "finalize()"); + Log.d(TAG, "finalize()"); if (mService != null) { try { BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP_SINK, diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 649900bc97bd..b9f7323b1a9e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -78,12 +78,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> private final static String MESSAGE_REJECTION_COUNT_PREFS_NAME = "bluetooth_message_reject"; - /** - * When we connect to multiple profiles, we only want to display a single - * error even if they all fail. This tracks that state. - */ - private boolean mIsConnectingErrorPossible; - public long getHiSyncId() { return mHiSyncId; } @@ -230,9 +224,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> return; } - // Reset the only-show-one-error-dialog tracking variable - mIsConnectingErrorPossible = true; - int preferredProfiles = 0; for (LocalBluetoothProfile profile : mProfiles) { if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) { @@ -253,8 +244,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> if (!ensurePaired()) { return; } - // Reset the only-show-one-error-dialog tracking variable - mIsConnectingErrorPossible = true; for (LocalBluetoothProfile profile : mProfiles) { if (profile.isAutoConnectable()) { @@ -271,8 +260,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> */ public void connectProfile(LocalBluetoothProfile profile) { mConnectAttempted = SystemClock.elapsedRealtime(); - // Reset the only-show-one-error-dialog tracking variable - mIsConnectingErrorPossible = true; connectInt(profile); // Refresh the UI based on profile.connect() call refresh(); diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java index f9f623395801..4b6a22c9b2c8 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java @@ -36,7 +36,6 @@ import java.util.List; */ final class HfpClientProfile implements LocalBluetoothProfile { private static final String TAG = "HfpClientProfile"; - private static boolean V = false; private BluetoothHeadsetClient mService; private boolean mIsProfileReady; @@ -60,7 +59,7 @@ final class HfpClientProfile implements LocalBluetoothProfile { @Override public void onServiceConnected(int profile, BluetoothProfile proxy) { - if (V) Log.d(TAG,"Bluetooth service connected"); + Log.d(TAG, "Bluetooth service connected"); mService = (BluetoothHeadsetClient) proxy; // We just bound to the service, so refresh the UI for any connected HFP devices. List<BluetoothDevice> deviceList = mService.getConnectedDevices(); @@ -81,7 +80,7 @@ final class HfpClientProfile implements LocalBluetoothProfile { @Override public void onServiceDisconnected(int profile) { - if (V) Log.d(TAG,"Bluetooth service disconnected"); + Log.d(TAG, "Bluetooth service disconnected"); mIsProfileReady=false; } } @@ -115,7 +114,9 @@ final class HfpClientProfile implements LocalBluetoothProfile { } public List<BluetoothDevice> getConnectedDevices() { - if (mService == null) return new ArrayList<BluetoothDevice>(0); + if (mService == null) { + return new ArrayList<BluetoothDevice>(0); + } return mService.getDevicesMatchingConnectionStates( new int[] {BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING, @@ -124,23 +125,17 @@ final class HfpClientProfile implements LocalBluetoothProfile { @Override public boolean connect(BluetoothDevice device) { - if (mService == null) return false; - List<BluetoothDevice> srcs = getConnectedDevices(); - if (srcs != null) { - for (BluetoothDevice src : srcs) { - if (src.equals(device)) { - // Connect to same device, Ignore it - Log.d(TAG,"Ignoring Connect"); - return true; - } - } + if (mService == null) { + return false; } return mService.connect(device); } @Override public boolean disconnect(BluetoothDevice device) { - if (mService == null) return false; + if (mService == null) { + return false; + } // Downgrade priority as user is disconnecting the headset. if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){ mService.setPriority(device, BluetoothProfile.PRIORITY_ON); @@ -158,19 +153,25 @@ final class HfpClientProfile implements LocalBluetoothProfile { @Override public boolean isPreferred(BluetoothDevice device) { - if (mService == null) return false; + if (mService == null) { + return false; + } return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; } @Override public int getPreferred(BluetoothDevice device) { - if (mService == null) return BluetoothProfile.PRIORITY_OFF; + if (mService == null) { + return BluetoothProfile.PRIORITY_OFF; + } return mService.getPriority(device); } @Override public void setPreferred(BluetoothDevice device, boolean preferred) { - if (mService == null) return; + if (mService == null) { + return; + } if (preferred) { if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { mService.setPriority(device, BluetoothProfile.PRIORITY_ON); @@ -216,7 +217,7 @@ final class HfpClientProfile implements LocalBluetoothProfile { } protected void finalize() { - if (V) Log.d(TAG, "finalize()"); + Log.d(TAG, "finalize()"); if (mService != null) { try { BluetoothAdapter.getDefaultAdapter().closeProfileProxy( diff --git a/packages/SettingsLib/tests/robotests/config/robolectric.properties b/packages/SettingsLib/tests/robotests/config/robolectric.properties index 34a2a1a28ada..6b5b8e59472b 100644 --- a/packages/SettingsLib/tests/robotests/config/robolectric.properties +++ b/packages/SettingsLib/tests/robotests/config/robolectric.properties @@ -1,2 +1,5 @@ manifest=frameworks/base/packages/SettingsLib/tests/robotests/AndroidManifest.xml -sdk=NEWEST_SDK
\ No newline at end of file +sdk=NEWEST_SDK + +shadows=\ + com.android.settingslib.testutils.shadow.ShadowXmlUtils
\ No newline at end of file diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java new file mode 100644 index 000000000000..274fff83ea8a --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpSinkProfileTest.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package com.android.settingslib.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothA2dpSink; +import android.bluetooth.BluetoothProfile; + +import com.android.settingslib.SettingsLibRobolectricTestRunner; +import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadow.api.Shadow; + +@RunWith(SettingsLibRobolectricTestRunner.class) +@Config(shadows = {ShadowBluetoothAdapter.class}) +public class A2dpSinkProfileTest { + + @Mock + private CachedBluetoothDeviceManager mDeviceManager; + @Mock + private LocalBluetoothProfileManager mProfileManager; + @Mock + private BluetoothA2dpSink mService; + @Mock + private CachedBluetoothDevice mCachedBluetoothDevice; + @Mock + private BluetoothDevice mBluetoothDevice; + private BluetoothProfile.ServiceListener mServiceListener; + private A2dpSinkProfile mProfile; + private ShadowBluetoothAdapter mShadowBluetoothAdapter; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); + mProfile = new A2dpSinkProfile(RuntimeEnvironment.application, + mDeviceManager, mProfileManager); + mServiceListener = mShadowBluetoothAdapter.getServiceListener(); + mServiceListener.onServiceConnected(BluetoothProfile.A2DP_SINK, mService); + } + + @Test + public void connect_shouldConnectBluetoothA2dpSink() { + mProfile.connect(mBluetoothDevice); + verify(mService).connect(mBluetoothDevice); + } + + @Test + public void disconnect_shouldDisconnectBluetoothA2dpSink() { + mProfile.disconnect(mBluetoothDevice); + verify(mService).disconnect(mBluetoothDevice); + } + + @Test + public void getConnectionStatus_shouldReturnConnectionState() { + when(mService.getConnectionState(mBluetoothDevice)). + thenReturn(BluetoothProfile.STATE_CONNECTED); + assertThat(mProfile.getConnectionStatus(mBluetoothDevice)). + isEqualTo(BluetoothProfile.STATE_CONNECTED); + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java new file mode 100644 index 000000000000..187be0bf647b --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HfpClientProfileTest.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package com.android.settingslib.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHeadsetClient; +import android.bluetooth.BluetoothProfile; + +import com.android.settingslib.SettingsLibRobolectricTestRunner; +import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadow.api.Shadow; + +@RunWith(SettingsLibRobolectricTestRunner.class) +@Config(shadows = {ShadowBluetoothAdapter.class}) +public class HfpClientProfileTest { + + @Mock + private CachedBluetoothDeviceManager mDeviceManager; + @Mock + private LocalBluetoothProfileManager mProfileManager; + @Mock + private BluetoothHeadsetClient mService; + @Mock + private CachedBluetoothDevice mCachedBluetoothDevice; + @Mock + private BluetoothDevice mBluetoothDevice; + private BluetoothProfile.ServiceListener mServiceListener; + private HfpClientProfile mProfile; + private ShadowBluetoothAdapter mShadowBluetoothAdapter; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); + mProfile = new HfpClientProfile(RuntimeEnvironment.application, + mDeviceManager, mProfileManager); + mServiceListener = mShadowBluetoothAdapter.getServiceListener(); + mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT, mService); + } + + @Test + public void connect_shouldConnectBluetoothHeadsetClient() { + mProfile.connect(mBluetoothDevice); + verify(mService).connect(mBluetoothDevice); + } + + @Test + public void disconnect_shouldDisconnectBluetoothHeadsetClient() { + mProfile.disconnect(mBluetoothDevice); + verify(mService).disconnect(mBluetoothDevice); + } + + @Test + public void getConnectionStatus_shouldReturnConnectionState() { + when(mService.getConnectionState(mBluetoothDevice)). + thenReturn(BluetoothProfile.STATE_CONNECTED); + assertThat(mProfile.getConnectionStatus(mBluetoothDevice)). + isEqualTo(BluetoothProfile.STATE_CONNECTED); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowXmlUtils.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowXmlUtils.java new file mode 100644 index 000000000000..3455765ce24c --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowXmlUtils.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package com.android.settingslib.testutils.shadow; + +import static org.robolectric.shadow.api.Shadow.directlyOn; + +import com.android.internal.util.XmlUtils; + +import org.robolectric.Robolectric; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.util.ReflectionHelpers; + +@Implements(XmlUtils.class) +public class ShadowXmlUtils { + + @Implementation + public static final int convertValueToInt(CharSequence charSeq, int defaultValue) { + final Class<?> xmlUtilsClass = ReflectionHelpers.loadClass( + Robolectric.class.getClassLoader(), "com.android.internal.util.XmlUtils"); + try { + return directlyOn(xmlUtilsClass, "convertValueToInt", + ReflectionHelpers.ClassParameter.from(CharSequence.class, charSeq), + ReflectionHelpers.ClassParameter.from(int.class, new Integer(defaultValue))); + } catch (NumberFormatException e) { + return defaultValue; + } + } +}
\ No newline at end of file diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 4fc190d43056..ec35b3df73c9 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -16,6 +16,8 @@ package com.android.shell; +import static android.content.pm.PackageManager.FEATURE_LEANBACK; +import static android.content.pm.PackageManager.FEATURE_TELEVISION; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import static com.android.shell.BugreportPrefs.STATE_HIDE; @@ -235,6 +237,7 @@ public class BugreportProgressService extends Service { private static final Bundle sNotificationBundle = new Bundle(); private boolean mIsWatch; + private boolean mIsTv; private int mLastProgressPercent; @@ -255,6 +258,9 @@ public class BugreportProgressService extends Service { final Configuration conf = mContext.getResources().getConfiguration(); mIsWatch = (conf.uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_WATCH; + PackageManager packageManager = getPackageManager(); + mIsTv = packageManager.hasSystemFeature(FEATURE_LEANBACK) + || packageManager.hasSystemFeature(FEATURE_TELEVISION); NotificationManager nm = NotificationManager.from(mContext); nm.createNotificationChannel( new NotificationChannel(NOTIFICATION_CHANNEL_ID, @@ -500,8 +506,8 @@ public class BugreportProgressService extends Service { .setProgress(info.max, info.progress, false) .setOngoing(true); - // Wear bugreport doesn't need the bug info dialog, screenshot and cancel action. - if (!mIsWatch) { + // Wear and ATV bugreport doesn't need the bug info dialog, screenshot and cancel action. + if (!(mIsWatch || mIsTv)) { final Action cancelAction = new Action.Builder(null, mContext.getString( com.android.internal.R.string.cancel), newCancelIntent(mContext, info)).build(); final Intent infoIntent = new Intent(mContext, BugreportProgressService.class); diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 091350334835..9c33116a149b 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -66,6 +66,7 @@ android_library { libs: [ "telephony-common", "android.car", + "android.car.user", ], aaptflags: [ @@ -119,6 +120,7 @@ android_library { "android.test.runner", "telephony-common", "android.car", + "android.car.user", "android.test.base", ], aaptflags: [ @@ -144,6 +146,7 @@ android_app { libs: [ "telephony-common", "android.car", + "android.car.user", ], dxflags: ["--multi-dex"], diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml index 45d218548d1a..2c5120dd06f3 100644 --- a/packages/SystemUI/res/values-night/colors.xml +++ b/packages/SystemUI/res/values-night/colors.xml @@ -25,10 +25,10 @@ <color name="notification_legacy_background_color">@*android:color/notification_material_background_color</color> <!-- The color of the material notification background when dimmed --> - <color name="notification_material_background_dimmed_color">#aa212121</color> + <color name="notification_material_background_dimmed_color">#aa000000</color> <!-- The color of the dividing line between grouped notifications while . --> - <color name="notification_divider_color">#000</color> + <color name="notification_divider_color">#212121</color> <!-- The background color of the notification shade --> <color name="notification_shade_background_color">#181818</color> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 67db68deb928..216ed68e4fbe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -1141,9 +1141,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } private void updateNotificationColor() { + Configuration currentConfig = getResources().getConfiguration(); + boolean nightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) + == Configuration.UI_MODE_NIGHT_YES; + mNotificationColor = ContrastColorUtil.resolveContrastColor(mContext, getStatusBarNotification().getNotification().color, - getBackgroundColorWithoutTint()); + getBackgroundColorWithoutTint(), nightMode); mNotificationColorAmbient = ContrastColorUtil.resolveAmbientColor(mContext, getStatusBarNotification().getNotification().color); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java index 2cbb78a4a8f5..3744105b8b94 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java @@ -356,10 +356,11 @@ public class CarVolumeDialogImpl implements VolumeDialog { if (supplementalIconId != 0) { Drawable supplementalIcon = mContext.getResources().getDrawable(supplementalIconId); supplementalIcon.mutate().setTint(color); - listItem.setSupplementalIcon(supplementalIcon, true, - supplementalIconOnClickListener); + listItem.setSupplementalIcon(supplementalIcon, true); + listItem.setSupplementalIconListener(supplementalIconOnClickListener); } else { listItem.setSupplementalEmptyIcon(true); + listItem.setSupplementalIconListener(null); } mVolumeLineItems.add(listItem); diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk index 6057614f26ee..aac37a290edc 100644 --- a/packages/SystemUI/tests/Android.mk +++ b/packages/SystemUI/tests/Android.mk @@ -38,7 +38,8 @@ LOCAL_JAVA_LIBRARIES := \ android.test.runner \ telephony-common \ android.test.base \ - android.car + android.car \ + android.car.user LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui:com.android.keyguard diff --git a/packages/VpnDialogs/res/values-es-rUS/strings.xml b/packages/VpnDialogs/res/values-es-rUS/strings.xml index 3732ebc6a333..21cfc042e707 100644 --- a/packages/VpnDialogs/res/values-es-rUS/strings.xml +++ b/packages/VpnDialogs/res/values-es-rUS/strings.xml @@ -17,7 +17,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="prompt" msgid="3183836924226407828">"Solicitud de conexión"</string> - <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN que permite controlar el tráfico de la red. Acéptala solo si confías en la fuente. <br /> <br /> <img src=vpn_icon /> aparece en la parte superior de la pantalla cuando la VPN está activa."</string> + <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN capaz de controlar el tráfico de la red. Acéptala solo si confías en la fuente. <br /> <br /> <img src=vpn_icon /> aparece en la parte superior de la pantalla cuando se activa la VPN."</string> <string name="legacy_title" msgid="192936250066580964">"La VPN está conectada."</string> <string name="session" msgid="6470628549473641030">"Sesión:"</string> <string name="duration" msgid="3584782459928719435">"Duración:"</string> diff --git a/proto/src/metrics_constants/OWNERS b/proto/src/metrics_constants/OWNERS index 9c70a5e366b9..7009282b66e1 100644 --- a/proto/src/metrics_constants/OWNERS +++ b/proto/src/metrics_constants/OWNERS @@ -1,3 +1,4 @@ +cwren@android.com yanglu@google.com yaochen@google.com yro@google.com diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/ChunkHash.java b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkHash.java new file mode 100644 index 000000000000..1ae598ec9920 --- /dev/null +++ b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkHash.java @@ -0,0 +1,89 @@ +/* + * 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 + */ + +package com.android.server.backup.encryption.chunk; + +import com.android.internal.util.Preconditions; +import java.util.Arrays; +import java.util.Base64; + +/** + * Represents the SHA-256 hash of the plaintext of a chunk, which is frequently used as a key. + * + * <p>This class is {@link Comparable} and implements {@link #equals(Object)} and {@link + * #hashCode()}. + */ +public class ChunkHash implements Comparable<ChunkHash> { + /** The length of the hash in bytes. The hash is a SHA-256, so this is 256 bits. */ + public static final int HASH_LENGTH_BYTES = 256 / 8; + + private static final int UNSIGNED_MASK = 0xFF; + + private final byte[] mHash; + + /** Constructs a new instance which wraps the given SHA-256 hash bytes. */ + public ChunkHash(byte[] hash) { + Preconditions.checkArgument(hash.length == HASH_LENGTH_BYTES, "Hash must have 256 bits"); + mHash = hash; + } + + public byte[] getHash() { + return mHash; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ChunkHash)) { + return false; + } + + ChunkHash chunkHash = (ChunkHash) o; + return Arrays.equals(mHash, chunkHash.mHash); + } + + @Override + public int hashCode() { + return Arrays.hashCode(mHash); + } + + @Override + public int compareTo(ChunkHash other) { + return lexicographicalCompareUnsignedBytes(getHash(), other.getHash()); + } + + @Override + public String toString() { + return Base64.getEncoder().encodeToString(mHash); + } + + private static int lexicographicalCompareUnsignedBytes(byte[] left, byte[] right) { + int minLength = Math.min(left.length, right.length); + for (int i = 0; i < minLength; i++) { + int result = toInt(left[i]) - toInt(right[i]); + if (result != 0) { + return result; + } + } + return left.length - right.length; + } + + private static int toInt(byte value) { + return value & UNSIGNED_MASK; + } +} diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 499c03d05bf2..ad2f82c9b19f 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -81,6 +81,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseLongArray; +import android.util.StatsLog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; @@ -3637,6 +3638,8 @@ class AlarmManagerService extends SystemService { if (DEBUG_BATCH) { Slog.v(TAG, "Time changed notification from kernel; rebatching"); } + // StatsLog requires currentTimeMillis(), which == nowRTC to within usecs. + StatsLog.write(StatsLog.WALL_CLOCK_TIME_SHIFTED, nowRTC); removeImpl(mTimeTickSender); removeImpl(mDateChangeSender); rebatchAllAlarms(); diff --git a/services/core/java/com/android/server/HardwarePropertiesManagerService.java b/services/core/java/com/android/server/HardwarePropertiesManagerService.java index 4016d29fd2e6..e21a3d7917d1 100644 --- a/services/core/java/com/android/server/HardwarePropertiesManagerService.java +++ b/services/core/java/com/android/server/HardwarePropertiesManagerService.java @@ -26,7 +26,6 @@ import static android.os.HardwarePropertiesManager.TEMPERATURE_THROTTLING; import static android.os.HardwarePropertiesManager.TEMPERATURE_THROTTLING_BELOW_VR_MIN; import android.Manifest; -import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.admin.DevicePolicyManager; import android.content.Context; @@ -34,8 +33,8 @@ import android.content.pm.PackageManager; import android.os.Binder; import android.os.CpuUsageInfo; import android.os.IHardwarePropertiesManager; -import android.os.Process; import android.os.UserHandle; + import com.android.internal.util.DumpUtils; import com.android.server.vr.VrManagerInternal; @@ -166,11 +165,11 @@ public class HardwarePropertiesManagerService extends IHardwarePropertiesManager final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class); final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); if (!dpm.isDeviceOwnerApp(callingPackage) - && !vrService.isCurrentVrListener(callingPackage, userId) && mContext.checkCallingOrSelfPermission(Manifest.permission.DEVICE_POWER) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("The caller is not a device owner, bound VrListenerService" - + ", or holding the DEVICE_POWER permission."); + != PackageManager.PERMISSION_GRANTED + && (vrService == null || !vrService.isCurrentVrListener(callingPackage, userId))) { + throw new SecurityException("The caller is neither a device owner" + + ", nor holding the DEVICE_POWER permission, nor the current VrListener."); } } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 01e81525d5b5..380f6a7e581e 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -612,7 +612,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecDeleteSecurityAssociation( - mResourceId, + uid, mConfig.getSourceAddress(), mConfig.getDestinationAddress(), spi, @@ -679,7 +679,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecDeleteSecurityAssociation( - mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0); + uid, mSourceAddress, mDestinationAddress, mSpi, 0, 0); } } catch (ServiceSpecificException | RemoteException e) { Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e); @@ -821,13 +821,13 @@ public class IpSecService extends IIpSecService.Stub { for (int selAddrFamily : ADDRESS_FAMILIES) { netd.ipSecDeleteSecurityPolicy( - 0, + uid, selAddrFamily, IpSecManager.DIRECTION_OUT, mOkey, 0xffffffff); netd.ipSecDeleteSecurityPolicy( - 0, + uid, selAddrFamily, IpSecManager.DIRECTION_IN, mIkey, @@ -1083,7 +1083,8 @@ public class IpSecService extends IIpSecService.Stub { } checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + int callingUid = Binder.getCallingUid(); + UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); final int resourceId = mNextResourceId++; int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; @@ -1096,7 +1097,7 @@ public class IpSecService extends IIpSecService.Stub { spi = mSrvConfig .getNetdInstance() - .ipSecAllocateSpi(resourceId, "", destinationAddress, requestedSpi); + .ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi); Log.d(TAG, "Allocated SPI " + spi); userRecord.mSpiRecords.put( resourceId, @@ -1264,7 +1265,8 @@ public class IpSecService extends IIpSecService.Stub { // TODO: Check that underlying network exists, and IP addresses not assigned to a different // network (b/72316676). - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + int callerUid = Binder.getCallingUid(); + UserRecord userRecord = mUserResourceTracker.getUserRecord(callerUid); if (!userRecord.mTunnelQuotaTracker.isAvailable()) { return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } @@ -1285,7 +1287,7 @@ public class IpSecService extends IIpSecService.Stub { for (int selAddrFamily : ADDRESS_FAMILIES) { // Always send down correct local/remote addresses for template. netd.ipSecAddSecurityPolicy( - 0, // Use 0 for reqId + callerUid, selAddrFamily, IpSecManager.DIRECTION_OUT, localAddr, @@ -1294,7 +1296,7 @@ public class IpSecService extends IIpSecService.Stub { okey, 0xffffffff); netd.ipSecAddSecurityPolicy( - 0, // Use 0 for reqId + callerUid, selAddrFamily, IpSecManager.DIRECTION_IN, remoteAddr, @@ -1532,7 +1534,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecAddSecurityAssociation( - resourceId, + Binder.getCallingUid(), c.getMode(), c.getSourceAddress(), c.getDestinationAddress(), @@ -1623,13 +1625,14 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void applyTransportModeTransform( ParcelFileDescriptor socket, int direction, int resourceId) throws RemoteException { - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + int callingUid = Binder.getCallingUid(); + UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); checkDirection(direction); // Get transform record; if no transform is found, will throw IllegalArgumentException TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId); // TODO: make this a function. - if (info.pid != getCallingPid() || info.uid != getCallingUid()) { + if (info.pid != getCallingPid() || info.uid != callingUid) { throw new SecurityException("Only the owner of an IpSec Transform may apply it!"); } @@ -1643,7 +1646,7 @@ public class IpSecService extends IIpSecService.Stub { .getNetdInstance() .ipSecApplyTransportModeTransform( socket.getFileDescriptor(), - resourceId, + callingUid, direction, c.getSourceAddress(), c.getDestinationAddress(), @@ -1675,7 +1678,8 @@ public class IpSecService extends IIpSecService.Stub { enforceTunnelPermissions(callingPackage); checkDirection(direction); - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + int callingUid = Binder.getCallingUid(); + UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); // Get transform record; if no transform is found, will throw IllegalArgumentException TransformRecord transformInfo = @@ -1717,7 +1721,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecUpdateSecurityPolicy( - 0, // Use 0 for reqId + callingUid, selAddrFamily, direction, tunnelInterfaceInfo.getLocalAddress(), diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java index 708350d6f174..40f81b3c2850 100644 --- a/services/core/java/com/android/server/TextServicesManagerService.java +++ b/services/core/java/com/android/server/TextServicesManagerService.java @@ -20,7 +20,7 @@ import static android.view.textservice.TextServicesManager.DISABLE_PER_PROFILE_S import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; -import com.android.internal.inputmethod.LocaleUtils; +import com.android.internal.inputmethod.InputMethodUtils; import com.android.internal.textservice.ISpellCheckerService; import com.android.internal.textservice.ISpellCheckerServiceCallback; import com.android.internal.textservice.ISpellCheckerSession; @@ -461,7 +461,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { // is pre-installed or not. final Locale systemLocal = mContext.getResources().getConfiguration().locale; final ArrayList<Locale> suitableLocales = - LocaleUtils.getSuitableLocalesForSpellChecker(systemLocal); + InputMethodUtils.getSuitableLocalesForSpellChecker(systemLocal); if (DBG) { Slog.w(TAG, "findAvailSystemSpellCheckerLocked suitableLocales=" + Arrays.toString(suitableLocales.toArray(new Locale[suitableLocales.size()]))); @@ -475,7 +475,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { final int subtypeCount = info.getSubtypeCount(); for (int subtypeIndex = 0; subtypeIndex < subtypeCount; ++subtypeIndex) { final SpellCheckerSubtype subtype = info.getSubtypeAt(subtypeIndex); - final Locale subtypeLocale = LocaleUtils.constructLocaleFromString( + final Locale subtypeLocale = InputMethodUtils.constructLocaleFromString( subtype.getLocale()); if (locale.equals(subtypeLocale)) { // TODO: We may have more spell checkers that fall into this category. diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2ee598fee535..b64e8b87aeec 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2382,7 +2382,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } int logSampleRate = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.HIDDEN_API_ACCESS_LOG_SAMPLING_RATE, -1); + Settings.Global.HIDDEN_API_ACCESS_LOG_SAMPLING_RATE, 0x200); if (logSampleRate < 0 || logSampleRate > 0x10000) { logSampleRate = -1; } @@ -11941,7 +11941,9 @@ public class ActivityManagerService extends IActivityManager.Stub printed = true; } pw.print(" "); UserHandle.formatUid(pw, reg.uid); - pw.print(" "); pw.print(reg.pkg); pw.print(":"); + pw.print(" "); pw.print(reg.pkg); + final IUidObserver observer = mUidObservers.getRegisteredCallbackItem(i); + pw.print(" "); pw.print(observer.getClass().getTypeName()); pw.print(":"); if ((reg.which&ActivityManager.UID_OBSERVER_IDLE) != 0) { pw.print(" IDLE"); } diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java index 347a357aae04..cd4d6a3e14c5 100644 --- a/services/core/java/com/android/server/am/BaseErrorDialog.java +++ b/services/core/java/com/android/server/am/BaseErrorDialog.java @@ -33,7 +33,7 @@ class BaseErrorDialog extends AlertDialog { private boolean mConsuming = true; public BaseErrorDialog(Context context) { - super(context, com.android.internal.R.style.Theme_Dialog_AppError); + super(context, com.android.internal.R.style.Theme_DeviceDefault_Dialog_AppError); context.assertRuntimeOverlayThemable(); getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index 1b688a6cd9c6..76c191d5e9ea 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -26,8 +26,8 @@ import android.util.Pair; import android.util.Slog; import android.util.Spline; -import com.android.internal.util.Preconditions; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; import com.android.server.display.utils.Plog; import java.io.PrintWriter; @@ -77,8 +77,8 @@ public abstract class BrightnessMappingStrategy { Slog.w(TAG, "Screen brightness mapping does not cover whole range of available " + "backlight values, autobrightness functionality may be impaired."); } - BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(); - builder.setCurve(luxLevels, brightnessLevelsNits); + BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder( + luxLevels, brightnessLevelsNits); return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange, autoBrightnessAdjustmentMaxGamma); } else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) { diff --git a/services/core/java/com/android/server/InputContentUriTokenHandler.java b/services/core/java/com/android/server/inputmethod/InputContentUriTokenHandler.java index 6338b2f338ab..845fca1127dd 100644 --- a/services/core/java/com/android/server/InputContentUriTokenHandler.java +++ b/services/core/java/com/android/server/inputmethod/InputContentUriTokenHandler.java @@ -14,11 +14,10 @@ ** limitations under the License. */ -package com.android.server; +package com.android.server.inputmethod; import android.annotation.NonNull; import android.annotation.UserIdInt; -import android.app.ActivityManager; import android.app.UriGrantsManager; import android.content.Intent; import android.net.Uri; @@ -28,6 +27,7 @@ import android.os.RemoteException; import com.android.internal.annotations.GuardedBy; import com.android.internal.inputmethod.IInputContentUriToken; +import com.android.server.LocalServices; import com.android.server.uri.UriGrantsManagerInternal; final class InputContentUriTokenHandler extends IInputContentUriToken.Stub { diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index e435a4fd6384..49f33e09a724 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -13,7 +13,7 @@ * the License. */ -package com.android.server; +package com.android.server.inputmethod; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; @@ -149,7 +149,9 @@ import com.android.internal.view.IInputMethodSession; import com.android.internal.view.IInputSessionCallback; import com.android.internal.view.InputBindResult; import com.android.internal.view.InputMethodClient; -import com.android.server.inputmethod.InputMethodManagerInternal; +import com.android.server.EventLogTags; +import com.android.server.LocalServices; +import com.android.server.SystemService; import com.android.server.statusbar.StatusBarManagerService; import com.android.server.wm.WindowManagerInternal; @@ -253,7 +255,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * the notification. */ private static final String ACTION_SHOW_INPUT_METHOD_PICKER = - "com.android.server.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER"; + "com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER"; /** * Debug flag for overriding runtime {@link SystemProperties}. diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java index b4bc7f507701..452b699667b7 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java +++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java @@ -46,9 +46,9 @@ public class NetworkPolicyLogger { static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE); private static final int MAX_LOG_SIZE = - ActivityManager.isLowRamDeviceStatic() ? 20 : 50; + ActivityManager.isLowRamDeviceStatic() ? 100 : 400; private static final int MAX_NETWORK_BLOCKED_LOG_SIZE = - ActivityManager.isLowRamDeviceStatic() ? 50 : 100; + ActivityManager.isLowRamDeviceStatic() ? 100 : 400; private static final int EVENT_TYPE_GENERIC = 0; private static final int EVENT_NETWORK_BLOCKED = 1; diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 76f969508b28..48e09d744ff4 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -796,7 +796,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { try { mActivityManager.registerUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE, - ActivityManager.PROCESS_STATE_UNKNOWN, null); + NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE, "android"); mNetworkManager.registerObserver(mAlertObserver); } catch (RemoteException e) { // ignored; both services live in system_server diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 340ae0ad637a..7751f5f9bcb8 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -694,7 +694,8 @@ abstract public class ManagedServices { for (int userId : userIds) { if (enabled) { - if (isPackageOrComponentAllowed(component.toString(), userId)) { + if (isPackageOrComponentAllowed(component.toString(), userId) + || isPackageOrComponentAllowed(component.getPackageName(), userId)) { registerServiceLocked(component, userId); } else { Slog.d(TAG, component + " no longer has permission to be bound"); diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 593e7cdf4d66..13ff6e8e551f 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -107,7 +107,7 @@ public class PreferencesHelper implements RankingConfig { } // pkg|uid => PackagePreferences - private final ArrayMap<String, PackagePreferences> mPackagePreferencess = new ArrayMap<>(); + private final ArrayMap<String, PackagePreferences> mPackagePreferences = new ArrayMap<>(); // pkg => PackagePreferences private final ArrayMap<String, PackagePreferences> mRestoredWithoutUids = new ArrayMap<>(); @@ -142,109 +142,117 @@ public class PreferencesHelper implements RankingConfig { if (type != XmlPullParser.START_TAG) return; String tag = parser.getName(); if (!TAG_RANKING.equals(tag)) return; - // Clobber groups and channels with the xml, but don't delete other data that wasn't present - // at the time of serialization. - mRestoredWithoutUids.clear(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { - tag = parser.getName(); - if (type == XmlPullParser.END_TAG && TAG_RANKING.equals(tag)) { - return; - } - if (type == XmlPullParser.START_TAG) { - if (TAG_PACKAGE.equals(tag)) { - int uid = XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID); - String name = parser.getAttributeValue(null, ATT_NAME); - if (!TextUtils.isEmpty(name)) { - if (forRestore) { - try { - //TODO: http://b/22388012 - uid = mPm.getPackageUidAsUser(name, - UserHandle.USER_SYSTEM); - } catch (PackageManager.NameNotFoundException e) { - // noop + synchronized (mPackagePreferences) { + // Clobber groups and channels with the xml, but don't delete other data that wasn't present + + // at the time of serialization. + mRestoredWithoutUids.clear(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { + tag = parser.getName(); + if (type == XmlPullParser.END_TAG && TAG_RANKING.equals(tag)) { + return; + } + if (type == XmlPullParser.START_TAG) { + if (TAG_PACKAGE.equals(tag)) { + int uid = XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID); + String name = parser.getAttributeValue(null, ATT_NAME); + if (!TextUtils.isEmpty(name)) { + if (forRestore) { + try { + //TODO: http://b/22388012 + uid = mPm.getPackageUidAsUser(name, + UserHandle.USER_SYSTEM); + } catch (PackageManager.NameNotFoundException e) { + // noop + } } - } - PackagePreferences r = getOrCreatePackagePreferences(name, uid, - XmlUtils.readIntAttribute( - parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE), - XmlUtils.readIntAttribute(parser, ATT_PRIORITY, DEFAULT_PRIORITY), - XmlUtils.readIntAttribute( - parser, ATT_VISIBILITY, DEFAULT_VISIBILITY), - XmlUtils.readBooleanAttribute( - parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE)); - r.importance = XmlUtils.readIntAttribute( - parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); - r.priority = XmlUtils.readIntAttribute( - parser, ATT_PRIORITY, DEFAULT_PRIORITY); - r.visibility = XmlUtils.readIntAttribute( - parser, ATT_VISIBILITY, DEFAULT_VISIBILITY); - r.showBadge = XmlUtils.readBooleanAttribute( - parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE); - r.lockedAppFields = XmlUtils.readIntAttribute(parser, - ATT_APP_USER_LOCKED_FIELDS, DEFAULT_LOCKED_APP_FIELDS); - - final int innerDepth = parser.getDepth(); - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > innerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } + PackagePreferences r = getOrCreatePackagePreferences(name, uid, + XmlUtils.readIntAttribute( + parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE), + XmlUtils.readIntAttribute(parser, ATT_PRIORITY, + DEFAULT_PRIORITY), + XmlUtils.readIntAttribute( + parser, ATT_VISIBILITY, DEFAULT_VISIBILITY), + XmlUtils.readBooleanAttribute( + parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE)); + r.importance = XmlUtils.readIntAttribute( + parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); + r.priority = XmlUtils.readIntAttribute( + parser, ATT_PRIORITY, DEFAULT_PRIORITY); + r.visibility = XmlUtils.readIntAttribute( + parser, ATT_VISIBILITY, DEFAULT_VISIBILITY); + r.showBadge = XmlUtils.readBooleanAttribute( + parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE); + r.lockedAppFields = XmlUtils.readIntAttribute(parser, + ATT_APP_USER_LOCKED_FIELDS, DEFAULT_LOCKED_APP_FIELDS); + + final int innerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } - String tagName = parser.getName(); - // Channel groups - if (TAG_GROUP.equals(tagName)) { - String id = parser.getAttributeValue(null, ATT_ID); - CharSequence groupName = parser.getAttributeValue(null, ATT_NAME); - if (!TextUtils.isEmpty(id)) { - NotificationChannelGroup group - = new NotificationChannelGroup(id, groupName); - group.populateFromXml(parser); - r.groups.put(id, group); + String tagName = parser.getName(); + // Channel groups + if (TAG_GROUP.equals(tagName)) { + String id = parser.getAttributeValue(null, ATT_ID); + CharSequence groupName = parser.getAttributeValue(null, + ATT_NAME); + if (!TextUtils.isEmpty(id)) { + NotificationChannelGroup group + = new NotificationChannelGroup(id, groupName); + group.populateFromXml(parser); + r.groups.put(id, group); + } } - } - // Channels - if (TAG_CHANNEL.equals(tagName)) { - String id = parser.getAttributeValue(null, ATT_ID); - String channelName = parser.getAttributeValue(null, ATT_NAME); - int channelImportance = XmlUtils.readIntAttribute( - parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); - if (!TextUtils.isEmpty(id) && !TextUtils.isEmpty(channelName)) { - NotificationChannel channel = new NotificationChannel(id, - channelName, channelImportance); - if (forRestore) { - channel.populateFromXmlForRestore(parser, mContext); - } else { - channel.populateFromXml(parser); + // Channels + if (TAG_CHANNEL.equals(tagName)) { + String id = parser.getAttributeValue(null, ATT_ID); + String channelName = parser.getAttributeValue(null, ATT_NAME); + int channelImportance = XmlUtils.readIntAttribute( + parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); + if (!TextUtils.isEmpty(id) && !TextUtils.isEmpty(channelName)) { + NotificationChannel channel = new NotificationChannel(id, + channelName, channelImportance); + if (forRestore) { + channel.populateFromXmlForRestore(parser, mContext); + } else { + channel.populateFromXml(parser); + } + r.channels.put(id, channel); } - r.channels.put(id, channel); } - } - // Delegate - if (TAG_DELEGATE.equals(tagName)) { - int delegateId = - XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID); - String delegateName = - XmlUtils.readStringAttribute(parser, ATT_NAME); - boolean delegateEnabled = XmlUtils.readBooleanAttribute( - parser, ATT_ENABLED, Delegate.DEFAULT_ENABLED); - boolean userAllowed = XmlUtils.readBooleanAttribute( - parser, ATT_USER_ALLOWED, Delegate.DEFAULT_USER_ALLOWED); - Delegate d = null; - if (delegateId != UNKNOWN_UID && !TextUtils.isEmpty(delegateName)) { - d = new Delegate( - delegateName, delegateId, delegateEnabled, userAllowed); + // Delegate + if (TAG_DELEGATE.equals(tagName)) { + int delegateId = + XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID); + String delegateName = + XmlUtils.readStringAttribute(parser, ATT_NAME); + boolean delegateEnabled = XmlUtils.readBooleanAttribute( + parser, ATT_ENABLED, Delegate.DEFAULT_ENABLED); + boolean userAllowed = XmlUtils.readBooleanAttribute( + parser, ATT_USER_ALLOWED, + Delegate.DEFAULT_USER_ALLOWED); + Delegate d = null; + if (delegateId != UNKNOWN_UID && !TextUtils.isEmpty( + delegateName)) { + d = new Delegate( + delegateName, delegateId, delegateEnabled, + userAllowed); + } + r.delegate = d; } - r.delegate = d; - } - } + } - try { - deleteDefaultChannelIfNeeded(r); - } catch (PackageManager.NameNotFoundException e) { - Slog.e(TAG, "deleteDefaultChannelIfNeeded - Exception: " + e); + try { + deleteDefaultChannelIfNeeded(r); + } catch (PackageManager.NameNotFoundException e) { + Slog.e(TAG, "deleteDefaultChannelIfNeeded - Exception: " + e); + } } } } @@ -255,8 +263,8 @@ public class PreferencesHelper implements RankingConfig { private PackagePreferences getPackagePreferences(String pkg, int uid) { final String key = packagePreferencesKey(pkg, uid); - synchronized (mPackagePreferencess) { - return mPackagePreferencess.get(key); + synchronized (mPackagePreferences) { + return mPackagePreferences.get(key); } } @@ -268,10 +276,10 @@ public class PreferencesHelper implements RankingConfig { private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid, int importance, int priority, int visibility, boolean showBadge) { final String key = packagePreferencesKey(pkg, uid); - synchronized (mPackagePreferencess) { + synchronized (mPackagePreferences) { PackagePreferences r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg) - : mPackagePreferencess.get(key); + : mPackagePreferences.get(key); if (r == null) { r = new PackagePreferences(); r.pkg = pkg; @@ -290,7 +298,7 @@ public class PreferencesHelper implements RankingConfig { if (r.uid == UNKNOWN_UID) { mRestoredWithoutUids.put(pkg, r); } else { - mPackagePreferencess.put(key, r); + mPackagePreferences.put(key, r); } } return r; @@ -364,10 +372,10 @@ public class PreferencesHelper implements RankingConfig { out.startTag(null, TAG_RANKING); out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION)); - synchronized (mPackagePreferencess) { - final int N = mPackagePreferencess.size(); + synchronized (mPackagePreferences) { + final int N = mPackagePreferences.size(); for (int i = 0; i < N; i++) { - final PackagePreferences r = mPackagePreferencess.valueAt(i); + final PackagePreferences r = mPackagePreferences.valueAt(i); //TODO: http://b/22388012 if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_SYSTEM) { continue; @@ -882,10 +890,10 @@ public class PreferencesHelper implements RankingConfig { public int getBlockedAppCount(int userId) { int count = 0; - synchronized (mPackagePreferencess) { - final int N = mPackagePreferencess.size(); + synchronized (mPackagePreferences) { + final int N = mPackagePreferences.size(); for (int i = 0; i < N; i++) { - final PackagePreferences r = mPackagePreferencess.valueAt(i); + final PackagePreferences r = mPackagePreferences.valueAt(i); if (userId == UserHandle.getUserId(r.uid) && r.importance == IMPORTANCE_NONE) { count++; @@ -896,11 +904,11 @@ public class PreferencesHelper implements RankingConfig { } public void updateChannelsBypassingDnd() { - synchronized (mPackagePreferencess) { - final int numPackagePreferencess = mPackagePreferencess.size(); + synchronized (mPackagePreferences) { + final int numPackagePreferencess = mPackagePreferences.size(); for (int PackagePreferencesIndex = 0; PackagePreferencesIndex < numPackagePreferencess; PackagePreferencesIndex++) { - final PackagePreferences r = mPackagePreferencess.valueAt(PackagePreferencesIndex); + final PackagePreferences r = mPackagePreferences.valueAt(PackagePreferencesIndex); final int numChannels = r.channels.size(); for (int channelIndex = 0; channelIndex < numChannels; channelIndex++) { @@ -1064,8 +1072,8 @@ public class PreferencesHelper implements RankingConfig { pw.println("per-package config:"); pw.println("PackagePreferencess:"); - synchronized (mPackagePreferencess) { - dumpPackagePreferencess(pw, prefix, filter, mPackagePreferencess); + synchronized (mPackagePreferences) { + dumpPackagePreferencess(pw, prefix, filter, mPackagePreferences); } pw.println("Restored without uid:"); dumpPackagePreferencess(pw, prefix, filter, mRestoredWithoutUids); @@ -1073,9 +1081,9 @@ public class PreferencesHelper implements RankingConfig { public void dump(ProtoOutputStream proto, @NonNull NotificationManagerService.DumpFilter filter) { - synchronized (mPackagePreferencess) { + synchronized (mPackagePreferences) { dumpPackagePreferencess(proto, RankingHelperProto.RECORDS, filter, - mPackagePreferencess); + mPackagePreferences); } dumpPackagePreferencess(proto, RankingHelperProto.RECORDS_RESTORED_WITHOUT_UID, filter, mRestoredWithoutUids); @@ -1160,10 +1168,10 @@ public class PreferencesHelper implements RankingConfig { } catch (JSONException e) { // pass } - synchronized (mPackagePreferencess) { - final int N = mPackagePreferencess.size(); + synchronized (mPackagePreferences) { + final int N = mPackagePreferences.size(); for (int i = 0; i < N; i++) { - final PackagePreferences r = mPackagePreferencess.valueAt(i); + final PackagePreferences r = mPackagePreferences.valueAt(i); if (filter == null || filter.matches(r.pkg)) { JSONObject PackagePreferences = new JSONObject(); try { @@ -1240,11 +1248,11 @@ public class PreferencesHelper implements RankingConfig { } public Map<Integer, String> getPackageBans() { - synchronized (mPackagePreferencess) { - final int N = mPackagePreferencess.size(); + synchronized (mPackagePreferences) { + final int N = mPackagePreferences.size(); ArrayMap<Integer, String> packageBans = new ArrayMap<>(N); for (int i = 0; i < N; i++) { - final PackagePreferences r = mPackagePreferencess.valueAt(i); + final PackagePreferences r = mPackagePreferences.valueAt(i); if (r.importance == IMPORTANCE_NONE) { packageBans.put(r.uid, r.pkg); } @@ -1284,9 +1292,9 @@ public class PreferencesHelper implements RankingConfig { private Map<String, Integer> getPackageChannels() { ArrayMap<String, Integer> packageChannels = new ArrayMap<>(); - synchronized (mPackagePreferencess) { - for (int i = 0; i < mPackagePreferencess.size(); i++) { - final PackagePreferences r = mPackagePreferencess.valueAt(i); + synchronized (mPackagePreferences) { + for (int i = 0; i < mPackagePreferences.size(); i++) { + final PackagePreferences r = mPackagePreferences.valueAt(i); int channelCount = 0; for (int j = 0; j < r.channels.size(); j++) { if (!r.channels.valueAt(j).isDeleted()) { @@ -1300,22 +1308,22 @@ public class PreferencesHelper implements RankingConfig { } public void onUserRemoved(int userId) { - synchronized (mPackagePreferencess) { - int N = mPackagePreferencess.size(); + synchronized (mPackagePreferences) { + int N = mPackagePreferences.size(); for (int i = N - 1; i >= 0; i--) { - PackagePreferences PackagePreferences = mPackagePreferencess.valueAt(i); + PackagePreferences PackagePreferences = mPackagePreferences.valueAt(i); if (UserHandle.getUserId(PackagePreferences.uid) == userId) { - mPackagePreferencess.removeAt(i); + mPackagePreferences.removeAt(i); } } } } protected void onLocaleChanged(Context context, int userId) { - synchronized (mPackagePreferencess) { - int N = mPackagePreferencess.size(); + synchronized (mPackagePreferences) { + int N = mPackagePreferences.size(); for (int i = 0; i < N; i++) { - PackagePreferences PackagePreferences = mPackagePreferencess.valueAt(i); + PackagePreferences PackagePreferences = mPackagePreferences.valueAt(i); if (UserHandle.getUserId(PackagePreferences.uid) == userId) { if (PackagePreferences.channels.containsKey( NotificationChannel.DEFAULT_CHANNEL_ID)) { @@ -1341,8 +1349,8 @@ public class PreferencesHelper implements RankingConfig { for (int i = 0; i < size; i++) { final String pkg = pkgList[i]; final int uid = uidList[i]; - synchronized (mPackagePreferencess) { - mPackagePreferencess.remove(packagePreferencesKey(pkg, uid)); + synchronized (mPackagePreferences) { + mPackagePreferences.remove(packagePreferencesKey(pkg, uid)); } mRestoredWithoutUids.remove(pkg); updated = true; @@ -1355,8 +1363,8 @@ public class PreferencesHelper implements RankingConfig { try { r.uid = mPm.getPackageUidAsUser(r.pkg, changeUserId); mRestoredWithoutUids.remove(pkg); - synchronized (mPackagePreferencess) { - mPackagePreferencess.put(packagePreferencesKey(r.pkg, r.uid), r); + synchronized (mPackagePreferences) { + mPackagePreferences.put(packagePreferencesKey(r.pkg, r.uid), r); } updated = true; } catch (PackageManager.NameNotFoundException e) { @@ -1365,11 +1373,13 @@ public class PreferencesHelper implements RankingConfig { } // Package upgrade try { - PackagePreferences fullPackagePreferences = getPackagePreferences(pkg, - mPm.getPackageUidAsUser(pkg, changeUserId)); - if (fullPackagePreferences != null) { - createDefaultChannelIfNeeded(fullPackagePreferences); - deleteDefaultChannelIfNeeded(fullPackagePreferences); + synchronized (mPackagePreferences) { + PackagePreferences fullPackagePreferences = getPackagePreferences(pkg, + mPm.getPackageUidAsUser(pkg, changeUserId)); + if (fullPackagePreferences != null) { + createDefaultChannelIfNeeded(fullPackagePreferences); + deleteDefaultChannelIfNeeded(fullPackagePreferences); + } } } catch (PackageManager.NameNotFoundException e) { } diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index df680f2582c6..ac496a84f178 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -356,8 +356,8 @@ public abstract class WindowManagerInternal { /** * Notifies WindowManagerService that the current IME window status is being changed. * - * <p>Only {@link com.android.server.InputMethodManagerService} is the expected and tested - * caller of this method.</p> + * <p>Only {@link com.android.server.inputmethod.InputMethodManagerService} is the expected and + * tested caller of this method.</p> * * @param imeToken token to track the active input method. Corresponding IME windows can be * identified by checking {@link android.view.WindowManager.LayoutParams#token}. @@ -376,8 +376,8 @@ public abstract class WindowManagerInternal { /** * Notifies WindowManagerService that the current IME window status is being changed. * - * <p>Only {@link com.android.server.InputMethodManagerService} is the expected and tested - * caller of this method.</p> + * <p>Only {@link com.android.server.inputmethod.InputMethodManagerService} is the expected and + * tested caller of this method.</p> * * @param imeToken token to track the active input method. Corresponding IME windows can be * identified by checking {@link android.view.WindowManager.LayoutParams#token}. diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 0b6a33f8c013..c80b9d84ce61 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -82,6 +82,7 @@ import com.android.server.biometrics.face.FaceService; import com.android.server.biometrics.fingerprint.FingerprintService; import com.android.server.hdmi.HdmiControlService; import com.android.server.input.InputManagerService; +import com.android.server.inputmethod.InputMethodManagerService; import com.android.server.job.JobSchedulerService; import com.android.server.lights.LightsService; import com.android.server.media.MediaResourceMonitorService; diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java index ccc092d3b0e7..0176dd496a33 100644 --- a/services/net/java/android/net/ip/IpClient.java +++ b/services/net/java/android/net/ip/IpClient.java @@ -228,6 +228,9 @@ public class IpClient extends StateMachine { // Encourages logging of any available arguments, and all call sites // are necessarily logged identically. // + // NOTE: Log first because passed objects may or may not be thread-safe and + // once passed on to the callback they may be modified by another thread. + // // TODO: Find an lighter weight approach. private class LoggingCallbackWrapper extends Callback { private static final String PREFIX = "INVOKE "; @@ -243,63 +246,63 @@ public class IpClient extends StateMachine { @Override public void onPreDhcpAction() { - mCallback.onPreDhcpAction(); log("onPreDhcpAction()"); + mCallback.onPreDhcpAction(); } @Override public void onPostDhcpAction() { - mCallback.onPostDhcpAction(); log("onPostDhcpAction()"); + mCallback.onPostDhcpAction(); } @Override public void onNewDhcpResults(DhcpResults dhcpResults) { - mCallback.onNewDhcpResults(dhcpResults); log("onNewDhcpResults({" + dhcpResults + "})"); + mCallback.onNewDhcpResults(dhcpResults); } @Override public void onProvisioningSuccess(LinkProperties newLp) { - mCallback.onProvisioningSuccess(newLp); log("onProvisioningSuccess({" + newLp + "})"); + mCallback.onProvisioningSuccess(newLp); } @Override public void onProvisioningFailure(LinkProperties newLp) { - mCallback.onProvisioningFailure(newLp); log("onProvisioningFailure({" + newLp + "})"); + mCallback.onProvisioningFailure(newLp); } @Override public void onLinkPropertiesChange(LinkProperties newLp) { - mCallback.onLinkPropertiesChange(newLp); log("onLinkPropertiesChange({" + newLp + "})"); + mCallback.onLinkPropertiesChange(newLp); } @Override public void onReachabilityLost(String logMsg) { - mCallback.onReachabilityLost(logMsg); log("onReachabilityLost(" + logMsg + ")"); + mCallback.onReachabilityLost(logMsg); } @Override public void onQuit() { - mCallback.onQuit(); log("onQuit()"); + mCallback.onQuit(); } @Override public void installPacketFilter(byte[] filter) { - mCallback.installPacketFilter(filter); log("installPacketFilter(byte[" + filter.length + "])"); + mCallback.installPacketFilter(filter); } @Override public void startReadPacketFilter() { - mCallback.startReadPacketFilter(); log("startReadPacketFilter()"); + mCallback.startReadPacketFilter(); } @Override public void setFallbackMulticastFilter(boolean enabled) { - mCallback.setFallbackMulticastFilter(enabled); log("setFallbackMulticastFilter(" + enabled + ")"); + mCallback.setFallbackMulticastFilter(enabled); } @Override public void setNeighborDiscoveryOffload(boolean enable) { - mCallback.setNeighborDiscoveryOffload(enable); log("setNeighborDiscoveryOffload(" + enable + ")"); + mCallback.setNeighborDiscoveryOffload(enable); } } diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk index 2691701f79af..8b5977144db1 100644 --- a/services/robotests/Android.mk +++ b/services/robotests/Android.mk @@ -75,6 +75,7 @@ LOCAL_AIDL_INCLUDES := \ LOCAL_STATIC_JAVA_LIBRARIES := \ platform-robolectric-android-all-stubs \ android-support-test \ + guava \ mockito-robolectric-prebuilt \ platform-test-annotations \ truth-prebuilt \ diff --git a/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkHashTest.java b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkHashTest.java new file mode 100644 index 000000000000..3b6e038ec8cb --- /dev/null +++ b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkHashTest.java @@ -0,0 +1,101 @@ +/* + * 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 + */ + +package com.android.server.backup.encryption.chunk; + +import static com.google.common.truth.Truth.assertThat; + +import android.platform.test.annotations.Presubmit; +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderPackages; +import com.google.common.primitives.Bytes; +import java.util.Arrays; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +@RunWith(FrameworkRobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 26) +@SystemLoaderPackages({"com.android.server.backup"}) +@Presubmit +public class ChunkHashTest { + private static final int HASH_LENGTH_BYTES = 256 / 8; + private static final byte[] TEST_HASH_1 = Arrays.copyOf(new byte[] {1}, HASH_LENGTH_BYTES); + private static final byte[] TEST_HASH_2 = Arrays.copyOf(new byte[] {2}, HASH_LENGTH_BYTES); + + @Test + public void testGetHash_returnsHash() { + ChunkHash chunkHash = new ChunkHash(TEST_HASH_1); + + byte[] hash = chunkHash.getHash(); + + assertThat(hash).asList().containsExactlyElementsIn(Bytes.asList(TEST_HASH_1)).inOrder(); + } + + @Test + public void testEquals() { + ChunkHash chunkHash1 = new ChunkHash(TEST_HASH_1); + ChunkHash equalChunkHash1 = new ChunkHash(TEST_HASH_1); + ChunkHash chunkHash2 = new ChunkHash(TEST_HASH_2); + + assertThat(chunkHash1).isEqualTo(equalChunkHash1); + assertThat(chunkHash1).isNotEqualTo(chunkHash2); + } + + @Test + public void testHashCode() { + ChunkHash chunkHash1 = new ChunkHash(TEST_HASH_1); + ChunkHash equalChunkHash1 = new ChunkHash(TEST_HASH_1); + ChunkHash chunkHash2 = new ChunkHash(TEST_HASH_2); + + int hash1 = chunkHash1.hashCode(); + int equalHash1 = equalChunkHash1.hashCode(); + int hash2 = chunkHash2.hashCode(); + + assertThat(hash1).isEqualTo(equalHash1); + assertThat(hash1).isNotEqualTo(hash2); + } + + @Test + public void testCompareTo_whenEqual_returnsZero() { + ChunkHash chunkHash = new ChunkHash(TEST_HASH_1); + ChunkHash equalChunkHash = new ChunkHash(TEST_HASH_1); + + int result = chunkHash.compareTo(equalChunkHash); + + assertThat(result).isEqualTo(0); + } + + @Test + public void testCompareTo_whenArgumentGreater_returnsNegative() { + ChunkHash chunkHash1 = new ChunkHash(TEST_HASH_1); + ChunkHash chunkHash2 = new ChunkHash(TEST_HASH_2); + + int result = chunkHash1.compareTo(chunkHash2); + + assertThat(result).isLessThan(0); + } + + @Test + public void testCompareTo_whenArgumentSmaller_returnsPositive() { + ChunkHash chunkHash1 = new ChunkHash(TEST_HASH_1); + ChunkHash chunkHash2 = new ChunkHash(TEST_HASH_2); + + int result = chunkHash2.compareTo(chunkHash1); + + assertThat(result).isGreaterThan(0); + } +} diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index eb28e1ae2f23..1eb88baafa48 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -100,6 +100,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkPolicy; +import android.net.NetworkPolicyManager; import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; @@ -365,7 +366,7 @@ public class NetworkPolicyManagerServiceTest { return null; } }).when(mActivityManager).registerUidObserver(any(), anyInt(), - eq(ActivityManager.PROCESS_STATE_UNKNOWN), isNull(String.class)); + eq(NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE), isNull(String.class)); mFutureIntent = newRestrictBackgroundChangedFuture(); mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java index e6ca03b17092..48dda019f570 100644 --- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java +++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java @@ -152,8 +152,7 @@ public class BrightnessMappingStrategyTest { final float[] lux = { 0f, 1f }; final float[] nits = { 0, PowerManager.BRIGHTNESS_ON }; - BrightnessConfiguration config = new BrightnessConfiguration.Builder() - .setCurve(lux, nits) + BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits) .build(); strategy.setBrightnessConfiguration(config); assertNotEquals(1.0f, strategy.getBrightness(1f), 0.01 /*tolerance*/); @@ -214,8 +213,7 @@ public class BrightnessMappingStrategyTest { DISPLAY_RANGE_NITS[DISPLAY_RANGE_NITS.length - 1] }; - BrightnessConfiguration config = new BrightnessConfiguration.Builder() - .setCurve(lux, nits) + BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits) .build(); strategy.setBrightnessConfiguration(config); assertEquals(1.0f, strategy.getBrightness(1f), 0.01 /*tolerance*/); diff --git a/startop/OWNERS b/startop/OWNERS new file mode 100644 index 000000000000..bfe96d3ed15c --- /dev/null +++ b/startop/OWNERS @@ -0,0 +1,5 @@ +# mailing list: startop-eng@google.com +chriswailes@google.com +eholk@google.com +iam@google.com +sehr@google.com diff --git a/startop/scripts/app_startup/analyze_metrics.py b/startop/scripts/app_startup/analyze_metrics.py new file mode 100755 index 000000000000..d74d6f68d823 --- /dev/null +++ b/startop/scripts/app_startup/analyze_metrics.py @@ -0,0 +1,457 @@ +#!/usr/bin/env python3 +# +# Copyright 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. + +""" +Perform statistical analysis on measurements produced by app_startup_runner.py + +Install: +$> sudo apt-get install python3-scipy + +Usage: +$> ./analyze_metrics.py <filename.csv> [<filename2.csv> ...] +$> ./analyze_metrics.py --help +""" + +import argparse +import csv +import itertools +import os +import subprocess +import sys +import tempfile +from typing import Any, List, Dict, Iterable, TextIO, Tuple + +from scipy import stats as sc +import numpy as np + + +# These CSV columns are considered labels. Everything after them in the same row are metrics. +_LABEL_COLUMNS=['packages', 'readaheads', 'compiler_filters'] +# The metric series with the 'cold' readahead is the baseline. +# All others (warm, jit, etc) are the potential improvements. + +#fixme: this should probably be an option +_BASELINE=('readaheads', 'cold') +# ignore this for some statistic calculations +_IGNORE_PAIR=('readaheads', 'warm') +_PLOT_SUBKEY='readaheads' +_PLOT_GROUPKEY='packages' +_PLOT_DATA_INDEX = 0 +_DELTA=50 +_DELTA2=100 +_PVALUE_THRESHOLD=0.10 +_debug = False # See -d/--debug flag. + +def parse_options(argv: List[str] = None): + """Parse command line arguments and return an argparse Namespace object.""" + parser = argparse.ArgumentParser(description="Perform statistical analysis on measurements produced by app_start_runner.py.") + parser.add_argument('input_files', metavar='file.csv', nargs='+', help='CSV file produced by app_startup_runner.py') + + parser.add_argument('-d', '--debug', dest='debug', action='store_true', help='Add extra debugging output') + parser.add_argument('-os', '--output-samples', dest='output_samples', default='/dev/null', action='store', help='Store CSV for per-sample data') + parser.add_argument('-oc', '--output-comparable', dest='output_comparable', default='/dev/null', action='store', help='Output CSV for comparable against baseline') + parser.add_argument('-ocs', '--output-comparable-significant', dest='output_comparable_significant', default='/dev/null', action='store', help='Output CSV for comparable against baseline (significant only)') + parser.add_argument('-pt', '--pvalue-threshold', dest='pvalue_threshold', type=float, default=_PVALUE_THRESHOLD, action='store') + parser.add_argument('-dt', '--delta-threshold', dest='delta_threshold', type=int, default=_DELTA, action='store') + + return parser.parse_args(argv) + +def _debug_print(*args, **kwargs): + """Print the args to sys.stderr if the --debug/-d flag was passed in.""" + global _debug + if _debug: + print(*args, **kwargs, file=sys.stderr) + +def _expand_gen_repr(args): + new_args_list = [] + for i in args: + # detect iterable objects that do not have their own override of __str__ + if hasattr(i, '__iter__'): + to_str = getattr(i, '__str__') + if to_str.__objclass__ == object: + # the repr for a generator is just type+address, expand it out instead. + new_args_list.append([_expand_gen_repr([j])[0] for j in i]) + continue + # normal case: uses the built-in to-string + new_args_list.append(i) + return new_args_list + +def _debug_print_gen(*args, **kwargs): + """Like _debug_print but will turn any iterable args into a list.""" + if not _debug: + return + + new_args_list = _expand_gen_repr(args) + _debug_print(*new_args_list, **kwargs) + +def read_headers(input_file: TextIO) -> Tuple[List[str], List[str]]: + _debug_print("read_headers for file: ", input_file.name) + csv_reader = csv.reader(input_file) + + label_num_columns = len(_LABEL_COLUMNS) + + try: + header = next(csv_reader) + except StopIteration: + header = None + _debug_print('header', header) + + if not header: + return (None, None) + + labels = header[0:label_num_columns] + data = header[label_num_columns:] + + return (labels, data) + +def read_labels_and_data(input_file: TextIO) -> Iterable[Tuple[List[str], List[int]]]: + _debug_print("print_analysis for file: ", input_file.name) + csv_reader = csv.reader(input_file) + + # Skip the header because it doesn't contain any data. + # To get the header see read_headers function. + try: + header = next(csv_reader) + except StopIteration: + header = None + + label_num_columns = len(_LABEL_COLUMNS) + + for row in csv_reader: + if len(row) > 0 and row[0][0] == ';': + _debug_print("skip comment line", row) + continue + + labels = row[0:label_num_columns] + data = [int(i) for i in row[label_num_columns:]] + +# _debug_print("labels:", labels) +# _debug_print("data:", data) + + yield (labels, data) + +def group_metrics_by_label(it: Iterable[Tuple[List[str], List[int]]]): + prev_labels = None + data_2d = [] + + for label_list, data_list in it: + if prev_labels != label_list: + if prev_labels: +# _debug_print("grouped labels:", prev_labels, "data_2d:", data_2d) + yield (prev_labels, data_2d) + data_2d = [] + + data_2d.append(data_list) + prev_labels = label_list + + if prev_labels: +# _debug_print("grouped labels:", prev_labels, "data_2d:", data_2d) + yield (prev_labels, data_2d) + +def data_to_numpy(it: Iterable[Tuple[List[str], List[List[int]]]]) -> Iterable[Tuple[List[str], Any]]: + for label_list, data_2d in it: + yield (label_list, np.asarray(data_2d, dtype=int)) + +def iterate_columns(np_data_2d): + for col in range(np_data_2d.shape[1]): + col_as_array = np_data_2d[:, col] + yield col_as_array + +def confidence_interval(np_data_2d, percent=0.95): + """ + Given some data [[a,b,c],[d,e,f,]...] + + We assume the same metric is in the column (e.g. [a,d]) + and that data in the rows (e.g. [b,e]) are separate metric values. + + We then calculate the CI for each metric individually returning it as a list of tuples. + """ + arr = [] + for col_2d in iterate_columns(np_data_2d): + mean = col_2d.mean() + sigma = col_2d.std() + + ci = sc.norm.interval(percent, loc=mean, scale=sigma / np.sqrt(len(col_2d))) + arr.append(ci) + + # TODO: This seems to be returning NaN when all the samples have the same exact value + # (e.g. stddev=0, which can trivially happen when sample count = 1). + + return arr + +def print_analysis(it, label_header: List[str], data_header: List[str], output_samples: str): + print(label_header) + + with open(output_samples, "w") as output_file: + + csv_writer = csv.writer(output_file) + csv_writer.writerow(label_header + ['mean', 'std', 'confidence_interval_a', 'confidence_interval_b']) + + for label_list, np_data_2d in it: + print("**********************") + print(label_list) + print() + print(" ", data_header) + # aggregate computation column-wise + print("Mean: ", np_data_2d.mean(axis=0)) + print("Std: ", np_data_2d.std(axis=0)) + print("CI95%:", confidence_interval(np_data_2d)) + print("SEM: ", stats_standard_error_one(np_data_2d, axis=0)) + + #ci = confidence_interval(np_data_2d)[_PLOT_DATA_INDEX] + sem = stats_standard_error_one(np_data_2d, axis=0)[_PLOT_DATA_INDEX] + mean = np_data_2d.mean(axis=0)[_PLOT_DATA_INDEX] + + ci = (mean - sem, mean + sem) + + csv_writer.writerow(label_list + [mean, np_data_2d.std(axis=0)[_PLOT_DATA_INDEX], ci[0], ci[1]]) + +def from_file_group_by_labels(input_file): + (label_header, data_header) = read_headers(input_file) + label_data_iter = read_labels_and_data(input_file) + grouped_iter = group_metrics_by_label(label_data_iter) + grouped_numpy_iter = data_to_numpy(grouped_iter) + + return grouped_numpy_iter, label_header, data_header + +def list_without_index(list, index): + return list[:index] + list[index+1:] + +def group_by_without_baseline_key(grouped_numpy_iter, label_header): + """ + Data is considered comparable if the only difference is the baseline key + (i.e. the readahead is different but the package, compilation filter, etc, are the same). + + Returns iterator that's grouped by the non-baseline labels to an iterator of + (label_list, data_2d). + """ + baseline_index = label_header.index(_BASELINE[0]) + + def get_label_without_baseline(tpl): + label_list, _ = tpl + return list_without_index(label_list, baseline_index) + # [['pkgname', 'compfilter', 'warm'], [data]] + # [['pkgname', 'compfilter', 'cold'], [data2]] + # [['pkgname2', 'compfilter', 'warm'], [data3]] + # + # -> + # ( [['pkgname', 'compfilter', 'warm'], [data]] # ignore baseline label change. + # [['pkgname', 'compfilter', 'cold'], [data2]] ), # split here because the pkgname changed. + # ( [['pkgname2', 'compfilter', 'warm'], [data3]] ) + for group_info, it in itertools.groupby(grouped_numpy_iter, key = get_label_without_baseline): + yield it + + # TODO: replace this messy manual iteration/grouping with pandas + +def iterate_comparable_metrics(without_baseline_iter, label_header): + baseline_index = label_header.index(_BASELINE[0]) + baseline_value = _BASELINE[1] + + _debug_print("iterate comparables") + + def is_baseline_fun(tp): + ll, dat = tp + return ll[baseline_index] == baseline_value + + # iterating here when everything but the baseline key is the same. + for it in without_baseline_iter: + it1, it2 = itertools.tee(it) + + # find all the baseline data. + baseline_filter_it = filter(is_baseline_fun, it1) + + # find non-baseline data. + nonbaseline_filter_it = itertools.filterfalse(is_baseline_fun, it2) + + yield itertools.product(baseline_filter_it, nonbaseline_filter_it) + +def stats_standard_error_one(a, axis): + a_std = a.std(axis=axis, ddof=0) + a_len = a.shape[axis] + + return a_std / np.sqrt(a_len) + +def stats_standard_error(a, b, axis): + a_std = a.std(axis=axis, ddof=0) + b_std = b.std(axis=axis, ddof=0) + + a_len = a.shape[axis] + b_len = b.shape[axis] + + temp1 = a_std*a_std/a_len + temp2 = b_std*b_std/b_len + + return np.sqrt(temp1 + temp2) + +def stats_tvalue(a, b, axis, delta = 0): + a_mean = a.mean(axis=axis) + b_mean = b.mean(axis=axis) + + return (a_mean - b_mean - delta) / stats_standard_error(a, b, axis) + +def stats_pvalue(a, b, axis, delta, left:bool = False): + """ + Single-tailed 2-sample t-test. + + Returns p-value for the null hypothesis: mean(a) - mean(b) >= delta. + :param a: numpy 2d array + :param b: numpy 2d array + :param axis: which axis to do the calculations across + :param delta: test value of mean differences + :param left: if true then use <= delta instead of >= delta + :return: p-value + """ + # implement our own pvalue calculation because the built-in t-test (t,p values) + # only offer delta=0 , e.g. m1-m1 ? 0 + # we are however interested in m1-m2 ? delta + t_value = stats_tvalue(a, b, axis, delta) + + # 2-sample degrees of freedom is using the array sizes - 2. + dof = a.shape[axis] + b.shape[axis] - 2 + + if left: + # left tailed test. e.g. m1-m2 <= delta + return sc.t.cdf(t_value, dof) + else: + # right tailed test. e.g. m1-m2 >= delta + return sc.t.sf(t_value, dof) + # a left+right tailed test is a 2-tail t-test and can be done using ttest_ind for delta=0 + +def print_comparable_analysis(comparable_metrics_iter, label_header, data_header, output_comparable: str, output_comparable_significant: str): + baseline_value = _BASELINE[1] + baseline_index = label_header.index(_BASELINE[0]) + + old_baseline_label_list = None + delta = _DELTA + filter_value = _IGNORE_PAIR[1] + filter_index = label_header.index(_IGNORE_PAIR[0]) + + pvalue_threshold = _PVALUE_THRESHOLD + ci_threshold = (1 - _PVALUE_THRESHOLD) * 100.0 + + with open(output_comparable, "w") as output_file: + + csv_writer = csv.writer(output_file) + csv_writer.writerow(label_header + ['mean', 'mean_diff', 'sem', 'pvalue_2tailed', 'pvalue_gt%d' %(_DELTA), 'pvalue_gt%d' %(_DELTA2)]) + + print("------------------------------------------------------------------") + print("Comparison against the baseline %s = %s" %(_BASELINE, baseline_value)) + print("--- Right-tailed t-test checks if the baseline >= current %s by at least %d" %(_BASELINE[0], delta)) + print() + + global_stats = {'better_than_delta': [], 'better_than_delta_p95': []} + + for nested_it in comparable_metrics_iter: + print("************************") + + better_than_delta = [] + better_than_delta_p95 = [] + + saw_baseline_once = False + + for ((baseline_label_list, baseline_np_data_2d), (rest_label_list, rest_np_data_2d)) in nested_it: + _debug_print("baseline_label_list:", baseline_label_list) + _debug_print("baseline_np_data_2d:", baseline_np_data_2d) + _debug_print("rest_label_list:", rest_label_list) + _debug_print("rest_np_data_2d:", rest_np_data_2d) + + mean_diff = baseline_np_data_2d.mean(axis=0) - rest_np_data_2d.mean(axis=0) + # 2-sample 2-tailed t-test with delta=0 + # e.g. "Is it true that usually the two sample means are different?" + t_statistic, t_pvalue = sc.ttest_ind(baseline_np_data_2d, rest_np_data_2d, axis=0) + + # 2-sample 1-tailed t-test with delta=50 + # e.g. "Is it true that usually the sample means better than 50ms?" + t2 = stats_tvalue(baseline_np_data_2d, rest_np_data_2d, axis=0, delta=delta) + p2 = stats_pvalue(baseline_np_data_2d, rest_np_data_2d, axis=0, delta=delta) + + t2_b = stats_tvalue(baseline_np_data_2d, rest_np_data_2d, axis=0, delta=_DELTA2) + p2_b = stats_pvalue(baseline_np_data_2d, rest_np_data_2d, axis=0, delta=_DELTA2) + + print("%s vs %s" %(rest_label_list, baseline_value)) + print(" ", data_header) + print("Mean Difference: ", mean_diff) + print("T-test (2-tailed) != 0: t=%s, p=%s" %(t_statistic, t_pvalue)) + print("T-test (right-tailed) >= %d: t=%s, p=%s" %(_DELTA, t2, p2)) + print("T-test (right-tailed) >= %d: t=%s, p=%s" %(_DELTA2, t2_b, p2_b)) + + def write_out_values(label_list, *args): + csv_writer.writerow(label_list + [i[_PLOT_DATA_INDEX] for i in args]) + + sem = stats_standard_error(baseline_np_data_2d, rest_np_data_2d, axis=0) + if saw_baseline_once == False: + saw_baseline_once = True + base_sem = stats_standard_error_one(baseline_np_data_2d, axis=0) + write_out_values(baseline_label_list, baseline_np_data_2d.mean(axis=0), [0], base_sem, [None], [None], [None]) + write_out_values(rest_label_list, rest_np_data_2d.mean(axis=0), mean_diff, sem, t_pvalue, p2, p2_b) + + # now do the global statistics aggregation + + if rest_label_list[filter_index] == filter_value: + continue + + if mean_diff > delta: + better_than_delta.append((mean_diff, p2, rest_label_list)) + + if p2 <= pvalue_threshold: + better_than_delta_p95.append((mean_diff, rest_label_list)) + + if better_than_delta: + global_stats['better_than_delta'].append(better_than_delta) + if better_than_delta_p95: + global_stats['better_than_delta_p95'].append(better_than_delta_p95) + + print("------------------------") + print("Global statistics:") + print("//// Rows with %s=%s are ignored here." %_IGNORE_PAIR) + print("- # of results with mean diff better than delta(%d) = %d" %(delta, len(global_stats['better_than_delta']))) + print(" > (meandiff, pvalue, labels)") + for i in global_stats['better_than_delta']: + print(" > %s" %i) + print("- # of results with mean diff better than delta(%d) CI%d%% = %d" %(delta, ci_threshold, len(global_stats['better_than_delta_p95']))) + print(" > (meandiff, labels)") + for i in global_stats['better_than_delta_p95']: + print(" > %s" %i) + +def main(): + global _debug + global _DELTA + global _PVALUE_THRESHOLD + + opts = parse_options() + _debug = opts.debug + _debug_print("parsed options: ", opts) + + _PVALUE_THRESHOLD = opts.pvalue_threshold or _PVALUE_THRESHOLD + + for file_name in opts.input_files: + with open(file_name, 'r') as input_file: + (grouped_numpy_iter, label_header, data_header) = from_file_group_by_labels(input_file) + print_analysis(grouped_numpy_iter, label_header, data_header, opts.output_samples) + + with open(file_name, 'r') as input_file: + (grouped_numpy_iter, label_header, data_header) = from_file_group_by_labels(input_file) + without_baseline_iter = group_by_without_baseline_key(grouped_numpy_iter, label_header) + #_debug_print_gen(without_baseline_iter) + + comparable_metrics_iter = iterate_comparable_metrics(without_baseline_iter, label_header) + print_comparable_analysis(comparable_metrics_iter, label_header, data_header, opts.output_comparable, opts.output_comparable_significant) + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/startop/scripts/app_startup/app_startup_runner.py b/startop/scripts/app_startup/app_startup_runner.py new file mode 100755 index 000000000000..780bb4eaeeef --- /dev/null +++ b/startop/scripts/app_startup/app_startup_runner.py @@ -0,0 +1,322 @@ +#!/usr/bin/env python3 +# +# Copyright 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. + +# +# +# Measure application start-up time by launching applications under various combinations. +# See --help for more details. +# +# +# Sample usage: +# $> ./app_startup_runner.py -p com.google.android.calculator -r warm -r cold -lc 10 -o out.csv +# $> ./analyze_metrics.py out.csv +# +# + +import argparse +import csv +import itertools +import os +import subprocess +import sys +import tempfile +from typing import Any, Callable, Dict, Generic, Iterable, List, NamedTuple, TextIO, Tuple, TypeVar, Optional, Union + +# The following command line options participate in the combinatorial generation. +# All other arguments have a global effect. +_COMBINATORIAL_OPTIONS=['packages', 'readaheads', 'compiler_filters'] +_TRACING_READAHEADS=['mlock', 'fadvise'] +_FORWARD_OPTIONS={'loop_count': '--count'} +_RUN_SCRIPT=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'run_app_with_prefetch') + +RunCommandArgs = NamedTuple('RunCommandArgs', [('package', str), ('readahead', str), ('compiler_filter', Optional[str])]) +CollectorPackageInfo = NamedTuple('CollectorPackageInfo', [('package', str), ('compiler_filter', str)]) +_COLLECTOR_SCRIPT=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'collector') +_COLLECTOR_TIMEOUT_MULTIPLIER = 2 # take the regular --timeout and multiply by 2; systrace starts up slowly. + +_UNLOCK_SCREEN_SCRIPT=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'unlock_screen') + +# This must be the only mutable global variable. All other global variables are constants to avoid magic literals. +_debug = False # See -d/--debug flag. +_DEBUG_FORCE = None # Ignore -d/--debug if this is not none. + +# Type hinting names. +T = TypeVar('T') +NamedTupleMeta = Callable[..., T] # approximation of a (S : NamedTuple<T> where S() == T) metatype. + +def parse_options(argv: List[str] = None): + """Parse command line arguments and return an argparse Namespace object.""" + parser = argparse.ArgumentParser(description="Run one or more Android applications under various settings in order to measure startup time.") + # argparse considers args starting with - and -- optional in --help, even though required=True. + # by using a named argument group --help will clearly say that it's required instead of optional. + required_named = parser.add_argument_group('required named arguments') + required_named.add_argument('-p', '--package', action='append', dest='packages', help='package of the application', required=True) + required_named.add_argument('-r', '--readahead', action='append', dest='readaheads', help='which readahead mode to use', choices=('warm', 'cold', 'mlock', 'fadvise'), required=True) + + # optional arguments + # use a group here to get the required arguments to appear 'above' the optional arguments in help. + optional_named = parser.add_argument_group('optional named arguments') + optional_named.add_argument('-c', '--compiler-filter', action='append', dest='compiler_filters', help='which compiler filter to use. if omitted it does not enforce the app\'s compiler filter', choices=('speed', 'speed-profile', 'quicken')) + optional_named.add_argument('-s', '--simulate', dest='simulate', action='store_true', help='Print which commands will run, but don\'t run the apps') + optional_named.add_argument('-d', '--debug', dest='debug', action='store_true', help='Add extra debugging output') + optional_named.add_argument('-o', '--output', dest='output', action='store', help='Write CSV output to file.') + optional_named.add_argument('-t', '--timeout', dest='timeout', action='store', type=int, help='Timeout after this many seconds when executing a single run.') + optional_named.add_argument('-lc', '--loop-count', dest='loop_count', default=1, type=int, action='store', help='How many times to loop a single run.') + optional_named.add_argument('-in', '--inodes', dest='inodes', type=str, action='store', help='Path to inodes file (system/extras/pagecache/pagecache.py -d inodes)') + + return parser.parse_args(argv) + +# TODO: refactor this with a common library file with analyze_metrics.py +def _debug_print(*args, **kwargs): + """Print the args to sys.stderr if the --debug/-d flag was passed in.""" + if _debug: + print(*args, **kwargs, file=sys.stderr) + +def _expand_gen_repr(args): + """Like repr but any generator-like object has its iterator consumed + and then called repr on.""" + new_args_list = [] + for i in args: + # detect iterable objects that do not have their own override of __str__ + if hasattr(i, '__iter__'): + to_str = getattr(i, '__str__') + if to_str.__objclass__ == object: + # the repr for a generator is just type+address, expand it out instead. + new_args_list.append([_expand_gen_repr([j])[0] for j in i]) + continue + # normal case: uses the built-in to-string + new_args_list.append(i) + return new_args_list + +def _debug_print_gen(*args, **kwargs): + """Like _debug_print but will turn any iterable args into a list.""" + if not _debug: + return + + new_args_list = _expand_gen_repr(args) + _debug_print(*new_args_list, **kwargs) + +def _debug_print_nd(*args, **kwargs): + """Like _debug_print but will turn any NamedTuple-type args into a string.""" + if not _debug: + return + + new_args_list = [] + for i in args: + if hasattr(i, '_field_types'): + new_args_list.append("%s: %s" %(i.__name__, i._field_types)) + else: + new_args_list.append(i) + + _debug_print(*new_args_list, **kwargs) + +def dict_lookup_any_key(dictionary: dict, *keys: List[Any]): + for k in keys: + if k in dictionary: + return dictionary[k] + raise KeyError("None of the keys %s were in the dictionary" %(keys)) + +def generate_run_combinations(named_tuple: NamedTupleMeta[T], opts_dict: Dict[str, List[Optional[str]]])\ + -> Iterable[T]: + """ + Create all possible combinations given the values in opts_dict[named_tuple._fields]. + + :type T: type annotation for the named_tuple type. + :param named_tuple: named tuple type, whose fields are used to make combinations for + :param opts_dict: dictionary of keys to value list. keys correspond to the named_tuple fields. + :return: an iterable over named_tuple instances. + """ + combinations_list = [] + for k in named_tuple._fields: + # the key can be either singular or plural , e.g. 'package' or 'packages' + val = dict_lookup_any_key(opts_dict, k, k + "s") + + # treat {'x': None} key value pairs as if it was [None] + # otherwise itertools.product throws an exception about not being able to iterate None. + combinations_list.append(val or [None]) + + _debug_print("opts_dict: ", opts_dict) + _debug_print_nd("named_tuple: ", named_tuple) + _debug_print("combinations_list: ", combinations_list) + + for combo in itertools.product(*combinations_list): + yield named_tuple(*combo) + +def key_to_cmdline_flag(key: str) -> str: + """Convert key into a command line flag, e.g. 'foo-bars' -> '--foo-bar' """ + if key.endswith("s"): + key = key[:-1] + return "--" + key.replace("_", "-") + +def as_run_command(tpl: NamedTuple) -> List[Union[str, Any]]: + """ + Convert a named tuple into a command-line compatible arguments list. + + Example: ABC(1, 2, 3) -> ['--a', 1, '--b', 2, '--c', 3] + """ + args = [] + for key, value in tpl._asdict().items(): + if value is None: + continue + args.append(key_to_cmdline_flag(key)) + args.append(value) + return args + +def generate_group_run_combinations(run_combinations: Iterable[NamedTuple], dst_nt: NamedTupleMeta[T])\ + -> Iterable[Tuple[T, Iterable[NamedTuple]]]: + + def group_by_keys(src_nt): + src_d = src_nt._asdict() + # now remove the keys that aren't legal in dst. + for illegal_key in set(src_d.keys()) - set(dst_nt._fields): + if illegal_key in src_d: + del src_d[illegal_key] + + return dst_nt(**src_d) + + for args_list_it in itertools.groupby(run_combinations, group_by_keys): + (group_key_value, args_it) = args_list_it + yield (group_key_value, args_it) + +def parse_run_script_csv_file(csv_file: TextIO) -> List[int]: + """Parse a CSV file full of integers into a flat int list.""" + csv_reader = csv.reader(csv_file) + arr = [] + for row in csv_reader: + for i in row: + if i: + arr.append(int(i)) + return arr + +def make_script_command_with_temp_output(script: str, args: List[str], **kwargs)\ + -> Tuple[str, TextIO]: + """ + Create a command to run a script given the args. + Appends --count <loop_count> --output <tmp-file-name>. + Returns a tuple (cmd, tmp_file) + """ + tmp_output_file = tempfile.NamedTemporaryFile(mode='r') + cmd = [script] + args + for key, value in kwargs.items(): + cmd += ['--%s' %(key), "%s" %(value)] + if _debug: + cmd += ['--verbose'] + cmd = cmd + ["--output", tmp_output_file.name] + return cmd, tmp_output_file + +def execute_arbitrary_command(cmd: List[str], simulate: bool, timeout: int) -> Tuple[bool, str]: + if simulate: + print(" ".join(cmd)) + return (True, "") + else: + _debug_print("[EXECUTE]", cmd) + proc = subprocess.Popen(cmd, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + universal_newlines=True) + try: + script_output = proc.communicate(timeout=timeout)[0] + except subprocess.TimeoutExpired: + print("[TIMEDOUT]") + proc.kill() + script_output = proc.communicate()[0] + + _debug_print("[STDOUT]", script_output) + return_code = proc.wait() + passed = (return_code == 0) + _debug_print("[$?]", return_code) + if not passed: + print("[FAILED, code:%s]" %(return_code), script_output, file=sys.stderr) + + return (passed, script_output) + +def execute_run_combos(grouped_run_combos: Iterable[Tuple[CollectorPackageInfo, Iterable[RunCommandArgs]]], simulate: bool, inodes_path: str, timeout: int, loop_count: int, need_trace: bool): + # nothing will work if the screen isn't unlocked first. + execute_arbitrary_command([_UNLOCK_SCREEN_SCRIPT], simulate, timeout) + + for collector_info, run_combos in grouped_run_combos: + #collector_args = ["--package", package_name] + collector_args = as_run_command(collector_info) + # TODO: forward --wait_time for how long systrace runs? + # TODO: forward --trace_buffer_size for size of systrace buffer size? + collector_cmd, collector_tmp_output_file = make_script_command_with_temp_output(_COLLECTOR_SCRIPT, collector_args, inodes=inodes_path) + + with collector_tmp_output_file: + collector_passed = True + if need_trace: + collector_timeout = timeout and _COLLECTOR_TIMEOUT_MULTIPLIER * timeout + (collector_passed, collector_script_output) = execute_arbitrary_command(collector_cmd, simulate, collector_timeout) + # TODO: consider to print a ; collector wrote file to <...> into the CSV file so we know it was ran. + + for combos in run_combos: + args = as_run_command(combos) + + cmd, tmp_output_file = make_script_command_with_temp_output(_RUN_SCRIPT, args, count=loop_count, input=collector_tmp_output_file.name) + with tmp_output_file: + (passed, script_output) = execute_arbitrary_command(cmd, simulate, timeout) + parsed_output = simulate and [1,2,3] or parse_run_script_csv_file(tmp_output_file) + yield (passed, script_output, parsed_output) + +def gather_results(commands: Iterable[Tuple[bool, str, List[int]]], key_list: List[str], value_list: List[Tuple[str, ...]]): + _debug_print("gather_results: key_list = ", key_list) + yield key_list + ["time(ms)"] + + stringify_none = lambda s: s is None and "<none>" or s + + for ((passed, script_output, run_result_list), values) in itertools.zip_longest(commands, value_list): + if not passed: + continue + for result in run_result_list: + yield [stringify_none(i) for i in values] + [result] + + yield ["; avg(%s), min(%s), max(%s), count(%s)" %(sum(run_result_list, 0.0) / len(run_result_list), min(run_result_list), max(run_result_list), len(run_result_list)) ] + +def eval_and_save_to_csv(output, annotated_result_values): + csv_writer = csv.writer(output) + for row in annotated_result_values: + csv_writer.writerow(row) + output.flush() # see the output live. + +def main(): + global _debug + + opts = parse_options() + _debug = opts.debug + if _DEBUG_FORCE is not None: + _debug = _DEBUG_FORCE + _debug_print("parsed options: ", opts) + need_trace = not not set(opts.readaheads).intersection(set(_TRACING_READAHEADS)) + if need_trace and not opts.inodes: + print("Error: Missing -in/--inodes, required when using a readahead of %s" %(_TRACING_READAHEADS), file=sys.stderr) + return 1 + + output_file = opts.output and open(opts.output, 'w') or sys.stdout + + combos = lambda: generate_run_combinations(RunCommandArgs, vars(opts)) + _debug_print_gen("run combinations: ", combos()) + + grouped_combos = lambda: generate_group_run_combinations(combos(), CollectorPackageInfo) + _debug_print_gen("grouped run combinations: ", grouped_combos()) + + exec = execute_run_combos(grouped_combos(), opts.simulate, opts.inodes, opts.timeout, opts.loop_count, need_trace) + results = gather_results(exec, _COMBINATORIAL_OPTIONS, combos()) + eval_and_save_to_csv(output_file, results) + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/startop/scripts/app_startup/app_startup_runner_test.py b/startop/scripts/app_startup/app_startup_runner_test.py new file mode 100755 index 000000000000..f96f802a3aef --- /dev/null +++ b/startop/scripts/app_startup/app_startup_runner_test.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 +# +# Copyright 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. +# + +""" +Unit tests for the app_startup_runner.py script. + +Install: + $> sudo apt-get install python3-pytest ## OR + $> pip install -U pytest +See also https://docs.pytest.org/en/latest/getting-started.html + +Usage: + $> ./app_startup_runner_test.py + $> pytest app_startup_runner_test.py + $> python -m pytest app_startup_runner_test.py + +See also https://docs.pytest.org/en/latest/usage.html +""" + +# global imports +from contextlib import contextmanager +import io +import shlex +import sys +import typing + +# pip imports +import pytest + +# local imports +import app_startup_runner as asr + +# +# Argument Parsing Helpers +# + +@contextmanager +def ignore_stdout_stderr(): + """Ignore stdout/stderr output for duration of this context.""" + old_stdout = sys.stdout + old_stderr = sys.stderr + sys.stdout = io.StringIO() + sys.stderr = io.StringIO() + try: + yield + finally: + sys.stdout = old_stdout + sys.stderr = old_stderr + +@contextmanager +def argparse_bad_argument(msg): + """ + Assert that a SystemExit is raised when executing this context. + If the assertion fails, print the message 'msg'. + """ + with pytest.raises(SystemExit, message=msg): + with ignore_stdout_stderr(): + yield + +def assert_bad_argument(args, msg): + """ + Assert that the command line arguments in 'args' are malformed. + Prints 'msg' if the assertion fails. + """ + with argparse_bad_argument(msg): + parse_args(args) + +def parse_args(args): + """ + :param args: command-line like arguments as a single string + :return: dictionary of parsed key/values + """ + # "-a b -c d" => ['-a', 'b', '-c', 'd'] + return vars(asr.parse_options(shlex.split(args))) + +def default_dict_for_parsed_args(**kwargs): + """ + # Combine it with all of the "optional" parameters' default values. + """ + d = {'compiler_filters': None, 'simulate': False, 'debug': False, 'output': None, 'timeout': None, 'loop_count': 1, 'inodes': None} + d.update(kwargs) + return d + +def default_mock_dict_for_parsed_args(include_optional=True, **kwargs): + """ + Combine default dict with all optional parameters with some mock required parameters. + """ + d = {'packages': ['com.fake.package'], 'readaheads': ['warm']} + if include_optional: + d.update(default_dict_for_parsed_args()) + d.update(kwargs) + return d + +def parse_optional_args(str): + """ + Parse an argument string which already includes all the required arguments + in default_mock_dict_for_parsed_args. + """ + req = "--package com.fake.package --readahead warm" + return parse_args("%s %s" %(req, str)) + +def test_argparse(): + # missing arguments + assert_bad_argument("", "-p and -r are required") + assert_bad_argument("-r warm", "-p is required") + assert_bad_argument("--readahead warm", "-p is required") + assert_bad_argument("-p com.fake.package", "-r is required") + assert_bad_argument("--package com.fake.package", "-r is required") + + # required arguments are parsed correctly + ad = default_dict_for_parsed_args # assert dict + + assert parse_args("--package xyz --readahead warm") == ad(packages=['xyz'], readaheads=['warm']) + assert parse_args("-p xyz -r warm") == ad(packages=['xyz'], readaheads=['warm']) + + assert parse_args("-p xyz -r warm -s") == ad(packages=['xyz'], readaheads=['warm'], simulate=True) + assert parse_args("-p xyz -r warm --simulate") == ad(packages=['xyz'], readaheads=['warm'], simulate=True) + + # optional arguments are parsed correctly. + mad = default_mock_dict_for_parsed_args # mock assert dict + assert parse_optional_args("--output filename.csv") == mad(output='filename.csv') + assert parse_optional_args("-o filename.csv") == mad(output='filename.csv') + + assert parse_optional_args("--timeout 123") == mad(timeout=123) + assert parse_optional_args("-t 456") == mad(timeout=456) + + assert parse_optional_args("--loop-count 123") == mad(loop_count=123) + assert parse_optional_args("-lc 456") == mad(loop_count=456) + + assert parse_optional_args("--inodes bar") == mad(inodes="bar") + assert parse_optional_args("-in baz") == mad(inodes="baz") + + +def generate_run_combinations(*args): + # expand out the generator values so that assert x == y works properly. + return [i for i in asr.generate_run_combinations(*args)] + +def test_generate_run_combinations(): + blank_nd = typing.NamedTuple('Blank') + assert generate_run_combinations(blank_nd, {}) == [()], "empty" + assert generate_run_combinations(blank_nd, {'a' : ['a1', 'a2']}) == [()], "empty filter" + a_nd = typing.NamedTuple('A', [('a', str)]) + assert generate_run_combinations(a_nd, {'a': None}) == [(None,)], "None" + assert generate_run_combinations(a_nd, {'a': ['a1', 'a2']}) == [('a1',), ('a2',)], "one item" + assert generate_run_combinations(a_nd, + {'a' : ['a1', 'a2'], 'b': ['b1', 'b2']}) == [('a1',), ('a2',)],\ + "one item filter" + ab_nd = typing.NamedTuple('AB', [('a', str), ('b', str)]) + assert generate_run_combinations(ab_nd, + {'a': ['a1', 'a2'], + 'b': ['b1', 'b2']}) == [ab_nd('a1', 'b1'), + ab_nd('a1', 'b2'), + ab_nd('a2', 'b1'), + ab_nd('a2', 'b2')],\ + "two items" + + assert generate_run_combinations(ab_nd, + {'as': ['a1', 'a2'], + 'bs': ['b1', 'b2']}) == [ab_nd('a1', 'b1'), + ab_nd('a1', 'b2'), + ab_nd('a2', 'b1'), + ab_nd('a2', 'b2')],\ + "two items plural" + +def test_key_to_cmdline_flag(): + assert asr.key_to_cmdline_flag("abc") == "--abc" + assert asr.key_to_cmdline_flag("foos") == "--foo" + assert asr.key_to_cmdline_flag("ba_r") == "--ba-r" + assert asr.key_to_cmdline_flag("ba_zs") == "--ba-z" + + +def test_make_script_command_with_temp_output(): + cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script", args=[], count=1) + with tmp_file: + assert cmd_str == ["fake_script", "--count", "1", "--output", tmp_file.name] + + cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script", args=['a', 'b'], count=2) + with tmp_file: + assert cmd_str == ["fake_script", "a", "b", "--count", "2", "--output", tmp_file.name] + +def test_parse_run_script_csv_file(): + # empty file -> empty list + f = io.StringIO("") + assert asr.parse_run_script_csv_file(f) == [] + + # common case + f = io.StringIO("1,2,3") + assert asr.parse_run_script_csv_file(f) == [1,2,3] + + # ignore trailing comma + f = io.StringIO("1,2,3,4,5,") + assert asr.parse_run_script_csv_file(f) == [1,2,3,4,5] + + +if __name__ == '__main__': + pytest.main() diff --git a/startop/scripts/app_startup/launch_application b/startop/scripts/app_startup/launch_application new file mode 100755 index 000000000000..bc4ec51d6d08 --- /dev/null +++ b/startop/scripts/app_startup/launch_application @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Copyright 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. + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source "$DIR/lib/common" + +launch_application() { + local package="$1" + local activity="$2" + local am_output="$(adb shell am start -S -W "$package"/"$activity")" + verbose_print adb shell am start -S -W "$package"/"$activity" + if [[ $? -ne 0 ]]; then + echo "am start failed" >&2 + + return 1 + fi + + # for everything else use the am start "TotalTime" output. + verbose_print "$am_output" + local total_time="$(echo "$am_output" | grep 'TotalTime:' | sed 's/TotalTime: //g')" + verbose_print "total time: $total_time" + + # TODO: Extract alternative metrics such as the #reportFullyDrawn. + + echo "$total_time" +} + +launch_application "$@" diff --git a/startop/scripts/app_startup/lib/common b/startop/scripts/app_startup/lib/common new file mode 100755 index 000000000000..4d5a53e4bb0c --- /dev/null +++ b/startop/scripts/app_startup/lib/common @@ -0,0 +1,14 @@ +#!/bin/bash + +if [[ -z $ANDROID_BUILD_TOP ]]; then + echo "Please run source build/envsetup.sh first" >&2 + exit 1 +fi + +source $ANDROID_BUILD_TOP/build/envsetup.sh + +verbose_print() { + if [[ "$verbose" == "y" ]]; then + echo "$@" >&2 + fi +} diff --git a/startop/scripts/app_startup/run_app_with_prefetch b/startop/scripts/app_startup/run_app_with_prefetch new file mode 100755 index 000000000000..1ff5fc64116f --- /dev/null +++ b/startop/scripts/app_startup/run_app_with_prefetch @@ -0,0 +1,344 @@ +#!/bin/bash +# +# Copyright 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. + +usage() { + cat <<EOF +Usage: run_app_with_prefetch --package <name> [OPTIONS]... + + -p, --package <name> package of the app to test + -a, --activity <name> activity to use + -h, --help usage information (this) + -v, --verbose enable extra verbose printing + -i, --input <file> trace file protobuf (default 'TraceFile.pb') + -r, --readahead <mode> cold, warm, fadvise, mlock (default 'warm') + -w, --when <when> aot or jit (default 'aot') + -c, --count <count> how many times to run (default 1) + -s, --sleep <sec> how long to sleep after readahead + -t, --timeout <sec> how many seconds to timeout in between each app run (default 10) + -o, --output <file.csv> what file to write the performance results into as csv (default stdout) +EOF +} + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source "$DIR/lib/common" + +needs_trace_file="n" +input_file="" +package="" +mode='warm' +count=2 +sleep_time=2 +timeout=10 +output="" # stdout by default +when="aot" +parse_arguments() { + while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + usage + exit 0 + ;; + -p|--package) + package="$2" + shift + ;; + -a|--activity) + activity="$2" + shift + ;; + -i|--input) + input_file="$2" + shift + ;; + -v|--verbose) + export verbose="y" + ;; + -r|--readahead) + mode="$2" + shift + ;; + -c|--count) + count="$2" + ((count+=1)) + shift + ;; + -s|--sleep) + sleep_time="$2" + shift + ;; + -t|--timeout) + timeout="$2" + shift + ;; + -o|--output) + output="$2" + shift + ;; + -w|--when) + when="$2" + shift + ;; + --compiler-filter) + # ignore any '--compiler-filter xyz' settings. + # FIXME: app_startup_runner.py should not be passing this flag. + shift + ;; + *) + echo "Invalid argument: $1" >&2 + exit 1 + esac + shift + done +} + +echo_to_output_file() { + if [[ "x$output" != x ]]; then + echo "$@" >> $output + fi + # Always echo to stdout as well. + echo "$@" +} + +get_activity_name() { + local package="$1" + local action_key="android.intent.action.MAIN:" + + local activity_line="$(adb shell cmd package query-activities --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER | grep "$package")" + #echo $activity_line + IFS="/" read -a array <<< "$activity_line" + local activity_name="${array[1]}" + echo "$activity_name" + #adb shell am start "$package/$activity_name" +} + +find_package_path() { + local pkg="$1" + + res="$(adb shell find "/data/app/$pkg"-'*' -maxdepth 0 2> /dev/null)" + if [[ -z $res ]]; then + res="$(adb shell find "/system/app/$pkg"-'*' -maxdepth 0 2> /dev/null)" + fi + echo "$res" +} + +remote_pkill() { + local what="$1" + adb shell "for i in $(pid $what); do kill \$i; done" +} + +# Main entry point +if [[ $# -eq 0 ]]; then + usage + exit 1 +else + parse_arguments "$@" + + # if we do not have have package exit early with an error + [[ "$package" == "" ]] && echo "--package not specified" 1>&2 && exit 1 + + if [[ $mode != "cold" && $mode != "warm" ]]; then + needs_trace_file="y" + if [[ -z "$input_file" ]] || ! [[ -f $input_file ]]; then + echo "--input not specified" 1>&2 + exit 1 + fi + fi + + if [[ "$activity" == "" ]]; then + activity="$(get_activity_name "$package")" + if [[ "$activity" == "" ]]; then + echo "Activity name could not be found, invalid package name?" 1>&2 + exit 1 + else + verbose_print "Activity name inferred: " "$activity" + fi + fi +fi + +adb root > /dev/null + +if [[ ($when == jit) || ($when == aot) ]] && [[ "$(adb shell getenforce)" != "Permissive" ]]; then + echo "Disable selinux permissions and restart framework." + adb shell setenforce 0 + adb shell stop + adb shell start + adb wait-for-device +fi + +# TODO: set performance governor etc, preferrably only once +# before every single app run. + +# Kill everything before running. +remote_pkill "$package" +sleep 1 + +timings_array=() + +package_path="$(find_package_path "$package")" +if [[ $? -ne 0 ]]; then + echo "Failed to detect package path for '$package'" >&2 + exit 1 +fi +verbose_print "Package was in path '$package_path'" + + + + +keep_application_trace_file=n +application_trace_file_path="$package_path/TraceFile.pb" +trace_file_directory="$package_path" +if [[ $needs_trace_file == y ]]; then + # system server always passes down the package path in a hardcoded spot. + if [[ $when == "jit" ]]; then + verbose_print adb push "$input_file" "$application_trace_file_path" + adb push "$input_file" "$application_trace_file_path" + keep_application_trace_file="y" + else + # otherwise use a temporary directory to get normal non-jit behavior. + trace_file_directory="/data/local/tmp/prefetch/$package" + adb shell mkdir -p "$trace_file_directory" + verbose_print adb push "$input_file" "$trace_file_directory/TraceFile.pb" + adb push "$input_file" "$trace_file_directory/TraceFile.pb" + fi +fi + +# Everything other than JIT: remove the trace file, +# otherwise system server activity hints will kick in +# and the new just-in-time app pre-warmup will happen. +if [[ $keep_application_trace_file == "n" ]]; then + adb shell "[[ -f '$application_trace_file_path' ]] && rm '$application_trace_file_path'" +fi + +# Perform AOT readahead/pinning/etc when an application is about to be launched. +# For JIT readahead, we allow the system to handle it itself (this is a no-op). +# +# For warm, cold, etc modes which don't need readahead this is always a no-op. +perform_aot() { + local the_when="$1" # user: aot, jit + local the_mode="$2" # warm, cold, fadvise, mlock, etc. + + if [[ $the_when != "aot" ]]; then + # TODO: just in time implementation.. should probably use system server. + return 0 + fi + + # any non-warm/non-cold modes should use the iorap-activity-hint wrapper script. + if [[ $the_mode != 'warm' && $the_mode != 'cold' ]]; then + + # TODO: add activity_hint_sender.exp + verbose_print "starting with package=$package package_path=$trace_file_directory" + coproc hint_sender_fd { $ANDROID_BUILD_TOP/system/iorap/src/sh/activity_hint_sender.exp "$package" "$trace_file_directory" "$the_mode"; } + hint_sender_pid=$! + verbose_print "Activity hint sender began" + + notification_success="n" + while read -r -u "${hint_sender_fd[0]}" hint_sender_output; do + verbose_print "$hint_sender_output" + if [[ "$hint_sender_output" == "Press any key to send completed event..."* ]]; then + verbose_print "WE DID SEE NOTIFICATION SUCCESS." + notification_success='y' + # Give it some time to actually perform the readaheads. + sleep $sleep_time + break + fi + done + + if [[ $notification_success == 'n' ]]; then + echo "[FATAL] Activity hint notification failed." 1>&2 + exit 1 + fi + fi +} + +perform_aot_cleanup() { + local the_when="$1" # user: aot, jit + local the_mode="$2" # warm, cold, fadvise, mlock, etc. + + if [[ $the_when != "aot" ]]; then + # TODO: just in time implementation.. should probably use system server. + return 0 + fi + + # any non-warm/non-cold modes should use the iorap-activity-hint wrapper script. + if [[ $the_mode != 'warm' && $the_mode != 'cold' ]]; then + # Clean up the hint sender by telling it that the launch was completed, + # and to shutdown the watcher. + echo "Done\n" >&"${hint_sender_fd[1]}" + + while read -r -u "${hint_sender_fd[0]}" hint_sender_output; do + verbose_print "$hint_sender_output" + done + + wait $hint_sender_pid + fi +} + +# TODO: This loop logic could probably be moved into app_startup_runner.py +for ((i=0;i<count;++i)) do + verbose_print "==========================================" + verbose_print "==== ITERATION $i ====" + verbose_print "==========================================" + if [[ $mode != "warm" ]]; then + verbose_print "Drop caches for non-warm start." + # Drop all caches to get cold starts. + adb shell "echo 3 > /proc/sys/vm/drop_caches" + fi + + perform_aot "$when" "$mode" + + verbose_print "Running with timeout $timeout" + + # TODO: multiple metrics output. + total_time="$(timeout $timeout $DIR/launch_application "$package" "$activity")" + + if [[ $? -ne 0 ]]; then + echo "WARNING: Skip bad result, try iteration again." >&2 + ((i=i-1)) + continue + fi + + perform_aot_cleanup "$when" "$mode" + + echo "Iteration $i. Total time was: $total_time" + + timings_array+=($total_time) +done + +# drop the first result which is usually garbage. +timings_array=("${timings_array[@]:1}") + + +# Print out interactive/debugging timings and averages. +# Other scripts should use the --output flag and parse the CSV. +for tim in "${timings_array[@]}"; do + echo_to_output_file -ne "$tim," +done +echo_to_output_file "" + +average_string=$(echo "${timings_array[@]}" | awk '{s+=$0}END{print "Average:",s/NR}' RS=" ") +echo -ne ${average_string}. +if [[ x$output != x ]]; then + echo " Saved results to '$output'" +fi + +# Temporary hack around multiple activities being launched with different package paths (for same app): +# Clean up all left-over TraceFile.pb +adb shell 'for i in $(find /data/app -name TraceFile.pb); do rm \$i; done' + +# Kill the process to ensure AM isn't keeping it around. +remote_pkill "$package" + +exit 0 diff --git a/core/tests/webkit/apk_with_native_libs/jni/Android.mk b/startop/scripts/app_startup/unlock_screen index fd5b5eb50c5f..478294c9f35d 100644..100755 --- a/core/tests/webkit/apk_with_native_libs/jni/Android.mk +++ b/startop/scripts/app_startup/unlock_screen @@ -1,32 +1,22 @@ +#!/bin/bash # -# Copyright (C) 2017 The Android Open Source Project +# Copyright 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 +# 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. -# - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE := libwebviewtest_jni - -LOCAL_MODULE_TAGS := optional - -LOCAL_SRC_FILES := WebViewTestJniOnLoad.cpp -LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) - -LOCAL_SDK_VERSION := current - -LOCAL_MULTILIB := both - -include $(BUILD_SHARED_LIBRARY) +# This turns the screen on if it's off. +# If it's on it does nothing unless its on the home screen, in which case it opens up some background +# menu. +# +# However, this menu is ignored because "am start" commands still work as expected. +adb shell input keyevent MENU diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 1d9e6052a31c..8ebfec47c4ea 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -1589,12 +1589,14 @@ public class SubscriptionManager { } /** - * @return true if a valid subId else false - * @hide + * Checks if the supplied subscription ID is valid. + * Note: a valid subscription ID does not necessarily correspond to an active subscription. + * + * @param subscriptionId The subscription ID. + * @return true if the supplied subscriptionId is valid; false otherwise. */ - @UnsupportedAppUsage - public static boolean isValidSubscriptionId(int subId) { - return subId > INVALID_SUBSCRIPTION_ID ; + public static boolean isValidSubscriptionId(int subscriptionId) { + return subscriptionId > INVALID_SUBSCRIPTION_ID; } /** diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java index 102cb7c77055..99a5a69213fa 100644 --- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java +++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java @@ -41,9 +41,9 @@ import android.net.Network; import android.net.NetworkUtils; import android.os.Binder; import android.os.ParcelFileDescriptor; -import android.test.mock.MockContext; import android.support.test.filters.SmallTest; import android.system.Os; +import android.test.mock.MockContext; import java.net.Socket; import java.util.Arrays; @@ -121,6 +121,7 @@ public class IpSecServiceParameterizedTest { IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig; IpSecService mIpSecService; Network fakeNetwork = new Network(0xAB); + int mUid = Os.getuid(); private static final IpSecAlgorithm AUTH_ALGO = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4); @@ -181,7 +182,7 @@ public class IpSecServiceParameterizedTest { verify(mMockNetd) .ipSecDeleteSecurityAssociation( - eq(spiResp.resourceId), + eq(mUid), anyString(), anyString(), eq(TEST_SPI), @@ -189,8 +190,7 @@ public class IpSecServiceParameterizedTest { anyInt()); // Verify quota and RefcountedResource objects cleaned up - IpSecService.UserRecord userRecord = - mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid()); + IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid); assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent); try { userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId); @@ -209,8 +209,7 @@ public class IpSecServiceParameterizedTest { mIpSecService.allocateSecurityParameterIndex( mDestinationAddr, TEST_SPI, new Binder()); - IpSecService.UserRecord userRecord = - mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid()); + IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid); IpSecService.RefcountedResource refcountedRecord = userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId); @@ -218,7 +217,7 @@ public class IpSecServiceParameterizedTest { verify(mMockNetd) .ipSecDeleteSecurityAssociation( - eq(spiResp.resourceId), + eq(mUid), anyString(), anyString(), eq(TEST_SPI), @@ -270,7 +269,7 @@ public class IpSecServiceParameterizedTest { verify(mMockNetd) .ipSecAddSecurityAssociation( - eq(createTransformResp.resourceId), + eq(mUid), anyInt(), anyString(), anyString(), @@ -305,7 +304,7 @@ public class IpSecServiceParameterizedTest { verify(mMockNetd) .ipSecAddSecurityAssociation( - eq(createTransformResp.resourceId), + eq(mUid), anyInt(), anyString(), anyString(), @@ -361,13 +360,12 @@ public class IpSecServiceParameterizedTest { IpSecTransformResponse createTransformResp = mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage"); - IpSecService.UserRecord userRecord = - mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid()); + IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid); assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent); mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId()); verify(mMockNetd, times(0)) .ipSecDeleteSecurityAssociation( - eq(createTransformResp.resourceId), + eq(mUid), anyString(), anyString(), eq(TEST_SPI), @@ -389,7 +387,7 @@ public class IpSecServiceParameterizedTest { verify(mMockNetd, times(1)) .ipSecDeleteSecurityAssociation( - eq(createTransformResp.resourceId), + eq(mUid), anyString(), anyString(), eq(TEST_SPI), @@ -397,8 +395,7 @@ public class IpSecServiceParameterizedTest { anyInt()); // Verify quota and RefcountedResource objects cleaned up - IpSecService.UserRecord userRecord = - mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid()); + IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid); assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent); assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent); @@ -433,8 +430,7 @@ public class IpSecServiceParameterizedTest { IpSecTransformResponse createTransformResp = mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage"); - IpSecService.UserRecord userRecord = - mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid()); + IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid); IpSecService.RefcountedResource refcountedRecord = userRecord.mTransformRecords.getRefcountedResourceOrThrow( createTransformResp.resourceId); @@ -443,7 +439,7 @@ public class IpSecServiceParameterizedTest { verify(mMockNetd) .ipSecDeleteSecurityAssociation( - eq(createTransformResp.resourceId), + eq(mUid), anyString(), anyString(), eq(TEST_SPI), @@ -477,7 +473,7 @@ public class IpSecServiceParameterizedTest { verify(mMockNetd) .ipSecApplyTransportModeTransform( eq(pfd.getFileDescriptor()), - eq(resourceId), + eq(mUid), eq(IpSecManager.DIRECTION_OUT), anyString(), anyString(), @@ -509,8 +505,7 @@ public class IpSecServiceParameterizedTest { createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage"); // Check that we have stored the tracking object, and retrieve it - IpSecService.UserRecord userRecord = - mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid()); + IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid); IpSecService.RefcountedResource refcountedRecord = userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow( createTunnelResp.resourceId); @@ -530,8 +525,7 @@ public class IpSecServiceParameterizedTest { IpSecTunnelInterfaceResponse createTunnelResp = createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage"); - IpSecService.UserRecord userRecord = - mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid()); + IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid); mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage"); @@ -551,8 +545,7 @@ public class IpSecServiceParameterizedTest { IpSecTunnelInterfaceResponse createTunnelResp = createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage"); - IpSecService.UserRecord userRecord = - mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid()); + IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid); IpSecService.RefcountedResource refcountedRecord = userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow( createTunnelResp.resourceId); diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh index 29bf74c7a8b9..e50c70d0656a 100755 --- a/tools/aosp/aosp_sha.sh +++ b/tools/aosp/aosp_sha.sh @@ -1,18 +1,24 @@ #!/bin/bash -LOCAL_DIR="$( dirname ${BASH_SOURCE} )" +LOCAL_DIR="$( dirname "${BASH_SOURCE}" )" -if git branch -vv | grep "^*" | grep "\[aosp/master" > /dev/null; then +if git branch -vv | grep -q -P "^\*[^\[]+\[aosp/"; then # Change appears to be in AOSP exit 0 else # Change appears to be non-AOSP; search for files - git show --name-only --pretty=format: $1 | grep $2 | while read file; do - echo + count=0 + while read -r file ; do + if (( count == 0 )); then + echo + fi echo -e "\033[0;31mThe source of truth for '$file' is in AOSP.\033[0m" + (( count++ )) + done < <(git show --name-only --pretty=format: $1 | grep -- "$2") + if (( count != 0 )); then echo - echo "If your change contains no confidential details, please upload and merge" - echo "this change at https://android-review.googlesource.com/." + echo "If your change contains no confidential details (such as security fixes), please" + echo "upload and merge this change at https://android-review.googlesource.com/." echo exit 77 - done + fi fi |