Merge "Move the job scheduler service code to its own jar file."
diff --git a/api/current.txt b/api/current.txt
index a7b38a5..363ce82 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2966,6 +2966,7 @@
}
public final class GestureDescription {
+ method public int getDisplayId();
method public static long getMaxGestureDuration();
method public static int getMaxStrokeCount();
method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(@IntRange(from=0) int);
@@ -2976,6 +2977,7 @@
ctor public GestureDescription.Builder();
method public android.accessibilityservice.GestureDescription.Builder addStroke(@NonNull android.accessibilityservice.GestureDescription.StrokeDescription);
method public android.accessibilityservice.GestureDescription build();
+ method @NonNull public android.accessibilityservice.GestureDescription.Builder setDisplayId(int);
}
public static class GestureDescription.StrokeDescription {
@@ -11757,6 +11759,9 @@
field public static final String FEATURE_SENSOR_RELATIVE_HUMIDITY = "android.hardware.sensor.relative_humidity";
field public static final String FEATURE_SENSOR_STEP_COUNTER = "android.hardware.sensor.stepcounter";
field public static final String FEATURE_SENSOR_STEP_DETECTOR = "android.hardware.sensor.stepdetector";
+ field public static final String FEATURE_SE_OMAPI_ESE = "android.hardware.se.omapi.ese";
+ field public static final String FEATURE_SE_OMAPI_SD = "android.hardware.se.omapi.sd";
+ field public static final String FEATURE_SE_OMAPI_UICC = "android.hardware.se.omapi.uicc";
field public static final String FEATURE_SIP = "android.software.sip";
field public static final String FEATURE_SIP_VOIP = "android.software.sip.voip";
field public static final String FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
@@ -43991,6 +43996,7 @@
public class CarrierConfigManager {
method @Nullable public android.os.PersistableBundle getConfig();
+ method @Nullable public android.os.PersistableBundle getConfigByComponentForSubId(String, int);
method @Nullable public android.os.PersistableBundle getConfigForSubId(int);
method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle);
method public void notifyConfigChangedForSubId(int);
@@ -44168,6 +44174,10 @@
field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
+ public static final class CarrierConfigManager.Ims {
+ field public static final String KEY_PREFIX = "ims.";
+ }
+
public abstract class CellIdentity implements android.os.Parcelable {
method public int describeContents();
method @Nullable public CharSequence getOperatorAlphaLong();
diff --git a/api/test-current.txt b/api/test-current.txt
index b393fcc..2624eee 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3028,6 +3028,7 @@
field public static final String PERSIST_PREFIX = "persist.sys.fflag.override.";
field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
+ field public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
}
public class TimeUtils {
diff --git a/cmds/locksettings/TEST_MAPPING b/cmds/locksettings/TEST_MAPPING
new file mode 100644
index 0000000..c1cba5f
--- /dev/null
+++ b/cmds/locksettings/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsDevicePolicyManagerTestCases",
+ "options": [
+ {
+ "include-annotation": "com.android.cts.devicepolicy.annotations.LockSettingsTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/cmds/statsd/tools/dogfood/Android.bp b/cmds/statsd/tools/dogfood/Android.bp
deleted file mode 100644
index bb494a6..0000000
--- a/cmds/statsd/tools/dogfood/Android.bp
+++ /dev/null
@@ -1,37 +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.
-//
-//
-
-android_app {
- name: "StatsdDogfood",
- platform_apis: true,
-
- srcs: ["src/**/*.java"],
-
- resource_dirs: ["res"],
- static_libs: [
- "platformprotoslite",
- "statsdprotolite",
- ],
-
- privileged: true,
- dex_preopt: {
- enabled: false,
- },
- certificate: "platform",
- optimize: {
- enabled: false,
- },
-}
diff --git a/cmds/statsd/tools/dogfood/AndroidManifest.xml b/cmds/statsd/tools/dogfood/AndroidManifest.xml
deleted file mode 100644
index 52673fb..0000000
--- a/cmds/statsd/tools/dogfood/AndroidManifest.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.statsd.dogfood"
- android:sharedUserId="android.uid.system"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-permission android:name="android.permission.DUMP" />
-
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name"
- android:launchMode="singleTop" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
-
- <service android:name=".MainActivity$ReceiverIntentService" android:exported="true" />
- </application>
-</manifest>
diff --git a/cmds/statsd/tools/dogfood/res/drawable-hdpi/ic_launcher.png b/cmds/statsd/tools/dogfood/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 55621cc..0000000
--- a/cmds/statsd/tools/dogfood/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/drawable-mdpi/ic_launcher.png b/cmds/statsd/tools/dogfood/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 11ec206..0000000
--- a/cmds/statsd/tools/dogfood/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/drawable-xhdpi/ic_launcher.png b/cmds/statsd/tools/dogfood/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 7c02b78..0000000
--- a/cmds/statsd/tools/dogfood/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/drawable-xxhdpi/ic_launcher.png b/cmds/statsd/tools/dogfood/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 915d914..0000000
--- a/cmds/statsd/tools/dogfood/res/drawable-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/layout/activity_main.xml b/cmds/statsd/tools/dogfood/res/layout/activity_main.xml
deleted file mode 100644
index 784ed40..0000000
--- a/cmds/statsd/tools/dogfood/res/layout/activity_main.xml
+++ /dev/null
@@ -1,162 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <Button
- android:id="@+id/push_config"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@android:color/holo_green_light"
- android:text="@string/push_config"/>
- <Button
- android:id="@+id/set_receiver"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@android:color/holo_green_light"
- android:text="@string/set_receiver"/>
- <Button
- android:id="@+id/remove_receiver"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@android:color/holo_green_light"
- android:text="@string/remove_receiver"/>
-
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button android:id="@+id/app_a_wake_lock_acquire1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_a_get_wl1"/>
- <Button android:id="@+id/app_a_wake_lock_release1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_a_release_wl1"/>
- </LinearLayout>
-
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button android:id="@+id/app_a_wake_lock_acquire2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_a_get_wl2"/>
- <Button android:id="@+id/app_a_wake_lock_release2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_a_release_wl2"/>
- </LinearLayout>
-
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button android:id="@+id/app_b_wake_lock_acquire1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_b_get_wl1"/>
- <Button android:id="@+id/app_b_wake_lock_release1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_b_release_wl1"/>
- </LinearLayout>
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button android:id="@+id/app_b_wake_lock_acquire2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_b_get_wl2"/>
- <Button android:id="@+id/app_b_wake_lock_release2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/app_b_release_wl2"/>
- </LinearLayout>
-
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button android:id="@+id/plug"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/plug"/>
-
- <Button android:id="@+id/unplug"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/unplug"/>
- </LinearLayout>
-
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button android:id="@+id/screen_on"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/screen_on"/>
-
- <Button android:id="@+id/screen_off"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/screen_off"/>
- </LinearLayout>
-
- <LinearLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <Button
- android:id="@+id/custom_start"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/custom_start" />
-
- <Button
- android:id="@+id/custom_stop"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/custom_stop" />
- </LinearLayout>
-
- <Button android:id="@+id/dump"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@android:color/holo_purple"
- android:text="@string/dump"/>
-
- <TextView
- android:id="@+id/header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/report_header"/>
-
- <TextView
- android:id="@+id/report_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
-</ScrollView>
\ No newline at end of file
diff --git a/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config b/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config
deleted file mode 100644
index d050061..0000000
--- a/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/values/strings.xml b/cmds/statsd/tools/dogfood/res/values/strings.xml
deleted file mode 100644
index 60948a1..0000000
--- a/cmds/statsd/tools/dogfood/res/values/strings.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<resources>
-
- <string name="app_name">Statsd Dogfood</string>
-
- <string name="statsd_running">Statsd Running</string>
- <string name="statsd_not_running">Statsd NOT Running</string>
-
- <string name="push_config">Push baseline config</string>
- <string name="set_receiver">Set pendingintent</string>
- <string name="remove_receiver">Remove pendingintent</string>
-
- <string name="app_a_foreground">App A foreground</string>
- <string name="app_b_foreground">App B foreground</string>
-
-
- <string name="app_a_get_wl1">App A get wl_1</string>
- <string name="app_a_release_wl1">App A release wl_1</string>
-
- <string name="app_a_get_wl2">App A get wl_2</string>
- <string name="app_a_release_wl2">App A release wl_2</string>
-
- <string name="app_b_get_wl1">App B get wl_1</string>
- <string name="app_b_release_wl1">App B release wl_1</string>
-
- <string name="app_b_get_wl2">App B get wl_2</string>
- <string name="app_b_release_wl2">App B release wl_2</string>
-
- <string name="plug">Plug</string>
- <string name="unplug">Unplug</string>
-
- <string name="screen_on">Screen On</string>
- <string name="screen_off">Screen Off</string>
-
- <string name="custom_start">App hook start</string>
- <string name="custom_stop">App hook stop</string>
-
- <string name="dump">DumpReport</string>
- <string name="report_header">Report details</string>
-</resources>
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
deleted file mode 100644
index b6b16e4..0000000
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
+++ /dev/null
@@ -1,158 +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.statsd.dogfood;
-
-import android.text.format.DateFormat;
-
-import com.android.os.StatsLog;
-
-import java.util.List;
-
-public class DisplayProtoUtils {
- public static void displayLogReport(StringBuilder sb, StatsLog.ConfigMetricsReportList reports) {
- sb.append("ConfigKey: ");
- if (reports.hasConfigKey()) {
- com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
- sb.append("\tuid: ").append(key.getUid()).append(" name: ").append(key.getId())
- .append("\n");
- }
-
- for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
- sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
- sb.append("Last report time:").append(getDateStr(report.getLastReportElapsedNanos())).
- append("\n");
- sb.append("Current report time:").append(getDateStr(report.getCurrentReportElapsedNanos())).
- append("\n");
- for (StatsLog.StatsLogReport log : report.getMetricsList()) {
- sb.append("\n\n");
- sb.append("metric id: ").append(log.getMetricId()).append("\n");
-
- switch (log.getDataCase()) {
- case DURATION_METRICS:
- sb.append("Duration metric data\n");
- displayDurationMetricData(sb, log);
- break;
- case EVENT_METRICS:
- sb.append("Event metric data\n");
- displayEventMetricData(sb, log);
- break;
- case COUNT_METRICS:
- sb.append("Count metric data\n");
- displayCountMetricData(sb, log);
- break;
- case GAUGE_METRICS:
- sb.append("Gauge metric data\n");
- displayGaugeMetricData(sb, log);
- break;
- case VALUE_METRICS:
- sb.append("Value metric data\n");
- displayValueMetricData(sb, log);
- break;
- case DATA_NOT_SET:
- sb.append("No metric data\n");
- break;
- }
- }
- }
- }
-
- public static String getDateStr(long nanoSec) {
- return DateFormat.format("dd/MM hh:mm:ss", nanoSec/1000000).toString();
- }
-
- private static void displayDimension(StringBuilder sb, StatsLog.DimensionsValue dimensionValue) {
- sb.append(dimensionValue.getField()).append(":");
- if (dimensionValue.hasValueBool()) {
- sb.append(dimensionValue.getValueBool());
- } else if (dimensionValue.hasValueFloat()) {
- sb.append(dimensionValue.getValueFloat());
- } else if (dimensionValue.hasValueInt()) {
- sb.append(dimensionValue.getValueInt());
- } else if (dimensionValue.hasValueStr()) {
- sb.append(dimensionValue.getValueStr());
- } else if (dimensionValue.hasValueTuple()) {
- sb.append("{");
- for (StatsLog.DimensionsValue child :
- dimensionValue.getValueTuple().getDimensionsValueList()) {
- displayDimension(sb, child);
- }
- sb.append("}");
- }
- sb.append(" ");
- }
-
- public static void displayDurationMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- StatsLog.StatsLogReport.DurationMetricDataWrapper durationMetricDataWrapper
- = log.getDurationMetrics();
- sb.append("Dimension size: ").append(durationMetricDataWrapper.getDataCount()).append("\n");
- for (StatsLog.DurationMetricData duration : durationMetricDataWrapper.getDataList()) {
- sb.append("dimension_in_what: ");
- displayDimension(sb, duration.getDimensionsInWhat());
- sb.append("\n");
- if (duration.hasDimensionsInCondition()) {
- sb.append("dimension_in_condition: ");
- displayDimension(sb, duration.getDimensionsInCondition());
- sb.append("\n");
- }
-
- for (StatsLog.DurationBucketInfo info : duration.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
- .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
- .append(info.getDurationNanos()).append(" ns\n");
- }
- }
- }
-
- public static void displayEventMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- sb.append("Contains ").append(log.getEventMetrics().getDataCount()).append(" events\n");
- StatsLog.StatsLogReport.EventMetricDataWrapper eventMetricDataWrapper =
- log.getEventMetrics();
- for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
- sb.append(getDateStr(event.getElapsedTimestampNanos())).append(": ");
- sb.append(event.getAtom().getPushedCase().toString()).append("\n");
- }
- }
-
- public static void displayCountMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- StatsLog.StatsLogReport.CountMetricDataWrapper countMetricDataWrapper
- = log.getCountMetrics();
- sb.append("Dimension size: ").append(countMetricDataWrapper.getDataCount()).append("\n");
- for (StatsLog.CountMetricData count : countMetricDataWrapper.getDataList()) {
- sb.append("dimension_in_what: ");
- displayDimension(sb, count.getDimensionsInWhat());
- sb.append("\n");
- if (count.hasDimensionsInCondition()) {
- sb.append("dimension_in_condition: ");
- displayDimension(sb, count.getDimensionsInCondition());
- sb.append("\n");
- }
-
- for (StatsLog.CountBucketInfo info : count.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
- .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
- .append(info.getCount()).append("\n");
- }
- }
- }
-
- public static void displayGaugeMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- sb.append("Display me!");
- }
-
- public static void displayValueMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- sb.append("Display me!");
- }
-}
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
deleted file mode 100644
index 4f4dd01..0000000
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
+++ /dev/null
@@ -1,361 +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.statsd.dogfood;
-
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.app.IntentService;
-import android.app.StatsManager;
-import android.app.StatsManager.StatsUnavailableException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.util.Log;
-import android.util.StatsLog;
-import android.view.View;
-import android.widget.TextView;
-import android.widget.Toast;
-import android.os.IStatsManager;
-import android.os.ServiceManager;
-
-import java.io.InputStream;
-
-import static com.android.statsd.dogfood.DisplayProtoUtils.displayLogReport;
-
-public class MainActivity extends Activity {
- private final static String TAG = "StatsdDogfood";
- private final static long CONFIG_ID = 987654321;
-
- final int[] mUids = {11111111, 2222222};
- StatsManager mStatsManager;
- TextView mReportText;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_main);
-
- findViewById(R.id.app_a_wake_lock_acquire1).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockAcquire(0, "wl_1");
- }
- });
-
- findViewById(R.id.app_b_wake_lock_acquire1).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockAcquire(1, "wl_1");
- }
- });
-
- findViewById(R.id.app_a_wake_lock_acquire2).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockAcquire(0, "wl_2");
- }
- });
-
- findViewById(R.id.app_b_wake_lock_acquire2).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockAcquire(1, "wl_2");
- }
- });
-
- findViewById(R.id.app_a_wake_lock_release1).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockRelease(0, "wl_1");
- }
- });
-
-
- findViewById(R.id.app_b_wake_lock_release1).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockRelease(1, "wl_1");
- }
- });
-
- findViewById(R.id.app_a_wake_lock_release2).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockRelease(0, "wl_2");
- }
- });
-
-
- findViewById(R.id.app_b_wake_lock_release2).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- onWakeLockRelease(1, "wl_2");
- }
- });
-
-
- findViewById(R.id.plug).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- StatsLog.write(StatsLog.PLUGGED_STATE_CHANGED,
- StatsLog.PLUGGED_STATE_CHANGED__STATE__BATTERY_PLUGGED_AC);
- }
- });
-
- findViewById(R.id.unplug).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- StatsLog.write(StatsLog.PLUGGED_STATE_CHANGED,
- StatsLog.PLUGGED_STATE_CHANGED__STATE__BATTERY_PLUGGED_NONE);
- }
- });
-
- findViewById(R.id.screen_on).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
- StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_ON);
- }
- });
-
- findViewById(R.id.screen_off).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
- StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF);
- }
- });
-
- findViewById(R.id.custom_start).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- StatsLog.logStart(8);
- }
- });
-
- findViewById(R.id.custom_stop).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- StatsLog.logStop(8);
- }
- });
-
- mReportText = (TextView) findViewById(R.id.report_text);
-
- findViewById(R.id.dump).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (!statsdRunning()) {
- return;
- }
- if (mStatsManager != null) {
- try {
- byte[] data = mStatsManager.getReports(CONFIG_ID);
- if (data != null) {
- displayData(data);
- return;
- }
- } catch (StatsUnavailableException e) {
- Log.e(TAG, "Failed to get data from statsd", e);
- }
- mReportText.setText("Failed!");
- }
- }
- });
-
- findViewById(R.id.push_config).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- try {
- if (!statsdRunning()) {
- return;
- }
- Resources res = getResources();
- InputStream inputStream = res.openRawResource(R.raw.statsd_baseline_config);
-
- byte[] config = new byte[inputStream.available()];
- inputStream.read(config);
- if (mStatsManager != null) {
- try {
- mStatsManager.addConfig(CONFIG_ID, config);
- Toast.makeText(
- MainActivity.this, "Config pushed", Toast.LENGTH_LONG).show();
- } catch (StatsUnavailableException | IllegalArgumentException e) {
- Toast.makeText(MainActivity.this, "Config push FAILED!",
- Toast.LENGTH_LONG).show();
- }
- }
- } catch (Exception e) {
- Toast.makeText(MainActivity.this, "failed to read config", Toast.LENGTH_LONG);
- }
- }
- });
-
- PendingIntent pi = PendingIntent.getService(this, 0,
- new Intent(this, ReceiverIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT);
- findViewById(R.id.set_receiver).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- try {
- if (!statsdRunning()) {
- return;
- }
- if (mStatsManager != null) {
- try {
- mStatsManager.setFetchReportsOperation(pi, CONFIG_ID);
- Toast.makeText(MainActivity.this,
- "Receiver specified to pending intent", Toast.LENGTH_LONG)
- .show();
- } catch (StatsUnavailableException e) {
- Toast.makeText(MainActivity.this, "Statsd did not set receiver",
- Toast.LENGTH_LONG)
- .show();
- }
- }
- } catch (Exception e) {
- Toast.makeText(MainActivity.this, "failed to set receiver", Toast.LENGTH_LONG);
- }
- }
- });
- findViewById(R.id.remove_receiver).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- try {
- if (!statsdRunning()) {
- return;
- }
- if (mStatsManager != null) {
- try {
- mStatsManager.setFetchReportsOperation(null, CONFIG_ID);
- Toast.makeText(MainActivity.this, "Receiver remove", Toast.LENGTH_LONG)
- .show();
- } catch (StatsUnavailableException e) {
- Toast.makeText(MainActivity.this, "Statsd did not remove receiver",
- Toast.LENGTH_LONG)
- .show();
- }
- }
- } catch (Exception e) {
- Toast.makeText(
- MainActivity.this, "failed to remove receiver", Toast.LENGTH_LONG);
- }
- }
- });
- mStatsManager = (StatsManager) getSystemService("stats");
- }
-
- private boolean statsdRunning() {
- if (IStatsManager.Stub.asInterface(ServiceManager.getService("stats")) == null) {
- Log.d(TAG, "Statsd not running");
- Toast.makeText(MainActivity.this, "Statsd NOT running!", Toast.LENGTH_LONG).show();
- return false;
- }
- return true;
- }
-
- @Override
- public void onNewIntent(Intent intent) {
- Log.d(TAG, "new intent: " + intent.getIntExtra("pkg", 0));
- int pkg = intent.getIntExtra("pkg", 0);
- String name = intent.getStringExtra("name");
- if (intent.hasExtra("acquire")) {
- onWakeLockAcquire(pkg, name);
- } else if (intent.hasExtra("release")) {
- onWakeLockRelease(pkg, name);
- }
- }
-
- private void displayData(byte[] data) {
- com.android.os.StatsLog.ConfigMetricsReportList reports = null;
- boolean good = false;
- if (data != null) {
- try {
- reports = com.android.os.StatsLog.ConfigMetricsReportList.parseFrom(data);
- good = true;
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- // display it in the text view.
- }
- }
- int size = data == null ? 0 : data.length;
- StringBuilder sb = new StringBuilder();
- sb.append(good ? "Proto parsing OK!" : "Proto parsing Error!");
- sb.append(" size:").append(size).append("\n");
-
- if (good && reports != null) {
- displayLogReport(sb, reports);
- mReportText.setText(sb.toString());
- }
- }
-
-
- private void onWakeLockAcquire(int id, String name) {
- if (id > 1) {
- Log.d(TAG, "invalid pkg id");
- return;
- }
- int[] uids = new int[]{mUids[id]};
- String[] tags = new String[]{"acquire"};
- StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
- StatsLog.WAKELOCK_STATE_CHANGED__TYPE__PARTIAL_WAKE_LOCK, name,
- StatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
- StringBuilder sb = new StringBuilder();
- sb.append("StagsLog.write(10, ").append(mUids[id]).append(", ").append(0)
- .append(", ").append(name).append(", 1);");
- Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
- }
-
- private void onWakeLockRelease(int id, String name) {
- if (id > 1) {
- Log.d(TAG, "invalid pkg id");
- return;
- }
- int[] uids = new int[]{mUids[id]};
- String[] tags = new String[]{"release"};
- StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
- StatsLog.WAKELOCK_STATE_CHANGED__TYPE__PARTIAL_WAKE_LOCK, name,
- StatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
- StringBuilder sb = new StringBuilder();
- sb.append("StagsLog.write(10, ").append(mUids[id]).append(", ").append(0)
- .append(", ").append(name).append(", 0);");
- Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
- }
-
- public static class ReceiverIntentService extends IntentService {
- public ReceiverIntentService() {
- super("ReceiverIntentService");
- }
-
- /**
- * The IntentService calls this method from the default worker thread with
- * the intent that started the service. When this method returns, IntentService
- * stops the service, as appropriate.
- */
- @Override
- protected void onHandleIntent(Intent intent) {
- Log.i(TAG, "Received notification that we should call getData");
- }
- }
-}
diff --git a/cmds/statsd/tools/loadtest/Android.bp b/cmds/statsd/tools/loadtest/Android.bp
deleted file mode 100644
index bf87fc5..0000000
--- a/cmds/statsd/tools/loadtest/Android.bp
+++ /dev/null
@@ -1,37 +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.
-//
-//
-
-android_app {
- name: "StatsdLoadtest",
- platform_apis: true,
-
- srcs: ["src/**/*.java"],
-
- resource_dirs: ["res"],
- static_libs: [
- "platformprotoslite",
- "statsdprotolite",
- ],
-
- certificate: "platform",
- privileged: true,
- dex_preopt: {
- enabled: false,
- },
- optimize: {
- enabled: false,
- },
-}
diff --git a/cmds/statsd/tools/loadtest/AndroidManifest.xml b/cmds/statsd/tools/loadtest/AndroidManifest.xml
deleted file mode 100644
index 2bf8ca9..0000000
--- a/cmds/statsd/tools/loadtest/AndroidManifest.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.statsd.loadtest"
- android:sharedUserId="android.uid.system"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-permission android:name="android.permission.DUMP" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name" >
- <activity
- android:name=".LoadtestActivity"
- android:label="@string/app_name"
- android:launchMode="singleTop" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <receiver android:name=".LoadtestActivity$PusherAlarmReceiver" />
- <receiver android:name=".LoadtestActivity$StopperAlarmReceiver"/>
- <receiver android:name=".PerfData$PerfAlarmReceiver"/>
- </application>
-</manifest>
diff --git a/cmds/statsd/tools/loadtest/res/drawable-hdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 55621cc..0000000
--- a/cmds/statsd/tools/loadtest/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/drawable-mdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 11ec206..0000000
--- a/cmds/statsd/tools/loadtest/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/drawable-xhdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 7c02b78..0000000
--- a/cmds/statsd/tools/loadtest/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/drawable-xxhdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 915d914..0000000
--- a/cmds/statsd/tools/loadtest/res/drawable-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml b/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
deleted file mode 100644
index d6f8047..0000000
--- a/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
+++ /dev/null
@@ -1,208 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <LinearLayout
- android:id="@+id/outside"
- android:clickable="true"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginRight="10dp"
- android:layout_marginLeft="10dp"
- android:orientation="vertical">
- <requestFocus />
-
- <LinearLayout
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
- <TextView
- android:textSize="30dp"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/replication_label" />
- <EditText
- android:id="@+id/replication"
- android:inputType="number"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLength="4"
- android:text="@integer/replication_default"
- android:textSize="30dp"/>
- </LinearLayout>
-
- <LinearLayout
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
- <TextView
- android:textSize="30dp"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/bucket_label" />
- <Spinner
- android:id="@+id/bucket_spinner"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:prompt="@string/bucket_label"/>
- </LinearLayout>
-
- <LinearLayout
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
- <TextView
- android:textSize="30dp"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/period_label" />
- <EditText
- android:id="@+id/period"
- android:inputType="number"
- android:layout_weight="1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:maxLength="3"
- android:text="@integer/period_default"
- android:textSize="30dp"/>
- </LinearLayout>
-
- <LinearLayout
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
- <TextView
- android:textSize="30dp"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/burst_label" />
- <EditText
- android:id="@+id/burst"
- android:inputType="number"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLength="4"
- android:text="@integer/burst_default"
- android:textSize="30dp"/>
- </LinearLayout>
-
- <LinearLayout
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
- <TextView
- android:textSize="30dp"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/duration_label" />
- <EditText
- android:id="@+id/duration"
- android:inputType="number"
- android:layout_weight="1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:maxLength="4"
- android:text="@integer/duration_default"
- android:textSize="30dp"/>
- </LinearLayout>
- <CheckBox
- android:id="@+id/placebo"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/placebo"
- android:checked="false" />
-
- <LinearLayout
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <CheckBox
- android:id="@+id/include_count"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/count"
- android:checked="true"/>
- <CheckBox
- android:id="@+id/include_duration"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/duration"
- android:checked="true"/>
- <CheckBox
- android:id="@+id/include_event"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/event"
- android:checked="true"/>
- <CheckBox
- android:id="@+id/include_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/value"
- android:checked="true"/>
- <CheckBox
- android:id="@+id/include_gauge"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/gauge"
- android:checked="true"/>
- </LinearLayout>
-
- <Space
- android:layout_width="1dp"
- android:layout_height="30dp"/>
-
- <Button
- android:id="@+id/start_stop"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="#ffff0000"
- android:text="@string/start"
- android:textSize="50dp"/>
-
- <Space
- android:layout_width="1dp"
- android:layout_height="30dp"/>
-
- <Space
- android:layout_width="1dp"
- android:layout_height="30dp"/>
-
- <TextView
- android:id="@+id/report_text"
- android:gravity="center"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
-</ScrollView>
diff --git a/cmds/statsd/tools/loadtest/res/layout/spinner_item.xml b/cmds/statsd/tools/loadtest/res/layout/spinner_item.xml
deleted file mode 100644
index b03da06..0000000
--- a/cmds/statsd/tools/loadtest/res/layout/spinner_item.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="30dp"
- android:gravity="left"
- android:padding="5dip"
- />
diff --git a/cmds/statsd/tools/loadtest/res/raw/loadtest_config b/cmds/statsd/tools/loadtest/res/raw/loadtest_config
deleted file mode 100755
index 2422190..0000000
--- a/cmds/statsd/tools/loadtest/res/raw/loadtest_config
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/values/integers.xml b/cmds/statsd/tools/loadtest/res/values/integers.xml
deleted file mode 100644
index c2407d3..0000000
--- a/cmds/statsd/tools/loadtest/res/values/integers.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<resources>
- <integer name="burst_default">1</integer>
- <integer name="period_default">2</integer>
- <integer name="replication_default">1</integer>
- <integer name="duration_default">240</integer>
-</resources>
diff --git a/cmds/statsd/tools/loadtest/res/values/strings.xml b/cmds/statsd/tools/loadtest/res/values/strings.xml
deleted file mode 100644
index e8ae3f8..0000000
--- a/cmds/statsd/tools/loadtest/res/values/strings.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<resources>
- <string name="app_name">Statsd Loadtest</string>
- <string name="bucket_label">bucket size (mins): </string>
- <string name="burst_label">burst: </string>
- <string name="bucket_default">FIVE_MINUTES</string>
- <string name="placebo">placebo</string>
- <string name="period_label">logging period (secs): </string>
- <string name="replication_label">metric replication: </string>
- <string name="duration_label">test duration (mins): </string>
- <string name="start">  Start  </string>
- <string name="stop">  Stop  </string>
- <string name="count"> count </string>
- <string name="duration"> duration </string>
- <string name="event"> event </string>
- <string name="value"> value </string>
- <string name="gauge"> gauge </string>
-
-</resources>
diff --git a/cmds/statsd/tools/loadtest/run_loadtest.sh b/cmds/statsd/tools/loadtest/run_loadtest.sh
deleted file mode 100755
index 3c93a06..0000000
--- a/cmds/statsd/tools/loadtest/run_loadtest.sh
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/bin/sh
-#
-# Script that measures statsd's PSS under an increasing number of metrics.
-
-# Globals.
-pss=""
-pid=""
-
-# Starts the loadtest.
-start_loadtest() {
- echo "Starting loadtest"
- adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "start"
-}
-
-# Stops the loadtest.
-stop_loadtest() {
- echo "Stopping loadtest"
- adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "stop"
-}
-
-# Sets the metrics replication.
-# Arguments:
-# $1: The replication factor.
-set_replication() {
- adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "set_replication" --ei "replication" "${1}"
- echo "Replication set to ${1}"
-}
-
-# Reads statsd's pid and PSS.
-update_pid_and_pss() {
- # Command that reads the PSS for statsd. This also gives us its pid.
- get_mem=$(adb shell dumpsys meminfo |grep statsd)
- # Looks for statsd's pid.
- regex="([0-9,]+)K: statsd \(pid ([0-9]+)\).*"
- if [[ $get_mem =~ $regex ]]; then
- pss=$(echo "${BASH_REMATCH[1]}" | tr -d , | sed 's/\.//g')
- pid=$(echo "${BASH_REMATCH[2]}")
- else
- echo $cmd doesnt match $regex
- fi
-}
-
-# Kills statsd.
-# Assumes the pid has been set.
-kill_statsd() {
- echo "Killing statsd (pid ${pid})"
- adb shell kill -9 "${pid}"
-}
-
-# Main loop.
-main() {
- start_time=$(date +%s)
- values=()
- stop_loadtest
-
- echo ""
- echo "********************* NEW LOADTEST ************************"
- update_pid_and_pss
- for replication in 1 2 4 8 16 32 64 128 256 512 1024 2048 4096
- do
- echo "**** Starting test at replication ${replication} ****"
-
- # (1) Restart statsd. This will ensure its state is empty.
- kill_statsd
- sleep 3 # wait a bit for it to restart
- update_pid_and_pss
- echo "Before the test, statsd's PSS is ${pss}"
-
- # (2) Set the replication.
- set_replication "${replication}"
- sleep 1 # wait a bit
-
- # (3) Start the loadtest.
- start_loadtest
-
- # (4) Wait several seconds, then read the PSS.
- sleep 100 && update_pid_and_pss
- echo "During the test, statsd's PSS is ${pss}"
- values+=(${pss})
-
- echo "Values: ${values[@]}"
-
- # (5) Stop loadtest.
- stop_loadtest
- sleep 2
-
- echo ""
- done
-
- end_time=$(date +%s)
- echo "Completed loadtest in $((${end_time} - ${start_time})) seconds."
-
- values_as_str=$(IFS=$'\n'; echo "${values[*]}")
- echo "The PSS values are:"
- echo "${values_as_str}"
- echo ""
-}
-
-main
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java
deleted file mode 100644
index bab0c1e..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java
+++ /dev/null
@@ -1,56 +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.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.util.Log;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-import java.text.ParseException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class BatteryDataRecorder extends PerfDataRecorder {
- private static final String TAG = "loadtest.BatteryDataRecorder";
- private static final String DUMP_FILENAME = TAG + "_dump.tmp";
-
- public BatteryDataRecorder(boolean placebo, int replication, TimeUnit bucket, long periodSecs,
- int burst, boolean includeCountMetric, boolean includeDurationMetric,
- boolean includeEventMetric, boolean includeValueMetric, boolean includeGaugeMetric) {
- super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
- includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
- }
-
- @Override
- public void startRecording(Context context) {
- // Reset batterystats.
- runDumpsysStats(context, DUMP_FILENAME, "batterystats", "--reset");
- }
-
- @Override
- public void onAlarm(Context context) {
- // Nothing to do as for battery, the whole data is in the final dumpsys call.
- }
-
- @Override
- public void stopRecording(Context context) {
- StringBuilder sb = new StringBuilder();
- // Don't use --checkin.
- runDumpsysStats(context, DUMP_FILENAME, "batterystats");
- readDumpData(context, DUMP_FILENAME, new BatteryStatsParser(), sb);
- writeData(context, "battery_", "time,battery_level", sb);
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java
deleted file mode 100644
index 203d97a..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java
+++ /dev/null
@@ -1,113 +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.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.util.Log;
-import java.text.ParseException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class BatteryStatsParser implements PerfParser {
-
- private static final Pattern LINE_PATTERN =
- Pattern.compile("\\s*\\+*(\\S*)\\s\\(\\d+\\)\\s(\\d\\d\\d)\\s.*");
- private static final Pattern TIME_PATTERN =
- Pattern.compile("(\\d+)?(h)?(\\d+)?(m)?(\\d+)?(s)?(\\d+)?(ms)?");
- private static final String TAG = "loadtest.BatteryStatsParser";
-
- private boolean mHistoryStarted;
- private boolean mHistoryEnded;
-
- public BatteryStatsParser() {
- }
-
- @Override
- @Nullable
- public String parseLine(String line) {
- if (mHistoryEnded) {
- return null;
- }
- if (!mHistoryStarted) {
- if (line.contains("Battery History")) {
- mHistoryStarted = true;
- }
- return null;
- }
- if (line.isEmpty()) {
- mHistoryEnded = true;
- return null;
- }
- Matcher lineMatcher = LINE_PATTERN.matcher(line);
- if (lineMatcher.find() && lineMatcher.group(1) != null && lineMatcher.group(2) != null) {
- if (lineMatcher.group(1).equals("0")) {
- return "0," + lineMatcher.group(2) + "\n";
- } else {
- Matcher timeMatcher = TIME_PATTERN.matcher(lineMatcher.group(1));
- if (timeMatcher.find()) {
- Long time = getTime(lineMatcher.group(1));
- if (time != null) {
- return time + "," + lineMatcher.group(2) + "\n";
- } else {
- return null; // bad time
- }
- } else {
- return null; // bad or no time
- }
- }
- }
- return null;
- }
-
- @Nullable
- private Long getTime(String group) {
- if ("0".equals(group)) {
- return 0L;
- }
- Matcher timeMatcher = TIME_PATTERN.matcher(group);
- if (!timeMatcher.find()) {
- return null;
- }
-
- // Get rid of "ms".
- String[] matches = group.split("ms", -1);
- if (matches.length > 1) {
- group = matches[0];
- }
-
- long time = 0L;
- matches = group.split("h");
- if (matches.length > 1) {
- time += Long.parseLong(matches[0]) * 60 * 60 * 1000; // hours
- group = matches[1];
- }
- matches = group.split("m");
- if (matches.length > 1) {
- time += Long.parseLong(matches[0]) * 60 * 1000; // minutes
- group = matches[1];
- }
- matches = group.split("s");
- if (matches.length > 1) {
- time += Long.parseLong(matches[0]) * 1000; // seconds
- group = matches[1];
- }
-
- if (!group.isEmpty()) {
- time += Long.parseLong(group); // milliseconds
- }
- return time;
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
deleted file mode 100644
index 2e0161b..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
+++ /dev/null
@@ -1,314 +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.statsd.loadtest;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-
-import com.android.internal.os.StatsdConfigProto.Predicate;
-import com.android.internal.os.StatsdConfigProto.CountMetric;
-import com.android.internal.os.StatsdConfigProto.DurationMetric;
-import com.android.internal.os.StatsdConfigProto.MetricConditionLink;
-import com.android.internal.os.StatsdConfigProto.EventMetric;
-import com.android.internal.os.StatsdConfigProto.GaugeMetric;
-import com.android.internal.os.StatsdConfigProto.ValueMetric;
-import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
-import com.android.internal.os.StatsdConfigProto.AtomMatcher;
-import com.android.internal.os.StatsdConfigProto.SimplePredicate;
-import com.android.internal.os.StatsdConfigProto.StatsdConfig;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Creates StatsdConfig protos for loadtesting.
- */
-public class ConfigFactory {
- public static class ConfigMetadata {
- public final byte[] bytes;
- public final int numMetrics;
-
- public ConfigMetadata(byte[] bytes, int numMetrics) {
- this.bytes = bytes;
- this.numMetrics = numMetrics;
- }
- }
-
- public static final long CONFIG_ID = 123456789;
-
- private static final String TAG = "loadtest.ConfigFactory";
-
- private final StatsdConfig mTemplate;
-
- public ConfigFactory(Context context) {
- // Read the config template from the resoures.
- Resources res = context.getResources();
- byte[] template = null;
- StatsdConfig templateProto = null;
- try {
- InputStream inputStream = res.openRawResource(R.raw.loadtest_config);
- template = new byte[inputStream.available()];
- inputStream.read(template);
- templateProto = StatsdConfig.parseFrom(template);
- } catch (IOException e) {
- Log.e(TAG, "Unable to read or parse loadtest config template. Using an empty config.");
- }
- mTemplate = templateProto == null ? StatsdConfig.newBuilder().build() : templateProto;
-
- Log.d(TAG, "Loadtest template config: " + mTemplate);
- }
-
- /**
- * Generates a config.
- *
- * All configs are based on the same template.
- * That template is designed to make the most use of the set of atoms that {@code SequencePusher}
- * pushes, and to exercise as many of the metrics features as possible.
- * Furthermore, by passing a replication factor to this method, one can artificially inflate
- * the number of metrics in the config. One can also adjust the bucket size for aggregate
- * metrics.
- *
- * @param replication The number of times each metric is replicated in the config.
- * If the config template has n metrics, the generated config will have n * replication
- * ones
- * @param bucketMillis The bucket size, in milliseconds, for aggregate metrics
- * @param placebo If true, only return an empty config
- * @return The serialized config and the number of metrics.
- */
- public ConfigMetadata getConfig(int replication, TimeUnit bucket, boolean placebo,
- boolean includeCount, boolean includeDuration, boolean includeEvent,
- boolean includeValue, boolean includeGauge) {
- StatsdConfig.Builder config = StatsdConfig.newBuilder()
- .setId(CONFIG_ID);
- if (placebo) {
- replication = 0; // Config will be empty, aside from a name.
- }
- int numMetrics = 0;
- for (int i = 0; i < replication; i++) {
- // metrics
- if (includeEvent) {
- for (EventMetric metric : mTemplate.getEventMetricList()) {
- addEventMetric(metric, i, config);
- numMetrics++;
- }
- }
- if (includeCount) {
- for (CountMetric metric : mTemplate.getCountMetricList()) {
- addCountMetric(metric, i, bucket, config);
- numMetrics++;
- }
- }
- if (includeDuration) {
- for (DurationMetric metric : mTemplate.getDurationMetricList()) {
- addDurationMetric(metric, i, bucket, config);
- numMetrics++;
- }
- }
- if (includeGauge) {
- for (GaugeMetric metric : mTemplate.getGaugeMetricList()) {
- addGaugeMetric(metric, i, bucket, config);
- numMetrics++;
- }
- }
- if (includeValue) {
- for (ValueMetric metric : mTemplate.getValueMetricList()) {
- addValueMetric(metric, i, bucket, config);
- numMetrics++;
- }
- }
- // predicates
- for (Predicate predicate : mTemplate.getPredicateList()) {
- addPredicate(predicate, i, config);
- }
- // matchers
- for (AtomMatcher matcher : mTemplate.getAtomMatcherList()) {
- addMatcher(matcher, i, config);
- }
- }
-
- Log.d(TAG, "Loadtest config is : " + config.build());
- Log.d(TAG, "Generated config has " + numMetrics + " metrics");
-
- return new ConfigMetadata(config.build().toByteArray(), numMetrics);
- }
-
- /**
- * Creates {@link MetricConditionLink}s that are identical to the one passed to this method,
- * except that the names are appended with the provided suffix.
- */
- private List<MetricConditionLink> getLinks(
- List<MetricConditionLink> links, int suffix) {
- List<MetricConditionLink> newLinks = new ArrayList();
- for (MetricConditionLink link : links) {
- newLinks.add(link.toBuilder()
- .setCondition(link.getCondition() + suffix)
- .build());
- }
- return newLinks;
- }
-
- /**
- * Creates an {@link EventMetric} based on the template. Makes sure that all names are appended
- * with the provided suffix. Then adds that metric to the config.
- */
- private void addEventMetric(EventMetric template, int suffix, StatsdConfig.Builder config) {
- EventMetric.Builder metric = template.toBuilder()
- .setId(template.getId() + suffix)
- .setWhat(template.getWhat() + suffix);
- if (template.hasCondition()) {
- metric.setCondition(template.getCondition() + suffix);
- }
- if (template.getLinksCount() > 0) {
- List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
- metric.clearLinks();
- metric.addAllLinks(links);
- }
- config.addEventMetric(metric);
- }
-
- /**
- * Creates a {@link CountMetric} based on the template. Makes sure that all names are appended
- * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
- */
- private void addCountMetric(CountMetric template, int suffix, TimeUnit bucket,
- StatsdConfig.Builder config) {
- CountMetric.Builder metric = template.toBuilder()
- .setId(template.getId() + suffix)
- .setWhat(template.getWhat() + suffix);
- if (template.hasCondition()) {
- metric.setCondition(template.getCondition() + suffix);
- }
- if (template.getLinksCount() > 0) {
- List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
- metric.clearLinks();
- metric.addAllLinks(links);
- }
- metric.setBucket(bucket);
- config.addCountMetric(metric);
- }
-
- /**
- * Creates a {@link DurationMetric} based on the template. Makes sure that all names are appended
- * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
- */
- private void addDurationMetric(DurationMetric template, int suffix, TimeUnit bucket,
- StatsdConfig.Builder config) {
- DurationMetric.Builder metric = template.toBuilder()
- .setId(template.getId() + suffix)
- .setWhat(template.getWhat() + suffix);
- if (template.hasCondition()) {
- metric.setCondition(template.getCondition() + suffix);
- }
- if (template.getLinksCount() > 0) {
- List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
- metric.clearLinks();
- metric.addAllLinks(links);
- }
- metric.setBucket(bucket);
- config.addDurationMetric(metric);
- }
-
- /**
- * Creates a {@link GaugeMetric} based on the template. Makes sure that all names are appended
- * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
- */
- private void addGaugeMetric(GaugeMetric template, int suffix, TimeUnit bucket,
- StatsdConfig.Builder config) {
- GaugeMetric.Builder metric = template.toBuilder()
- .setId(template.getId() + suffix)
- .setWhat(template.getWhat() + suffix);
- if (template.hasCondition()) {
- metric.setCondition(template.getCondition() + suffix);
- }
- if (template.getLinksCount() > 0) {
- List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
- metric.clearLinks();
- metric.addAllLinks(links);
- }
- metric.setBucket(bucket);
- config.addGaugeMetric(metric);
- }
-
- /**
- * Creates a {@link ValueMetric} based on the template. Makes sure that all names are appended
- * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
- */
- private void addValueMetric(ValueMetric template, int suffix, TimeUnit bucket,
- StatsdConfig.Builder config) {
- ValueMetric.Builder metric = template.toBuilder()
- .setId(template.getId() + suffix)
- .setWhat(template.getWhat() + suffix);
- if (template.hasCondition()) {
- metric.setCondition(template.getCondition() + suffix);
- }
- if (template.getLinksCount() > 0) {
- List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
- metric.clearLinks();
- metric.addAllLinks(links);
- }
- metric.setBucket(bucket);
- config.addValueMetric(metric);
- }
-
- /**
- * Creates a {@link Predicate} based on the template. Makes sure that all names
- * are appended with the provided suffix. Then adds that predicate to the config.
- */
- private void addPredicate(Predicate template, int suffix, StatsdConfig.Builder config) {
- Predicate.Builder predicate = template.toBuilder()
- .setId(template.getId() + suffix);
- if (template.hasCombination()) {
- Predicate.Combination.Builder cb = template.getCombination().toBuilder()
- .clearPredicate();
- for (long child : template.getCombination().getPredicateList()) {
- cb.addPredicate(child + suffix);
- }
- predicate.setCombination(cb.build());
- }
- if (template.hasSimplePredicate()) {
- SimplePredicate.Builder sc = template.getSimplePredicate().toBuilder()
- .setStart(template.getSimplePredicate().getStart() + suffix)
- .setStop(template.getSimplePredicate().getStop() + suffix);
- if (template.getSimplePredicate().hasStopAll()) {
- sc.setStopAll(template.getSimplePredicate().getStopAll() + suffix);
- }
- predicate.setSimplePredicate(sc.build());
- }
- config.addPredicate(predicate);
- }
-
- /**
- * Creates a {@link AtomMatcher} based on the template. Makes sure that all names
- * are appended with the provided suffix. Then adds that matcher to the config.
- */
- private void addMatcher(AtomMatcher template, int suffix, StatsdConfig.Builder config) {
- AtomMatcher.Builder matcher = template.toBuilder()
- .setId(template.getId() + suffix);
- if (template.hasCombination()) {
- AtomMatcher.Combination.Builder cb = template.getCombination().toBuilder()
- .clearMatcher();
- for (long child : template.getCombination().getMatcherList()) {
- cb.addMatcher(child + suffix);
- }
- matcher.setCombination(cb);
- }
- config.addAtomMatcher(matcher);
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
deleted file mode 100644
index d55f3f3..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
+++ /dev/null
@@ -1,169 +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.statsd.loadtest;
-
-import android.text.format.DateFormat;
-
-import com.android.os.StatsLog;
-
-import java.util.List;
-
-public class DisplayProtoUtils {
- private static final int MAX_NUM_METRICS_TO_DISPLAY = 10;
-
- public static void displayLogReport(StringBuilder sb, StatsLog.ConfigMetricsReportList reports) {
- sb.append("******************** Report ********************\n");
- if (reports.hasConfigKey()) {
- sb.append("ConfigKey: ");
- com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
- sb.append("\tuid: ").append(key.getUid()).append(" id: ").append(key.getId())
- .append("\n");
- }
-
- int numMetrics = 0;
- for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
- sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
- sb.append("Last report time:").append(getDateStr(report.getLastReportElapsedNanos())).
- append("\n");
- sb.append("Current report time:").append(getDateStr(report.getCurrentReportElapsedNanos())).
- append("\n");
- for (StatsLog.StatsLogReport log : report.getMetricsList()) {
- numMetrics++;
- if (numMetrics > MAX_NUM_METRICS_TO_DISPLAY) {
- sb.append("... output truncated\n");
- sb.append("************************************************");
- return;
- }
- sb.append("\n");
- sb.append("metric id: ").append(log.getMetricId()).append("\n");
-
- switch (log.getDataCase()) {
- case DURATION_METRICS:
- sb.append("Duration metric data\n");
- displayDurationMetricData(sb, log);
- break;
- case EVENT_METRICS:
- sb.append("Event metric data\n");
- displayEventMetricData(sb, log);
- break;
- case COUNT_METRICS:
- sb.append("Count metric data\n");
- displayCountMetricData(sb, log);
- break;
- case GAUGE_METRICS:
- sb.append("Gauge metric data\n");
- displayGaugeMetricData(sb, log);
- break;
- case VALUE_METRICS:
- sb.append("Value metric data\n");
- displayValueMetricData(sb, log);
- break;
- case DATA_NOT_SET:
- sb.append("No metric data\n");
- break;
- }
- }
- }
- sb.append("************************************************");
- }
-
- public static String getDateStr(long nanoSec) {
- return DateFormat.format("dd/MM hh:mm:ss", nanoSec/1000000).toString();
- }
-
- private static void displayDimension(StringBuilder sb, StatsLog.DimensionsValue dimensionValue) {
- sb.append(dimensionValue.getField()).append(":");
- if (dimensionValue.hasValueBool()) {
- sb.append(dimensionValue.getValueBool());
- } else if (dimensionValue.hasValueFloat()) {
- sb.append(dimensionValue.getValueFloat());
- } else if (dimensionValue.hasValueInt()) {
- sb.append(dimensionValue.getValueInt());
- } else if (dimensionValue.hasValueStr()) {
- sb.append(dimensionValue.getValueStr());
- } else if (dimensionValue.hasValueTuple()) {
- sb.append("{");
- for (StatsLog.DimensionsValue child :
- dimensionValue.getValueTuple().getDimensionsValueList()) {
- displayDimension(sb, child);
- }
- sb.append("}");
- }
- sb.append(" ");
- }
-
- public static void displayDurationMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- StatsLog.StatsLogReport.DurationMetricDataWrapper durationMetricDataWrapper
- = log.getDurationMetrics();
- sb.append("Dimension size: ").append(durationMetricDataWrapper.getDataCount()).append("\n");
- for (StatsLog.DurationMetricData duration : durationMetricDataWrapper.getDataList()) {
- sb.append("dimension_in_what: ");
- displayDimension(sb, duration.getDimensionsInWhat());
- sb.append("\n");
- if (duration.hasDimensionsInCondition()) {
- sb.append("dimension_in_condition: ");
- displayDimension(sb, duration.getDimensionsInCondition());
- sb.append("\n");
- }
-
- for (StatsLog.DurationBucketInfo info : duration.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
- .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
- .append(info.getDurationNanos()).append(" ns\n");
- }
- }
- }
-
- public static void displayEventMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- sb.append("Contains ").append(log.getEventMetrics().getDataCount()).append(" events\n");
- StatsLog.StatsLogReport.EventMetricDataWrapper eventMetricDataWrapper =
- log.getEventMetrics();
- for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
- sb.append(getDateStr(event.getElapsedTimestampNanos())).append(": ");
- sb.append(event.getAtom().getPushedCase().toString()).append("\n");
- }
- }
-
- public static void displayCountMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- StatsLog.StatsLogReport.CountMetricDataWrapper countMetricDataWrapper
- = log.getCountMetrics();
- sb.append("Dimension size: ").append(countMetricDataWrapper.getDataCount()).append("\n");
- for (StatsLog.CountMetricData count : countMetricDataWrapper.getDataList()) {
- sb.append("dimension_in_what: ");
- displayDimension(sb, count.getDimensionsInWhat());
- sb.append("\n");
- if (count.hasDimensionsInCondition()) {
- sb.append("dimension_in_condition: ");
- displayDimension(sb, count.getDimensionsInCondition());
- sb.append("\n");
- }
-
- for (StatsLog.CountBucketInfo info : count.getBucketInfoList()) {
- sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
- .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
- .append(info.getCount()).append("\n");
- }
- }
- }
-
- public static void displayGaugeMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- sb.append("Display me!");
- }
-
- public static void displayValueMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
- sb.append("Display me!");
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
deleted file mode 100644
index 769f78c..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
+++ /dev/null
@@ -1,756 +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.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.StatsManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IStatsManager;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Log;
-import android.util.StatsLog;
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-import android.view.MotionEvent;
-import android.view.View.OnFocusChangeListener;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.Spinner;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.os.StatsLog.ConfigMetricsReport;
-import com.android.os.StatsLog.ConfigMetricsReportList;
-import com.android.os.StatsLog.StatsdStatsReport;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Runs a load test for statsd.
- * How it works:
- * <ul>
- * <li> Sets up and pushes a custom config with metrics that exercise a large swath of code paths.
- * <li> Periodically logs certain atoms into logd.
- * <li> Impact on battery can be printed to logcat, or a bug report can be filed and analyzed
- * in battery Historian.
- * </ul>
- * The load depends on how demanding the config is, as well as how frequently atoms are pushsed
- * to logd. Those are all controlled by 4 adjustable parameters:
- * <ul>
- * <li> The 'replication' parameter artificially multiplies the number of metrics in the config.
- * <li> The bucket size controls the time-bucketing the aggregate metrics.
- * <li> The period parameter controls how frequently atoms are pushed to logd.
- * <li> The 'burst' parameter controls how many atoms are pushed at the same time (per period).
- * </ul>
- */
-public class LoadtestActivity extends Activity implements AdapterView.OnItemSelectedListener {
-
- private static final String TAG = "loadtest.LoadtestActivity";
- public static final String TYPE = "type";
- private static final String PUSH_ALARM = "push_alarm";
- public static final String PERF_ALARM = "perf_alarm";
- private static final String SET_REPLICATION = "set_replication";
- private static final String REPLICATION = "replication";
- private static final String START = "start";
- private static final String STOP = "stop";
- private static final Map<String, TimeUnit> TIME_UNIT_MAP = initializeTimeUnitMap();
- private static final List<String> TIME_UNIT_LABELS = initializeTimeUnitLabels();
-
- public final static class PusherAlarmReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Intent activityIntent = new Intent(context, LoadtestActivity.class);
- activityIntent.putExtra(TYPE, PUSH_ALARM);
- context.startActivity(activityIntent);
- }
- }
-
- public final static class StopperAlarmReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Intent activityIntent = new Intent(context, LoadtestActivity.class);
- activityIntent.putExtra(TYPE, STOP);
- context.startActivity(activityIntent);
- }
- }
-
- private static Map<String, TimeUnit> initializeTimeUnitMap() {
- Map<String, TimeUnit> labels = new HashMap();
- labels.put("1m", TimeUnit.ONE_MINUTE);
- labels.put("5m", TimeUnit.FIVE_MINUTES);
- labels.put("10m", TimeUnit.TEN_MINUTES);
- labels.put("30m", TimeUnit.THIRTY_MINUTES);
- labels.put("1h", TimeUnit.ONE_HOUR);
- labels.put("3h", TimeUnit.THREE_HOURS);
- labels.put("6h", TimeUnit.SIX_HOURS);
- labels.put("12h", TimeUnit.TWELVE_HOURS);
- labels.put("1d", TimeUnit.ONE_DAY);
- labels.put("1s", TimeUnit.CTS);
- return labels;
- }
-
- private static List<String> initializeTimeUnitLabels() {
- List<String> labels = new ArrayList();
- labels.add("1s");
- labels.add("1m");
- labels.add("5m");
- labels.add("10m");
- labels.add("30m");
- labels.add("1h");
- labels.add("3h");
- labels.add("6h");
- labels.add("12h");
- labels.add("1d");
- return labels;
- }
-
- private AlarmManager mAlarmMgr;
-
- /**
- * Used to periodically log atoms to logd.
- */
- private PendingIntent mPushPendingIntent;
-
- /**
- * Used to end the loadtest.
- */
- private PendingIntent mStopPendingIntent;
-
- private Button mStartStop;
- private EditText mReplicationText;
- private Spinner mBucketSpinner;
- private EditText mPeriodText;
- private EditText mBurstText;
- private EditText mDurationText;
- private TextView mReportText;
- private CheckBox mPlaceboCheckBox;
- private CheckBox mCountMetricCheckBox;
- private CheckBox mDurationMetricCheckBox;
- private CheckBox mEventMetricCheckBox;
- private CheckBox mValueMetricCheckBox;
- private CheckBox mGaugeMetricCheckBox;
-
- /**
- * When the load test started.
- */
- private long mStartedTimeMillis;
-
- /**
- * For measuring perf data.
- */
- private PerfData mPerfData;
-
- /**
- * For communicating with statsd.
- */
- private StatsManager mStatsManager;
-
- private PowerManager mPowerManager;
- private WakeLock mWakeLock;
-
- /**
- * If true, we only measure the effect of the loadtest infrastructure. No atom are pushed and
- * the configuration is empty.
- */
- private boolean mPlacebo;
-
- /**
- * Whether to include CountMetric in the config.
- */
- private boolean mIncludeCountMetric;
-
- /**
- * Whether to include DurationMetric in the config.
- */
- private boolean mIncludeDurationMetric;
-
- /**
- * Whether to include EventMetric in the config.
- */
- private boolean mIncludeEventMetric;
-
- /**
- * Whether to include ValueMetric in the config.
- */
- private boolean mIncludeValueMetric;
-
- /**
- * Whether to include GaugeMetric in the config.
- */
- private boolean mIncludeGaugeMetric;
-
- /**
- * The burst size.
- */
- private int mBurst;
-
- /**
- * The metrics replication.
- */
- private int mReplication;
-
- /**
- * The period, in seconds, at which batches of atoms are pushed.
- */
- private long mPeriodSecs;
-
- /**
- * The bucket size, in minutes, for aggregate metrics.
- */
- private TimeUnit mBucket;
-
- /**
- * The duration, in minutes, of the loadtest.
- */
- private long mDurationMins;
-
- /**
- * Whether the loadtest has started.
- */
- private boolean mStarted = false;
-
- /**
- * Orchestrates the logging of pushed events into logd.
- */
- private SequencePusher mPusher;
-
- /**
- * Generates statsd configs.
- */
- private ConfigFactory mFactory;
-
- /**
- * For intra-minute periods.
- */
- private final Handler mHandler = new Handler();
-
- /**
- * Number of metrics in the current config.
- */
- private int mNumMetrics;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- Log.d(TAG, "Starting loadtest Activity");
-
- setContentView(R.layout.activity_loadtest);
- mReportText = (TextView) findViewById(R.id.report_text);
- initBurst();
- initReplication();
- initBucket();
- initPeriod();
- initDuration();
- initPlacebo();
- initMetricWhitelist();
-
- // Hide the keyboard outside edit texts.
- findViewById(R.id.outside).setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- InputMethodManager imm =
- (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- if (getCurrentFocus() != null) {
- imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
- }
- return true;
- }
- });
-
- mStartStop = findViewById(R.id.start_stop);
- mStartStop.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (mStarted) {
- stopLoadtest();
- } else {
- startLoadtest();
- }
- }
- });
-
- mAlarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
- mStatsManager = (StatsManager) getSystemService("stats");
- mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
- mFactory = new ConfigFactory(this);
- stopLoadtest();
- mReportText.setText("");
- }
-
- @Override
- public void onNewIntent(Intent intent) {
- String type = intent.getStringExtra(TYPE);
- if (type == null) {
- return;
- }
- switch (type) {
- case PERF_ALARM:
- onPerfAlarm();
- break;
- case PUSH_ALARM:
- onAlarm();
- break;
- case SET_REPLICATION:
- if (intent.hasExtra(REPLICATION)) {
- setReplication(intent.getIntExtra(REPLICATION, 0));
- }
- break;
- case START:
- startLoadtest();
- break;
- case STOP:
- stopLoadtest();
- break;
- default:
- throw new IllegalArgumentException("Unknown type: " + type);
- }
- }
-
- @Override
- public void onDestroy() {
- Log.d(TAG, "Destroying");
- mPerfData.onDestroy();
- stopLoadtest();
- clearConfigs();
- super.onDestroy();
- }
-
- @Nullable
- public StatsdStatsReport getMetadata() {
- if (!statsdRunning()) {
- return null;
- }
- if (mStatsManager != null) {
- byte[] data;
- try {
- data = mStatsManager.getStatsMetadata();
- } catch (StatsManager.StatsUnavailableException e) {
- Log.e(TAG, "Failed to get data from statsd", e);
- return null;
- }
- if (data != null) {
- StatsdStatsReport report = null;
- boolean good = false;
- try {
- return StatsdStatsReport.parseFrom(data);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- Log.d(TAG, "Bad StatsdStatsReport");
- }
- }
- }
- return null;
- }
-
- @Nullable
- public List<ConfigMetricsReport> getData() {
- if (!statsdRunning()) {
- return null;
- }
- if (mStatsManager != null) {
- byte[] data;
- try {
- data = mStatsManager.getReports(ConfigFactory.CONFIG_ID);
- } catch (StatsManager.StatsUnavailableException e) {
- Log.e(TAG, "Failed to get data from statsd", e);
- return null;
- }
- if (data != null) {
- ConfigMetricsReportList reports = null;
- try {
- reports = ConfigMetricsReportList.parseFrom(data);
- Log.d(TAG, "Num reports: " + reports.getReportsCount());
- StringBuilder sb = new StringBuilder();
- DisplayProtoUtils.displayLogReport(sb, reports);
- Log.d(TAG, sb.toString());
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- Log.d(TAG, "Invalid data");
- }
- if (reports != null) {
- return reports.getReportsList();
- }
- }
- }
- return null;
- }
-
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- String item = parent.getItemAtPosition(position).toString();
-
- mBucket = TIME_UNIT_MAP.get(item);
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- // Another interface callback
- }
-
- private void onPerfAlarm() {
- if (mPerfData != null) {
- mPerfData.onAlarm(this);
- }
- // Piggy-back on that alarm to show the elapsed time.
- long elapsedTimeMins = (long) Math.floor(
- (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
- mReportText.setText("Loadtest in progress.\n"
- + "num metrics =" + mNumMetrics
- + "\nElapsed time = " + elapsedTimeMins + " min(s)");
- }
-
- private void onAlarm() {
- Log.d(TAG, "ON ALARM");
-
- // Set the next task.
- scheduleNext();
-
- // Do the work.
- mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "StatsdLoadTest");
- mWakeLock.acquire();
- if (mPusher != null) {
- mPusher.next();
- }
- mWakeLock.release();
- mWakeLock = null;
- }
-
- /**
- * Schedules the next cycle of pushing atoms into logd.
- */
- private void scheduleNext() {
- Intent intent = new Intent(this, PusherAlarmReceiver.class);
- intent.putExtra(TYPE, PUSH_ALARM);
- mPushPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
- long nextTime = SystemClock.elapsedRealtime() + mPeriodSecs * 1000;
- mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mPushPendingIntent);
- }
-
- private synchronized void startLoadtest() {
- if (mStarted) {
- return;
- }
-
- // Clean up the state.
- stopLoadtest();
-
- // Prepare to push a sequence of atoms to logd.
- mPusher = new SequencePusher(mBurst, mPlacebo);
-
- // Create a config and push it to statsd.
- if (!setConfig(mFactory.getConfig(mReplication, mBucket, mPlacebo,
- mIncludeCountMetric, mIncludeDurationMetric, mIncludeEventMetric,
- mIncludeValueMetric, mIncludeGaugeMetric))) {
- return;
- }
-
- // Remember to stop in the future.
- Intent intent = new Intent(this, StopperAlarmReceiver.class);
- intent.putExtra(TYPE, STOP);
- mStopPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
- long nextTime = SystemClock.elapsedRealtime() + mDurationMins * 60 * 1000;
- mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mStopPendingIntent);
-
- // Log atoms.
- scheduleNext();
-
- // Start tracking performance.
- mPerfData = new PerfData(this, mPlacebo, mReplication, mBucket, mPeriodSecs, mBurst,
- mIncludeCountMetric, mIncludeDurationMetric, mIncludeEventMetric, mIncludeValueMetric,
- mIncludeGaugeMetric);
- mPerfData.startRecording(this);
-
- mReportText.setText("Loadtest in progress.\nnum metrics =" + mNumMetrics);
- mStartedTimeMillis = SystemClock.elapsedRealtime();
-
- updateStarted(true);
- }
-
- private synchronized void stopLoadtest() {
- if (mPushPendingIntent != null) {
- Log.d(TAG, "Canceling pre-existing push alarm");
- mAlarmMgr.cancel(mPushPendingIntent);
- mPushPendingIntent = null;
- }
- if (mStopPendingIntent != null) {
- Log.d(TAG, "Canceling pre-existing stop alarm");
- mAlarmMgr.cancel(mStopPendingIntent);
- mStopPendingIntent = null;
- }
- if (mWakeLock != null) {
- mWakeLock.release();
- mWakeLock = null;
- }
- if (mPerfData != null) {
- mPerfData.stopRecording(this);
- mPerfData.onDestroy();
- mPerfData = null;
- }
-
- // Obtain the latest data and display it.
- getData();
-
- long elapsedTimeMins = (long) Math.floor(
- (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
- mReportText.setText("Loadtest ended. Elapsed time = " + elapsedTimeMins + " min(s)");
- clearConfigs();
- updateStarted(false);
- }
-
- private synchronized void updateStarted(boolean started) {
- mStarted = started;
- mStartStop.setBackgroundColor(started ?
- Color.parseColor("#FFFF0000") : Color.parseColor("#FF00FF00"));
- mStartStop.setText(started ? getString(R.string.stop) : getString(R.string.start));
- updateControlsEnabled();
- }
-
- private void updateControlsEnabled() {
- mBurstText.setEnabled(!mPlacebo && !mStarted);
- mReplicationText.setEnabled(!mPlacebo && !mStarted);
- mPeriodText.setEnabled(!mStarted);
- mBucketSpinner.setEnabled(!mPlacebo && !mStarted);
- mDurationText.setEnabled(!mStarted);
- mPlaceboCheckBox.setEnabled(!mStarted);
-
- boolean enabled = !mStarted && !mPlaceboCheckBox.isChecked();
- mCountMetricCheckBox.setEnabled(enabled);
- mDurationMetricCheckBox.setEnabled(enabled);
- mEventMetricCheckBox.setEnabled(enabled);
- mValueMetricCheckBox.setEnabled(enabled);
- mGaugeMetricCheckBox.setEnabled(enabled);
- }
-
- private boolean statsdRunning() {
- if (IStatsManager.Stub.asInterface(ServiceManager.getService("stats")) == null) {
- Log.d(TAG, "Statsd not running");
- Toast.makeText(LoadtestActivity.this, "Statsd NOT running!", Toast.LENGTH_LONG).show();
- return false;
- }
- return true;
- }
-
- private int sanitizeInt(int val, int min, int max) {
- if (val > max) {
- val = max;
- } else if (val < min) {
- val = min;
- }
- return val;
- }
-
- private void clearConfigs() {
- // TODO: Clear all configs instead of specific ones.
- if (mStatsManager != null) {
- if (mStarted) {
- try {
- mStatsManager.removeConfig(ConfigFactory.CONFIG_ID);
- Log.d(TAG, "Removed loadtest statsd configs.");
- } catch (StatsManager.StatsUnavailableException e) {
- Log.e(TAG, "Failed to remove loadtest configs.", e);
- }
- }
- }
- }
-
- private boolean setConfig(ConfigFactory.ConfigMetadata configData) {
- if (mStatsManager != null) {
- try {
- mStatsManager.addConfig(ConfigFactory.CONFIG_ID, configData.bytes);
- mNumMetrics = configData.numMetrics;
- Log.d(TAG, "Config pushed to statsd");
- return true;
- } catch (StatsManager.StatsUnavailableException | IllegalArgumentException e) {
- Log.e(TAG, "Failed to push config to statsd", e);
- }
- }
- return false;
- }
-
- private synchronized void setReplication(int replication) {
- if (mStarted) {
- return;
- }
- mReplicationText.setText("" + replication);
- }
-
- private synchronized void setPeriodSecs(long periodSecs) {
- mPeriodSecs = periodSecs;
- }
-
- private synchronized void setBurst(int burst) {
- mBurst = burst;
- }
-
- private synchronized void setDurationMins(long durationMins) {
- mDurationMins = durationMins;
- }
-
-
- private void handleFocus(EditText editText) {
- /*
- editText.setOnFocusChangeListener(new OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (!hasFocus && editText.getText().toString().isEmpty()) {
- editText.setText("-1", TextView.BufferType.EDITABLE);
- }
- }
- });
- */
- }
-
- private void initBurst() {
- mBurst = getResources().getInteger(R.integer.burst_default);
- mBurstText = (EditText) findViewById(R.id.burst);
- mBurstText.addTextChangedListener(new NumericalWatcher(mBurstText, 0, 1000) {
- @Override
- public void onNewValue(int newValue) {
- setBurst(newValue);
- }
- });
- handleFocus(mBurstText);
- }
-
- private void initReplication() {
- mReplication = getResources().getInteger(R.integer.replication_default);
- mReplicationText = (EditText) findViewById(R.id.replication);
- mReplicationText.addTextChangedListener(new NumericalWatcher(mReplicationText, 1, 4096) {
- @Override
- public void onNewValue(int newValue) {
- mReplication = newValue;
- }
- });
- handleFocus(mReplicationText);
- }
-
- private void initBucket() {
- String defaultValue = getResources().getString(R.string.bucket_default);
- mBucket = TimeUnit.valueOf(defaultValue);
- mBucketSpinner = (Spinner) findViewById(R.id.bucket_spinner);
-
- ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(
- this, R.layout.spinner_item, TIME_UNIT_LABELS);
-
- mBucketSpinner.setAdapter(dataAdapter);
- mBucketSpinner.setOnItemSelectedListener(this);
-
- for (String label : TIME_UNIT_MAP.keySet()) {
- if (defaultValue.equals(TIME_UNIT_MAP.get(label).toString())) {
- mBucketSpinner.setSelection(dataAdapter.getPosition(label));
- }
- }
- }
-
- private void initPeriod() {
- mPeriodSecs = getResources().getInteger(R.integer.period_default);
- mPeriodText = (EditText) findViewById(R.id.period);
- mPeriodText.addTextChangedListener(new NumericalWatcher(mPeriodText, 1, 60) {
- @Override
- public void onNewValue(int newValue) {
- setPeriodSecs(newValue);
- }
- });
- handleFocus(mPeriodText);
- }
-
- private void initDuration() {
- mDurationMins = getResources().getInteger(R.integer.duration_default);
- mDurationText = (EditText) findViewById(R.id.duration);
- mDurationText.addTextChangedListener(new NumericalWatcher(mDurationText, 1, 24 * 60) {
- @Override
- public void onNewValue(int newValue) {
- setDurationMins(newValue);
- }
- });
- handleFocus(mDurationText);
- }
-
- private void initPlacebo() {
- mPlaceboCheckBox = findViewById(R.id.placebo);
- mPlacebo = false;
- mPlaceboCheckBox.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mPlacebo = mPlaceboCheckBox.isChecked();
- updateControlsEnabled();
- }
- });
- }
-
- private void initMetricWhitelist() {
- mCountMetricCheckBox = findViewById(R.id.include_count);
- mCountMetricCheckBox.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mIncludeCountMetric = mCountMetricCheckBox.isChecked();
- }
- });
- mDurationMetricCheckBox = findViewById(R.id.include_duration);
- mDurationMetricCheckBox.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mIncludeDurationMetric = mDurationMetricCheckBox.isChecked();
- }
- });
- mEventMetricCheckBox = findViewById(R.id.include_event);
- mEventMetricCheckBox.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mIncludeEventMetric = mEventMetricCheckBox.isChecked();
- }
- });
- mValueMetricCheckBox = findViewById(R.id.include_value);
- mValueMetricCheckBox.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mIncludeValueMetric = mValueMetricCheckBox.isChecked();
- }
- });
- mGaugeMetricCheckBox = findViewById(R.id.include_gauge);
- mGaugeMetricCheckBox.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mIncludeGaugeMetric = mGaugeMetricCheckBox.isChecked();
- }
- });
-
- mIncludeCountMetric = mCountMetricCheckBox.isChecked();
- mIncludeDurationMetric = mDurationMetricCheckBox.isChecked();
- mIncludeEventMetric = mEventMetricCheckBox.isChecked();
- mIncludeValueMetric = mValueMetricCheckBox.isChecked();
- mIncludeGaugeMetric = mGaugeMetricCheckBox.isChecked();
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java
deleted file mode 100644
index 01eebf2..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java
+++ /dev/null
@@ -1,69 +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.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.os.SystemClock;
-import android.util.Log;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/** Parses PSS info from dumpsys meminfo */
-public class MemInfoParser implements PerfParser {
-
- private static final Pattern LINE_PATTERN =
- Pattern.compile("\\s*(\\d*,*\\d*)K:\\s(\\S*)\\s\\.*");
- private static final String PSS_BY_PROCESS = "Total PSS by process:";
- private static final String TAG = "loadtest.MemInfoParser";
-
- private boolean mPssStarted;
- private boolean mPssEnded;
- private final long mStartTimeMillis;
-
- public MemInfoParser(long startTimeMillis) {
- mStartTimeMillis = startTimeMillis;
- }
-
- @Override
- @Nullable
- public String parseLine(String line) {
- if (mPssEnded) {
- return null;
- }
- if (!mPssStarted) {
- if (line.contains(PSS_BY_PROCESS)) {
- mPssStarted = true;
- }
- return null;
- }
- if (line.isEmpty()) {
- mPssEnded = true;
- return null;
- }
- Matcher lineMatcher = LINE_PATTERN.matcher(line);
- if (lineMatcher.find() && lineMatcher.group(1) != null && lineMatcher.group(2) != null) {
- if (lineMatcher.group(2).equals("statsd")) {
- long timeDeltaMillis = SystemClock.elapsedRealtime() - mStartTimeMillis;
- return timeDeltaMillis + "," + convertToPss(lineMatcher.group(1));
- }
- }
- return null;
- }
-
- private String convertToPss(String input) {
- return input.replace(",", "");
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java
deleted file mode 100644
index af7bd4d..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java
+++ /dev/null
@@ -1,53 +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.statsd.loadtest;
-
-import android.content.Context;
-import android.os.SystemClock;
-import android.util.Log;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-public class MemoryDataRecorder extends PerfDataRecorder {
- private static final String TAG = "loadtest.MemoryDataDataRecorder";
- private static final String DUMP_FILENAME = TAG + "_dump.tmp";
-
- private long mStartTimeMillis;
- private StringBuilder mSb;
-
- public MemoryDataRecorder(boolean placebo, int replication, TimeUnit bucket, long periodSecs,
- int burst, boolean includeCountMetric, boolean includeDurationMetric,
- boolean includeEventMetric, boolean includeValueMetric, boolean includeGaugeMetric) {
- super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
- includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
- }
-
- @Override
- public void startRecording(Context context) {
- mStartTimeMillis = SystemClock.elapsedRealtime();
- mSb = new StringBuilder();
- }
-
- @Override
- public void onAlarm(Context context) {
- runDumpsysStats(context, DUMP_FILENAME, "meminfo");
- readDumpData(context, DUMP_FILENAME, new MemInfoParser(mStartTimeMillis), mSb);
- }
-
- @Override
- public void stopRecording(Context context) {
- writeData(context, "meminfo_", "time,pss", mSb);
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java
deleted file mode 100644
index 555e6dd..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java
+++ /dev/null
@@ -1,70 +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.statsd.loadtest;
-
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Log;
-import android.widget.TextView;
-
-public abstract class NumericalWatcher implements TextWatcher {
-
- private static final String TAG = "loadtest.NumericalWatcher";
-
- private final TextView mTextView;
- private final int mMin;
- private final int mMax;
- private int currentValue = -1;
-
- public NumericalWatcher(TextView textView, int min, int max) {
- mTextView = textView;
- mMin = min;
- mMax = max;
- }
-
- public abstract void onNewValue(int newValue);
-
- @Override
- final public void afterTextChanged(Editable editable) {
- String s = mTextView.getText().toString();
- if (s.isEmpty()) {
- return;
- }
- int unsanitized = Integer.parseInt(s);
- int newValue = sanitize(unsanitized);
- if (currentValue != newValue || unsanitized != newValue) {
- currentValue = newValue;
- editable.clear();
- editable.append(newValue + "");
- }
- onNewValue(newValue);
- }
-
- @Override
- final public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
-
- @Override
- final public void onTextChanged(CharSequence s, int start, int before, int count) {}
-
- private int sanitize(int val) {
- if (val > mMax) {
- val = mMax;
- } else if (val < mMin) {
- val = mMin;
- }
- return val;
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java
deleted file mode 100644
index 7a01ade..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java
+++ /dev/null
@@ -1,116 +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.statsd.loadtest;
-
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-import android.annotation.Nullable;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/** Prints some information about the device via Dumpsys in order to evaluate health metrics. */
-public class PerfData extends PerfDataRecorder {
-
- private static final String TAG = "loadtest.PerfData";
-
- /** Polling period for performance snapshots like memory. */
- private static final long POLLING_PERIOD_MILLIS = 1 * 60 * 1000;
-
- public final static class PerfAlarmReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Intent activityIntent = new Intent(context, LoadtestActivity.class);
- activityIntent.putExtra(LoadtestActivity.TYPE, LoadtestActivity.PERF_ALARM);
- context.startActivity(activityIntent);
- }
- }
-
- private AlarmManager mAlarmMgr;
-
- /** Used to periodically poll some dumpsys data. */
- private PendingIntent mPendingIntent;
-
- private final Set<PerfDataRecorder> mRecorders;
-
- public PerfData(LoadtestActivity loadtestActivity, boolean placebo, int replication,
- TimeUnit bucket, long periodSecs, int burst, boolean includeCountMetric,
- boolean includeDurationMetric, boolean includeEventMetric, boolean includeValueMetric,
- boolean includeGaugeMetric) {
- super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
- includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
- mRecorders = new HashSet();
- mRecorders.add(new BatteryDataRecorder(placebo, replication, bucket, periodSecs, burst,
- includeCountMetric, includeDurationMetric, includeEventMetric, includeValueMetric,
- includeGaugeMetric));
- mRecorders.add(new MemoryDataRecorder(placebo, replication, bucket, periodSecs, burst,
- includeCountMetric, includeDurationMetric, includeEventMetric, includeValueMetric,
- includeGaugeMetric));
- mRecorders.add(new StatsdStatsRecorder(loadtestActivity, placebo, replication, bucket,
- periodSecs, burst, includeCountMetric, includeDurationMetric, includeEventMetric,
- includeValueMetric, includeGaugeMetric));
- mRecorders.add(new ValidationRecorder(loadtestActivity, placebo, replication, bucket,
- periodSecs, burst, includeCountMetric, includeDurationMetric, includeEventMetric,
- includeValueMetric, includeGaugeMetric));
- mAlarmMgr = (AlarmManager) loadtestActivity.getSystemService(Context.ALARM_SERVICE);
- }
-
- public void onDestroy() {
- if (mPendingIntent != null) {
- mAlarmMgr.cancel(mPendingIntent);
- mPendingIntent = null;
- }
- }
-
- @Override
- public void startRecording(Context context) {
- Intent intent = new Intent(context, PerfAlarmReceiver.class);
- intent.putExtra(LoadtestActivity.TYPE, LoadtestActivity.PERF_ALARM);
- mPendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
- mAlarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, -1 /* now */,
- POLLING_PERIOD_MILLIS, mPendingIntent);
-
- for (PerfDataRecorder recorder : mRecorders) {
- recorder.startRecording(context);
- }
- }
-
- @Override
- public void onAlarm(Context context) {
- for (PerfDataRecorder recorder : mRecorders) {
- recorder.onAlarm(context);
- }
- }
-
- @Override
- public void stopRecording(Context context) {
- if (mPendingIntent != null) {
- mAlarmMgr.cancel(mPendingIntent);
- mPendingIntent = null;
- }
-
- for (PerfDataRecorder recorder : mRecorders) {
- recorder.stopRecording(context);
- }
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java
deleted file mode 100644
index 8613ac1..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java
+++ /dev/null
@@ -1,174 +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.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.os.Environment;
-import android.util.Log;
-import android.os.Debug;
-
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-import java.io.BufferedReader;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-public abstract class PerfDataRecorder {
- private static final String TAG = "loadtest.PerfDataRecorder";
-
- protected final String mTimeAsString;
- protected final String mColumnSuffix;
-
- protected PerfDataRecorder(boolean placebo, int replication, TimeUnit bucket, long periodSecs,
- int burst, boolean includeCountMetric, boolean includeDurationMetric,
- boolean includeEventMetric, boolean includeValueMetric, boolean includeGaugeMetric) {
- mTimeAsString = new SimpleDateFormat("YYYY_MM_dd_HH_mm_ss").format(new Date());
- mColumnSuffix = getColumnSuffix(placebo, replication, bucket, periodSecs, burst,
- includeCountMetric, includeDurationMetric, includeEventMetric, includeValueMetric,
- includeGaugeMetric);
- }
-
- /** Starts recording performance data. */
- public abstract void startRecording(Context context);
-
- /** Called periodically. For the recorder to sample data, if needed. */
- public abstract void onAlarm(Context context);
-
- /** Stops recording performance data, and writes it to disk. */
- public abstract void stopRecording(Context context);
-
- /** Runs the dumpsys command. */
- protected void runDumpsysStats(Context context, String dumpFilename, String cmd,
- String... args) {
- boolean success = false;
- // Call dumpsys Dump statistics to a file.
- FileOutputStream fo = null;
- try {
- fo = context.openFileOutput(dumpFilename, Context.MODE_PRIVATE);
- if (!Debug.dumpService(cmd, fo.getFD(), args)) {
- Log.w(TAG, "Dumpsys failed.");
- }
- success = true;
- } catch (IOException | SecurityException | NullPointerException e) {
- // SecurityException may occur when trying to dump multi-user info.
- // NPE can occur during dumpService (root cause unknown).
- throw new RuntimeException(e);
- } finally {
- closeQuietly(fo);
- }
- }
-
- /**
- * Reads a text file and parses each line, one by one. The result of the parsing is stored
- * in the passed {@link StringBuffer}.
- */
- protected void readDumpData(Context context, String dumpFilename, PerfParser parser,
- StringBuilder sb) {
- FileInputStream fi = null;
- BufferedReader br = null;
- try {
- fi = context.openFileInput(dumpFilename);
- br = new BufferedReader(new InputStreamReader(fi));
- String line = br.readLine();
- while (line != null) {
- String recordLine = parser.parseLine(line);
- if (recordLine != null) {
- sb.append(recordLine).append('\n');
- }
- line = br.readLine();
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- } finally {
- closeQuietly(br);
- }
- }
-
- /** Writes CSV data to a file. */
- protected void writeData(Context context, String filePrefix, String columnPrefix,
- StringBuilder sb) {
- File dataFile = new File(getStorageDir(), filePrefix + mTimeAsString + ".csv");
-
- FileWriter writer = null;
- try {
- writer = new FileWriter(dataFile);
- writer.append(columnPrefix + mColumnSuffix + "\n");
- writer.append(sb.toString());
- writer.flush();
- Log.d(TAG, "Finished writing data at " + dataFile.getAbsolutePath());
- } catch (IOException e) {
- throw new RuntimeException(e);
- } finally {
- closeQuietly(writer);
- }
- }
-
- /** Gets the suffix to use in the column name for perf data. */
- private String getColumnSuffix(boolean placebo, int replication, TimeUnit bucket,
- long periodSecs, int burst, boolean includeCountMetric, boolean includeDurationMetric,
- boolean includeEventMetric, boolean includeValueMetric, boolean includeGaugeMetric) {
- if (placebo) {
- return "_placebo_p=" + periodSecs;
- }
- StringBuilder sb = new StringBuilder()
- .append("_r=" + replication)
- .append("_bkt=" + bucket)
- .append("_p=" + periodSecs)
- .append("_bst=" + burst)
- .append("_m=");
- if (includeCountMetric) {
- sb.append("c");
- }
- if (includeEventMetric) {
- sb.append("e");
- }
- if (includeDurationMetric) {
- sb.append("d");
- }
- if (includeGaugeMetric) {
- sb.append("g");
- }
- if (includeValueMetric) {
- sb.append("v");
- }
- return sb.toString();
- }
-
- private File getStorageDir() {
- File file = new File(Environment.getExternalStoragePublicDirectory(
- Environment.DIRECTORY_DOCUMENTS), "loadtest/" + mTimeAsString);
- if (!file.mkdirs()) {
- Log.e(TAG, "Directory not created");
- }
- return file;
- }
-
- private void closeQuietly(@Nullable Closeable c) {
- if (c != null) {
- try {
- c.close();
- } catch (IOException ignore) {
- }
- }
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
deleted file mode 100644
index e000918..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
+++ /dev/null
@@ -1,27 +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.statsd.loadtest;
-
-import android.annotation.Nullable;
-
-public interface PerfParser {
-
- /**
- * Parses one line of the dumpsys output, and returns a string to write to the data file,
- * or null if no string should be written.
- */
- @Nullable String parseLine(String line);
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java
deleted file mode 100644
index 5dcce9a..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java
+++ /dev/null
@@ -1,165 +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.statsd.loadtest;
-
-import android.util.Log;
-import android.util.StatsLog;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Manages the pushing of atoms into logd for loadtesting.
- * We rely on small number of pushed atoms, and a config with metrics based on those atoms.
- * The atoms are:
- * <ul>
- * <li> BatteryLevelChanged - For EventMetric, CountMetric and GaugeMetric (no dimensions).
- * <li> BleScanResultReceived - For CountMetric and ValueMetric, sliced by uid.
- * <li> ChargingStateChanged - For DurationMetric (no dimension).
- * <li> GpsScanStateChanged - For DurationMetric, sliced by uid.
- * <li> ScreenStateChanged - For Conditions with no dimensions.
- * <li> AudioStateChanged - For Conditions with dimensions (uid).
- * </ul>
- * The sequence is played over and over at a given frequency.
- */
-public class SequencePusher {
- private static final String TAG = "SequencePusher";
-
- /** Some atoms are pushed in burst of {@code mBurst} events. */
- private final int mBurst;
-
- /** If this is true, we don't log anything in logd. */
- private final boolean mPlacebo;
-
- /** Current state in the automaton. */
- private int mCursor = 0;
-
- public SequencePusher(int burst, boolean placebo) {
- mBurst = burst;
- mPlacebo = placebo;
- }
-
- /**
- * Pushes the next atom to logd.
- * This follows a small automaton which makes the right events and conditions overlap:
- * (0) Push a burst of BatteryLevelChanged atoms.
- * (1) Push a burst of BleScanResultReceived atoms.
- * (2) Push ChargingStateChanged with BATTERY_STATUS_CHARGING once.
- * (3) Push a burst of GpsScanStateChanged atoms with ON, with a different uid each time.
- * (4) Push ChargingStateChanged with BATTERY_STATUS_NOT_CHARGING once.
- * (5) Push a burst GpsScanStateChanged atoms with OFF, with a different uid each time.
- * (6) Push ScreenStateChanged with STATE_ON once.
- * (7) Push a burst of AudioStateChanged with ON, with a different uid each time.
- * (8) Repeat steps (0)-(5).
- * (9) Push ScreenStateChanged with STATE_OFF once.
- * (10) Push a burst of AudioStateChanged with OFF, with a different uid each time.
- * and repeat.
- */
- public void next() {
- Log.d(TAG, "Next step: " + mCursor);
- if (mPlacebo) {
- return;
- }
- switch (mCursor) {
- case 0:
- case 8:
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.BATTERY_LEVEL_CHANGED, 50 + i /* battery_level */);
- }
- break;
- case 1:
- case 9:
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.BLE_SCAN_RESULT_RECEIVED, i /* uid */,
- 100 /* num_of_results */);
- }
- break;
- case 2:
- case 10:
- StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
- StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_CHARGING
- /* charging_state */);
- break;
- case 3:
- case 11:
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
- StatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON /* state */);
- }
- break;
- case 4:
- case 12:
- StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
- StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_NOT_CHARGING
- /* charging_state */);
- break;
- case 5:
- case 13:
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
- StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF /* state */);
- }
- break;
- case 6:
- StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
- StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_ON /* display_state */);
- break;
- case 7:
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
- StatsLog.AUDIO_STATE_CHANGED__STATE__ON /* state */);
- }
- break;
- case 14:
- StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
- StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF /* display_state */);
- break;
- case 15:
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
- StatsLog.AUDIO_STATE_CHANGED__STATE__OFF /* state */);
- }
- break;
- default:
- }
- mCursor++;
- if (mCursor > 15) {
- mCursor = 0;
- }
- }
-
- /**
- * Properly finishes in order to be close all conditions and durations.
- */
- public void finish() {
- // Screen goes back to off. This will ensure that conditions get back to false.
- StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
- StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF /* display_state */);
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
- StatsLog.AUDIO_STATE_CHANGED__STATE__OFF /* state */);
- }
- // Stop charging, to ensure the corresponding durations are closed.
- StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
- StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_NOT_CHARGING
- /* charging_state */);
- // Stop scanning GPS, to ensure the corresponding conditions get back to false.
- for (int i = 0; i < mBurst; i++) {
- StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
- StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF /* state */);
- }
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/StatsdStatsRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/StatsdStatsRecorder.java
deleted file mode 100644
index 3939e7e..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/StatsdStatsRecorder.java
+++ /dev/null
@@ -1,62 +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.statsd.loadtest;
-
-import android.content.Context;
-import com.android.os.StatsLog.StatsdStatsReport;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-public class StatsdStatsRecorder extends PerfDataRecorder {
- private static final String TAG = "loadtest.StatsdStatsRecorder";
-
- private final LoadtestActivity mLoadtestActivity;
-
- public StatsdStatsRecorder(LoadtestActivity loadtestActivity, boolean placebo, int replication,
- TimeUnit bucket, long periodSecs, int burst, boolean includeCountMetric,
- boolean includeDurationMetric, boolean includeEventMetric, boolean includeValueMetric,
- boolean includeGaugeMetric) {
- super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
- includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
- mLoadtestActivity = loadtestActivity;
- }
-
- @Override
- public void startRecording(Context context) {
- // Nothing to do.
- }
-
- @Override
- public void onAlarm(Context context) {
- // Nothing to do.
- }
-
- @Override
- public void stopRecording(Context context) {
- StatsdStatsReport metadata = mLoadtestActivity.getMetadata();
- if (metadata != null) {
- int numConfigs = metadata.getConfigStatsCount();
- StringBuilder sb = new StringBuilder();
- StatsdStatsReport.ConfigStats configStats = metadata.getConfigStats(numConfigs - 1);
- sb.append("metric_count,")
- .append(configStats.getMetricCount() + "\n")
- .append("condition_count,")
- .append(configStats.getConditionCount() + "\n")
- .append("matcher_count,")
- .append(configStats.getMatcherCount() + "\n");
- writeData(context, "statsdstats_", "stat,value", sb);
- }
- }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
deleted file mode 100644
index d9f0ca9..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
+++ /dev/null
@@ -1,93 +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.statsd.loadtest;
-
-import android.content.Context;
-import android.util.Log;
-import com.android.os.StatsLog.ConfigMetricsReport;
-import com.android.os.StatsLog.EventMetricData;
-import com.android.os.StatsLog.StatsLogReport;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Checks the correctness of the stats.
- */
-public class ValidationRecorder extends PerfDataRecorder {
- private static final String TAG = "loadtest.ValidationRecorder";
-
- private final LoadtestActivity mLoadtestActivity;
-
- public ValidationRecorder(LoadtestActivity loadtestActivity, boolean placebo, int replication,
- TimeUnit bucket, long periodSecs, int burst, boolean includeCountMetric,
- boolean includeDurationMetric, boolean includeEventMetric, boolean includeValueMetric,
- boolean includeGaugeMetric) {
- super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
- includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
- mLoadtestActivity = loadtestActivity;
- }
-
- @Override
- public void startRecording(Context context) {
- // Nothing to do.
- }
-
- @Override
- public void onAlarm(Context context) {
- validateData();
- }
-
- @Override
- public void stopRecording(Context context) {
- validateData();
- }
-
- private void validateData() {
- // The code below is commented out because it calls getData, which has the side-effect
- // of clearing statsd's data buffer.
- /*
- List<ConfigMetricsReport> reports = mLoadtestActivity.getData();
- if (reports != null) {
- Log.d(TAG, "GOT DATA");
- for (ConfigMetricsReport report : reports) {
- for (StatsLogReport logReport : report.getMetricsList()) {
- if (!logReport.hasMetricId()) {
- Log.e(TAG, "Metric missing name.");
- }
- }
- }
- }
- */
- }
-
- private void validateEventBatteryLevelChanges(StatsLogReport logReport) {
- Log.d(TAG, "Validating " + logReport.getMetricId());
- if (logReport.hasEventMetrics()) {
- Log.d(TAG, "Num events captured: " + logReport.getEventMetrics().getDataCount());
- for (EventMetricData data : logReport.getEventMetrics().getDataList()) {
- Log.d(TAG, " Event : " + data.getAtom());
- }
- } else {
- Log.d(TAG, "Metric is invalid");
- }
- }
-
- private void validateEventBatteryLevelChangesWhileScreenIsOn(StatsLogReport logReport) {
- Log.d(TAG, "Validating " + logReport.getMetricId());
- }
-}
diff --git a/config/boot-profile.txt b/config/boot-profile.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/config/boot-profile.txt
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 4aafa53..ffba115 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -777,8 +777,8 @@
callback, handler);
mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo);
}
- connection.sendGesture(mGestureStatusCallbackSequence,
- new ParceledListSlice<>(steps));
+ connection.dispatchGesture(mGestureStatusCallbackSequence,
+ new ParceledListSlice<>(steps), gesture.getDisplayId());
}
} catch (RemoteException re) {
throw new RuntimeException(re);
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index a3e7ad5..3b79d21 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -23,6 +23,7 @@
import android.graphics.RectF;
import android.os.Parcel;
import android.os.Parcelable;
+import android.view.Display;
import com.android.internal.util.Preconditions;
@@ -33,7 +34,7 @@
* Accessibility services with the
* {@link android.R.styleable#AccessibilityService_canPerformGestures} property can dispatch
* gestures. This class describes those gestures. Gestures are made up of one or more strokes.
- * Gestures are immutable once built.
+ * Gestures are immutable once built and will be dispatched to the specified display.
* <p>
* Spatial dimensions throughout are in screen pixels. Time is measured in milliseconds.
*/
@@ -48,6 +49,7 @@
private final List<StrokeDescription> mStrokes = new ArrayList<>();
private final float[] mTempPos = new float[2];
+ private final int mDisplayId;
/**
* Get the upper limit for the number of strokes a gesture may contain.
@@ -67,10 +69,17 @@
return MAX_GESTURE_DURATION_MS;
}
- private GestureDescription() {}
+ private GestureDescription() {
+ this(new ArrayList<>());
+ }
private GestureDescription(List<StrokeDescription> strokes) {
+ this(strokes, Display.DEFAULT_DISPLAY);
+ }
+
+ private GestureDescription(List<StrokeDescription> strokes, int displayId) {
mStrokes.addAll(strokes);
+ mDisplayId = displayId;
}
/**
@@ -94,6 +103,16 @@
}
/**
+ * Returns the ID of the display this gesture is sent on, for use with
+ * {@link android.hardware.display.DisplayManager#getDisplay(int)}.
+ *
+ * @return The logical display id.
+ */
+ public int getDisplayId() {
+ return mDisplayId;
+ }
+
+ /**
* Return the smallest key point (where a path starts or ends) that is at least a specified
* offset
* @param offset the minimum start time
@@ -160,9 +179,10 @@
public static class Builder {
private final List<StrokeDescription> mStrokes = new ArrayList<>();
+ private int mDisplayId = Display.DEFAULT_DISPLAY;
/**
- * Add a stroke to the gesture description. Up to
+ * Adds a stroke to the gesture description. Up to
* {@link GestureDescription#getMaxStrokeCount()} paths may be
* added to a gesture, and the total gesture duration (earliest path start time to latest
* path end time) may not exceed {@link GestureDescription#getMaxGestureDuration()}.
@@ -187,11 +207,23 @@
return this;
}
+ /**
+ * Sets the id of the display to dispatch gestures.
+ *
+ * @param displayId The logical display id
+ *
+ * @return this
+ */
+ public @NonNull Builder setDisplayId(int displayId) {
+ mDisplayId = displayId;
+ return this;
+ }
+
public GestureDescription build() {
if (mStrokes.size() == 0) {
throw new IllegalStateException("Gestures must have at least one stroke");
}
- return new GestureDescription(mStrokes);
+ return new GestureDescription(mStrokes, mDisplayId);
}
}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index c8e0132..1ca07dd 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -95,6 +95,8 @@
void sendGesture(int sequence, in ParceledListSlice gestureSteps);
+ void dispatchGesture(int sequence, in ParceledListSlice gestureSteps, int displayId);
+
boolean isFingerprintGestureDetectionAvailable();
IBinder getOverlayWindowToken(int displayid);
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 755f047..415ec64 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -386,9 +386,15 @@
// Also report this geometry information to InputMethodManagerService.
// TODO(b/115693908): Unify this logic into the above WMS-based one.
+ // TODO(b/138175283): Address the location update when the host of this view is
+ // moving.
final Matrix matrix = new Matrix();
+ final int[] locationOnScreen = new int[2];
+ getLocationOnScreen(locationOnScreen);
+ final int dx = locationOnScreen[0];
+ final int dy = locationOnScreen[1];
matrix.set(getMatrix());
- matrix.postTranslate(x, y);
+ matrix.postTranslate(dx, dy);
mContext.getSystemService(InputMethodManager.class)
.reportActivityView(displayId, matrix);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5aa1f8f..372eab2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5437,10 +5437,11 @@
/**
* Construct a RemoteViews for the display in public contexts like on the lockscreen.
*
+ * @param isLowPriority is this notification low priority
* @hide
*/
@UnsupportedAppUsage
- public RemoteViews makePublicContentView() {
+ public RemoteViews makePublicContentView(boolean isLowPriority) {
if (mN.publicVersion != null) {
final Builder builder = recoverBuilder(mContext, mN.publicVersion);
return builder.createContentView();
@@ -5467,7 +5468,11 @@
}
mN.extras = publicExtras;
RemoteViews view;
- view = makeNotificationHeader();
+ StandardTemplateParams params = mParams.reset().fillTextsFrom(this);
+ if (isLowPriority) {
+ params.forceDefaultColor();
+ }
+ view = makeNotificationHeader(params);
view.setBoolean(R.id.notification_header, "setExpandOnlyOnButton", true);
mN.extras = savedBundle;
mN.mLargeIcon = largeIcon;
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index 05833b5..5d00f09 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -126,6 +126,17 @@
"android.bluetooth.headsetclient.profile.action.RESULT";
/**
+ * Intent that notifies about vendor specific event arrival. Events not defined in
+ * HFP spec will be matched with supported vendor event list and this intent will
+ * be broadcasted upon a match. Supported vendor events are of format of
+ * of "+eventCode" or "+eventCode=xxxx" or "+eventCode:=xxxx".
+ * Vendor event can be a response to an vendor specific command or unsolicited.
+ *
+ */
+ public static final String ACTION_VENDOR_SPECIFIC_HEADSETCLIENT_EVENT =
+ "android.bluetooth.headsetclient.profile.action.VENDOR_SPECIFIC_EVENT";
+
+ /**
* Intent that notifies about the number attached to the last voice tag
* recorded on AG.
*
@@ -243,6 +254,28 @@
public static final String EXTRA_CME_CODE =
"android.bluetooth.headsetclient.extra.CME_CODE";
+ /**
+ * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that
+ * indicates vendor ID.
+ */
+ public static final String EXTRA_VENDOR_ID =
+ "android.bluetooth.headsetclient.extra.VENDOR_ID";
+
+ /**
+ * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that
+ * indicates vendor event code.
+ */
+ public static final String EXTRA_VENDOR_EVENT_CODE =
+ "android.bluetooth.headsetclient.extra.VENDOR_EVENT_CODE";
+
+ /**
+ * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that
+ * contains full vendor event including event code and full arguments.
+ */
+ public static final String EXTRA_VENDOR_EVENT_FULL_ARGS =
+ "android.bluetooth.headsetclient.extra.VENDOR_EVENT_FULL_ARGS";
+
+
/* Extras for AG_FEATURES, extras type is boolean */
// TODO verify if all of those are actually useful
/**
@@ -588,6 +621,31 @@
}
/**
+ * Send vendor specific AT command.
+ *
+ * @param device remote device
+ * @param vendorId vendor number by Bluetooth SIG
+ * @param atCommand command to be sent. It start with + prefix and only one command at one time.
+ * @return <code>true</code> if command has been issued successfully; <code>false</code>
+ * otherwise.
+ */
+ public boolean sendVendorAtCommand(BluetoothDevice device, int vendorId,
+ String atCommand) {
+ if (DBG) log("sendVendorSpecificCommand()");
+ final IBluetoothHeadsetClient service =
+ getService();
+ if (service != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return service.sendVendorAtCommand(device, vendorId, atCommand);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
* Stops voice recognition.
*
* @param device remote device
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 4d8a0c4..895eba6 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2044,6 +2044,30 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports Open Mobile API capable UICC-based secure
+ * elements.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_SE_OMAPI_UICC = "android.hardware.se.omapi.uicc";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports Open Mobile API capable eSE-based secure
+ * elements.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_SE_OMAPI_ESE = "android.hardware.se.omapi.ese";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports Open Mobile API capable SD-based secure
+ * elements.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_SE_OMAPI_SD = "android.hardware.se.omapi.sd";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports the OpenGL ES
* <a href="http://www.khronos.org/registry/gles/extensions/ANDROID/ANDROID_extension_pack_es31a.txt">
* Android Extension Pack</a>.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e690a7f..a4933ef 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -66,6 +66,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
@@ -2445,6 +2446,8 @@
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
+ } else if (tagName.equals("queries")) {
+ parseQueries(pkg, res, parser, flags, outError);
} else {
Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
+ " at " + mArchiveSourcePath + " "
@@ -3538,6 +3541,9 @@
owner.mRequiredAccountType = requiredAccountType;
}
+ owner.mForceQueryable =
+ sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false);
+
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
false)) {
@@ -3953,7 +3959,6 @@
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL;
}
XmlUtils.skipCurrentTag(parser);
-
} else {
if (!RIGID_PARSER) {
Slog.w(TAG, "Unknown element under <application>: " + tagName
@@ -4000,6 +4005,67 @@
return true;
}
+ private boolean parseQueries(Package owner, Resources res, XmlResourceParser parser, int flags,
+ String[] outError)
+ throws IOException, XmlPullParserException {
+
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ if (parser.getName().equals("intent")) {
+ QueriesIntentInfo intentInfo = new QueriesIntentInfo();
+ if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
+ intentInfo, outError)) {
+ return false;
+ }
+ Intent intent = new Intent();
+ if (intentInfo.countActions() != 1) {
+ outError[0] = "intent tags must contain exactly one action.";
+ return false;
+ }
+ intent.setAction(intentInfo.getAction(0));
+ for (int i = 0, max = intentInfo.countCategories(); i < max; i++) {
+ intent.addCategory(intentInfo.getCategory(i));
+ }
+ Uri data = null;
+ String dataType = null;
+ if (intentInfo.countDataTypes() > 1) {
+ outError[0] = "intent tag may have at most one data type.";
+ return false;
+ }
+ if (intentInfo.countDataSchemes() > 1) {
+ outError[0] = "intent tag may have at most one data scheme.";
+ return false;
+ }
+ if (intentInfo.countDataTypes() == 1) {
+ data = Uri.fromParts(intentInfo.getDataType(0), "", null);
+ }
+ if (intentInfo.countDataSchemes() == 1) {
+ dataType = intentInfo.getDataScheme(0);
+ }
+ intent.setDataAndType(data, dataType);
+ owner.mQueriesIntents = ArrayUtils.add(owner.mQueriesIntents, intent);
+ } else if (parser.getName().equals("package")) {
+ final TypedArray sa = res.obtainAttributes(parser,
+ com.android.internal.R.styleable.AndroidManifestQueriesPackage);
+ final String packageName =
+ sa.getString(R.styleable.AndroidManifestQueriesPackage_name);
+ if (TextUtils.isEmpty(packageName)) {
+ outError[0] = "Package name is missing from package tag.";
+ return false;
+ }
+ owner.mQueriesPackages =
+ ArrayUtils.add(owner.mQueriesPackages, packageName.intern());
+ }
+ }
+ return true;
+ }
+
/**
* Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
*/
@@ -6514,6 +6580,9 @@
// The major version code declared for this package.
public int mVersionCodeMajor;
+ // Whether the package declares that it should be queryable by all normal apps on device.
+ public boolean mForceQueryable;
+
// Return long containing mVersionCode and mVersionCodeMajor.
public long getLongVersionCode() {
return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
@@ -6619,6 +6688,9 @@
/** Whether or not the package is a stub and must be replaced by the full version. */
public boolean isStub;
+ public ArrayList<String> mQueriesPackages;
+ public ArrayList<Intent> mQueriesIntents;
+
@UnsupportedAppUsage
public Package(String packageName) {
this.packageName = packageName;
@@ -7122,6 +7194,9 @@
use32bitAbi = (dest.readInt() == 1);
restrictUpdateHash = dest.createByteArray();
visibleToInstantApps = dest.readInt() == 1;
+ mForceQueryable = dest.readBoolean();
+ mQueriesIntents = dest.createTypedArrayList(Intent.CREATOR);
+ mQueriesPackages = dest.createStringArrayList();
}
private static void internStringArrayList(List<String> list) {
@@ -7247,6 +7322,9 @@
dest.writeInt(use32bitAbi ? 1 : 0);
dest.writeByteArray(restrictUpdateHash);
dest.writeInt(visibleToInstantApps ? 1 : 0);
+ dest.writeBoolean(mForceQueryable);
+ dest.writeTypedList(mQueriesIntents);
+ dest.writeList(mQueriesPackages);
}
@@ -8257,6 +8335,8 @@
}
}
+ public static final class QueriesIntentInfo extends IntentInfo {}
+
public final static class ActivityIntentInfo extends IntentInfo {
@UnsupportedAppUsage
public Activity activity;
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index 57a8801..3e2ba3d 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -62,7 +62,7 @@
mMemoryRegistration = new MemoryRegistration(mSize);
mCleaner = Cleaner.create(mFileDescriptor,
- new Closer(mFileDescriptor, mMemoryRegistration));
+ new Closer(mFileDescriptor.getInt$(), mMemoryRegistration));
}
/**
@@ -290,10 +290,10 @@
* Cleaner that closes the FD
*/
private static final class Closer implements Runnable {
- private FileDescriptor mFd;
+ private int mFd;
private MemoryRegistration mMemoryReference;
- private Closer(FileDescriptor fd, MemoryRegistration memoryReference) {
+ private Closer(int fd, MemoryRegistration memoryReference) {
mFd = fd;
mMemoryReference = memoryReference;
}
@@ -301,7 +301,9 @@
@Override
public void run() {
try {
- Os.close(mFd);
+ FileDescriptor fd = new FileDescriptor();
+ fd.setInt$(mFd);
+ Os.close(fd);
} catch (ErrnoException e) { /* swallow error */ }
mMemoryReference.release();
mMemoryReference = null;
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 5a9ab38..6aef5a5 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -40,6 +40,7 @@
public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
+ public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
private static final Map<String, String> DEFAULT_FLAGS;
@@ -56,6 +57,7 @@
DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false");
DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true");
+ DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false");
}
/**
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index 956161a..955be8d 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -77,23 +77,9 @@
void hideCurrentInputMethod();
/**
- * Set a state for controller whether would like to cancel recents animations with deferred
- * task screenshot presentation.
- *
- * When we cancel the recents animation due to a stack order change, we can't just cancel it
- * immediately as it would lead to a flicker in Launcher if we just remove the task from the
- * leash. Instead we screenshot the previous task and replace the child of the leash with the
- * screenshot, so that Launcher can still control the leash lifecycle & make the next app
- * transition animate smoothly without flickering.
- *
- * @param screenshot When set {@code true}, means recents animation will be canceled when the
- * next app launch. System will take previous task's screenshot when the next
- * app transition starting, and skip previous task's animation.
- * Set {@code false} means will not take screenshot & skip animation
- * for previous task.
- *
- * @see #cleanupScreenshot()
- * @see IRecentsAnimationRunner#onCancelled
+ * This call is deprecated, use #setDeferCancelUntilNextTransition() instead
+ * TODO(138144750): Remove this method once there are no callers
+ * @deprecated
*/
void setCancelWithDeferredScreenshot(boolean screenshot);
@@ -104,4 +90,34 @@
* @see {@link IRecentsAnimationRunner#onAnimationCanceled}
*/
void cleanupScreenshot();
+
+ /**
+ * Set a state for controller whether would like to cancel recents animations with deferred
+ * task screenshot presentation.
+ *
+ * When we cancel the recents animation due to a stack order change, we can't just cancel it
+ * immediately as it would lead to a flicker in Launcher if we just remove the task from the
+ * leash. Instead we screenshot the previous task and replace the child of the leash with the
+ * screenshot, so that Launcher can still control the leash lifecycle & make the next app
+ * transition animate smoothly without flickering.
+ *
+ * @param defer When set {@code true}, means that the recents animation will defer canceling the
+ * animation when a stack order change is triggered until the subsequent app
+ * transition start and skip previous task's animation.
+ * When set to {@code false}, means that the recents animation will be canceled
+ * immediately when the stack order changes.
+ * @param screenshot When set {@code true}, means that the system will take previous task's
+ * screenshot and replace the contents of the leash with it when the next app
+ * transition starting. The runner must call #cleanupScreenshot() to end the
+ * recents animation.
+ * When set to {@code false}, means that the system will simply wait for the
+ * next app transition start to immediately cancel the recents animation. This
+ * can be useful when you want an immediate transition into a state where the
+ * task is shown in the home/recents activity (without waiting for a
+ * screenshot).
+ *
+ * @see #cleanupScreenshot()
+ * @see IRecentsAnimationRunner#onCancelled
+ */
+ void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot);
}
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index 9c652a8..6cda60c 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -36,7 +36,7 @@
* @param deferredWithScreenshot If set to {@code true}, the contents of the task will be
* replaced with a screenshot, such that the runner's leash is
* still active. As soon as the runner doesn't need the leash
- * anymore, it can call
+ * anymore, it must call
* {@link IRecentsAnimationController#cleanupScreenshot).
*
* @see {@link RecentsAnimationController#cleanupScreenshot}
diff --git a/core/java/android/widget/ViewAnimator.java b/core/java/android/widget/ViewAnimator.java
index 80ea363..d36f343 100644
--- a/core/java/android/widget/ViewAnimator.java
+++ b/core/java/android/widget/ViewAnimator.java
@@ -57,6 +57,9 @@
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ViewAnimator);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ViewAnimator,
+ attrs, a, 0, 0);
+
int resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_inAnimation, 0);
if (resource > 0) {
setInAnimation(context, resource);
@@ -90,6 +93,8 @@
// attribute to override.
final TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.FrameLayout);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.FrameLayout,
+ attrs, a, 0, 0);
final boolean measureAllChildren = a.getBoolean(
com.android.internal.R.styleable.FrameLayout_measureAllChildren, true);
setMeasureAllChildren(measureAllChildren);
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index 3ac58e0..d53fada 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -27,6 +27,7 @@
import com.android.internal.annotations.VisibleForTesting;
+import java.io.File;
import java.io.FileInputStream;
import java.util.Iterator;
@@ -38,6 +39,7 @@
private static int sKernelWakelockUpdateVersion = 0;
private static final String sWakelockFile = "/proc/wakelocks";
private static final String sWakeupSourceFile = "/d/wakeup_sources";
+ private static final String sSysClassWakeupDir = "/sys/class/wakeup";
private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
Process.PROC_TAB_TERM|Process.PROC_OUT_STRING| // 0: name
@@ -71,99 +73,108 @@
* @return the updated data.
*/
public final KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats) {
- byte[] buffer = new byte[32*1024];
- int len = 0;
- boolean wakeup_sources;
- final long startTime = SystemClock.uptimeMillis();
+ boolean useSystemSuspend = (new File(sSysClassWakeupDir)).exists();
- final int oldMask = StrictMode.allowThreadDiskReadsMask();
- try {
- FileInputStream is;
- try {
- is = new FileInputStream(sWakelockFile);
- wakeup_sources = false;
- } catch (java.io.FileNotFoundException e) {
+ if (useSystemSuspend) {
+ WakeLockInfo[] wlStats = null;
+ if (mSuspendControlService == null) {
try {
- is = new FileInputStream(sWakeupSourceFile);
- wakeup_sources = true;
- } catch (java.io.FileNotFoundException e2) {
- Slog.wtf(TAG, "neither " + sWakelockFile + " nor " +
- sWakeupSourceFile + " exists");
+ mSuspendControlService = ISuspendControlService.Stub.asInterface(
+ ServiceManager.getServiceOrThrow("suspend_control"));
+ } catch (ServiceNotFoundException e) {
+ Slog.wtf(TAG, "Required service suspend_control not available", e);
return null;
}
}
- int cnt;
- while ((cnt = is.read(buffer, len, buffer.length - len)) > 0) {
- len += cnt;
+ try {
+ wlStats = mSuspendControlService.getWakeLockStats();
+ updateVersion(staleStats);
+ updateWakelockStats(wlStats, staleStats);
+ } catch (RemoteException e) {
+ Slog.wtf(TAG, "Failed to obtain wakelock stats from ISuspendControlService", e);
+ return null;
}
- is.close();
- } catch (java.io.IOException e) {
- Slog.wtf(TAG, "failed to read kernel wakelocks", e);
- return null;
- } finally {
- StrictMode.setThreadPolicyMask(oldMask);
- }
+ return removeOldStats(staleStats);
- final long readTime = SystemClock.uptimeMillis() - startTime;
- if (readTime > 100) {
- Slog.w(TAG, "Reading wakelock stats took " + readTime + "ms");
- }
+ } else {
+ byte[] buffer = new byte[32*1024];
+ int len = 0;
+ boolean wakeup_sources;
+ final long startTime = SystemClock.uptimeMillis();
- if (len > 0) {
- if (len >= buffer.length) {
- Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
+ try {
+ FileInputStream is;
+ try {
+ is = new FileInputStream(sWakelockFile);
+ wakeup_sources = false;
+ } catch (java.io.FileNotFoundException e) {
+ try {
+ is = new FileInputStream(sWakeupSourceFile);
+ wakeup_sources = true;
+ } catch (java.io.FileNotFoundException e2) {
+ Slog.wtf(TAG, "neither " + sWakelockFile + " nor " +
+ sWakeupSourceFile + " exists");
+ return null;
+ }
+ }
+
+ int cnt;
+ while ((cnt = is.read(buffer, len, buffer.length - len)) > 0) {
+ len += cnt;
+ }
+
+ is.close();
+ } catch (java.io.IOException e) {
+ Slog.wtf(TAG, "failed to read kernel wakelocks", e);
+ return null;
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
}
- int i;
- for (i=0; i<len; i++) {
- if (buffer[i] == '\0') {
- len = i;
- break;
+
+ final long readTime = SystemClock.uptimeMillis() - startTime;
+ if (readTime > 100) {
+ Slog.w(TAG, "Reading wakelock stats took " + readTime + "ms");
+ }
+
+ if (len > 0) {
+ if (len >= buffer.length) {
+ Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
+ }
+ int i;
+ for (i=0; i<len; i++) {
+ if (buffer[i] == '\0') {
+ len = i;
+ break;
+ }
}
}
+
+ updateVersion(staleStats);
+ parseProcWakelocks(buffer, len, wakeup_sources, staleStats);
+ return removeOldStats(staleStats);
}
-
- updateVersion(staleStats);
-
- parseProcWakelocks(buffer, len, wakeup_sources, staleStats);
-
- if (mSuspendControlService == null) {
- try {
- mSuspendControlService = ISuspendControlService.Stub.asInterface(
- ServiceManager.getServiceOrThrow("suspend_control"));
- } catch (ServiceNotFoundException e) {
- Slog.wtf(TAG, "Required service suspend_control not available", e);
- }
- }
-
- try {
- WakeLockInfo[] wlStats = mSuspendControlService.getWakeLockStats();
- getNativeWakelockStats(wlStats, staleStats);
- } catch (RemoteException e) {
- Slog.wtf(TAG, "Failed to obtain wakelock stats from ISuspendControlService", e);
- }
-
- return removeOldStats(staleStats);
}
/**
- * Reads native wakelock stats from SystemSuspend and updates staleStats with the new
- * information.
+ * Updates statleStats with stats from SystemSuspend.
* @param staleStats Existing object to update.
* @return the updated stats.
*/
@VisibleForTesting
- public KernelWakelockStats getNativeWakelockStats(WakeLockInfo[] wlStats,
+ public KernelWakelockStats updateWakelockStats(WakeLockInfo[] wlStats,
final KernelWakelockStats staleStats) {
for (WakeLockInfo info : wlStats) {
if (!staleStats.containsKey(info.name)) {
staleStats.put(info.name, new KernelWakelockStats.Entry((int) info.activeCount,
- info.totalTime, sKernelWakelockUpdateVersion));
+ info.totalTime * 1000 /* ms to us */, sKernelWakelockUpdateVersion));
} else {
KernelWakelockStats.Entry kwlStats = staleStats.get(info.name);
kwlStats.mCount = (int) info.activeCount;
- kwlStats.mTotalTime = info.totalTime;
+ // Convert milliseconds to microseconds
+ kwlStats.mTotalTime = info.totalTime * 1000;
kwlStats.mVersion = sKernelWakelockUpdateVersion;
}
}
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index a3d4798..71e3860 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -7,7 +7,7 @@
yro@google.com
# Settings UI
-per-file settings_enums.proto=zhfan@google.com
+per-file settings_enums.proto=tmfang@google.com
# Frameworks
ogunwale@google.com
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index c023438..3323095 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2401,4 +2401,11 @@
// OS: Q
// Note: Gear icon is shown next to gesture navigation preference and opens sensitivity dialog
SETTINGS_GESTURE_NAV_BACK_SENSITIVITY_DLG = 1748;
+
+ // ---- End Q Constants, all Q constants go above this line ----
+ // OPEN: Settings > Network & Internet > Wi-Fi > Click new network
+ // CATEGORY: SETTINGS
+ // OS: R
+ SETTINGS_WIFI_CONFIGURE_NETWORK = 1800;
+
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index df45ec5..aa440d3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4610,6 +4610,7 @@
android:supportsRtl="true"
android:theme="@style/Theme.DeviceDefault.Light.DarkActionBar"
android:defaultToDeviceProtectedStorage="true"
+ android:forceQueryable="true"
android:directBootAware="true">
<activity android:name="com.android.internal.app.ChooserActivity"
android:theme="@style/Theme.DeviceDefault.Resolver"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index be6cdcf..3ea8a77 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1743,6 +1743,13 @@
- {@code true} for apps with targetSdkVersion < 29.
-->
<attr name="requestLegacyExternalStorage" format="boolean" />
+
+ <!-- If {@code true} this app declares that it should be visible to all other apps on
+ device, regardless of what they declare via the {@code queries} tags in their
+ manifest.
+
+ The default value is {@code false}. -->
+ <attr name="forceQueryable" format="boolean" />
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
@@ -1977,6 +1984,12 @@
<attr name="name" />
</declare-styleable>
+ <declare-styleable name="AndroidManifestQueries" parent="AndroidManifest" />
+ <declare-styleable name="AndroidManifestQueriesPackage" parent="AndroidManifestQueries">
+ <attr name="name" />
+ </declare-styleable>
+ <declare-styleable name="AndroidManifestQueriesIntent" parent="AndroidManifestQueries" />
+
<!-- The <code>static-library</code> tag declares that this apk is providing itself
as a static shared library for other applications to use. Any app can declare such
@@ -2477,6 +2490,7 @@
<!-- High dynamic range color mode. -->
<enum name="hdr" value="2" />
</attr>
+ <attr name="forceQueryable" format="boolean" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3b12753..dce4bf3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1700,6 +1700,12 @@
<!-- Add packages here -->
</string-array>
+ <string-array name="config_forceQueryablePackages" translatable="false">
+ <item>com.android.settings</item>
+ <!-- Add packages here -->
+ </string-array>
+
+
<!-- Component name of the default wallpaper. This will be ImageWallpaper if not
specified -->
<string name="default_wallpaper_component" translatable="false">@null</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d91bbd0..123deeb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -786,6 +786,7 @@
<java-symbol type="string" name="widget_default_class_name" />
<java-symbol type="string" name="emergency_calls_only" />
<java-symbol type="array" name="config_ephemeralResolverPackage" />
+ <java-symbol type="array" name="config_forceQueryablePackages" />
<java-symbol type="string" name="eventTypeAnniversary" />
<java-symbol type="string" name="eventTypeBirthday" />
<java-symbol type="string" name="eventTypeCustom" />
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index adaae5c..682416c 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -132,6 +132,8 @@
public void sendGesture(int sequence, ParceledListSlice gestureSteps) {}
+ public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {}
+
public boolean isFingerprintGestureDetectionAvailable() {
return false;
}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
index 008085e..a935737 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
@@ -68,12 +68,7 @@
private WakeLockInfo createWakeLockInfo(String name, int activeCount, long totalTime) {
WakeLockInfo info = new WakeLockInfo();
info.name = name;
- info.pid = 1;
info.activeCount = activeCount;
- info.isActive = true;
- info.activeSince = 0;
- info.lastChange = 0;
- info.maxTime = 0;
info.totalTime = totalTime;
return info;
}
@@ -89,7 +84,7 @@
byte[] buffer, WakeLockInfo[] wlStats) {
mReader.updateVersion(staleStats);
mReader.parseProcWakelocks(buffer, buffer.length, true, staleStats);
- mReader.getNativeWakelockStats(wlStats, staleStats);
+ mReader.updateWakelockStats(wlStats, staleStats);
return mReader.removeOldStats(staleStats);
}
@@ -101,7 +96,7 @@
mReader = new KernelWakelockReader();
}
-// ------------------------- Kernel Wakelock Stats Test ------------------------
+// ------------------------- Legacy Wakelock Stats Test ------------------------
@SmallTest
public void testParseEmptyFile() throws Exception {
KernelWakelockStats staleStats = mReader.parseProcWakelocks(new byte[0], 0, true,
@@ -196,10 +191,10 @@
assertFalse(staleStats.containsKey("Fakelock"));
}
-// -------------------- Native (SystemSuspend) Wakelock Stats Test -------------------
+// -------------------- SystemSuspend Wakelock Stats Test -------------------
@SmallTest
public void testEmptyWakeLockInfoList() {
- KernelWakelockStats staleStats = mReader.getNativeWakelockStats(new WakeLockInfo[0],
+ KernelWakelockStats staleStats = mReader.updateWakelockStats(new WakeLockInfo[0],
new KernelWakelockStats());
assertTrue(staleStats.isEmpty());
@@ -208,9 +203,9 @@
@SmallTest
public void testOneWakeLockInfo() {
WakeLockInfo[] wlStats = new WakeLockInfo[1];
- wlStats[0] = createWakeLockInfo("WakeLock", 20, 10000);
+ wlStats[0] = createWakeLockInfo("WakeLock", 20, 1000); // Milliseconds
- KernelWakelockStats staleStats = mReader.getNativeWakelockStats(wlStats,
+ KernelWakelockStats staleStats = mReader.updateWakelockStats(wlStats,
new KernelWakelockStats());
assertEquals(1, staleStats.size());
@@ -219,16 +214,16 @@
KernelWakelockStats.Entry entry = staleStats.get("WakeLock");
assertEquals(20, entry.mCount);
- assertEquals(10000, entry.mTotalTime);
+ assertEquals(1000 * 1000, entry.mTotalTime); // Microseconds
}
@SmallTest
public void testTwoWakeLockInfos() {
WakeLockInfo[] wlStats = new WakeLockInfo[2];
- wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000);
- wlStats[1] = createWakeLockInfo("WakeLock2", 20, 2000);
+ wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000); // Milliseconds
+ wlStats[1] = createWakeLockInfo("WakeLock2", 20, 2000); // Milliseconds
- KernelWakelockStats staleStats = mReader.getNativeWakelockStats(wlStats,
+ KernelWakelockStats staleStats = mReader.updateWakelockStats(wlStats,
new KernelWakelockStats());
assertEquals(2, staleStats.size());
@@ -238,17 +233,17 @@
KernelWakelockStats.Entry entry1 = staleStats.get("WakeLock1");
assertEquals(10, entry1.mCount);
- assertEquals(1000, entry1.mTotalTime);
+ assertEquals(1000 * 1000, entry1.mTotalTime); // Microseconds
KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
assertEquals(20, entry2.mCount);
- assertEquals(2000, entry2.mTotalTime);
+ assertEquals(2000 * 1000, entry2.mTotalTime); // Microseconds
}
@SmallTest
public void testWakeLockInfosBecomeStale() {
WakeLockInfo[] wlStats = new WakeLockInfo[1];
- wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000);
+ wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000); // Milliseconds
KernelWakelockStats staleStats = new KernelWakelockStats();
@@ -259,9 +254,9 @@
assertTrue(staleStats.containsKey("WakeLock1"));
KernelWakelockStats.Entry entry = staleStats.get("WakeLock1");
assertEquals(10, entry.mCount);
- assertEquals(1000, entry.mTotalTime);
+ assertEquals(1000 * 1000, entry.mTotalTime); // Microseconds
- wlStats[0] = createWakeLockInfo("WakeLock2", 20, 2000);
+ wlStats[0] = createWakeLockInfo("WakeLock2", 20, 2000); // Milliseconds
readKernelWakelockStats(staleStats, new byte[0], wlStats);
@@ -271,146 +266,6 @@
assertTrue(staleStats.containsKey("WakeLock2"));
entry = staleStats.get("WakeLock2");
assertEquals(20, entry.mCount);
- assertEquals(2000, entry.mTotalTime);
- }
-
-// -------------------- Aggregate Wakelock Stats Tests --------------------
- @SmallTest
- public void testAggregateStatsEmpty() throws Exception {
- KernelWakelockStats staleStats = new KernelWakelockStats();
-
- byte[] buffer = new byte[0];
- WakeLockInfo[] wlStats = new WakeLockInfo[0];
-
- readKernelWakelockStats(staleStats, buffer, wlStats);
-
- assertTrue(staleStats.isEmpty());
- }
-
- @SmallTest
- public void testAggregateStatsNoNativeWakelocks() throws Exception {
- KernelWakelockStats staleStats = new KernelWakelockStats();
-
- byte[] buffer = new ProcFileBuilder()
- .addLine("Wakelock", 34, 123) // Milliseconds
- .getBytes();
- WakeLockInfo[] wlStats = new WakeLockInfo[0];
-
- readKernelWakelockStats(staleStats, buffer, wlStats);
-
- assertEquals(1, staleStats.size());
-
- assertTrue(staleStats.containsKey("Wakelock"));
-
- KernelWakelockStats.Entry entry = staleStats.get("Wakelock");
- assertEquals(34, entry.mCount);
- assertEquals(1000 * 123, entry.mTotalTime); // Microseconds
- }
-
- @SmallTest
- public void testAggregateStatsNoKernelWakelocks() throws Exception {
- KernelWakelockStats staleStats = new KernelWakelockStats();
-
- byte[] buffer = new byte[0];
- WakeLockInfo[] wlStats = new WakeLockInfo[1];
- wlStats[0] = createWakeLockInfo("WakeLock", 10, 1000);
-
- readKernelWakelockStats(staleStats, buffer, wlStats);
-
- assertEquals(1, staleStats.size());
-
- assertTrue(staleStats.containsKey("WakeLock"));
-
- KernelWakelockStats.Entry entry = staleStats.get("WakeLock");
- assertEquals(10, entry.mCount);
- assertEquals(1000, entry.mTotalTime);
- }
-
- @SmallTest
- public void testAggregateStatsBothKernelAndNativeWakelocks() throws Exception {
- KernelWakelockStats staleStats = new KernelWakelockStats();
-
- byte[] buffer = new ProcFileBuilder()
- .addLine("WakeLock1", 34, 123) // Milliseconds
- .getBytes();
- WakeLockInfo[] wlStats = new WakeLockInfo[1];
- wlStats[0] = createWakeLockInfo("WakeLock2", 10, 1000);
-
- readKernelWakelockStats(staleStats, buffer, wlStats);
-
- assertEquals(2, staleStats.size());
-
- assertTrue(staleStats.containsKey("WakeLock1"));
- KernelWakelockStats.Entry entry1 = staleStats.get("WakeLock1");
- assertEquals(34, entry1.mCount);
- assertEquals(123 * 1000, entry1.mTotalTime); // Microseconds
-
- assertTrue(staleStats.containsKey("WakeLock2"));
- KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
- assertEquals(10, entry2.mCount);
- assertEquals(1000, entry2.mTotalTime);
- }
-
- @SmallTest
- public void testAggregateStatsUpdate() throws Exception {
- KernelWakelockStats staleStats = new KernelWakelockStats();
-
- byte[] buffer = new ProcFileBuilder()
- .addLine("WakeLock1", 34, 123) // Milliseconds
- .addLine("WakeLock2", 46, 345) // Milliseconds
- .getBytes();
- WakeLockInfo[] wlStats = new WakeLockInfo[2];
- wlStats[0] = createWakeLockInfo("WakeLock3", 10, 1000);
- wlStats[1] = createWakeLockInfo("WakeLock4", 20, 2000);
-
- readKernelWakelockStats(staleStats, buffer, wlStats);
-
- assertEquals(4, staleStats.size());
-
- assertTrue(staleStats.containsKey("WakeLock1"));
- assertTrue(staleStats.containsKey("WakeLock2"));
- assertTrue(staleStats.containsKey("WakeLock3"));
- assertTrue(staleStats.containsKey("WakeLock4"));
-
- KernelWakelockStats.Entry entry1 = staleStats.get("WakeLock1");
- assertEquals(34, entry1.mCount);
- assertEquals(123 * 1000, entry1.mTotalTime); // Microseconds
-
- KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
- assertEquals(46, entry2.mCount);
- assertEquals(345 * 1000, entry2.mTotalTime); // Microseconds
-
- KernelWakelockStats.Entry entry3 = staleStats.get("WakeLock3");
- assertEquals(10, entry3.mCount);
- assertEquals(1000, entry3.mTotalTime);
-
- KernelWakelockStats.Entry entry4 = staleStats.get("WakeLock4");
- assertEquals(20, entry4.mCount);
- assertEquals(2000, entry4.mTotalTime);
-
- buffer = new ProcFileBuilder()
- .addLine("WakeLock1", 45, 789) // Milliseconds
- .addLine("WakeLock1", 56, 123) // Milliseconds
- .getBytes();
- wlStats = new WakeLockInfo[1];
- wlStats[0] = createWakeLockInfo("WakeLock4", 40, 4000);
-
- readKernelWakelockStats(staleStats, buffer, wlStats);
-
- assertEquals(2, staleStats.size());
-
- assertTrue(staleStats.containsKey("WakeLock1"));
- assertTrue(staleStats.containsKey("WakeLock4"));
-
- assertFalse(staleStats.containsKey("WakeLock2"));
- assertFalse(staleStats.containsKey("WakeLock3"));
-
- entry1 = staleStats.get("WakeLock1");
- assertEquals(45 + 56, entry1.mCount);
- assertEquals((789 + 123) * 1000, entry1.mTotalTime); // Microseconds
-
- entry2 = staleStats.get("WakeLock4");
- assertEquals(40, entry2.mCount);
- assertEquals(4000, entry4.mTotalTime);
+ assertEquals(2000 * 1000, entry.mTotalTime); // Micro seconds
}
}
diff --git a/packages/SystemUI/plugin/ExamplePlugin/Android.bp b/packages/SystemUI/plugin/ExamplePlugin/Android.bp
index a0eaf14..c6c80f3 100644
--- a/packages/SystemUI/plugin/ExamplePlugin/Android.bp
+++ b/packages/SystemUI/plugin/ExamplePlugin/Android.bp
@@ -11,4 +11,5 @@
srcs: ["src/**/*.java"],
+ platform_apis: true,
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index cc7863c..2a890fe 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -80,6 +80,8 @@
public static final int SYSUI_STATE_HOME_DISABLED = 1 << 8;
// The keyguard is showing, but occluded
public static final int SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED = 1 << 9;
+ // The search feature is disabled (either by SUW/SysUI/device policy)
+ public static final int SYSUI_STATE_SEARCH_DISABLED = 1 << 10;
@Retention(RetentionPolicy.SOURCE)
@IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -91,7 +93,8 @@
SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
SYSUI_STATE_OVERVIEW_DISABLED,
- SYSUI_STATE_HOME_DISABLED
+ SYSUI_STATE_HOME_DISABLED,
+ SYSUI_STATE_SEARCH_DISABLED
})
public @interface SystemUiStateFlags {}
@@ -100,6 +103,7 @@
str.add((flags & SYSUI_STATE_SCREEN_PINNING) != 0 ? "screen_pinned" : "");
str.add((flags & SYSUI_STATE_OVERVIEW_DISABLED) != 0 ? "overview_disabled" : "");
str.add((flags & SYSUI_STATE_HOME_DISABLED) != 0 ? "home_disabled" : "");
+ str.add((flags & SYSUI_STATE_SEARCH_DISABLED) != 0 ? "search_disabled" : "");
str.add((flags & SYSUI_STATE_NAV_BAR_HIDDEN) != 0 ? "navbar_hidden" : "");
str.add((flags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0 ? "notif_visible" : "");
str.add((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING) != 0 ? "keygrd_visible" : "");
@@ -150,10 +154,11 @@
* disabled.
*/
public static boolean isAssistantGestureDisabled(int sysuiStateFlags) {
- // Disable when in screen pinning, immersive, the bouncer is showing
+ // Disable when in screen pinning, immersive, the bouncer is showing, or search is disabled
int disableFlags = SYSUI_STATE_SCREEN_PINNING
| SYSUI_STATE_NAV_BAR_HIDDEN
- | SYSUI_STATE_BOUNCER_SHOWING;
+ | SYSUI_STATE_BOUNCER_SHOWING
+ | SYSUI_STATE_SEARCH_DISABLED;
if ((sysuiStateFlags & disableFlags) != 0) {
return true;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java
deleted file mode 100644
index a529903..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.systemui.shared.system;
-
-import android.app.ActivityManager;
-import android.content.ComponentName;
-
-public class RecentTaskInfoCompat {
-
- private ActivityManager.RecentTaskInfo mInfo;
-
- public RecentTaskInfoCompat(ActivityManager.RecentTaskInfo info) {
- mInfo = info;
- }
-
- public int getUserId() {
- return mInfo.userId;
- }
-
- public boolean supportsSplitScreenMultiWindow() {
- return mInfo.supportsSplitScreenMultiWindow;
- }
-
- public ComponentName getTopActivity() {
- return mInfo.topActivity;
- }
-
- public ActivityManager.TaskDescription getTaskDescription() {
- return mInfo.taskDescription;
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index d2fe5cd..2ef0422 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -91,6 +91,7 @@
}
}
+ @Deprecated
public void setCancelWithDeferredScreenshot(boolean screenshot) {
try {
mAnimationController.setCancelWithDeferredScreenshot(screenshot);
@@ -99,6 +100,14 @@
}
}
+ public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
+ try {
+ mAnimationController.setDeferCancelUntilNextTransition(defer, screenshot);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to set deferred cancel with screenshot", e);
+ }
+ }
+
public void cleanupScreenshot() {
try {
mAnimationController.cleanupScreenshot();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java
new file mode 100644
index 0000000..326c2aa
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java
@@ -0,0 +1,48 @@
+/*
+ * 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.systemui.shared.system;
+
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.content.ComponentName;
+
+public class TaskInfoCompat {
+
+ public static int getUserId(TaskInfo info) {
+ return info.userId;
+ }
+
+ public static int getActivityType(TaskInfo info) {
+ return info.configuration.windowConfiguration.getActivityType();
+ }
+
+ public static int getWindowingMode(TaskInfo info) {
+ return info.configuration.windowConfiguration.getWindowingMode();
+ }
+
+ public static boolean supportsSplitScreenMultiWindow(TaskInfo info) {
+ return info.supportsSplitScreenMultiWindow;
+ }
+
+ public static ComponentName getTopActivity(TaskInfo info) {
+ return info.topActivity;
+ }
+
+ public static ActivityManager.TaskDescription getTaskDescription(TaskInfo info) {
+ return info.taskDescription;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 4ad262f..8059dcf 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -269,7 +269,7 @@
*/
private void updateBiometricRetry() {
SecurityMode securityMode = getSecurityMode();
- mSwipeUpToRetry = mUnlockMethodCache.isUnlockingWithFacePossible()
+ mSwipeUpToRetry = mUnlockMethodCache.isFaceAuthEnabled()
&& securityMode != SecurityMode.SimPin
&& securityMode != SecurityMode.SimPuk
&& securityMode != SecurityMode.None;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index fd618b0..4e7b157 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1783,13 +1783,15 @@
&& mFpm.getEnrolledFingerprints(userId).size() > 0;
}
+ private boolean isUnlockWithFacePossible(int userId) {
+ return isFaceAuthEnabledForUser(userId) && !isFaceDisabled(userId);
+ }
+
/**
* If face hardware is available, user has enrolled and enabled auth via setting.
- * Not considering encryption or lock down state.
*/
- public boolean isUnlockWithFacePossible(int userId) {
+ public boolean isFaceAuthEnabledForUser(int userId) {
return mFaceManager != null && mFaceManager.isHardwareDetected()
- && !isFaceDisabled(userId)
&& mFaceManager.hasEnrolledTemplates(userId)
&& mFaceSettingEnabledForUser.get(userId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index a5857df..ce67577 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -111,6 +111,9 @@
protected boolean mRequireConfirmation;
private int mUserId; // used to determine if we should show work background
+ private boolean mCompletedAnimatingIn;
+ private boolean mPendingDismissDialog;
+
protected abstract int getHintStringResourceId();
protected abstract int getAuthenticatedAccessibilityResourceId();
protected abstract int getIconDescriptionResourceId();
@@ -332,6 +335,7 @@
mDialog.setAlpha(1.0f);
mDialog.setTranslationY(0);
mLayout.setAlpha(1.0f);
+ mCompletedAnimatingIn = true;
} else {
// Dim the background and slide the dialog up
mDialog.setTranslationY(mAnimationTranslationOffset);
@@ -352,6 +356,12 @@
}
public void startDismiss() {
+ if (!mCompletedAnimatingIn) {
+ Log.w(TAG, "startDismiss(): waiting for onDialogAnimatedIn");
+ mPendingDismissDialog = true;
+ return;
+ }
+
mAnimatingAway = true;
// This is where final cleanup should occur.
@@ -499,6 +509,13 @@
}
public void onDialogAnimatedIn() {
+ mCompletedAnimatingIn = true;
+
+ if (mPendingDismissDialog) {
+ Log.d(TAG, "onDialogAnimatedIn(): mPendingDismissDialog=true, dismissing now");
+ startDismiss();
+ mPendingDismissDialog = false;
+ }
}
public void restoreState(Bundle bundle) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
index 729242e..ae6cb5c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
@@ -460,6 +460,7 @@
@Override
public void onDialogAnimatedIn() {
+ super.onDialogAnimatedIn();
mDialogAnimatedIn = true;
mIconController.startPulsing();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index cee01a4..41f20ec 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -105,10 +105,12 @@
}
private void sessionStart() {
- logDebug("Starting Session");
- mSessionStarted = true;
- registerSensors();
- mClassifiers.forEach(FalsingClassifier::onSessionStarted);
+ if (!mSessionStarted) {
+ logDebug("Starting Session");
+ mSessionStarted = true;
+ registerSensors();
+ mClassifiers.forEach(FalsingClassifier::onSessionStarted);
+ }
}
private void sessionEnd() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index a9896f5..822a666 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -22,6 +22,8 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
+import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -48,6 +50,7 @@
import java.io.File;
import java.io.IOException;
+import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
@@ -158,19 +161,34 @@
case ACTION_STOP:
stopRecording();
- // Move temp file to user directory
- File recordDir = new File(
- Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES),
- RECORD_DIR);
- recordDir.mkdirs();
-
String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'")
.format(new Date());
- Path path = new File(recordDir, fileName).toPath();
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);
+ values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
+ values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis());
+ values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
+
+ ContentResolver resolver = getContentResolver();
+ Uri collectionUri = MediaStore.Video.Media.getContentUri(
+ MediaStore.VOLUME_EXTERNAL_PRIMARY);
+ Uri itemUri = resolver.insert(collectionUri, values);
+
+ File recordDir = new File(getExternalFilesDir(Environment.DIRECTORY_MOVIES),
+ RECORD_DIR);
+ recordDir.mkdirs();
+ Path path = new File(recordDir, fileName).toPath();
try {
+ // Move file out of temp directory
Files.move(mTempFile.toPath(), path);
- Notification notification = createSaveNotification(path);
+
+ // Add to the mediastore
+ OutputStream os = resolver.openOutputStream(itemUri, "w");
+ Files.copy(path, os);
+ os.close();
+
+ Notification notification = createSaveNotification(itemUri, path);
notificationManager.notify(NOTIFICATION_ID, notification);
} catch (IOException e) {
e.printStackTrace();
@@ -352,13 +370,12 @@
notificationManager.notify(NOTIFICATION_ID, mRecordingNotificationBuilder.build());
}
- private Notification createSaveNotification(Path path) {
- Uri saveUri = FileProvider.getUriForFile(this, FILE_PROVIDER, path.toFile());
- Log.d(TAG, "Screen recording saved to " + path.toString());
+ private Notification createSaveNotification(Uri uri, Path path) {
+ Log.d(TAG, "Screen recording saved to " + uri.toString() + ", " + path.toString());
Intent viewIntent = new Intent(Intent.ACTION_VIEW)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION)
- .setDataAndType(saveUri, "video/mp4");
+ .setDataAndType(uri, "video/mp4");
Notification.Action shareAction = new Notification.Action.Builder(
Icon.createWithResource(this, R.drawable.ic_android),
@@ -366,7 +383,7 @@
PendingIntent.getService(
this,
REQUEST_CODE,
- getShareIntent(this, path.toString()),
+ getShareIntent(this, uri.toString()),
PendingIntent.FLAG_UPDATE_CURRENT))
.build();
@@ -376,7 +393,7 @@
PendingIntent.getService(
this,
REQUEST_CODE,
- getDeleteIntent(this, path.toString()),
+ getDeleteIntent(this, uri.toString()),
PendingIntent.FLAG_UPDATE_CURRENT))
.build();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 0fe5f8a..4cc5b21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -15,7 +15,6 @@
package com.android.systemui.statusbar;
import android.content.pm.UserInfo;
-import android.service.notification.StatusBarNotification;
import android.util.SparseArray;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -58,7 +57,7 @@
boolean shouldHideNotifications(int userId);
boolean shouldHideNotifications(String key);
- boolean shouldShowOnKeyguard(StatusBarNotification sbn);
+ boolean shouldShowOnKeyguard(NotificationEntry entry);
boolean isAnyProfilePublicMode();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 4ea1ed5..e08a5ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -33,7 +33,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -302,7 +301,7 @@
Notification.VISIBILITY_SECRET;
}
- public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
+ public boolean shouldShowOnKeyguard(NotificationEntry entry) {
if (getEntryManager() == null) {
Log.wtf(TAG, "mEntryManager was null!", new Throwable());
return false;
@@ -310,10 +309,10 @@
boolean exceedsPriorityThreshold;
if (NotificationUtils.useNewInterruptionModel(mContext)
&& hideSilentNotificationsOnLockscreen()) {
- exceedsPriorityThreshold = getEntryManager().getNotificationData().isHighPriority(sbn);
+ exceedsPriorityThreshold = entry.isTopBucket();
} else {
exceedsPriorityThreshold =
- !getEntryManager().getNotificationData().isAmbient(sbn.getKey());
+ !getEntryManager().getNotificationData().isAmbient(entry.key);
}
return mShowLockscreenNotifications && exceedsPriorityThreshold;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 22c9164..6e75c03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -397,15 +397,13 @@
int userId = entry.notification.getUserId();
boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
entry.notification) && !entry.isRowRemoved();
- boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry
- .notification);
+ boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry);
if (!showOnKeyguard) {
// min priority notifications should show if their summary is showing
if (mGroupManager.isChildInGroupWithSummary(entry.notification)) {
NotificationEntry summary = mGroupManager.getLogicalGroupSummary(
entry.notification);
- if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(
- summary.notification)) {
+ if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(summary)) {
showOnKeyguard = true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
index ea474ce..fbaefde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
@@ -63,7 +63,7 @@
enabled = Settings.Secure.getIntForUser(
context.contentResolver,
Settings.Secure.SHOW_MEDIA_WHEN_BYPASSING,
- 1 /* default */,
+ 0 /* default */,
KeyguardUpdateMonitor.getCurrentUser()) != 0
}, Settings.Secure.SHOW_MEDIA_WHEN_BYPASSING)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index f7e5bcf..6af1f5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -29,6 +29,7 @@
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.NotificationIconAreaController
+import com.android.systemui.statusbar.phone.PanelExpansionListener
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
import javax.inject.Inject
@@ -40,7 +41,8 @@
private val mHeadsUpManagerPhone: HeadsUpManagerPhone,
private val statusBarStateController: StatusBarStateController,
private val bypassController: KeyguardBypassController)
- : OnHeadsUpChangedListener, StatusBarStateController.StateListener {
+ : OnHeadsUpChangedListener, StatusBarStateController.StateListener,
+ PanelExpansionListener {
private val mNotificationVisibility
= object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") {
@@ -98,7 +100,9 @@
}
}
+ private var collapsedEnoughToHide: Boolean = false
lateinit var iconAreaController : NotificationIconAreaController
+
var pulsing: Boolean = false
set(value) {
field = value
@@ -120,7 +124,6 @@
}
}
}
-
/**
* True if we can show pulsing heads up notifications
*/
@@ -132,6 +135,10 @@
// We also allow pulsing on the lock screen!
canShow = canShow || (wakingUp || willWakeUp || fullyAwake)
&& statusBarStateController.state == StatusBarState.KEYGUARD
+ // We want to hide the notifications when collapsed too much
+ if (collapsedEnoughToHide) {
+ canShow = false
+ }
}
return canShow
}
@@ -247,6 +254,18 @@
this.state = newState
}
+ override fun onPanelExpansionChanged(expansion: Float, tracking: Boolean) {
+ val collapsedEnough = expansion <= 0.9f
+ if (collapsedEnough != this.collapsedEnoughToHide) {
+ val couldShowPulsingHuns = canShowPulsingHuns;
+ this.collapsedEnoughToHide = collapsedEnough
+ if (couldShowPulsingHuns && !canShowPulsingHuns) {
+ updateNotificationVisibility(animate = true, increaseSpeed = true)
+ mHeadsUpManagerPhone.releaseAllImmediately()
+ }
+ }
+ }
+
private fun updateDozeAmountIfBypass(): Boolean {
if (bypassController.bypassEnabled) {
var amount = 1.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index fca520f..1ce4934 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -25,7 +25,6 @@
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
-import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
@@ -108,10 +107,19 @@
boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH
&& isSystemNotification(nb);
- boolean isHeadsUp = a.getRow().isHeadsUp();
- if (isHeadsUp != b.getRow().isHeadsUp()) {
- return isHeadsUp ? -1 : 1;
- } else if (isHeadsUp) {
+
+ boolean aHeadsUp = a.getRow().isHeadsUp();
+ boolean bHeadsUp = b.getRow().isHeadsUp();
+
+ // HACK: This should really go elsewhere, but it's currently not straightforward to
+ // extract the comparison code and we're guaranteed to touch every element, so this is
+ // the best place to set the buckets for the moment.
+ a.setIsTopBucket(aHeadsUp || aMedia || aSystemMax || a.isHighPriority());
+ b.setIsTopBucket(bHeadsUp || bMedia || bSystemMax || b.isHighPriority());
+
+ if (aHeadsUp != bHeadsUp) {
+ return aHeadsUp ? -1 : 1;
+ } else if (aHeadsUp) {
// Provide consistent ranking with headsUpManager
return mHeadsUpManager.compare(a, b);
} else if (aMedia != bMedia) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index b19d2ca..d718570 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -173,6 +173,9 @@
* the lock screen/status bar and in the top section in the shade.
*/
private boolean mHighPriority;
+
+ private boolean mIsTopBucket;
+
private boolean mSensitive = true;
private Runnable mOnSensitiveChangedListener;
private boolean mAutoHeadsUp;
@@ -224,6 +227,18 @@
this.mHighPriority = highPriority;
}
+ /**
+ * @return True if the notif should appear in the "top" or "important" section of notifications
+ * (as opposed to the "bottom" or "silent" section). This is usually the same as
+ * {@link #isHighPriority()}, but there are certain exceptions, such as media notifs.
+ */
+ public boolean isTopBucket() {
+ return mIsTopBucket;
+ }
+ public void setIsTopBucket(boolean isTopBucket) {
+ mIsTopBucket = isTopBucket;
+ }
+
public boolean isBubble() {
return (notification.getNotification().flags & FLAG_BUBBLE) != 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index d057a1d..48a8295 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -349,7 +349,7 @@
}
if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
- result.newPublicView = builder.makePublicContentView();
+ result.newPublicView = builder.makePublicContentView(isLowPriority);
}
result.packageContext = packageContext;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 212808d..15cc72c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -184,4 +184,6 @@
default boolean containsView(View v) {
return true;
}
+
+ default void setWillExpand(boolean willExpand) {};
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 170a4d5..d119fb79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -133,7 +133,7 @@
if (child instanceof ExpandableNotificationRow
&& child.getVisibility() != View.GONE) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- if (!row.getEntry().isHighPriority()) {
+ if (!row.getEntry().isTopBucket()) {
firstGentleNotifIndex = i;
mFirstGentleNotif = row;
break;
@@ -248,7 +248,7 @@
View child = mParent.getChildAt(i);
if (child.getVisibility() != View.GONE && child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- if (!row.getEntry().isHighPriority()) {
+ if (!row.getEntry().isTopBucket()) {
break;
} else {
lastChildBeforeGap = row;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 04cbb13..18a51b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -499,6 +499,7 @@
private boolean mAnimateBottomOnLayout;
private float mLastSentAppear;
private float mLastSentExpandedHeight;
+ private boolean mWillExpand;
@Inject
public NotificationStackScrollLayout(
@@ -4406,6 +4407,7 @@
mStateAnimator.setShadeExpanded(isExpanded);
mSwipeHelper.setIsExpanded(isExpanded);
if (changed) {
+ mWillExpand = false;
if (!mIsExpanded) {
mGroupManager.collapseAllGroups();
mExpandHelper.cancelImmediately();
@@ -5054,7 +5056,7 @@
if (mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed)) {
mHeadsUpChangeAnimations.add(new Pair<>(row, isHeadsUp));
mNeedsAnimation = true;
- if (!mIsExpanded && !isHeadsUp) {
+ if (!mIsExpanded && !mWillExpand && !isHeadsUp) {
row.setHeadsUpAnimatingAway(true);
}
requestChildrenUpdate();
@@ -5075,6 +5077,11 @@
requestChildrenUpdate();
}
+ @Override
+ public void setWillExpand(boolean willExpand) {
+ mWillExpand = willExpand;
+ }
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setTrackingHeadsUp(ExpandableNotificationRow row) {
mTrackingHeadsUp = row != null;
@@ -5675,6 +5682,8 @@
// The bottom might change because we're using the final actual height of the view
mAnimateBottomOnLayout = true;
}
+ // Let's update the footer once the notifications have been updated (in the next frame)
+ post(this::updateFooter);
}
public void setOnPulseHeightChangedListener(Runnable listener) {
@@ -5745,7 +5754,7 @@
currentIndex++;
boolean beforeSpeedBump;
if (mHighPriorityBeforeSpeedBump) {
- beforeSpeedBump = row.getEntry().isHighPriority();
+ beforeSpeedBump = row.getEntry().isTopBucket();
} else {
beforeSpeedBump = !row.getEntry().ambient;
}
@@ -5803,9 +5812,9 @@
case ROWS_ALL:
return true;
case ROWS_HIGH_PRIORITY:
- return row.getEntry().isHighPriority();
+ return row.getEntry().isTopBucket();
case ROWS_GENTLE:
- return !row.getEntry().isHighPriority();
+ return !row.getEntry().isTopBucket();
default:
throw new IllegalArgumentException("Unknown selection: " + selection);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index d6f8a60..40085a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -170,7 +170,7 @@
// Split up the work over multiple frames.
DejankUtils.removeCallbacks(mResetRunnable);
- if (mUnlockMethodCache.isUnlockingWithFacePossible() && !needsFullscreenBouncer()
+ if (mUnlockMethodCache.isFaceAuthEnabled() && !needsFullscreenBouncer()
&& !mKeyguardUpdateMonitor.userNeedsStrongAuth()) {
mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
} else {
@@ -349,7 +349,7 @@
* {@link #show(boolean)} was called but we're not showing yet, or being dragged.
*/
public boolean inTransit() {
- return mShowingSoon || mExpansion != EXPANSION_HIDDEN;
+ return mShowingSoon || mExpansion != EXPANSION_HIDDEN && mExpansion != EXPANSION_VISIBLE;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 0aec2b1..70d3bff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -47,7 +47,7 @@
* If face unlock dismisses the lock screen or keeps user on keyguard for the current user.
*/
var bypassEnabled: Boolean = false
- get() = field && unlockMethodCache.isUnlockingWithFacePossible
+ get() = field && unlockMethodCache.isFaceAuthEnabled
private set
var bouncerShowing: Boolean = false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index b13af8b..c9c80d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -323,14 +323,24 @@
}
updateDarkTint();
+ updateIconVisibility();
+ updateClickability();
+
+ return true;
+ }
+
+ /**
+ * Update the icon visibility
+ * @return true if the visibility changed
+ */
+ private boolean updateIconVisibility() {
boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
|| mShowingLaunchAffordance;
if (mBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
- if (mHeadsUpManager.isHeadsUpGoingAway()
- || mHeadsUpManager.hasPinnedHeadsUp()
- || (mStatusBarStateController.getState() == StatusBarState.KEYGUARD
- && !mWakeUpCoordinator.getNotificationsFullyHidden())) {
+ if ((mHeadsUpManager.isHeadsUpGoingAway() || mHeadsUpManager.hasPinnedHeadsUp())
+ && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
+ && !mWakeUpCoordinator.getNotificationsFullyHidden()) {
invisible = true;
}
}
@@ -349,10 +359,9 @@
.setDuration(233)
.start();
}
+ return true;
}
- updateClickability();
-
- return true;
+ return false;
}
private boolean canBlockUpdates() {
@@ -440,7 +449,10 @@
@Override
public void onFullyHiddenChanged(boolean isFullyHidden) {
if (mBypassController.getBypassEnabled()) {
- update();
+ boolean changed = updateIconVisibility();
+ if (changed) {
+ update();
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 22e3edb..9296f7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -22,6 +22,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SEARCH_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.isGesturalMode;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
@@ -719,6 +720,8 @@
(mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0, displayId);
mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_HOME_DISABLED,
(mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0, displayId);
+ mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SEARCH_DISABLED,
+ (mDisabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0, displayId);
if (mPanelView != null) {
mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
mPanelView.isFullyExpanded() && !mPanelView.isInSettings(), displayId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 901afab..670deef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -808,8 +808,7 @@
if (suppressedSummary) {
continue;
}
- if (!mLockscreenUserManager.shouldShowOnKeyguard(
- row.getStatusBarNotification())) {
+ if (!mLockscreenUserManager.shouldShowOnKeyguard(row.getEntry())) {
continue;
}
if (row.isRemoved()) {
@@ -1283,6 +1282,7 @@
}
mExpectingSynthesizedDown = true;
onTrackingStarted();
+ updatePanelExpanded();
}
/**
@@ -1722,8 +1722,8 @@
mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
}
- if (mExpansionListener != null) {
- mExpansionListener.onQsExpansionChanged(mQsMaxExpansionHeight != 0
+ for (int i = 0; i < mExpansionListeners.size(); i++) {
+ mExpansionListeners.get(i).onQsExpansionChanged(mQsMaxExpansionHeight != 0
? mQsExpansionHeight / mQsMaxExpansionHeight : 0);
}
if (DEBUG) {
@@ -2034,7 +2034,7 @@
}
private void updatePanelExpanded() {
- boolean isExpanded = !isFullyCollapsed();
+ boolean isExpanded = !isFullyCollapsed() || mExpectingSynthesizedDown;
if (mPanelExpanded != isExpanded) {
mHeadsUpManager.setIsPanelExpanded(isExpanded);
mStatusBar.setPanelExpanded(isExpanded);
@@ -3379,24 +3379,4 @@
mOnReinflationListener = onReinflationListener;
}
- /**
- * Panel and QS expansion callbacks.
- */
- public interface PanelExpansionListener {
- /**
- * Invoked whenever the notification panel expansion changes, at every animation frame.
- * This is the main expansion that happens when the user is swiping up to dismiss the
- * lock screen.
- *
- * @param expansion 0 when collapsed, 1 when expanded.
- * @param tracking {@code true} when the user is actively dragging the panel.
- */
- void onPanelExpansionChanged(float expansion, boolean tracking);
-
- /**
- * Invoked whenever the QS expansion changes, at every animation frame.
- * @param expansion 0 when collapsed, 1 when expanded.
- */
- void onQsExpansionChanged(float expansion);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java
new file mode 100644
index 0000000..655a25d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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.systemui.statusbar.phone;
+
+/**
+ * Panel and QS expansion callbacks.
+ */
+public interface PanelExpansionListener {
+ /**
+ * Invoked whenever the notification panel expansion changes, at every animation frame.
+ * This is the main expansion that happens when the user is swiping up to dismiss the
+ * lock screen.
+ *
+ * @param expansion 0 when collapsed, 1 when expanded.
+ * @param tracking {@code true} when the user is actively dragging the panel.
+ */
+ void onPanelExpansionChanged(float expansion, boolean tracking);
+
+ /**
+ * Invoked whenever the QS expansion changes, at every animation frame.
+ * @param expansion 0 when collapsed, 1 when expanded.
+ */
+ default void onQsExpansionChanged(float expansion) {};
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 853faab..727f72b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -49,11 +49,11 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.phone.NotificationPanelView.PanelExpansionListener;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
public abstract class PanelView extends FrameLayout {
public static final boolean DEBUG = PanelBar.DEBUG;
@@ -68,7 +68,7 @@
private boolean mVibrateOnOpening;
protected boolean mLaunchingNotification;
private int mFixedDuration = NO_FIXED_DURATION;
- protected PanelExpansionListener mExpansionListener;
+ protected ArrayList<PanelExpansionListener> mExpansionListeners = new ArrayList<>();
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -1173,13 +1173,13 @@
|| mPeekAnimator != null || mInstantExpanding
|| isPanelVisibleBecauseOfHeadsUp() || mTracking || mHeightAnimator != null);
}
- if (mExpansionListener != null) {
- mExpansionListener.onPanelExpansionChanged(mExpandedFraction, mTracking);
+ for (int i = 0; i < mExpansionListeners.size(); i++) {
+ mExpansionListeners.get(i).onPanelExpansionChanged(mExpandedFraction, mTracking);
}
}
- public void setExpansionListener(PanelExpansionListener panelExpansionListener) {
- mExpansionListener = panelExpansionListener;
+ public void addExpansionListener(PanelExpansionListener panelExpansionListener) {
+ mExpansionListeners.add(panelExpansionListener);
}
protected abstract boolean isPanelVisibleBecauseOfHeadsUp();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 1aec5e4..b12bf5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -491,8 +491,10 @@
* away once the display turns on.
*/
public void prepareForGentleWakeUp() {
- if (mState == ScrimState.AOD && mDozeParameters.getAlwaysOn()) {
+ if (mState == ScrimState.AOD) {
mCurrentInFrontAlpha = 1f;
+ mCurrentInFrontTint = Color.BLACK;
+ mCurrentBehindTint = Color.BLACK;
mAnimateChange = false;
updateScrims();
mAnimateChange = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 763e0d7..c706062 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -129,7 +129,10 @@
public void prepare(ScrimState previousState) {
mCurrentInFrontAlpha = 0f;
mCurrentBehindTint = Color.BLACK;
+ mCurrentInFrontTint = Color.BLACK;
mBlankScreen = mDisplayRequiresBlanking;
+ mAnimationDuration = mWakeLockScreenSensorActive
+ ? ScrimController.ANIMATION_DURATION_LONG : ScrimController.ANIMATION_DURATION;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 9f1ec4d..881fb9d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -813,6 +813,7 @@
inflateShelf();
mNotificationIconAreaController.setupShelf(mNotificationShelf);
mNotificationPanel.setOnReinflationListener(mNotificationIconAreaController::initAodIcons);
+ mNotificationPanel.addExpansionListener(mWakeUpCoordinator);
Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
// Allow plugins to reference DarkIconDispatcher and StatusBarStateController
@@ -1802,6 +1803,8 @@
mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
}
mNotificationPanel.expand(true /* animate */);
+ ((NotificationListContainer) mStackScroller).setWillExpand(true);
+ mHeadsUpManager.unpinAll(true /* userUnpinned */);
mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
} else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){
mNotificationPanel.flingSettings(0 /* velocity */,
@@ -1939,7 +1942,6 @@
if (start) {
mNotificationPanel.startWaitingForOpenPanelGesture();
- setPanelExpanded(true);
} else {
mNotificationPanel.stopWaitingForOpenPanelGesture(velocity);
}
@@ -2388,6 +2390,10 @@
mLightBarController.dump(fd, pw, args);
}
+ if (mUnlockMethodCache != null) {
+ mUnlockMethodCache.dump(pw);
+ }
+
if (mKeyguardBypassController != null) {
mKeyguardBypassController.dump(pw);
}
@@ -3563,6 +3569,9 @@
userAllowsPrivateNotificationsInPublic(mLockscreenUserManager.getCurrentUserId())
|| !mLockscreenUserManager.shouldShowLockscreenNotifications()
|| mFalsingManager.shouldEnforceBouncer();
+ if (mKeyguardBypassController.getBypassEnabled()) {
+ fullShadeNeedsBouncer = false;
+ }
if (mLockscreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
showBouncerIfKeyguard();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 5ce1329..197c09d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -70,7 +70,7 @@
*/
public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
- NotificationPanelView.PanelExpansionListener, NavigationModeController.ModeChangedListener {
+ PanelExpansionListener, NavigationModeController.ModeChangedListener {
// When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
@@ -223,7 +223,7 @@
mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry,
mExpansionCallback, falsingManager);
mNotificationPanelView = notificationPanelView;
- notificationPanelView.setExpansionListener(this);
+ notificationPanelView.addExpansionListener(this);
mBypassController = bypassController;
mNotificationContainer = notificationContainer;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index f1049f0..33b863f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -418,7 +418,7 @@
if (mNotificationPanel.isFullyExpanded()
&& mStatusBarStateController.getState() == StatusBarState.KEYGUARD
&& !mService.isBouncerShowing()
- && !mBypassController.getBypassEnabled()
+ && (!mBypassController.getBypassEnabled() || mNotificationPanel.isQsExpanded())
&& !mService.isDozing()) {
intercept = mDragDownHelper.onInterceptTouchEvent(ev);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index a71fcdb..b1d6ca6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -28,6 +28,7 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import java.io.PrintWriter;
import java.util.ArrayList;
/**
@@ -51,7 +52,7 @@
private boolean mTrustManaged;
private boolean mTrusted;
private boolean mDebugUnlocked = false;
- private boolean mIsUnlockingWithFacePossible;
+ private boolean mFaceAuthEnabled;
private UnlockMethodCache(Context ctx) {
mLockPatternUtils = new LockPatternUtils(ctx);
@@ -110,8 +111,8 @@
/**
* If there are faces enrolled and user enabled face auth on keyguard.
*/
- public boolean isUnlockingWithFacePossible() {
- return mIsUnlockingWithFacePossible;
+ public boolean isFaceAuthEnabled() {
+ return mFaceAuthEnabled;
}
private void update(boolean updateAlways) {
@@ -122,16 +123,16 @@
|| (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB && mDebugUnlocked);
boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user);
- boolean isUnlockingWithFacePossible = mKeyguardUpdateMonitor.isUnlockWithFacePossible(user);
+ boolean faceAuthEnabled = mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(user);
boolean changed = secure != mSecure || canSkipBouncer != mCanSkipBouncer
|| trustManaged != mTrustManaged
- || mIsUnlockingWithFacePossible != isUnlockingWithFacePossible;
+ || mFaceAuthEnabled != faceAuthEnabled;
if (changed || updateAlways) {
mSecure = secure;
mCanSkipBouncer = canSkipBouncer;
mTrusted = trusted;
mTrustManaged = trustManaged;
- mIsUnlockingWithFacePossible = isUnlockingWithFacePossible;
+ mFaceAuthEnabled = faceAuthEnabled;
notifyListeners();
}
Trace.endSection();
@@ -143,6 +144,16 @@
}
}
+ public void dump(PrintWriter pw) {
+ pw.println("UnlockMethodCache");
+ pw.println(" mSecure: " + mSecure);
+ pw.println(" mCanSkipBouncer: " + mCanSkipBouncer);
+ pw.println(" mTrustManaged: " + mTrustManaged);
+ pw.println(" mTrusted: " + mTrusted);
+ pw.println(" mDebugUnlocked: " + mDebugUnlocked);
+ pw.println(" mFaceAuthEnabled: " + mFaceAuthEnabled);
+ }
+
private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onUserSwitchComplete(int userId) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 49a263a..57dd8c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -38,7 +38,6 @@
import android.os.Looper;
import android.os.UserManager;
import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -48,6 +47,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -166,7 +166,7 @@
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1);
when(mNotificationData.isHighPriority(any())).thenReturn(false);
- assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(mock(StatusBarNotification.class)));
+ assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(mock(NotificationEntry.class)));
}
@Test
@@ -179,7 +179,7 @@
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0);
when(mNotificationData.isHighPriority(any())).thenReturn(false);
- assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(mock(StatusBarNotification.class)));
+ assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(mock(NotificationEntry.class)));
}
private class TestNotificationLockscreenUserManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 73abda9..59d0f91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -263,6 +263,8 @@
when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
when(notifRow.getEntry().isHighPriority())
.thenReturn(children[i] == ChildType.HIPRI);
+ when(notifRow.getEntry().isTopBucket())
+ .thenReturn(children[i] == ChildType.HIPRI);
when(notifRow.getParent()).thenReturn(mNssl);
child = notifRow;
break;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 7d9920d..4a41349 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -82,7 +82,7 @@
MockitoAnnotations.initMocks(this);
when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
- when(mUnlockMethodCache.isUnlockingWithFacePossible()).thenReturn(true);
+ when(mUnlockMethodCache.isFaceAuthEnabled()).thenReturn(true);
when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
when(mKeyguardBypassController.canPlaySubtleWindowAnimations()).thenReturn(true);
mContext.addMockSystemService(PowerManager.class, mPowerManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 4e0ef56..907e695 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -379,7 +379,7 @@
@Test
public void testShow_delaysIfFaceAuthIsRunning() {
- when(mUnlockMethodCache.isUnlockingWithFacePossible()).thenReturn(true);
+ when(mUnlockMethodCache.isFaceAuthEnabled()).thenReturn(true);
mBouncer.show(true /* reset */);
ArgumentCaptor<Runnable> showRunnable = ArgumentCaptor.forClass(Runnable.class);
@@ -394,4 +394,15 @@
public void testRegisterUpdateMonitorCallback() {
verify(mKeyguardUpdateMonitor).registerCallback(any());
}
+
+ @Test
+ public void testInTransit_whenTranslation() {
+ mBouncer.show(true);
+ mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
+ assertThat(mBouncer.inTransit()).isFalse();
+ mBouncer.setExpansion(0.5f);
+ assertThat(mBouncer.inTransit()).isTrue();
+ mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
+ assertThat(mBouncer.inTransit()).isFalse();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index d8e90a5..0dbf308 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -225,11 +225,12 @@
mScrimController.transitionTo(ScrimState.PULSING);
mScrimController.finishAnimationsImmediately();
- // Front scrim should be transparent
+ // Front scrim should be transparent, but tinted
// Back scrim should be semi-transparent so the user can see the wallpaper
// Pulse callback should have been invoked
assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
assertScrimTint(mScrimBehind, true /* tinted */);
+ assertScrimTint(mScrimInFront, true /* tinted */);
mScrimController.setWakeLockScreenSensorActive(true);
mScrimController.finishAnimationsImmediately();
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 2db7f0e..123dfee 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -89,7 +89,7 @@
protected final Context mContext;
protected final SystemSupport mSystemSupport;
- private final WindowManagerInternal mWindowManagerService;
+ protected final WindowManagerInternal mWindowManagerService;
private final GlobalActionPerformer mGlobalActionPerformer;
private final AccessibilityWindowManager mA11yWindowManager;
private final DisplayManager mDisplayManager;
@@ -167,9 +167,10 @@
@Nullable MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId);
/**
- * @return The current injector of motion events, if one exists
+ * @param displayId The display id.
+ * @return The current injector of motion events used on the display, if one exists.
*/
- @Nullable MotionEventInjector getMotionEventInjectorLocked();
+ @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId);
/**
* @return The current dispatcher for fingerprint gestures, if one exists
@@ -715,6 +716,10 @@
}
@Override
+ public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
+ }
+
+ @Override
public boolean performAccessibilityAction(int accessibilityWindowId,
long accessibilityNodeId, int action, Bundle arguments, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index b6cbbac..5111bec 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -114,7 +114,7 @@
private final SparseArray<MagnificationGestureHandler> mMagnificationGestureHandler =
new SparseArray<>(0);
- private final SparseArray<MotionEventInjector> mMotionEventInjector = new SparseArray<>(0);
+ private final SparseArray<MotionEventInjector> mMotionEventInjectors = new SparseArray<>(0);
private AutoclickController mAutoclickController;
@@ -412,12 +412,14 @@
MotionEventInjector injector = new MotionEventInjector(
mContext.getMainLooper());
addFirstEventHandler(displayId, injector);
- // TODO: Need to set MotionEventInjector per display.
- mAms.setMotionEventInjector(injector);
- mMotionEventInjector.put(displayId, injector);
+ mMotionEventInjectors.put(displayId, injector);
}
}
+ if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
+ mAms.setMotionEventInjectors(mMotionEventInjectors);
+ }
+
if ((mEnabledFeatures & FLAG_FEATURE_FILTER_KEY_EVENTS) != 0) {
mKeyboardInterceptor = new KeyboardInterceptor(mAms,
LocalServices.getService(WindowManagerPolicy.class));
@@ -462,15 +464,14 @@
}
private void disableFeatures() {
- for (int i = mMotionEventInjector.size() - 1; i >= 0; i--) {
- final MotionEventInjector injector = mMotionEventInjector.valueAt(i);
- // TODO: Need to set MotionEventInjector per display.
- mAms.setMotionEventInjector(null);
+ for (int i = mMotionEventInjectors.size() - 1; i >= 0; i--) {
+ final MotionEventInjector injector = mMotionEventInjectors.valueAt(i);
if (injector != null) {
injector.onDestroy();
}
}
- mMotionEventInjector.clear();
+ mAms.setMotionEventInjectors(null);
+ mMotionEventInjectors.clear();
if (mAutoclickController != null) {
mAutoclickController.onDestroy();
mAutoclickController = null;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index a220451..3db79b2 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -210,7 +210,7 @@
private KeyEventDispatcher mKeyEventDispatcher;
- private MotionEventInjector mMotionEventInjector;
+ private SparseArray<MotionEventInjector> mMotionEventInjectors;
private FingerprintGestureDispatcher mFingerprintGestureDispatcher;
@@ -860,30 +860,34 @@
* Called by AccessibilityInputFilter when it creates or destroys the motionEventInjector.
* Not using a getter because the AccessibilityInputFilter isn't thread-safe
*
- * @param motionEventInjector The new value of the motionEventInjector. May be null.
+ * @param motionEventInjectors The array of motionEventInjectors. May be null.
+ *
*/
- void setMotionEventInjector(MotionEventInjector motionEventInjector) {
+ void setMotionEventInjectors(SparseArray<MotionEventInjector> motionEventInjectors) {
synchronized (mLock) {
- mMotionEventInjector = motionEventInjector;
+ mMotionEventInjectors = motionEventInjectors;
// We may be waiting on this object being set
mLock.notifyAll();
}
}
@Override
- public MotionEventInjector getMotionEventInjectorLocked() {
+ public @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId) {
final long endMillis = SystemClock.uptimeMillis() + WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS;
- while ((mMotionEventInjector == null) && (SystemClock.uptimeMillis() < endMillis)) {
+ MotionEventInjector motionEventInjector = null;
+ while ((mMotionEventInjectors == null) && (SystemClock.uptimeMillis() < endMillis)) {
try {
mLock.wait(endMillis - SystemClock.uptimeMillis());
} catch (InterruptedException ie) {
/* ignore */
}
}
- if (mMotionEventInjector == null) {
+ if (mMotionEventInjectors == null) {
Slog.e(LOG_TAG, "MotionEventInjector installation timed out");
+ } else {
+ motionEventInjector = mMotionEventInjectors.get(displayId);
}
- return mMotionEventInjector;
+ return motionEventInjector;
}
/**
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 02306c0..961168a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -238,7 +238,6 @@
return (userState != null) ? userState.getSoftKeyboardShowMode() : 0;
}
-
@Override
public boolean isAccessibilityButtonAvailable() {
synchronized (mLock) {
@@ -354,12 +353,13 @@
}
@Override
- public void sendGesture(int sequence, ParceledListSlice gestureSteps) {
+ public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
+ final boolean isTouchableDisplay = mWindowManagerService.isTouchableDisplay(displayId);
synchronized (mLock) {
if (mSecurityPolicy.canPerformGestures(this)) {
MotionEventInjector motionEventInjector =
- mSystemSupport.getMotionEventInjectorLocked();
- if (motionEventInjector != null) {
+ mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId);
+ if (motionEventInjector != null && isTouchableDisplay) {
motionEventInjector.injectEvents(
gestureSteps.getList(), mServiceInterface, sequence);
} else {
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 73f5cb8..e2cdddb 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -165,7 +165,13 @@
mComponentName = componentName;
mCompatMode = compatMode;
- context = new ContextThemeWrapper(context, mThemeId);
+ context = new ContextThemeWrapper(context, mThemeId) {
+ @Override
+ public void startActivity(Intent intent) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ super.startActivity(intent);
+ }
+ };
final LayoutInflater inflater = LayoutInflater.from(context);
final View view = inflater.inflate(R.layout.autofill_save, null);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 9855e4e..9518196 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -13,6 +13,7 @@
},
srcs: [
"java/**/*.java",
+ ":platformcompat_aidl",
":dumpstate_aidl",
":idmap2_aidl",
":installd_aidl",
@@ -80,3 +81,11 @@
name: "gps_debug.conf",
src: "java/com/android/server/location/gps_debug.conf",
}
+
+filegroup {
+ name: "platformcompat_aidl",
+ srcs: [
+ "java/com/android/server/compat/IPlatformCompat.aidl",
+ ],
+ path: "java",
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 30a3563..b9d7c68 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -48,7 +48,6 @@
import android.os.ShellCommand;
import android.os.SystemProperties;
import android.os.UserHandle;
-import android.os.UserManager;
import android.provider.Settings.Secure;
import android.service.dreams.Sandman;
import android.service.vr.IVrManager;
@@ -218,6 +217,15 @@
}
};
+ private final ContentObserver mDarkThemeObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ int mode = Secure.getIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE,
+ mNightMode, 0);
+ SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode));
+ }
+ };
+
@Override
public void onSwitchUser(int userHandle) {
super.onSwitchUser(userHandle);
@@ -293,6 +301,9 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
context.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler);
+
+ context.getContentResolver().registerContentObserver(Secure.getUriFor(Secure.UI_NIGHT_MODE),
+ false, mDarkThemeObserver, 0);
}
// Records whether setup wizard has happened or not and adds an observer for this user if not.
@@ -417,11 +428,6 @@
if (!mCarModeEnabled) {
Secure.putIntForUser(getContext().getContentResolver(),
Secure.UI_NIGHT_MODE, mode, user);
-
- if (UserManager.get(getContext()).isPrimaryUser()) {
- SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME,
- Integer.toString(mode));
- }
}
mNightMode = mode;
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 33070dc..0dd7199 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -79,7 +79,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
-import android.text.format.Time;
import android.util.ArrayMap;
import android.util.DebugUtils;
import android.util.DisplayMetrics;
@@ -98,12 +97,16 @@
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URISyntaxException;
+import java.time.Clock;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -116,10 +119,14 @@
final class ActivityManagerShellCommand extends ShellCommand {
public static final String NO_CLASS_ERROR_CODE = "Error type 3";
+
private static final String SHELL_PACKAGE_NAME = "com.android.shell";
private static final int USER_OPERATION_TIMEOUT_MS = 2 * 60 * 1000; // 2 minutes
+ private static final DateTimeFormatter LOG_NAME_TIME_FORMATTER =
+ DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss", Locale.ROOT);
+
// IPC interface to activity manager -- don't need to do additional security checks.
final IActivityManager mInterface;
final IActivityTaskManager mTaskInterface;
@@ -922,9 +929,9 @@
String process = getNextArgRequired();
String heapFile = getNextArg();
if (heapFile == null) {
- final Time t = new Time();
- t.set(System.currentTimeMillis());
- heapFile = "/data/local/tmp/heapdump-" + t.format("%Y%m%d-%H%M%S") + ".prof";
+ LocalDateTime localDateTime = LocalDateTime.now(Clock.systemDefaultZone());
+ String logNameTimeString = LOG_NAME_TIME_FORMATTER.format(localDateTime);
+ heapFile = "/data/local/tmp/heapdump-" + logNameTimeString + ".prof";
}
pw.println("File: " + heapFile);
pw.flush();
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 20eb618..f3f9754 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -282,10 +282,10 @@
public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
IBinder token, ServiceListener listener, int userId, int groupId,
byte[] cryptoToken, boolean restricted, String owner,
- final int[] disabledFeatures) {
+ final int[] disabledFeatures, int timeoutSec) {
super(context, getConstants(), daemon, halDeviceId, token, listener,
userId, groupId, cryptoToken, restricted, owner, getBiometricUtils(),
- disabledFeatures);
+ disabledFeatures, timeoutSec);
}
@Override
@@ -912,8 +912,12 @@
}
protected void setActiveUserInternal(int userId) {
- // Do not put on handler, since it should finish before returning to caller.
- updateActiveGroup(userId, null /* clientPackage */);
+ mHandler.post(() -> {
+ if (DEBUG) {
+ Slog.d(getTag(), "setActiveUser(" + userId + ")");
+ }
+ updateActiveGroup(userId, null /* clientPackage */);
+ });
}
protected void removeInternal(RemovalClient client) {
diff --git a/services/core/java/com/android/server/biometrics/EnrollClient.java b/services/core/java/com/android/server/biometrics/EnrollClient.java
index 854528f..7ebb7c0 100644
--- a/services/core/java/com/android/server/biometrics/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/EnrollClient.java
@@ -31,11 +31,11 @@
* A class to keep track of the enrollment state for a given client.
*/
public abstract class EnrollClient extends ClientMonitor {
- private static final long MS_PER_SEC = 1000;
- private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
private final byte[] mCryptoToken;
private final BiometricUtils mBiometricUtils;
private final int[] mDisabledFeatures;
+ private final int mTimeoutSec;
+
private long mEnrollmentStartTimeMs;
public abstract boolean shouldVibrate();
@@ -44,12 +44,13 @@
BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
BiometricServiceBase.ServiceListener listener, int userId, int groupId,
byte[] cryptoToken, boolean restricted, String owner, BiometricUtils utils,
- final int[] disabledFeatures) {
+ final int[] disabledFeatures, int timeoutSec) {
super(context, constants, daemon, halDeviceId, token, listener, userId, groupId, restricted,
owner, 0 /* cookie */);
mBiometricUtils = utils;
mCryptoToken = Arrays.copyOf(cryptoToken, cryptoToken.length);
mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length);
+ mTimeoutSec = timeoutSec;
}
@Override
@@ -94,14 +95,13 @@
@Override
public int start() {
mEnrollmentStartTimeMs = System.currentTimeMillis();
- final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
try {
final ArrayList<Integer> disabledFeatures = new ArrayList<>();
for (int i = 0; i < mDisabledFeatures.length; i++) {
disabledFeatures.add(mDisabledFeatures[i]);
}
- final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), timeout,
+ final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), mTimeoutSec,
disabledFeatures);
if (result != 0) {
Slog.w(getLogTag(), "startEnroll failed, result=" + result);
diff --git a/services/core/java/com/android/server/biometrics/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
index 6c7cbc1..ecf3864 100644
--- a/services/core/java/com/android/server/biometrics/LoggableMonitor.java
+++ b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
@@ -93,7 +93,7 @@
statsAction(),
statsClient(),
acquiredInfo,
- 0 /* vendorCode */, // Don't log vendorCode for now
+ vendorCode,
Utils.isDebugEnabled(context, targetUserId));
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index a38abdc..9d51abe 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -329,6 +329,7 @@
* Receives the incoming binder calls from FaceManager.
*/
private final class FaceServiceWrapper extends IFaceService.Stub {
+ private static final int ENROLL_TIMEOUT_SEC = 75;
/**
* The following methods contain common code which is shared in biometrics/common.
@@ -368,7 +369,8 @@
final boolean restricted = isRestricted();
final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId,
- 0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures) {
+ 0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures,
+ ENROLL_TIMEOUT_SEC) {
@Override
public int[] getAcquireIgnorelist() {
@@ -609,27 +611,32 @@
public void resetLockout(byte[] token) {
checkPermission(MANAGE_BIOMETRIC);
- if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
- Slog.w(TAG, "Ignoring lockout reset, no templates enrolled");
- return;
- }
+ mHandler.post(() -> {
+ if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
+ Slog.w(TAG, "Ignoring lockout reset, no templates enrolled");
+ return;
+ }
- Slog.d(TAG, "Resetting lockout for user: " + mCurrentUserId);
+ Slog.d(TAG, "Resetting lockout for user: " + mCurrentUserId);
- try {
- mDaemonWrapper.resetLockout(token);
- } catch (RemoteException e) {
- Slog.e(getTag(), "Unable to reset lockout", e);
- }
+ try {
+ mDaemonWrapper.resetLockout(token);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to reset lockout", e);
+ }
+ });
}
@Override
public void setFeature(int userId, int feature, boolean enabled, final byte[] token,
IFaceServiceReceiver receiver, final String opPackageName) {
checkPermission(MANAGE_BIOMETRIC);
- updateActiveGroup(userId, opPackageName);
mHandler.post(() -> {
+ if (DEBUG) {
+ Slog.d(TAG, "setFeature for user(" + userId + ")");
+ }
+ updateActiveGroup(userId, opPackageName);
if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
Slog.e(TAG, "No enrolled biometrics while setting feature: " + feature);
return;
@@ -660,9 +667,12 @@
public void getFeature(int userId, int feature, IFaceServiceReceiver receiver,
final String opPackageName) {
checkPermission(MANAGE_BIOMETRIC);
- updateActiveGroup(userId, opPackageName);
mHandler.post(() -> {
+ if (DEBUG) {
+ Slog.d(TAG, "getFeature for user(" + userId + ")");
+ }
+ updateActiveGroup(userId, opPackageName);
// This should ideally return tri-state, but the user isn't shown settings unless
// they are enrolled so it's fine for now.
if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 28336f4..320e102 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -176,6 +176,7 @@
* Receives the incoming binder calls from FingerprintManager.
*/
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+ private static final int ENROLL_TIMEOUT_SEC = 60;
/**
* The following methods contain common code which is shared in biometrics/common.
@@ -203,7 +204,8 @@
final int groupId = userId; // default group for fingerprint enrollment
final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId,
- cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */) {
+ cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */,
+ ENROLL_TIMEOUT_SEC) {
@Override
public boolean shouldVibrate() {
return true;
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index bcf1d80..c59b065 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -24,6 +24,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import java.io.PrintWriter;
/**
* This class maintains state relating to platform compatibility changes.
*
@@ -169,4 +170,22 @@
return overrideExists;
}
+ /**
+ * Dumps the current list of compatibility config information.
+ *
+ * @param pw The {@link PrintWriter} instance to which the information will be dumped.
+ */
+ public void dumpConfig(PrintWriter pw) {
+ synchronized (mChanges) {
+ if (mChanges.size() == 0) {
+ pw.println("No compat overrides.");
+ return;
+ }
+ for (int i = 0; i < mChanges.size(); ++i) {
+ CompatChange c = mChanges.valueAt(i);
+ pw.println(c.toString());
+ }
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/compat/IPlatformCompat.aidl b/services/core/java/com/android/server/compat/IPlatformCompat.aidl
new file mode 100644
index 0000000..8ab08f9
--- /dev/null
+++ b/services/core/java/com/android/server/compat/IPlatformCompat.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 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.compat;
+
+import android.content.pm.ApplicationInfo;
+
+/**
+ * System private API for talking with the PlatformCompat service.
+ * {@hide}
+ */
+interface IPlatformCompat
+{
+
+ /**
+ * Reports that a compatibility change is affecting an app process now.
+ *
+ * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, ApplicationInfo)},
+ * you do not need to call this API directly. The change will be reported for you in the case
+ * that {@link #isChangeEnabled(long, ApplicationInfo)} returns {@code true}.
+ *
+ * @param changeId The ID of the compatibility change taking effect.
+ * @param appInfo Representing the affected app.
+ */
+ void reportChange(long changeId, in ApplicationInfo appInfo);
+
+ /**
+ * Query if a given compatibility change is enabled for an app process. This method should
+ * be called when implementing functionality on behalf of the affected app.
+ *
+ * <p>If this method returns {@code true}, the calling code should implement the compatibility
+ * change, resulting in differing behaviour compared to earlier releases. If this method returns
+ * {@code false}, the calling code should behave as it did in earlier releases.
+ *
+ * <p>When this method returns {@code true}, it will also report the change as
+ * {@link #reportChange(long, ApplicationInfo)} would, so there is no need to call that method
+ * directly.
+ *
+ * @param changeId The ID of the compatibility change in question.
+ * @param appInfo Representing the app in question.
+ * @return {@code true} if the change is enabled for the current app.
+ */
+ boolean isChangeEnabled(long changeId, in ApplicationInfo appInfo);
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 456d15e..3eea194 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -16,52 +16,46 @@
package com.android.server.compat;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.util.Slog;
+import com.android.internal.util.DumpUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* System server internal API for gating and reporting compatibility changes.
*/
-public class PlatformCompat {
+public class PlatformCompat extends IPlatformCompat.Stub {
private static final String TAG = "Compatibility";
- /**
- * Reports that a compatibility change is affecting an app process now.
- *
- * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, ApplicationInfo)},
- * you do not need to call this API directly. The change will be reported for you in the case
- * that {@link #isChangeEnabled(long, ApplicationInfo)} returns {@code true}.
- *
- * @param changeId The ID of the compatibility change taking effect.
- * @param appInfo Representing the affected app.
- */
- public static void reportChange(long changeId, ApplicationInfo appInfo) {
+ private final Context mContext;
+
+ public PlatformCompat(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public void reportChange(long changeId, ApplicationInfo appInfo) {
Slog.d(TAG, "Compat change reported: " + changeId + "; UID " + appInfo.uid);
// TODO log via StatsLog
}
- /**
- * Query if a given compatibility change is enabled for an app process. This method should
- * be called when implementing functionality on behalf of the affected app.
- *
- * <p>If this method returns {@code true}, the calling code should implement the compatibility
- * change, resulting in differing behaviour compared to earlier releases. If this method returns
- * {@code false}, the calling code should behave as it did in earlier releases.
- *
- * <p>When this method returns {@code true}, it will also report the change as
- * {@link #reportChange(long, ApplicationInfo)} would, so there is no need to call that method
- * directly.
- *
- * @param changeId The ID of the compatibility change in question.
- * @param appInfo Representing the app in question.
- * @return {@code true} if the change is enabled for the current app.
- */
- public static boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
+ @Override
+ public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) {
reportChange(changeId, appInfo);
return true;
}
return false;
}
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
+ CompatConfig.get().dumpConfig(pw);
+ }
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 6911b7c..461f19b 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1608,13 +1608,11 @@
if (DEBUG) Log.d(TAG, "reportGnssServiceDied");
mHandler.post(() -> {
setupNativeGnssService(/* reinitializeGnssServiceHandle = */ true);
+ // resend configuration into the restarted HAL service.
+ reloadGpsProperties();
if (isGpsEnabled()) {
setGpsEnabled(false);
-
updateEnabled();
-
- // resend configuration into the restarted HAL service.
- reloadGpsProperties();
}
});
}
diff --git a/services/core/java/com/android/server/locksettings/TEST_MAPPING b/services/core/java/com/android/server/locksettings/TEST_MAPPING
new file mode 100644
index 0000000..c1cba5f
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsDevicePolicyManagerTestCases",
+ "options": [
+ {
+ "include-annotation": "com.android.cts.devicepolicy.annotations.LockSettingsTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index c54bfc0..0ad6c2a 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -19,6 +19,7 @@
import android.app.KeyguardManager;
import android.content.Context;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.security.GateKeeper;
import android.security.keystore.AndroidKeyStoreSecretKey;
import android.security.keystore.KeyPermanentlyInvalidatedException;
@@ -437,25 +438,31 @@
// so it may live in memory for some time.
SecretKey secretKey = generateAesKey();
- long secureUserId = getGateKeeperService().getSecureUserId(userId);
- // TODO(b/124095438): Propagate this failure instead of silently failing.
- if (secureUserId == GateKeeper.INVALID_SECURE_USER_ID) {
- Log.e(TAG, "No SID available for user " + userId);
- return;
- }
-
- // Store decryption key first since it is more likely to fail.
- mKeyStore.setEntry(
- decryptAlias,
- new KeyStore.SecretKeyEntry(secretKey),
+ KeyProtection.Builder decryptionKeyProtection =
new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
.setUserAuthenticationRequired(true)
.setUserAuthenticationValidityDurationSeconds(
USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
- .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE);
+ if (userId != UserHandle.USER_SYSTEM) {
+ // Bind decryption key to secondary profile lock screen secret.
+ long secureUserId = getGateKeeperService().getSecureUserId(userId);
+ // TODO(b/124095438): Propagate this failure instead of silently failing.
+ if (secureUserId == GateKeeper.INVALID_SECURE_USER_ID) {
+ Log.e(TAG, "No SID available for user " + userId);
+ return;
+ }
+ decryptionKeyProtection
.setBoundToSpecificSecureUserId(secureUserId)
- .build());
+ // Ignore caller uid which always belongs to the primary profile.
+ .setCriticalToDeviceEncryption(true);
+ }
+ // Store decryption key first since it is more likely to fail.
+ mKeyStore.setEntry(
+ decryptAlias,
+ new KeyStore.SecretKeyEntry(secretKey),
+ decryptionKeyProtection.build());
mKeyStore.setEntry(
encryptAlias,
new KeyStore.SecretKeyEntry(secretKey),
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 6f28675..934511b 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -296,22 +296,12 @@
*/
private void updateAndRefreshOverlaysForTarget(@NonNull final String targetPackageName,
final int userId, final int flags) {
- final List<OverlayInfo> ois = new ArrayList<>();
+ final List<OverlayInfo> targetOverlays = mSettings.getOverlaysForTarget(targetPackageName,
+ userId);
- // Framework overlays added first because order matters when resolving a resource
- if (!"android".equals(targetPackageName)) {
- ois.addAll(mSettings.getOverlaysForTarget("android", userId));
- }
-
- // Then add the targeted, non-framework overlays which have higher priority
- ois.addAll(mSettings.getOverlaysForTarget(targetPackageName, userId));
-
- final List<String> enabledBaseCodePaths = new ArrayList<>(ois.size());
-
+ // Update the state for any overlay that targets this package.
boolean modified = false;
- final int n = ois.size();
- for (int i = 0; i < n; i++) {
- final OverlayInfo oi = ois.get(i);
+ for (final OverlayInfo oi : targetOverlays) {
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName,
userId);
if (overlayPackage == null) {
@@ -324,25 +314,39 @@
Slog.e(TAG, "failed to update settings", e);
modified |= mSettings.remove(oi.packageName, userId);
}
-
- if (oi.isEnabled() && overlayPackage.applicationInfo != null) {
- enabledBaseCodePaths.add(overlayPackage.applicationInfo.getBaseCodePath());
- }
}
}
if (!modified) {
+ // Update the overlay paths of the target within package manager if necessary.
+ final List<String> enabledOverlayPaths = new ArrayList<>(targetOverlays.size());
+
+ // Framework overlays are first in the overlay paths of a package within PackageManager.
+ for (final OverlayInfo oi : mSettings.getOverlaysForTarget("android", userId)) {
+ if (oi.isEnabled()) {
+ enabledOverlayPaths.add(oi.baseCodePath);
+ }
+ }
+
+ for (final OverlayInfo oi : targetOverlays) {
+ if (oi.isEnabled()) {
+ enabledOverlayPaths.add(oi.baseCodePath);
+ }
+ }
+
+ // TODO(): Use getEnabledOverlayPaths(userId, targetPackageName) instead of
+ // resourceDirs if in the future resourceDirs contains APKs other than overlays
PackageInfo packageInfo = mPackageManager.getPackageInfo(targetPackageName, userId);
ApplicationInfo appInfo = packageInfo == null ? null : packageInfo.applicationInfo;
String[] resourceDirs = appInfo == null ? null : appInfo.resourceDirs;
// If the lists aren't the same length, the enabled overlays have changed
- if (ArrayUtils.size(resourceDirs) != enabledBaseCodePaths.size()) {
+ if (ArrayUtils.size(resourceDirs) != enabledOverlayPaths.size()) {
modified = true;
} else if (resourceDirs != null) {
// If any element isn't equal, an overlay or the order of overlays has changed
for (int index = 0; index < resourceDirs.length; index++) {
- if (!resourceDirs[index].equals(enabledBaseCodePaths.get(index))) {
+ if (!resourceDirs[index].equals(enabledOverlayPaths.get(index))) {
modified = true;
break;
}
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
new file mode 100644
index 0000000..da45582
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 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.pm;
+
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.util.List;
+import java.util.Set;
+
+@VisibleForTesting
+interface PackageAbiHelper {
+ /**
+ * Derive and set the location of native libraries for the given package,
+ * which varies depending on where and how the package was installed.
+ *
+ * WARNING: This API enables modifying of the package.
+ * TODO(b/137881067): Modify so that caller is responsible for setting pkg fields as necessary
+ */
+ void setNativeLibraryPaths(PackageParser.Package pkg, File appLib32InstallDir);
+
+ /**
+ * Calculate the abis and roots for a bundled app. These can uniquely
+ * be determined from the contents of the system partition, i.e whether
+ * it contains 64 or 32 bit shared libraries etc. We do not validate any
+ * of this information, and instead assume that the system was built
+ * sensibly.
+ *
+ * WARNING: This API enables modifying of the package.
+ * TODO(b/137881067): Modify so that caller is responsible for setting pkg fields as necessary
+ */
+ void setBundledAppAbisAndRoots(PackageParser.Package pkg,
+ PackageSetting pkgSetting);
+
+ /**
+ * Derive the ABI of a non-system package located at {@code scanFile}. This information
+ * is derived purely on the basis of the contents of {@code scanFile} and
+ * {@code cpuAbiOverride}.
+ *
+ * If {@code extractLibs} is true, native libraries are extracted from the app if required.
+ *
+ * WARNING: This API enables modifying of the package.
+ * TODO(b/137881067): Modify so that caller is responsible for setting pkg fields as necessary
+ */
+ void derivePackageAbi(PackageParser.Package pkg, String cpuAbiOverride,
+ boolean extractLibs)
+ throws PackageManagerException;
+
+ /**
+ * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
+ * i.e, so that all packages can be run inside a single process if required.
+ *
+ * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
+ * this function will either try and make the ABI for all packages in
+ * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
+ * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
+ * variant is used when installing or updating a package that belongs to a shared user.
+ *
+ * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
+ * adds unnecessary complexity.
+ *
+ * WARNING: This API enables modifying of the package.
+ * TODO(b/137881067): Modify so that caller is responsible for setting pkg fields as necessary
+ */
+ @Nullable
+ List<String> adjustCpuAbisForSharedUser(
+ Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage);
+}
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
new file mode 100644
index 0000000..4ecc888
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2019 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.pm;
+
+import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+import static android.content.pm.PackageParser.isApkFile;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
+import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
+import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
+import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
+
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.os.Build;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Trace;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.util.ArrayUtils;
+
+import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+final class PackageAbiHelperImpl implements PackageAbiHelper {
+
+ @Override
+ public void setNativeLibraryPaths(PackageParser.Package pkg, File appLib32InstallDir) {
+ final ApplicationInfo info = pkg.applicationInfo;
+ final String codePath = pkg.codePath;
+ final File codeFile = new File(codePath);
+ final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp();
+
+ info.nativeLibraryRootDir = null;
+ info.nativeLibraryRootRequiresIsa = false;
+ info.nativeLibraryDir = null;
+ info.secondaryNativeLibraryDir = null;
+
+ if (isApkFile(codeFile)) {
+ // Monolithic install
+ if (bundledApp) {
+ // If "/system/lib64/apkname" exists, assume that is the per-package
+ // native library directory to use; otherwise use "/system/lib/apkname".
+ final String apkRoot = calculateBundledApkRoot(info.sourceDir);
+ final boolean is64Bit = VMRuntime.is64BitInstructionSet(
+ getPrimaryInstructionSet(info));
+
+ // This is a bundled system app so choose the path based on the ABI.
+ // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
+ // is just the default path.
+ final String apkName = deriveCodePathName(codePath);
+ final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
+ info.nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
+ apkName).getAbsolutePath();
+
+ if (info.secondaryCpuAbi != null) {
+ final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
+ info.secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
+ secondaryLibDir, apkName).getAbsolutePath();
+ }
+ } else {
+ final String apkName = deriveCodePathName(codePath);
+ info.nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
+ .getAbsolutePath();
+ }
+
+ info.nativeLibraryRootRequiresIsa = false;
+ info.nativeLibraryDir = info.nativeLibraryRootDir;
+ } else {
+ // Cluster install
+ info.nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
+ info.nativeLibraryRootRequiresIsa = true;
+
+ info.nativeLibraryDir = new File(info.nativeLibraryRootDir,
+ getPrimaryInstructionSet(info)).getAbsolutePath();
+
+ if (info.secondaryCpuAbi != null) {
+ info.secondaryNativeLibraryDir = new File(info.nativeLibraryRootDir,
+ VMRuntime.getInstructionSet(info.secondaryCpuAbi)).getAbsolutePath();
+ }
+ }
+ }
+
+ @Override
+ public void setBundledAppAbisAndRoots(PackageParser.Package pkg,
+ PackageSetting pkgSetting) {
+ final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
+
+ // If "/system/lib64/apkname" exists, assume that is the per-package
+ // native library directory to use; otherwise use "/system/lib/apkname".
+ final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
+ setBundledAppAbi(pkg, apkRoot, apkName);
+ // pkgSetting might be null during rescan following uninstall of updates
+ // to a bundled app, so accommodate that possibility. The settings in
+ // that case will be established later from the parsed package.
+ //
+ // If the settings aren't null, sync them up with what we've just derived.
+ // note that apkRoot isn't stored in the package settings.
+ if (pkgSetting != null) {
+ pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
+ pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
+ }
+ }
+
+ /**
+ * Deduces the ABI of a bundled app and sets the relevant fields on the
+ * parsed pkg object.
+ *
+ * @param apkRoot the root of the installed apk, something like {@code /system} or
+ * {@code /oem} under which system libraries are installed.
+ * @param apkName the name of the installed package.
+ */
+ private void setBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
+ final File codeFile = new File(pkg.codePath);
+
+ final boolean has64BitLibs;
+ final boolean has32BitLibs;
+ if (isApkFile(codeFile)) {
+ // Monolithic install
+ has64BitLibs =
+ (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
+ has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
+ } else {
+ // Cluster install
+ final File rootDir = new File(codeFile, LIB_DIR_NAME);
+ if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
+ && !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
+ final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
+ has64BitLibs = (new File(rootDir, isa)).exists();
+ } else {
+ has64BitLibs = false;
+ }
+ if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
+ && !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
+ final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
+ has32BitLibs = (new File(rootDir, isa)).exists();
+ } else {
+ has32BitLibs = false;
+ }
+ }
+
+ if (has64BitLibs && !has32BitLibs) {
+ // The package has 64 bit libs, but not 32 bit libs. Its primary
+ // ABI should be 64 bit. We can safely assume here that the bundled
+ // native libraries correspond to the most preferred ABI in the list.
+
+ pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+ pkg.applicationInfo.secondaryCpuAbi = null;
+ } else if (has32BitLibs && !has64BitLibs) {
+ // The package has 32 bit libs but not 64 bit libs. Its primary
+ // ABI should be 32 bit.
+
+ pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+ pkg.applicationInfo.secondaryCpuAbi = null;
+ } else if (has32BitLibs && has64BitLibs) {
+ // The application has both 64 and 32 bit bundled libraries. We check
+ // here that the app declares multiArch support, and warn if it doesn't.
+ //
+ // We will be lenient here and record both ABIs. The primary will be the
+ // ABI that's higher on the list, i.e, a device that's configured to prefer
+ // 64 bit apps will see a 64 bit primary ABI,
+
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
+ Slog.e(PackageManagerService.TAG,
+ "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
+ }
+
+ if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
+ pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+ pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+ } else {
+ pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+ pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+ }
+ } else {
+ pkg.applicationInfo.primaryCpuAbi = null;
+ pkg.applicationInfo.secondaryCpuAbi = null;
+ }
+ }
+
+ @Override
+ public void derivePackageAbi(PackageParser.Package pkg, String cpuAbiOverride,
+ boolean extractLibs)
+ throws PackageManagerException {
+ // Give ourselves some initial paths; we'll come back for another
+ // pass once we've determined ABI below.
+ setNativeLibraryPaths(pkg, PackageManagerService.sAppLib32InstallDir);
+
+ // We shouldn't attempt to extract libs from system app when it was not updated.
+ if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
+ extractLibs = false;
+ }
+
+ final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
+ final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
+
+ NativeLibraryHelper.Handle handle = null;
+ try {
+ handle = NativeLibraryHelper.Handle.create(pkg);
+ // TODO(multiArch): This can be null for apps that didn't go through the
+ // usual installation process. We can calculate it again, like we
+ // do during install time.
+ //
+ // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
+ // unnecessary.
+ final File nativeLibraryRoot = new File(nativeLibraryRootStr);
+
+ // Null out the abis so that they can be recalculated.
+ pkg.applicationInfo.primaryCpuAbi = null;
+ pkg.applicationInfo.secondaryCpuAbi = null;
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0) {
+ // Warn if we've set an abiOverride for multi-lib packages..
+ // By definition, we need to copy both 32 and 64 bit libraries for
+ // such packages.
+ if (pkg.cpuAbiOverride != null
+ && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
+ Slog.w(PackageManagerService.TAG,
+ "Ignoring abiOverride for multi arch application.");
+ }
+
+ int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
+ int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
+ if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+ if (extractLibs) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
+ useIsaSpecificSubdirs);
+ } else {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+ abi32 = NativeLibraryHelper.findSupportedAbi(
+ handle, Build.SUPPORTED_32_BIT_ABIS);
+ }
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ // Shared library native code should be in the APK zip aligned
+ if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Shared library native lib extraction not supported");
+ }
+
+ maybeThrowExceptionForMultiArchCopy(
+ "Error unpackaging 32 bit native libs for multiarch app.", abi32);
+
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+ if (extractLibs) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
+ useIsaSpecificSubdirs);
+ } else {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+ abi64 = NativeLibraryHelper.findSupportedAbi(
+ handle, Build.SUPPORTED_64_BIT_ABIS);
+ }
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ maybeThrowExceptionForMultiArchCopy(
+ "Error unpackaging 64 bit native libs for multiarch app.", abi64);
+
+ if (abi64 >= 0) {
+ // Shared library native libs should be in the APK zip aligned
+ if (extractLibs && pkg.isLibrary()) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Shared library native lib extraction not supported");
+ }
+ pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
+ }
+
+ if (abi32 >= 0) {
+ final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
+ if (abi64 >= 0) {
+ if (pkg.use32bitAbi) {
+ pkg.applicationInfo.secondaryCpuAbi =
+ pkg.applicationInfo.primaryCpuAbi;
+ pkg.applicationInfo.primaryCpuAbi = abi;
+ } else {
+ pkg.applicationInfo.secondaryCpuAbi = abi;
+ }
+ } else {
+ pkg.applicationInfo.primaryCpuAbi = abi;
+ }
+ }
+ } else {
+ String[] abiList = (cpuAbiOverride != null)
+ ? new String[]{cpuAbiOverride} : Build.SUPPORTED_ABIS;
+
+ // Enable gross and lame hacks for apps that are built with old
+ // SDK tools. We must scan their APKs for renderscript bitcode and
+ // not launch them if it's present. Don't bother checking on devices
+ // that don't have 64 bit support.
+ boolean needsRenderScriptOverride = false;
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null
+ && NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
+ abiList = Build.SUPPORTED_32_BIT_ABIS;
+ needsRenderScriptOverride = true;
+ }
+
+ final int copyRet;
+ if (extractLibs) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
+ } else {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
+ copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
+ }
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+
+ if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Error unpackaging native libs for app, errorCode=" + copyRet);
+ }
+
+ if (copyRet >= 0) {
+ // Shared libraries that have native libs must be multi-architecture
+ if (pkg.isLibrary()) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Shared library with native libs must be multiarch");
+ }
+ pkg.applicationInfo.primaryCpuAbi = abiList[copyRet];
+ } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES
+ && cpuAbiOverride != null) {
+ pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride;
+ } else if (needsRenderScriptOverride) {
+ pkg.applicationInfo.primaryCpuAbi = abiList[0];
+ }
+ }
+ } catch (IOException ioe) {
+ Slog.e(PackageManagerService.TAG, "Unable to get canonical file " + ioe.toString());
+ } finally {
+ IoUtils.closeQuietly(handle);
+ }
+
+ // Now that we've calculated the ABIs and determined if it's an internal app,
+ // we will go ahead and populate the nativeLibraryPath.
+ setNativeLibraryPaths(pkg, PackageManagerService.sAppLib32InstallDir);
+ }
+
+ /**
+ * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
+ * i.e, so that all packages can be run inside a single process if required.
+ *
+ * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
+ * this function will either try and make the ABI for all packages in
+ * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
+ * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
+ * variant is used when installing or updating a package that belongs to a shared user.
+ *
+ * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
+ * adds unnecessary complexity.
+ */
+ @Override
+ @Nullable
+ public List<String> adjustCpuAbisForSharedUser(
+ Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
+ List<String> changedAbiCodePath = null;
+ String requiredInstructionSet = null;
+ if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
+ requiredInstructionSet = VMRuntime.getInstructionSet(
+ scannedPackage.applicationInfo.primaryCpuAbi);
+ }
+
+ PackageSetting requirer = null;
+ for (PackageSetting ps : packagesForUser) {
+ // If packagesForUser contains scannedPackage, we skip it. This will happen
+ // when scannedPackage is an update of an existing package. Without this check,
+ // we will never be able to change the ABI of any package belonging to a shared
+ // user, even if it's compatible with other packages.
+ if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
+ if (ps.primaryCpuAbiString == null) {
+ continue;
+ }
+
+ final String instructionSet =
+ VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
+ if (requiredInstructionSet != null
+ && !instructionSet.equals(requiredInstructionSet)) {
+ // We have a mismatch between instruction sets (say arm vs arm64) warn about
+ // this but there's not much we can do.
+ String errorMessage = "Instruction set mismatch, "
+ + ((requirer == null) ? "[caller]" : requirer)
+ + " requires " + requiredInstructionSet + " whereas " + ps
+ + " requires " + instructionSet;
+ Slog.w(PackageManagerService.TAG, errorMessage);
+ }
+
+ if (requiredInstructionSet == null) {
+ requiredInstructionSet = instructionSet;
+ requirer = ps;
+ }
+ }
+ }
+
+ if (requiredInstructionSet != null) {
+ String adjustedAbi;
+ if (requirer != null) {
+ // requirer != null implies that either scannedPackage was null or that
+ // scannedPackage did not require an ABI, in which case we have to adjust
+ // scannedPackage to match the ABI of the set (which is the same as
+ // requirer's ABI)
+ adjustedAbi = requirer.primaryCpuAbiString;
+ if (scannedPackage != null) {
+ scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
+ }
+ } else {
+ // requirer == null implies that we're updating all ABIs in the set to
+ // match scannedPackage.
+ adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
+ }
+
+ for (PackageSetting ps : packagesForUser) {
+ if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
+ if (ps.primaryCpuAbiString != null) {
+ continue;
+ }
+
+ ps.primaryCpuAbiString = adjustedAbi;
+ if (ps.pkg != null && ps.pkg.applicationInfo != null
+ && !TextUtils.equals(
+ adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
+ ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
+ if (PackageManagerService.DEBUG_ABI_SELECTION) {
+ Slog.i(PackageManagerService.TAG,
+ "Adjusting ABI for " + ps.name + " to " + adjustedAbi
+ + " (requirer="
+ + (requirer != null ? requirer.pkg : "null")
+ + ", scannedPackage="
+ + (scannedPackage != null ? scannedPackage : "null")
+ + ")");
+ }
+ if (changedAbiCodePath == null) {
+ changedAbiCodePath = new ArrayList<>();
+ }
+ changedAbiCodePath.add(ps.codePathString);
+ }
+ }
+ }
+ }
+ return changedAbiCodePath;
+ }
+
+ private static String calculateBundledApkRoot(final String codePathString) {
+ final File codePath = new File(codePathString);
+ final File codeRoot;
+ if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
+ codeRoot = Environment.getRootDirectory();
+ } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
+ codeRoot = Environment.getOemDirectory();
+ } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
+ codeRoot = Environment.getVendorDirectory();
+ } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
+ codeRoot = Environment.getOdmDirectory();
+ } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
+ codeRoot = Environment.getProductDirectory();
+ } else if (FileUtils.contains(Environment.getSystemExtDirectory(), codePath)) {
+ codeRoot = Environment.getSystemExtDirectory();
+ } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
+ codeRoot = Environment.getOdmDirectory();
+ } else {
+ // Unrecognized code path; take its top real segment as the apk root:
+ // e.g. /something/app/blah.apk => /something
+ try {
+ File f = codePath.getCanonicalFile();
+ File parent = f.getParentFile(); // non-null because codePath is a file
+ File tmp;
+ while ((tmp = parent.getParentFile()) != null) {
+ f = parent;
+ parent = tmp;
+ }
+ codeRoot = f;
+ Slog.w(PackageManagerService.TAG, "Unrecognized code path "
+ + codePath + " - using " + codeRoot);
+ } catch (IOException e) {
+ // Can't canonicalize the code path -- shenanigans?
+ Slog.w(PackageManagerService.TAG, "Can't canonicalize code path " + codePath);
+ return Environment.getRootDirectory().getPath();
+ }
+ }
+ return codeRoot.getPath();
+ }
+
+ // Utility method that returns the relative package path with respect
+ // to the installation directory. Like say for /data/data/com.test-1.apk
+ // string com.test-1 is returned.
+ private static String deriveCodePathName(String codePath) {
+ if (codePath == null) {
+ return null;
+ }
+ final File codeFile = new File(codePath);
+ final String name = codeFile.getName();
+ if (codeFile.isDirectory()) {
+ return name;
+ } else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
+ final int lastDot = name.lastIndexOf('.');
+ return name.substring(0, lastDot);
+ } else {
+ Slog.w(PackageManagerService.TAG, "Odd, " + codePath + " doesn't look like an APK");
+ return null;
+ }
+ }
+
+ private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
+ PackageManagerException {
+ if (copyRet < 0) {
+ if (copyRet != PackageManager.NO_NATIVE_LIBRARIES
+ && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
+ throw new PackageManagerException(copyRet, message);
+ }
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index dfdefe1..ebbb193 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -94,14 +94,12 @@
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
-import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
-import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
@@ -277,6 +275,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
@@ -429,7 +428,7 @@
// user, but by default initialize to this.
public static final boolean DEBUG_DEXOPT = false;
- private static final boolean DEBUG_ABI_SELECTION = false;
+ static final boolean DEBUG_ABI_SELECTION = false;
private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
private static final boolean DEBUG_APP_DATA = false;
@@ -653,7 +652,8 @@
private static final File sAppInstallDir =
new File(Environment.getDataDirectory(), "app");
/** Directory where installed application's 32-bit native libraries are copied. */
- private static final File sAppLib32InstallDir =
+ @VisibleForTesting
+ static final File sAppLib32InstallDir =
new File(Environment.getDataDirectory(), "app-lib");
// ----------------------------------------------------------------
@@ -744,6 +744,30 @@
private final ApexManager mApexManager;
+ private final Injector mInjector;
+
+ /**
+ * Unit tests will instantiate and / or extend to mock dependencies / behaviors.
+ */
+ @VisibleForTesting
+ static class Injector {
+ private final UserManagerInternal mUserManager;
+ private final PackageAbiHelper mAbiHelper;
+
+ Injector(UserManagerInternal userManager, PackageAbiHelper abiHelper) {
+ mUserManager = userManager;
+ mAbiHelper = abiHelper;
+ }
+
+ public UserManagerInternal getUserManager() {
+ return mUserManager;
+ }
+
+ public PackageAbiHelper getAbiHelper() {
+ return mAbiHelper;
+ }
+ }
+
class PackageParserCallback implements PackageParser.Callback {
@Override public final boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -2007,8 +2031,8 @@
// survive long enough to benefit of background optimizations.
for (int userId : firstUserIds) {
PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
- // There's a race currently where some install events may interleave with an uninstall.
- // This can lead to package info being null (b/36642664).
+ // There's a race currently where some install events may interleave with an
+ // uninstall. This can lead to package info being null (b/36642664).
if (info != null) {
mDexManager.notifyPackageInstalled(info, userId);
}
@@ -2078,6 +2102,7 @@
* external/removable/unprotected storage.
* @return {@link StorageEnum#TYPE_UNKNOWN} if the package is not stored externally or the
* corresponding {@link StorageEnum} storage type value if it is.
+ * corresponding {@link StorageEnum} storage type value if it is.
*/
private static int getPackageExternalStorageType(VolumeInfo packageVolume,
boolean packageIsExternal) {
@@ -2340,6 +2365,10 @@
mPermissionManager.getPermissionSettings(), mPackages);
}
}
+
+ // TODO(b/137961986): We should pass this via constructor, but would first need to create
+ // a packages lock that could also be passed in.
+ mInjector = new Injector(getUserManagerInternal(), new PackageAbiHelperImpl());
// CHECKSTYLE:ON IndentationCheck
t.traceEnd();
@@ -3048,7 +3077,8 @@
// the rest of the commands above) because there's precious little we
// can do about it. A settings error is reported, though.
final List<String> changedAbiCodePath =
- adjustCpuAbisForSharedUserLPw(setting.packages, null /*scannedPackage*/);
+ mInjector.getAbiHelper().adjustCpuAbisForSharedUser(
+ setting.packages, null /*scannedPackage*/);
if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
final String codePathString = changedAbiCodePath.get(i);
@@ -8791,7 +8821,8 @@
null /* originalPkgSetting */, null, parseFlags, scanFlags,
(pkg == mPlatformPackage), user);
applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
- final ScanResult scanResult = scanPackageOnlyLI(request, mFactoryTest, -1L);
+ final ScanResult scanResult =
+ scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting);
}
@@ -10151,7 +10182,8 @@
}
/** The result of a package scan. */
- private static class ScanResult {
+ @VisibleForTesting
+ static class ScanResult {
/** The request that initiated the scan that produced this result. */
public final ScanRequest request;
/** Whether or not the package scan was successful */
@@ -10190,7 +10222,8 @@
}
/** A package to be scanned */
- private static class ScanRequest {
+ @VisibleForTesting
+ static class ScanRequest {
/** The parsed package */
@NonNull public final PackageParser.Package pkg;
/** The package this package replaces */
@@ -10383,7 +10416,7 @@
pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
originalPkgSetting, realPkgName, parseFlags, scanFlags,
(pkg == mPlatformPackage), user);
- return scanPackageOnlyLI(request, mFactoryTest, currentTime);
+ return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime);
}
}
@@ -10609,15 +10642,21 @@
* method potentially modifies a live {@link PackageSetting} object representing
* the package being scanned. This will be resolved in the future.
*
+ * @param injector injector for acquiring dependencies
* @param request Information about the package to be scanned
* @param isUnderFactoryTest Whether or not the device is under factory test
* @param currentTime The current time, in millis
* @return The results of the scan
*/
@GuardedBy("mInstallLock")
- private static @NonNull ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
+ @VisibleForTesting
+ @NonNull
+ static ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
+ Injector injector,
boolean isUnderFactoryTest, long currentTime)
- throws PackageManagerException {
+ throws PackageManagerException {
+ final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
+ final UserManagerInternal userManager = injector.getUserManager();
final PackageParser.Package pkg = request.pkg;
PackageSetting pkgSetting = request.pkgSetting;
final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
@@ -10723,7 +10762,7 @@
if (!createNewPackage) {
final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
- setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
+ setInstantAppForUser(userManager, pkgSetting, userId, instantApp, fullApp);
}
// TODO(patb): see if we can do away with disabled check here.
if (disabledPkgSetting != null
@@ -10769,7 +10808,7 @@
if (needToDeriveAbi) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
final boolean extractNativeLibs = !pkg.isLibrary();
- derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
+ packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Some system apps still use directory structure for native libraries
@@ -10777,8 +10816,8 @@
// structure. Try to detect abi based on directory structure.
if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
pkg.applicationInfo.primaryCpuAbi == null) {
- setBundledAppAbisAndRoots(pkg, pkgSetting);
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ packageAbiHelper.setBundledAppAbisAndRoots(pkg, pkgSetting);
+ packageAbiHelper.setNativeLibraryPaths(pkg, sAppLib32InstallDir);
}
} else {
// This is not a first boot or an upgrade, don't bother deriving the
@@ -10787,7 +10826,7 @@
pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ packageAbiHelper.setNativeLibraryPaths(pkg, sAppLib32InstallDir);
if (DEBUG_ABI_SELECTION) {
Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
@@ -10808,7 +10847,7 @@
// ABIs we've determined above. For non-moves, the path will be updated based on the
// ABIs we determined during compilation, but the path will depend on the final
// package path (after the rename away from the stage path).
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+ packageAbiHelper.setNativeLibraryPaths(pkg, sAppLib32InstallDir);
}
// This is a special case for the "system" package, where the ABI is
@@ -10862,8 +10901,8 @@
// We also do this *before* we perform dexopt on this package, so that
// we can avoid redundant dexopts, and also to make sure we've got the
// code and package path correct.
- changedAbiCodePath =
- adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages, pkg);
+ changedAbiCodePath = packageAbiHelper.adjustCpuAbisForSharedUser(
+ pkgSetting.sharedUser.packages, pkg);
}
if (isUnderFactoryTest && pkg.requestedPermissions.contains(
@@ -11713,264 +11752,6 @@
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- /**
- * Derive the ABI of a non-system package located at {@code scanFile}. This information
- * is derived purely on the basis of the contents of {@code scanFile} and
- * {@code cpuAbiOverride}.
- *
- * If {@code extractLibs} is true, native libraries are extracted from the app if required.
- */
- private static void derivePackageAbi(PackageParser.Package pkg, String cpuAbiOverride,
- boolean extractLibs)
- throws PackageManagerException {
- // Give ourselves some initial paths; we'll come back for another
- // pass once we've determined ABI below.
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
-
- // We shouldn't attempt to extract libs from system app when it was not updated.
- if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
- extractLibs = false;
- }
-
- final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
- final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
-
- NativeLibraryHelper.Handle handle = null;
- try {
- handle = NativeLibraryHelper.Handle.create(pkg);
- // TODO(multiArch): This can be null for apps that didn't go through the
- // usual installation process. We can calculate it again, like we
- // do during install time.
- //
- // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
- // unnecessary.
- final File nativeLibraryRoot = new File(nativeLibraryRootStr);
-
- // Null out the abis so that they can be recalculated.
- pkg.applicationInfo.primaryCpuAbi = null;
- pkg.applicationInfo.secondaryCpuAbi = null;
- if (isMultiArch(pkg.applicationInfo)) {
- // Warn if we've set an abiOverride for multi-lib packages..
- // By definition, we need to copy both 32 and 64 bit libraries for
- // such packages.
- if (pkg.cpuAbiOverride != null
- && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
- Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
- }
-
- int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
- int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
- if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
- if (extractLibs) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
- useIsaSpecificSubdirs);
- } else {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
- abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
- }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- // Shared library native code should be in the APK zip aligned
- if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Shared library native lib extraction not supported");
- }
-
- maybeThrowExceptionForMultiArchCopy(
- "Error unpackaging 32 bit native libs for multiarch app.", abi32);
-
- if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
- if (extractLibs) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
- useIsaSpecificSubdirs);
- } else {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
- abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
- }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- maybeThrowExceptionForMultiArchCopy(
- "Error unpackaging 64 bit native libs for multiarch app.", abi64);
-
- if (abi64 >= 0) {
- // Shared library native libs should be in the APK zip aligned
- if (extractLibs && pkg.isLibrary()) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Shared library native lib extraction not supported");
- }
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];
- }
-
- if (abi32 >= 0) {
- final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
- if (abi64 >= 0) {
- if (pkg.use32bitAbi) {
- pkg.applicationInfo.secondaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
- pkg.applicationInfo.primaryCpuAbi = abi;
- } else {
- pkg.applicationInfo.secondaryCpuAbi = abi;
- }
- } else {
- pkg.applicationInfo.primaryCpuAbi = abi;
- }
- }
- } else {
- String[] abiList = (cpuAbiOverride != null) ?
- new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
-
- // Enable gross and lame hacks for apps that are built with old
- // SDK tools. We must scan their APKs for renderscript bitcode and
- // not launch them if it's present. Don't bother checking on devices
- // that don't have 64 bit support.
- boolean needsRenderScriptOverride = false;
- if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null &&
- NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
- abiList = Build.SUPPORTED_32_BIT_ABIS;
- needsRenderScriptOverride = true;
- }
-
- final int copyRet;
- if (extractLibs) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
- } else {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
- copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
- }
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-
- if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Error unpackaging native libs for app, errorCode=" + copyRet);
- }
-
- if (copyRet >= 0) {
- // Shared libraries that have native libs must be multi-architecture
- if (pkg.isLibrary()) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Shared library with native libs must be multiarch");
- }
- pkg.applicationInfo.primaryCpuAbi = abiList[copyRet];
- } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES && cpuAbiOverride != null) {
- pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride;
- } else if (needsRenderScriptOverride) {
- pkg.applicationInfo.primaryCpuAbi = abiList[0];
- }
- }
- } catch (IOException ioe) {
- Slog.e(TAG, "Unable to get canonical file " + ioe.toString());
- } finally {
- IoUtils.closeQuietly(handle);
- }
-
- // Now that we've calculated the ABIs and determined if it's an internal app,
- // we will go ahead and populate the nativeLibraryPath.
- setNativeLibraryPaths(pkg, sAppLib32InstallDir);
- }
-
- /**
- * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
- * i.e, so that all packages can be run inside a single process if required.
- *
- * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
- * this function will either try and make the ABI for all packages in {@code packagesForUser}
- * match {@code scannedPackage} or will update the ABI of {@code scannedPackage} to match
- * the ABI selected for {@code packagesForUser}. This variant is used when installing or
- * updating a package that belongs to a shared user.
- *
- * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
- * adds unnecessary complexity.
- */
- private static @Nullable List<String> adjustCpuAbisForSharedUserLPw(
- Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
- List<String> changedAbiCodePath = null;
- String requiredInstructionSet = null;
- if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
- requiredInstructionSet = VMRuntime.getInstructionSet(
- scannedPackage.applicationInfo.primaryCpuAbi);
- }
-
- PackageSetting requirer = null;
- for (PackageSetting ps : packagesForUser) {
- // If packagesForUser contains scannedPackage, we skip it. This will happen
- // when scannedPackage is an update of an existing package. Without this check,
- // we will never be able to change the ABI of any package belonging to a shared
- // user, even if it's compatible with other packages.
- if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
- if (ps.primaryCpuAbiString == null) {
- continue;
- }
-
- final String instructionSet = VMRuntime.getInstructionSet(ps.primaryCpuAbiString);
- if (requiredInstructionSet != null && !instructionSet.equals(requiredInstructionSet)) {
- // We have a mismatch between instruction sets (say arm vs arm64) warn about
- // this but there's not much we can do.
- String errorMessage = "Instruction set mismatch, "
- + ((requirer == null) ? "[caller]" : requirer)
- + " requires " + requiredInstructionSet + " whereas " + ps
- + " requires " + instructionSet;
- Slog.w(TAG, errorMessage);
- }
-
- if (requiredInstructionSet == null) {
- requiredInstructionSet = instructionSet;
- requirer = ps;
- }
- }
- }
-
- if (requiredInstructionSet != null) {
- String adjustedAbi;
- if (requirer != null) {
- // requirer != null implies that either scannedPackage was null or that scannedPackage
- // did not require an ABI, in which case we have to adjust scannedPackage to match
- // the ABI of the set (which is the same as requirer's ABI)
- adjustedAbi = requirer.primaryCpuAbiString;
- if (scannedPackage != null) {
- scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
- }
- } else {
- // requirer == null implies that we're updating all ABIs in the set to
- // match scannedPackage.
- adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
- }
-
- for (PackageSetting ps : packagesForUser) {
- if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
- if (ps.primaryCpuAbiString != null) {
- continue;
- }
-
- ps.primaryCpuAbiString = adjustedAbi;
- if (ps.pkg != null && ps.pkg.applicationInfo != null &&
- !TextUtils.equals(adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
- ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
- if (DEBUG_ABI_SELECTION) {
- Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi
- + " (requirer="
- + (requirer != null ? requirer.pkg : "null")
- + ", scannedPackage="
- + (scannedPackage != null ? scannedPackage : "null")
- + ")");
- }
- if (changedAbiCodePath == null) {
- changedAbiCodePath = new ArrayList<>();
- }
- changedAbiCodePath.add(ps.codePathString);
- }
- }
- }
- }
- return changedAbiCodePath;
- }
-
private void setUpCustomResolverActivity(PackageParser.Package pkg) {
synchronized (mPackages) {
mResolverReplaced = true;
@@ -12022,207 +11803,6 @@
| IntentFilter.MATCH_ADJUSTMENT_NORMAL;
}
- private static String calculateBundledApkRoot(final String codePathString) {
- final File codePath = new File(codePathString);
- final File codeRoot;
- if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
- codeRoot = Environment.getRootDirectory();
- } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
- codeRoot = Environment.getOemDirectory();
- } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
- codeRoot = Environment.getVendorDirectory();
- } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
- codeRoot = Environment.getOdmDirectory();
- } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
- codeRoot = Environment.getProductDirectory();
- } else if (FileUtils.contains(Environment.getSystemExtDirectory(), codePath)) {
- codeRoot = Environment.getSystemExtDirectory();
- } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
- codeRoot = Environment.getOdmDirectory();
- } else {
- // Unrecognized code path; take its top real segment as the apk root:
- // e.g. /something/app/blah.apk => /something
- try {
- File f = codePath.getCanonicalFile();
- File parent = f.getParentFile(); // non-null because codePath is a file
- File tmp;
- while ((tmp = parent.getParentFile()) != null) {
- f = parent;
- parent = tmp;
- }
- codeRoot = f;
- Slog.w(TAG, "Unrecognized code path "
- + codePath + " - using " + codeRoot);
- } catch (IOException e) {
- // Can't canonicalize the code path -- shenanigans?
- Slog.w(TAG, "Can't canonicalize code path " + codePath);
- return Environment.getRootDirectory().getPath();
- }
- }
- return codeRoot.getPath();
- }
-
- /**
- * Derive and set the location of native libraries for the given package,
- * which varies depending on where and how the package was installed.
- */
- private static void setNativeLibraryPaths(PackageParser.Package pkg, File appLib32InstallDir) {
- final ApplicationInfo info = pkg.applicationInfo;
- final String codePath = pkg.codePath;
- final File codeFile = new File(codePath);
- final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp();
-
- info.nativeLibraryRootDir = null;
- info.nativeLibraryRootRequiresIsa = false;
- info.nativeLibraryDir = null;
- info.secondaryNativeLibraryDir = null;
-
- if (isApkFile(codeFile)) {
- // Monolithic install
- if (bundledApp) {
- // If "/system/lib64/apkname" exists, assume that is the per-package
- // native library directory to use; otherwise use "/system/lib/apkname".
- final String apkRoot = calculateBundledApkRoot(info.sourceDir);
- final boolean is64Bit = VMRuntime.is64BitInstructionSet(
- getPrimaryInstructionSet(info));
-
- // This is a bundled system app so choose the path based on the ABI.
- // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
- // is just the default path.
- final String apkName = deriveCodePathName(codePath);
- final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
- info.nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
- apkName).getAbsolutePath();
-
- if (info.secondaryCpuAbi != null) {
- final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
- info.secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
- secondaryLibDir, apkName).getAbsolutePath();
- }
- } else {
- final String apkName = deriveCodePathName(codePath);
- info.nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
- .getAbsolutePath();
- }
-
- info.nativeLibraryRootRequiresIsa = false;
- info.nativeLibraryDir = info.nativeLibraryRootDir;
- } else {
- // Cluster install
- info.nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
- info.nativeLibraryRootRequiresIsa = true;
-
- info.nativeLibraryDir = new File(info.nativeLibraryRootDir,
- getPrimaryInstructionSet(info)).getAbsolutePath();
-
- if (info.secondaryCpuAbi != null) {
- info.secondaryNativeLibraryDir = new File(info.nativeLibraryRootDir,
- VMRuntime.getInstructionSet(info.secondaryCpuAbi)).getAbsolutePath();
- }
- }
- }
-
- /**
- * Calculate the abis and roots for a bundled app. These can uniquely
- * be determined from the contents of the system partition, i.e whether
- * it contains 64 or 32 bit shared libraries etc. We do not validate any
- * of this information, and instead assume that the system was built
- * sensibly.
- */
- private static void setBundledAppAbisAndRoots(PackageParser.Package pkg,
- PackageSetting pkgSetting) {
- final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
-
- // If "/system/lib64/apkname" exists, assume that is the per-package
- // native library directory to use; otherwise use "/system/lib/apkname".
- final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
- setBundledAppAbi(pkg, apkRoot, apkName);
- // pkgSetting might be null during rescan following uninstall of updates
- // to a bundled app, so accommodate that possibility. The settings in
- // that case will be established later from the parsed package.
- //
- // If the settings aren't null, sync them up with what we've just derived.
- // note that apkRoot isn't stored in the package settings.
- if (pkgSetting != null) {
- pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
- pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
- }
- }
-
- /**
- * Deduces the ABI of a bundled app and sets the relevant fields on the
- * parsed pkg object.
- *
- * @param apkRoot the root of the installed apk, something like {@code /system} or {@code /oem}
- * under which system libraries are installed.
- * @param apkName the name of the installed package.
- */
- private static void setBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
- final File codeFile = new File(pkg.codePath);
-
- final boolean has64BitLibs;
- final boolean has32BitLibs;
- if (isApkFile(codeFile)) {
- // Monolithic install
- has64BitLibs = (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
- has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
- } else {
- // Cluster install
- final File rootDir = new File(codeFile, LIB_DIR_NAME);
- if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
- && !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
- final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
- has64BitLibs = (new File(rootDir, isa)).exists();
- } else {
- has64BitLibs = false;
- }
- if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
- && !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
- final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
- has32BitLibs = (new File(rootDir, isa)).exists();
- } else {
- has32BitLibs = false;
- }
- }
-
- if (has64BitLibs && !has32BitLibs) {
- // The package has 64 bit libs, but not 32 bit libs. Its primary
- // ABI should be 64 bit. We can safely assume here that the bundled
- // native libraries correspond to the most preferred ABI in the list.
-
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
- pkg.applicationInfo.secondaryCpuAbi = null;
- } else if (has32BitLibs && !has64BitLibs) {
- // The package has 32 bit libs but not 64 bit libs. Its primary
- // ABI should be 32 bit.
-
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
- pkg.applicationInfo.secondaryCpuAbi = null;
- } else if (has32BitLibs && has64BitLibs) {
- // The application has both 64 and 32 bit bundled libraries. We check
- // here that the app declares multiArch support, and warn if it doesn't.
- //
- // We will be lenient here and record both ABIs. The primary will be the
- // ABI that's higher on the list, i.e, a device that's configured to prefer
- // 64 bit apps will see a 64 bit primary ABI,
-
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
- Slog.e(TAG, "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
- }
-
- if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
- pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
- } else {
- pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
- pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
- }
- } else {
- pkg.applicationInfo.primaryCpuAbi = null;
- pkg.applicationInfo.secondaryCpuAbi = null;
- }
- }
-
private void killApplication(String pkgName, int appId, String reason) {
killApplication(pkgName, appId, UserHandle.USER_ALL, reason);
}
@@ -12948,7 +12528,8 @@
// upgrade app from instant to full; we don't allow app downgrade
installed = true;
}
- setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
+ setInstantAppForUser(
+ getUserManagerInternal(), pkgSetting, userId, instantApp, fullApp);
}
if (installed) {
@@ -12996,8 +12577,8 @@
}
}
- static void setInstantAppForUser(PackageSetting pkgSetting, int userId,
- boolean instantApp, boolean fullApp) {
+ static void setInstantAppForUser(UserManagerInternal userManager, PackageSetting pkgSetting,
+ int userId, boolean instantApp, boolean fullApp) {
// no state specified; do nothing
if (!instantApp && !fullApp) {
return;
@@ -13009,7 +12590,7 @@
pkgSetting.setInstantApp(false /*instantApp*/, userId);
}
} else {
- for (int currentUserId : sUserManager.getUserIds()) {
+ for (int currentUserId : userManager.getUserIds()) {
if (instantApp && !pkgSetting.getInstantApp(currentUserId)) {
pkgSetting.setInstantApp(true /*instantApp*/, currentUserId);
} else if (fullApp && pkgSetting.getInstantApp(currentUserId)) {
@@ -15201,16 +14782,6 @@
}
}
- private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
- PackageManagerException {
- if (copyRet < 0) {
- if (copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
- copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
- throw new PackageManagerException(copyRet, message);
- }
- }
- }
-
/**
* Logic to handle movement of existing installed applications.
*/
@@ -15337,26 +14908,6 @@
return result;
}
- // Utility method that returns the relative package path with respect
- // to the installation directory. Like say for /data/data/com.test-1.apk
- // string com.test-1 is returned.
- static String deriveCodePathName(String codePath) {
- if (codePath == null) {
- return null;
- }
- final File codeFile = new File(codePath);
- final String name = codeFile.getName();
- if (codeFile.isDirectory()) {
- return name;
- } else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
- final int lastDot = name.lastIndexOf('.');
- return name.substring(0, lastDot);
- } else {
- Slog.w(TAG, "Odd, " + codePath + " doesn't look like an APK");
- return null;
- }
- }
-
static class PackageInstalledInfo {
String name;
int uid;
@@ -16288,7 +15839,8 @@
final PrepareResult prepareResult;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
- prepareResult = preparePackageLI(request.args, request.installResult);
+ prepareResult =
+ preparePackageLI(request.args, request.installResult);
} catch (PrepareFailure prepareFailure) {
request.installResult.setError(prepareFailure.error,
prepareFailure.getMessage());
@@ -16948,7 +16500,7 @@
String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
args.abiOverride : pkg.cpuAbiOverride);
final boolean extractNativeLibs = !pkg.isLibrary();
- derivePackageAbi(pkg, abiOverride, extractNativeLibs);
+ mInjector.getAbiHelper().derivePackageAbi(pkg, abiOverride, extractNativeLibs);
} catch (PackageManagerException pme) {
Slog.e(TAG, "Error deriving application ABI", pme);
throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
@@ -17477,10 +17029,6 @@
}
}
- private static boolean isMultiArch(ApplicationInfo info) {
- return (info.flags & ApplicationInfo.FLAG_MULTIARCH) != 0;
- }
-
private static boolean isExternal(PackageParser.Package pkg) {
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
@@ -17489,7 +17037,7 @@
return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
- private static boolean isSystemApp(PackageParser.Package pkg) {
+ static boolean isSystemApp(PackageParser.Package pkg) {
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 58f262c..029673f 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -270,7 +270,8 @@
updateAvailable = orig.updateAvailable;
}
- private PackageUserState modifyUserState(int userId) {
+ @VisibleForTesting
+ PackageUserState modifyUserState(int userId) {
PackageUserState state = mUserState.get(userId);
if (state == null) {
state = new PackageUserState();
@@ -463,6 +464,18 @@
state.harmfulAppWarning = harmfulAppWarning;
}
+ void setUserState(int userId, PackageUserState otherState) {
+ setUserState(userId, otherState.ceDataInode, otherState.enabled, otherState.installed,
+ otherState.stopped, otherState.notLaunched, otherState.hidden,
+ otherState.distractionFlags, otherState.suspended, otherState.suspendingPackage,
+ otherState.dialogInfo, otherState.suspendedAppExtras,
+ otherState.suspendedLauncherExtras, otherState.instantApp,
+ otherState.virtualPreload, otherState.lastDisableAppCaller,
+ otherState.enabledComponents, otherState.disabledComponents,
+ otherState.domainVerificationStatus, otherState.appLinkGeneration,
+ otherState.installReason, otherState.harmfulAppWarning);
+ }
+
ArraySet<String> getEnabledComponents(int userId) {
return readUserState(userId).enabledComponents;
}
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index b829f0b..f7b60c2 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -8,6 +8,20 @@
},
{
"name": "CtsCompilationTestCases"
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.pm."
+ },
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
],
"postsubmit": [
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 673ab6c..03be8e1 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -54,6 +54,7 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
+import android.app.AppOpsManager;
import android.app.ApplicationPackageManager;
import android.app.IActivityManager;
import android.content.Context;
@@ -1447,7 +1448,7 @@
/**
* Reverts user permission state changes (permissions and flags).
*
- * @param ps The package for which to reset.
+ * @param pkg The package for which to reset.
* @param userId The device user for which to do a reset.
*/
@GuardedBy("mPackages")
@@ -1521,6 +1522,7 @@
}
};
+ final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
for (int i = 0; i < permissionCount; i++) {
final String permName = pkg.requestedPermissions.get(i);
final BasePermission bp;
@@ -1588,6 +1590,14 @@
if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
grantRuntimePermissionInternal(permName, packageName, false,
Process.SYSTEM_UID, userId, delayingPermCallback);
+ // Allow app op later as we are holding mPackages
+ // PermissionPolicyService will handle the app op for foreground/background
+ // permissions.
+ String appOp = AppOpsManager.permissionToOp(permName);
+ if (appOp != null) {
+ mHandler.post(() -> appOpsManager.setUidMode(appOp, uid,
+ AppOpsManager.MODE_ALLOWED));
+ }
// If permission review is enabled the permissions for a legacy apps
// are represented as constantly granted runtime ones, so don't revoke.
} else if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index beff5fb..1c56a10 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1191,8 +1191,7 @@
final PackageInfo packageInfo;
try {
packageInfo = mService.mContext.getPackageManager()
- .getPackageInfoAsUser(callingPackage, PackageManager.GET_PERMISSIONS,
- UserHandle.getUserId(callingUid));
+ .getPackageInfo(callingPackage, PackageManager.GET_PERMISSIONS);
} catch (PackageManager.NameNotFoundException e) {
Slog.i(TAG, "Cannot find package info for " + callingPackage);
return ACTIVITY_RESTRICTION_NONE;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7e741a0..b351faf 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1012,7 +1012,6 @@
public final int startActivities(IApplicationThread caller, String callingPackage,
Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions,
int userId) {
- assertPackageMatchesCallingUid(callingPackage);
final String reason = "startActivities";
enforceNotIsolatedCaller(reason);
userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, reason);
@@ -1032,11 +1031,10 @@
true /*validateIncomingUser*/);
}
- private int startActivityAsUser(IApplicationThread caller, String callingPackage,
+ int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
boolean validateIncomingUser) {
- assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
@@ -1209,7 +1207,6 @@
public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
- assertPackageMatchesCallingUid(callingPackage);
final WaitResult res = new WaitResult();
synchronized (mGlobalLock) {
enforceNotIsolatedCaller("startActivityAndWait");
@@ -1237,7 +1234,6 @@
public final int startActivityWithConfig(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, Configuration config, Bundle bOptions, int userId) {
- assertPackageMatchesCallingUid(callingPackage);
synchronized (mGlobalLock) {
enforceNotIsolatedCaller("startActivityWithConfig");
userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
@@ -1287,7 +1283,6 @@
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, IBinder permissionToken,
boolean ignoreTargetSecurity, int userId) {
- assertPackageMatchesCallingUid(callingPackage);
// This is very dangerous -- it allows you to perform a start activity (including
// permission grants) as any app that may launch one of your own activities. So we only
// allow this in two cases:
@@ -1417,7 +1412,6 @@
Intent intent, String resolvedType, IVoiceInteractionSession session,
IVoiceInteractor interactor, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions, int userId) {
- assertPackageMatchesCallingUid(callingPackage);
mAmInternal.enforceCallingPermission(BIND_VOICE_INTERACTION, "startVoiceActivity()");
if (session == null || interactor == null) {
throw new NullPointerException("null session or interactor");
@@ -1441,7 +1435,6 @@
@Override
public int startAssistantActivity(String callingPackage, int callingPid, int callingUid,
Intent intent, String resolvedType, Bundle bOptions, int userId) {
- assertPackageMatchesCallingUid(callingPackage);
mAmInternal.enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()");
userId = handleIncomingUser(callingPid, callingUid, userId, "startAssistantActivity");
@@ -2367,9 +2360,15 @@
void moveTaskToFrontLocked(@Nullable IApplicationThread appThread,
@Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options,
boolean fromRecents) {
+
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
- assertPackageMatchesCallingUid(callingPackage);
+ if (!isSameApp(callingUid, callingPackage)) {
+ String msg = "Permission Denial: moveTaskToFrontLocked() from pid="
+ + Binder.getCallingPid() + " as package " + callingPackage;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
if (!checkAppSwitchAllowedLocked(callingPid, callingUid, -1, -1, "Task to front")) {
SafeActivityOptions.abort(options);
return;
@@ -2421,7 +2420,7 @@
/**
* Return true if callingUid is system, or packageName belongs to that callingUid.
*/
- private boolean isSameApp(int callingUid, @Nullable String packageName) {
+ boolean isSameApp(int callingUid, @Nullable String packageName) {
try {
if (callingUid != 0 && callingUid != SYSTEM_UID) {
if (packageName == null) {
@@ -2438,21 +2437,6 @@
return true;
}
- /**
- * Checks that the provided package name matches the current calling UID, throws a security
- * exception if it doesn't.
- */
- void assertPackageMatchesCallingUid(@Nullable String packageName) {
- final int callingUid = Binder.getCallingUid();
- if (isSameApp(callingUid, packageName)) {
- return;
- }
- final String msg = "Permission Denial: package=" + packageName
- + " does not belong to uid=" + callingUid;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
-
boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
int callingPid, int callingUid, String name) {
if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
@@ -2986,7 +2970,6 @@
@Override
public List<IBinder> getAppTasks(String callingPackage) {
int callingUid = Binder.getCallingUid();
- assertPackageMatchesCallingUid(callingPackage);
long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -6093,7 +6076,6 @@
SafeActivityOptions options, int userId, boolean validateIncomingUser,
PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart) {
- assertPackageMatchesCallingUid(callingPackage);
synchronized (mGlobalLock) {
return getActivityStartController().startActivitiesInPackage(uid, realCallingPid,
realCallingUid, callingPackage, intents, resolvedTypes, resultTo, options,
@@ -6109,7 +6091,6 @@
int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
PendingIntentRecord originatingPendingIntent,
boolean allowBackgroundActivityStart) {
- assertPackageMatchesCallingUid(callingPackage);
synchronized (mGlobalLock) {
return getActivityStartController().startActivityInPackage(uid, realCallingPid,
realCallingUid, callingPackage, intent, resolvedType, resultTo, resultWho,
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index a8f7768..1eb7455 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -27,6 +27,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.UserHandle;
+import android.util.Slog;
/**
* An implementation of IAppTask, that allows an app to manage its own tasks via
@@ -96,7 +97,12 @@
// Will bring task to front if it already has a root activity.
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
- mService.assertPackageMatchesCallingUid(callingPackage);
+ if (!mService.isSameApp(callingUid, callingPackage)) {
+ String msg = "Permission Denial: moveToFront() from pid="
+ + Binder.getCallingPid() + " as package " + callingPackage;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mService.mGlobalLock) {
@@ -128,7 +134,6 @@
public int startActivity(IBinder whoThread, String callingPackage,
Intent intent, String resolvedType, Bundle bOptions) {
checkCaller();
- mService.assertPackageMatchesCallingUid(callingPackage);
int callingUser = UserHandle.getCallingUserId();
TaskRecord tr;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 592fa58..aefc152 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -2487,7 +2487,7 @@
// transformed the task.
final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
if (controller != null && controller.isAnimatingTask(getTask())
- && controller.shouldCancelWithDeferredScreenshot()) {
+ && controller.shouldDeferCancelUntilNextTransition()) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index a46fa13..207e8ef 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -30,6 +30,7 @@
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.os.Environment;
+import android.os.FileUtils;
import android.provider.Settings;
import android.util.AtomicFile;
import android.util.Slog;
@@ -64,6 +65,11 @@
class DisplayWindowSettings {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayWindowSettings" : TAG_WM;
+ private static final String SYSTEM_DIRECTORY = "system";
+ private static final String DISPLAY_SETTINGS_FILE_NAME = "display_settings.xml";
+ private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/" + DISPLAY_SETTINGS_FILE_NAME;
+ private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays";
+
private static final int IDENTIFIER_UNIQUE_ID = 0;
private static final int IDENTIFIER_PORT = 1;
@IntDef(prefix = { "IDENTIFIER_" }, value = {
@@ -688,8 +694,26 @@
private final AtomicFile mAtomicFile;
AtomicFileStorage() {
- final File folder = new File(Environment.getDataDirectory(), "system");
- mAtomicFile = new AtomicFile(new File(folder, "display_settings.xml"), "wm-displays");
+ final File folder = new File(Environment.getDataDirectory(), SYSTEM_DIRECTORY);
+ final File settingsFile = new File(folder, DISPLAY_SETTINGS_FILE_NAME);
+ // If display_settings.xml doesn't exist, try to copy the vendor's one instead
+ // in order to provide the vendor specific initialization.
+ if (!settingsFile.exists()) {
+ copyVendorSettings(settingsFile);
+ }
+ mAtomicFile = new AtomicFile(settingsFile, WM_DISPLAY_COMMIT_TAG);
+ }
+
+ private static void copyVendorSettings(File target) {
+ final File vendorFile = new File(Environment.getVendorDirectory(),
+ VENDOR_DISPLAY_SETTINGS_PATH);
+ if (vendorFile.canRead()) {
+ try {
+ FileUtils.copy(vendorFile, target);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to copy vendor display_settings.xml");
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 422b6e5..85ba95f 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -90,24 +90,11 @@
}
/**
- * @return true if either Keyguard or AOD are showing, not going away, and not being occluded
- * on the given display, false otherwise.
+ * @return true if either 1) AOD is showing, or 2) Keyguard is showing, not going away, and not
+ * being occluded on the given display, false otherwise.
*/
boolean isKeyguardOrAodShowing(int displayId) {
- return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway
- && !isDisplayOccluded(displayId);
- }
-
- /**
- * @return {@code true} for default display when AOD is showing. Otherwise, same as
- * {@link #isKeyguardOrAodShowing(int)}
- * TODO(b/125198167): Replace isKeyguardOrAodShowing() by this logic.
- */
- boolean isKeyguardUnoccludedOrAodShowing(int displayId) {
- if (displayId == DEFAULT_DISPLAY && mAodShowing) {
- return true;
- }
- return isKeyguardOrAodShowing(displayId);
+ return mAodShowing || isKeyguardShowing(displayId);
}
/**
@@ -115,7 +102,7 @@
* display, false otherwise
*/
boolean isKeyguardShowing(int displayId) {
- return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId);
+ return mKeyguardShowing && !mKeyguardGoingAway && !isKeyguardOccluded(displayId);
}
/**
@@ -328,7 +315,7 @@
return;
}
- mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY));
+ mWindowManager.onKeyguardOccludedChanged(isKeyguardOccluded(DEFAULT_DISPLAY));
if (isKeyguardLocked()) {
mWindowManager.deferSurfaceLayout();
try {
@@ -373,7 +360,7 @@
}
}
- private boolean isDisplayOccluded(int displayId) {
+ private boolean isKeyguardOccluded(int displayId) {
return getDisplay(displayId).mOccluded;
}
@@ -391,13 +378,13 @@
if (mBeforeUnoccludeTransit != TRANSIT_UNSET
&& dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
// TODO(b/113840485): Handle app transition for individual display.
- && isDisplayOccluded(DEFAULT_DISPLAY)) {
+ && isKeyguardOccluded(DEFAULT_DISPLAY)) {
// Reuse old transit in case we are occluding Keyguard again, meaning that we never
// actually occclude/unocclude Keyguard, but just run a normal transition.
return mBeforeUnoccludeTransit;
// TODO(b/113840485): Handle app transition for individual display.
- } else if (!isDisplayOccluded(DEFAULT_DISPLAY)) {
+ } else if (!isKeyguardOccluded(DEFAULT_DISPLAY)) {
// Save transit in case we dismiss/occlude Keyguard shortly after.
mBeforeUnoccludeTransit = dc.mAppTransition.getAppTransition();
@@ -409,7 +396,7 @@
private void dismissDockedStackIfNeeded() {
// TODO(b/113840485): Handle docked stack for individual display.
- if (mKeyguardShowing && isDisplayOccluded(DEFAULT_DISPLAY)) {
+ if (mKeyguardShowing && isKeyguardOccluded(DEFAULT_DISPLAY)) {
// The lock screen is currently showing, but is occluded by a window that can
// show on top of the lock screen. In this can we want to dismiss the docked
// stack since it will be complicated/risky to try to put the activity on top
@@ -434,9 +421,9 @@
private void updateKeyguardSleepToken(int displayId) {
final KeyguardDisplayState state = getDisplay(displayId);
- if (isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken == null) {
+ if (isKeyguardOrAodShowing(displayId) && state.mSleepToken == null) {
state.acquiredSleepToken();
- } else if (!isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken != null) {
+ } else if (!isKeyguardOrAodShowing(displayId) && state.mSleepToken != null) {
state.releaseSleepToken();
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index bf627ec..0a3e7a4 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -355,7 +355,7 @@
// launch-behind state is restored. That also prevents the next transition
// type being disturbed if the visibility is updated after setting the next
// transition (the target activity will be one of closing apps).
- if (!controller.shouldCancelWithDeferredScreenshot()
+ if (!controller.shouldDeferCancelWithScreenshot()
&& !targetStack.isFocusedStackOnDisplay()) {
targetStack.ensureActivitiesVisibleLocked(null /* starting */,
0 /* starting */, false /* preserveWindows */);
@@ -415,16 +415,18 @@
final DisplayContent dc =
mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
dc.mBoundsAnimationController.setAnimationType(
- controller.shouldCancelWithDeferredScreenshot() ? FADE_IN : BOUNDS);
+ controller.shouldDeferCancelUntilNextTransition() ? FADE_IN : BOUNDS);
- // Cancel running recents animation and screenshot previous task when the next
- // transition starts in below cases:
- // 1) The next launching task is not in recents animation task.
+ // We defer canceling the recents animation until the next app transition in the following
+ // cases:
+ // 1) The next launching task is not being animated by the recents animation
// 2) The next task is home activity. (i.e. pressing home key to back home in recents).
if ((!controller.isAnimatingTask(stack.getTaskStack().getTopChild())
|| controller.isTargetApp(stack.getTopActivity().mAppWindowToken))
- && controller.shouldCancelWithDeferredScreenshot()) {
- controller.cancelOnNextTransitionStart();
+ && controller.shouldDeferCancelUntilNextTransition()) {
+ // Always prepare an app transition since we rely on the transition callbacks to cleanup
+ mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+ controller.setCancelOnNextTransitionStart();
} else {
// Just cancel directly to unleash from launcher when the next launching task is the
// current top task.
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 163be1e..6ea4d58 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -97,10 +97,9 @@
private final Runnable mFailsafeRunnable = () ->
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "failSafeRunnable");
- final Object mLock = new Object();
-
// The recents component app token that is shown behind the visibile tasks
private AppWindowToken mTargetAppToken;
+ private DisplayContent mDisplayContent;
private int mTargetActivityType;
private Rect mMinimizedHomeBounds = new Rect();
@@ -124,25 +123,47 @@
private boolean mLinkedToDeathOfRunner;
- private boolean mCancelWithDeferredScreenshot;
-
+ // Whether to try to defer canceling from a stack order change until the next transition
+ private boolean mRequestDeferCancelUntilNextTransition;
+ // Whether to actually defer canceling until the next transition
private boolean mCancelOnNextTransitionStart;
+ // Whether to take a screenshot when handling a deferred cancel
+ private boolean mCancelDeferredWithScreenshot;
/**
* Animates the screenshot of task that used to be controlled by RecentsAnimation.
- * @see {@link #cancelOnNextTransitionStart}
+ * @see {@link #setCancelOnNextTransitionStart}
*/
SurfaceAnimator mRecentScreenshotAnimator;
+ /**
+ * An app transition listener to cancel the recents animation only after the app transition
+ * starts or is canceled.
+ */
final AppTransitionListener mAppTransitionListener = new AppTransitionListener() {
@Override
public int onAppTransitionStartingLocked(int transit, long duration,
long statusBarAnimationStartTime, long statusBarAnimationDuration) {
- onTransitionStart();
- mService.mRoot.getDisplayContent(mDisplayId).mAppTransition
- .unregisterListener(this);
+ continueDeferredCancel();
return 0;
}
+
+ @Override
+ public void onAppTransitionCancelledLocked(int transit) {
+ continueDeferredCancel();
+ }
+
+ private void continueDeferredCancel() {
+ mDisplayContent.mAppTransition.unregisterListener(this);
+ if (mCanceled) {
+ return;
+ }
+
+ if (mCancelOnNextTransitionStart) {
+ mCancelOnNextTransitionStart = false;
+ cancelAnimationWithScreenshot(mCancelDeferredWithScreenshot);
+ }
+ }
};
public interface RecentsAnimationCallbacks {
@@ -202,8 +223,7 @@
? REORDER_MOVE_TO_TOP
: REORDER_MOVE_TO_ORIGINAL_POSITION,
true /* runSynchronously */, sendUserLeaveHint);
- final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
- dc.mBoundsAnimationController.setAnimationType(FADE_IN);
+ mDisplayContent.mBoundsAnimationController.setAnimationType(FADE_IN);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -240,8 +260,7 @@
}
mInputConsumerEnabled = enabled;
- final InputMonitor inputMonitor =
- mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+ final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
inputMonitor.updateInputWindowsLw(true /*force*/);
mService.scheduleAnimationLocked();
}
@@ -282,15 +301,23 @@
}
@Override
+ @Deprecated
public void setCancelWithDeferredScreenshot(boolean screenshot) {
- synchronized (mLock) {
- setCancelWithDeferredScreenshotLocked(screenshot);
+ synchronized (mService.mGlobalLock) {
+ setDeferredCancel(true /* deferred */, screenshot);
+ }
+ }
+
+ @Override
+ public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
+ synchronized (mService.mGlobalLock) {
+ setDeferredCancel(defer, screenshot);
}
}
@Override
public void cleanupScreenshot() {
- synchronized (mLock) {
+ synchronized (mService.mGlobalLock) {
if (mRecentScreenshotAnimator != null) {
mRecentScreenshotAnimator.cancelAnimation();
mRecentScreenshotAnimator = null;
@@ -312,10 +339,7 @@
mCallbacks = callbacks;
mDisplayId = displayId;
mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
- }
-
- public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
- initialize(mService.mRoot.getDisplayContent(mDisplayId), targetActivityType, recentTaskIds);
+ mDisplayContent = service.mRoot.getDisplayContent(displayId);
}
/**
@@ -323,15 +347,15 @@
* because it may call cancelAnimation() which needs to properly clean up the controller
* in the window manager.
*/
- @VisibleForTesting
- void initialize(DisplayContent dc, int targetActivityType, SparseBooleanArray recentTaskIds) {
+ public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
mTargetActivityType = targetActivityType;
- dc.mAppTransition.registerListenerLocked(mAppTransitionListener);
+ mDisplayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
// Make leashes for each of the visible/target tasks and add it to the recents animation to
// be started
- final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
- final TaskStack targetStack = dc.getStack(WINDOWING_MODE_UNDEFINED, targetActivityType);
+ final ArrayList<Task> visibleTasks = mDisplayContent.getVisibleTasks();
+ final TaskStack targetStack = mDisplayContent.getStack(WINDOWING_MODE_UNDEFINED,
+ targetActivityType);
if (targetStack != null) {
for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
final Task t = targetStack.getChildAt(i);
@@ -365,29 +389,31 @@
}
// Adjust the wallpaper visibility for the showing target activity
- final AppWindowToken recentsComponentAppToken = dc.getStack(WINDOWING_MODE_UNDEFINED,
- targetActivityType).getTopChild().getTopFullscreenAppToken();
+ final AppWindowToken recentsComponentAppToken =
+ targetStack.getTopChild().getTopFullscreenAppToken();
if (recentsComponentAppToken != null) {
if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setHomeApp("
+ recentsComponentAppToken.getName() + ")");
mTargetAppToken = recentsComponentAppToken;
if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) {
- dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- dc.setLayoutNeeded();
+ mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ mDisplayContent.setLayoutNeeded();
}
}
// Save the minimized home height
- final TaskStack dockedStack = dc.getSplitScreenPrimaryStackIgnoringVisibility();
- dc.getDockedDividerController().getHomeStackBoundsInDockedMode(
- dc.getConfiguration(),
+ final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+ mDisplayContent.getDockedDividerController().getHomeStackBoundsInDockedMode(
+ mDisplayContent.getConfiguration(),
dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide(),
mMinimizedHomeBounds);
mService.mWindowPlacerLocked.performSurfacePlacement();
// Notify that the animation has started
- mStatusBar.onRecentsAnimationStateChanged(true /* running */);
+ if (mStatusBar != null) {
+ mStatusBar.onRecentsAnimationStateChanged(true /* running */);
+ }
}
@VisibleForTesting
@@ -441,8 +467,7 @@
// Perform layout if it was scheduled before to make sure that we get correct content
// insets for the target app window after a rotation
- final DisplayContent displayContent = mService.mRoot.getDisplayContent(mDisplayId);
- displayContent.performLayout(false /* initial */, false /* updateInputWindows */);
+ mDisplayContent.performLayout(false /* initial */, false /* updateInputWindows */);
final Rect minimizedHomeBounds = mTargetAppToken != null
&& mTargetAppToken.inSplitScreenSecondaryWindowingMode()
@@ -480,9 +505,8 @@
cancelAnimation(reorderMode, true /* runSynchronously */, false /* screenshot */, reason);
}
- void cancelAnimationWithScreenShot() {
- cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, true /* screenshot */,
- "stackOrderChanged");
+ void cancelAnimationWithScreenshot(boolean screenshot) {
+ cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, screenshot, "stackOrderChanged");
}
private void cancelAnimation(@ReorderMode int reorderMode, boolean runSynchronously,
@@ -496,21 +520,29 @@
}
mService.mH.removeCallbacks(mFailsafeRunnable);
mCanceled = true;
- try {
- if (screenshot) {
- // Screen shot previous task when next task starts transition.
- final Task task = mPendingAnimations.get(0).mTask;
- screenshotRecentTask(task, reorderMode, runSynchronously);
+
+ if (screenshot) {
+ // Screen shot previous task when next task starts transition and notify the runner.
+ // We will actually finish the animation once the runner calls cleanUpScreenshot().
+ final Task task = mPendingAnimations.get(0).mTask;
+ screenshotRecentTask(task, reorderMode, runSynchronously);
+ try {
mRunner.onAnimationCanceled(true /* deferredWithScreenshot */);
- return;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to cancel recents animation", e);
}
- mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to cancel recents animation", e);
+ } else {
+ // Otherwise, notify the runner and clean up the animation immediately
+ // Note: In the fallback case, this can trigger multiple onAnimationCancel() calls
+ // to the runner if we this actually triggers cancel twice on the caller
+ try {
+ mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to cancel recents animation", e);
+ }
+ mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
+ false /* sendUserLeaveHint */);
}
- // Clean up and return to the previous app
- mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
- false /* sendUserLeaveHint */);
}
}
@@ -523,27 +555,36 @@
* screenshot, so that Launcher can still control the leash lifecycle & make the next app
* transition animate smoothly without flickering.
*/
- void cancelOnNextTransitionStart() {
+ void setCancelOnNextTransitionStart() {
mCancelOnNextTransitionStart = true;
}
- void setCancelWithDeferredScreenshotLocked(boolean screenshot) {
- mCancelWithDeferredScreenshot = screenshot;
+ /**
+ * Requests that we attempt to defer the cancel until the next app transition if we are
+ * canceling from a stack order change. If {@param screenshot} is specified, then the system
+ * will replace the contents of the leash with a screenshot, which must be cleaned up when the
+ * runner calls cleanUpScreenshot().
+ */
+ void setDeferredCancel(boolean defer, boolean screenshot) {
+ mRequestDeferCancelUntilNextTransition = defer;
+ mCancelDeferredWithScreenshot = screenshot;
}
- boolean shouldCancelWithDeferredScreenshot() {
- return mCancelWithDeferredScreenshot;
+ /**
+ * @return Whether we should defer the cancel from a stack order change until the next app
+ * transition.
+ */
+ boolean shouldDeferCancelUntilNextTransition() {
+ return mRequestDeferCancelUntilNextTransition;
}
- void onTransitionStart() {
- if (mCanceled) {
- return;
- }
-
- if (mCancelOnNextTransitionStart) {
- mCancelOnNextTransitionStart = false;
- cancelAnimationWithScreenShot();
- }
+ /**
+ * @return Whether we should both defer the cancel from a stack order change until the next
+ * app transition, and also that the deferred cancel should replace the contents of the leash
+ * with a screenshot.
+ */
+ boolean shouldDeferCancelWithScreenshot() {
+ return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
}
void screenshotRecentTask(Task task, @ReorderMode int reorderMode, boolean runSynchronously) {
@@ -576,6 +617,7 @@
// Clear any pending failsafe runnables
mService.mH.removeCallbacks(mFailsafeRunnable);
+ mDisplayContent.mAppTransition.unregisterListener(mAppTransitionListener);
// Clear references to the runner
unlinkToDeathOfRunner();
@@ -589,21 +631,22 @@
}
// Update the input windows after the animation is complete
- final InputMonitor inputMonitor =
- mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+ final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
inputMonitor.updateInputWindowsLw(true /*force*/);
// We have deferred all notifications to the target app as a part of the recents animation,
// so if we are actually transitioning there, notify again here
if (mTargetAppToken != null) {
if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
- mService.mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.notifyAppTransitionFinishedLocked(mTargetAppToken.token);
+ mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(
+ mTargetAppToken.token);
}
}
// Notify that the animation has ended
- mStatusBar.onRecentsAnimationStateChanged(false /* running */);
+ if (mStatusBar != null) {
+ mStatusBar.onRecentsAnimationStateChanged(false /* running */);
+ }
}
void scheduleFailsafe() {
@@ -630,8 +673,7 @@
synchronized (mService.getWindowManagerLock()) {
// Clear associated input consumers on runner death
- final InputMonitor inputMonitor =
- mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+ final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
inputMonitor.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
}
}
@@ -827,5 +869,11 @@
pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized);
pw.print(innerPrefix); pw.println("mTargetAppToken=" + mTargetAppToken);
pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper());
+ pw.print(innerPrefix); pw.println("mRequestDeferCancelUntilNextTransition="
+ + mRequestDeferCancelUntilNextTransition);
+ pw.print(innerPrefix); pw.println("mCancelOnNextTransitionStart="
+ + mCancelOnNextTransitionStart);
+ pw.print(innerPrefix); pw.println("mCancelDeferredWithScreenshot="
+ + mCancelDeferredWithScreenshot);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
index 1a57168..143543e 100644
--- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
+++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
@@ -28,7 +28,7 @@
* Class used by {@link RecentsAnimationController} to create a surface control with taking
* screenshot of task when canceling recents animation.
*
- * @see {@link RecentsAnimationController#cancelOnNextTransitionStart}
+ * @see {@link RecentsAnimationController#setCancelOnNextTransitionStart}
*/
class TaskScreenshotAnimatable implements SurfaceAnimator.Animatable {
private static final String TAG = "TaskScreenshotAnim";
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 636f4e6..05cfbd4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -511,4 +511,9 @@
*/
public abstract void removeNonHighRefreshRatePackage(@NonNull String packageName);
+ /**
+ * Checks if this display is touchable.
+ */
+ public abstract boolean isTouchableDisplay(int displayId);
+
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 70e446c..fbdc54a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7455,6 +7455,17 @@
.removeNonHighRefreshRatePackage(packageName));
}
}
+
+ @Override
+ public boolean isTouchableDisplay(int displayId) {
+ synchronized (mGlobalLock) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ final Configuration configuration =
+ displayContent != null ? displayContent.getConfiguration() : null;
+ return configuration != null
+ && configuration.touchscreen == Configuration.TOUCHSCREEN_FINGER;
+ }
+ }
}
void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 1c8c46c..466ca93 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -41,7 +41,6 @@
#include <utils/Looper.h>
#include <utils/threads.h>
#include <utils/Trace.h>
-#include <utils/SortedVector.h>
#include <binder/IServiceManager.h>
@@ -307,7 +306,7 @@
wp<PointerController> pointerController;
// Input devices to be disabled
- SortedVector<int32_t> disabledInputDevices;
+ std::set<int32_t> disabledInputDevices;
// Associated Pointer controller display.
int32_t pointerDisplayId;
@@ -898,13 +897,13 @@
{ // acquire lock
AutoMutex _l(mLock);
- ssize_t index = mLocked.disabledInputDevices.indexOf(deviceId);
- bool currentlyEnabled = index < 0;
+ auto it = mLocked.disabledInputDevices.find(deviceId);
+ bool currentlyEnabled = it == mLocked.disabledInputDevices.end();
if (!enabled && currentlyEnabled) {
- mLocked.disabledInputDevices.add(deviceId);
+ mLocked.disabledInputDevices.insert(deviceId);
}
if (enabled && !currentlyEnabled) {
- mLocked.disabledInputDevices.remove(deviceId);
+ mLocked.disabledInputDevices.erase(deviceId);
}
} // release lock
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 565ba67..8161ac9 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -87,6 +87,7 @@
import com.android.server.broadcastradio.BroadcastRadioService;
import com.android.server.camera.CameraServiceProxy;
import com.android.server.clipboard.ClipboardService;
+import com.android.server.compat.PlatformCompat;
import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.coverage.CoverageService;
@@ -1097,6 +1098,11 @@
t.traceBegin("SignedConfigService");
SignedConfigService.registerUpdateReceiver(mSystemContext);
t.traceEnd();
+
+ t.traceBegin("PlatformCompat");
+ ServiceManager.addService("platform_compat", new PlatformCompat(context));
+ t.traceEnd();
+
} catch (RuntimeException e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service", e);
diff --git a/services/robotests/Android.bp b/services/robotests/Android.bp
new file mode 100644
index 0000000..3ce514a
--- /dev/null
+++ b/services/robotests/Android.bp
@@ -0,0 +1,53 @@
+// Copyright (C) 2016 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.
+
+//##################################################################
+// FrameworksServicesLib app just for Robolectric test target #
+//##################################################################
+
+android_app {
+ name: "FrameworksServicesLib",
+ platform_apis: true,
+
+ privileged: true,
+
+ static_libs: [
+ "services.core",
+ "services.net",
+ ],
+}
+
+//##################################################################
+// FrameworksServicesLib Robolectric test target. #
+//##################################################################
+android_robolectric_test {
+ name: "FrameworksServicesRoboTests",
+
+ srcs: ["src/**/*.java"],
+
+ java_resource_dirs: ["config"],
+
+ // Include the testing libraries
+ libs: [
+ "platform-test-annotations",
+ "testng",
+ ],
+
+ instrumentation_for: "FrameworksServicesLib",
+}
+
+filegroup {
+ name: "FrameworksServicesRoboShadows",
+ srcs: ["src/com/android/server/testing/shadows/**/*.java"],
+}
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
deleted file mode 100644
index 0cf0d34..0000000
--- a/services/robotests/Android.mk
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright (C) 2016 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.
-
-###################################################################
-# FrameworksServicesLib app just for Robolectric test target #
-###################################################################
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := FrameworksServicesLib
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- services.core \
- services.net
-
-include $(BUILD_PACKAGE)
-
-###################################################################
-# FrameworksServicesLib Robolectric test target. #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := FrameworksServicesRoboTests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/res
-
-LOCAL_JAVA_RESOURCE_DIRS := config
-
-# Include the testing libraries
-LOCAL_JAVA_LIBRARIES := \
- platform-test-annotations \
- robolectric_android-all-stub \
- Robolectric_all-target \
- mockito-robolectric-prebuilt \
- truth-prebuilt \
- testng
-
-LOCAL_INSTRUMENTATION_FOR := FrameworksServicesLib
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-###################################################################
-# FrameworksServicesLib runner target to run the previous target. #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := RunFrameworksServicesRoboTests
-
-LOCAL_JAVA_LIBRARIES := \
- FrameworksServicesRoboTests \
- platform-test-annotations \
- robolectric_android-all-stub \
- Robolectric_all-target \
- mockito-robolectric-prebuilt \
- truth-prebuilt \
- testng
-
-LOCAL_TEST_PACKAGE := FrameworksServicesLib
-
-LOCAL_ROBOTEST_FILES := $(call find-files-in-subdirs,$(LOCAL_PATH)/src,*Test.java,.)
-
-include external/robolectric-shadows/run_robotests.mk
-
-###################################################################
-# include subdir Android.mk files
-###################################################################
-include $(CLEAR_VARS)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/robotests/AndroidManifest.xml b/services/robotests/AndroidManifest.xml
new file mode 100644
index 0000000..828c8fa
--- /dev/null
+++ b/services/robotests/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 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"
+ coreApp="true"
+ package="com.android.server.robotests">
+
+ <application/>
+
+</manifest>
diff --git a/services/robotests/backup/Android.bp b/services/robotests/backup/Android.bp
new file mode 100644
index 0000000..9d384e9
--- /dev/null
+++ b/services/robotests/backup/Android.bp
@@ -0,0 +1,53 @@
+// 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.
+
+//##################################################################
+// BackupFrameworksServicesLib app just for Robolectric test target #
+//##################################################################
+android_app {
+ name: "BackupFrameworksServicesLib",
+ platform_apis: true,
+
+ privileged: true,
+
+ static_libs: [
+ "bmgr",
+ "bu",
+ "services.backup",
+ "services.core",
+ "services.net",
+ ],
+}
+
+//##################################################################
+// BackupFrameworksServicesLib Robolectric test target. #
+//##################################################################
+android_robolectric_test {
+ name: "BackupFrameworksServicesRoboTests",
+ srcs: [
+ "src/**/*.java",
+ ":FrameworksServicesRoboShadows",
+ ],
+
+ java_resource_dirs: ["config"],
+
+ // Include the testing libraries
+ libs: [
+ "platform-test-annotations",
+ "testng",
+ ],
+
+ instrumentation_for: "BackupFrameworksServicesLib",
+
+}
diff --git a/services/robotests/backup/Android.mk b/services/robotests/backup/Android.mk
deleted file mode 100644
index bd4ebbd..0000000
--- a/services/robotests/backup/Android.mk
+++ /dev/null
@@ -1,84 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-###################################################################
-# BackupFrameworksServicesLib app just for Robolectric test target #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := BackupFrameworksServicesLib
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- bmgr \
- bu \
- services.backup \
- services.core \
- services.net
-
-include $(BUILD_PACKAGE)
-
-###################################################################
-# BackupFrameworksServicesLib Robolectric test target. #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := BackupFrameworksServicesRoboTests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
- $(call all-java-files-under, ../src/com/android/server/testing/shadows)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_JAVA_RESOURCE_DIRS := config
-
-# Include the testing libraries
-LOCAL_JAVA_LIBRARIES := \
- platform-test-annotations \
- robolectric_android-all-stub \
- Robolectric_all-target \
- mockito-robolectric-prebuilt \
- truth-prebuilt \
- testng
-
-LOCAL_INSTRUMENTATION_FOR := BackupFrameworksServicesLib
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-###################################################################
-# BackupFrameworksServicesLib runner target to run the previous target. #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := RunBackupFrameworksServicesRoboTests
-
-LOCAL_JAVA_LIBRARIES := \
- BackupFrameworksServicesRoboTests \
- platform-test-annotations \
- robolectric_android-all-stub \
- Robolectric_all-target \
- mockito-robolectric-prebuilt \
- truth-prebuilt \
- testng
-
-LOCAL_TEST_PACKAGE := BackupFrameworksServicesLib
-
-include external/robolectric-shadows/run_robotests.mk
diff --git a/services/robotests/backup/AndroidManifest.xml b/services/robotests/backup/AndroidManifest.xml
new file mode 100644
index 0000000..0932378
--- /dev/null
+++ b/services/robotests/backup/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 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"
+ coreApp="true"
+ package="com.android.server.backup.robotests">
+
+ <application/>
+
+</manifest>
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index ba2959f..2f9f9bb 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -23,21 +23,25 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.GestureDescription;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.view.Display;
import com.android.server.wm.WindowManagerInternal;
@@ -50,6 +54,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
/**
@@ -73,6 +78,9 @@
@Mock GlobalActionPerformer mMockGlobalActionPerformer;
@Mock KeyEventDispatcher mMockKeyEventDispatcher;
@Mock MagnificationController mMockMagnificationController;
+ @Mock IBinder mMockIBinder;
+ @Mock IAccessibilityServiceClient mMockServiceClient;
+ @Mock MotionEventInjector mMockMotionEventInjector;
MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
@@ -82,15 +90,22 @@
when(mMockSystemSupport.getKeyEventDispatcher()).thenReturn(mMockKeyEventDispatcher);
when(mMockSystemSupport.getMagnificationController())
.thenReturn(mMockMagnificationController);
+ when(mMockSystemSupport.getMotionEventInjectorForDisplayLocked(
+ Display.DEFAULT_DISPLAY)).thenReturn(mMockMotionEventInjector);
when(mMockServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
mMockResolveInfo.serviceInfo = mock(ServiceInfo.class);
mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
+ when(mMockIBinder.queryLocalInterface(any())).thenReturn(mMockServiceClient);
+ when(mMockWindowManagerInternal.isTouchableDisplay(Display.DEFAULT_DISPLAY)).thenReturn(
+ true);
+
mConnection = new AccessibilityServiceConnection(mMockUserState, mMockContext,
COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, mHandler, new Object(),
mMockSecurityPolicy, mMockSystemSupport, mMockWindowManagerInternal,
mMockGlobalActionPerformer, mMockA11yWindowManager);
+ when(mMockSecurityPolicy.canPerformGestures(mConnection)).thenReturn(true);
}
@After
@@ -115,25 +130,23 @@
@Test
public void bindConnectUnbind_linksAndUnlinksToServiceDeath() throws RemoteException {
- IBinder mockBinder = mock(IBinder.class);
setServiceBinding(COMPONENT_NAME);
mConnection.bindLocked();
- mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
- verify(mockBinder).linkToDeath(eq(mConnection), anyInt());
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+ verify(mMockIBinder).linkToDeath(eq(mConnection), anyInt());
mConnection.unbindLocked();
- verify(mockBinder).unlinkToDeath(eq(mConnection), anyInt());
+ verify(mMockIBinder).unlinkToDeath(eq(mConnection), anyInt());
}
@Test
public void connectedServiceCrashedAndRestarted_crashReportedInServiceInfo() {
- IBinder mockBinder = mock(IBinder.class);
setServiceBinding(COMPONENT_NAME);
mConnection.bindLocked();
- mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
assertFalse(mConnection.getServiceInfo().crashed);
mConnection.binderDied();
assertTrue(mConnection.getServiceInfo().crashed);
- mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
mHandler.sendAllMessages();
assertFalse(mConnection.getServiceInfo().crashed);
}
@@ -145,10 +158,9 @@
@Test
public void binderDied_keysGetFlushed() {
- IBinder mockBinder = mock(IBinder.class);
setServiceBinding(COMPONENT_NAME);
mConnection.bindLocked();
- mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
mConnection.binderDied();
assertTrue(mConnection.getServiceInfo().crashed);
verify(mMockKeyEventDispatcher).flush(mConnection);
@@ -157,17 +169,63 @@
@Test
public void connectedService_notInEnabledServiceList_doNotInitClient()
throws RemoteException {
- IBinder mockBinder = mock(IBinder.class);
- IAccessibilityServiceClient mockClient = mock(IAccessibilityServiceClient.class);
- when(mockBinder.queryLocalInterface(any())).thenReturn(mockClient);
when(mMockUserState.getEnabledServicesLocked())
.thenReturn(Collections.emptySet());
setServiceBinding(COMPONENT_NAME);
mConnection.bindLocked();
- mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
mHandler.sendAllMessages();
verify(mMockSystemSupport, times(2)).onClientChangeLocked(false);
- verify(mockClient, times(0)).init(any(), anyInt(), any());
+ verify(mMockServiceClient, times(0)).init(any(), anyInt(), any());
}
+
+ @Test
+ public void sendGesture_touchableDisplay_injectEvents()
+ throws RemoteException {
+ setServiceBinding(COMPONENT_NAME);
+ mConnection.bindLocked();
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+
+ ParceledListSlice parceledListSlice = mock(ParceledListSlice.class);
+ List<GestureDescription.GestureStep> gestureSteps = mock(List.class);
+ when(parceledListSlice.getList()).thenReturn(gestureSteps);
+ mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY);
+
+ verify(mMockMotionEventInjector).injectEvents(gestureSteps, mMockServiceClient, 0);
+ }
+
+ @Test
+ public void sendGesture_untouchableDisplay_performGestureResultFailed()
+ throws RemoteException {
+ when(mMockWindowManagerInternal.isTouchableDisplay(Display.DEFAULT_DISPLAY)).thenReturn(
+ false);
+ setServiceBinding(COMPONENT_NAME);
+ mConnection.bindLocked();
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+
+ ParceledListSlice parceledListSlice = mock(ParceledListSlice.class);
+ List<GestureDescription.GestureStep> gestureSteps = mock(List.class);
+ when(parceledListSlice.getList()).thenReturn(gestureSteps);
+ mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY);
+
+ verify(mMockMotionEventInjector, never()).injectEvents(gestureSteps, mMockServiceClient, 0);
+ verify(mMockServiceClient).onPerformGestureResult(0, false);
+ }
+
+ @Test
+ public void sendGesture_invalidDisplay_performGestureResultFailed()
+ throws RemoteException {
+ setServiceBinding(COMPONENT_NAME);
+ mConnection.bindLocked();
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+
+ ParceledListSlice parceledListSlice = mock(ParceledListSlice.class);
+ List<GestureDescription.GestureStep> gestureSteps = mock(List.class);
+ when(parceledListSlice.getList()).thenReturn(gestureSteps);
+ mConnection.dispatchGesture(0, parceledListSlice, Display.INVALID_DISPLAY);
+
+ verify(mMockServiceClient).onPerformGestureResult(0, false);
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
new file mode 100644
index 0000000..470d4fa
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2019 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.pm;
+
+import android.content.pm.PackageParser;
+
+import com.android.internal.util.ArrayUtils;
+
+class PackageBuilder {
+ final PackageParser.Package mPkg;
+
+ PackageBuilder(String packageName) {
+ mPkg = new PackageParser.Package(packageName);
+ }
+
+ PackageBuilder setApplicationInfoCodePath(String codePath) {
+ mPkg.applicationInfo.setCodePath(codePath);
+ return this;
+ }
+
+ PackageBuilder setApplicationInfoResourcePath(String resourcePath) {
+ mPkg.applicationInfo.setResourcePath(resourcePath);
+ return this;
+ }
+
+ PackageBuilder setCodePath(String codePath) {
+ mPkg.codePath = codePath;
+ return this;
+ }
+
+ PackageBuilder setBaseCodePath(String baseCodePath) {
+ mPkg.baseCodePath = baseCodePath;
+ return this;
+ }
+
+ PackageBuilder addUsesStaticLibrary(String name, long version) {
+ mPkg.usesStaticLibraries = ArrayUtils.add(mPkg.usesStaticLibraries, name);
+ mPkg.usesStaticLibrariesVersions =
+ ArrayUtils.appendLong(mPkg.usesStaticLibrariesVersions, version);
+ return this;
+ }
+
+ PackageBuilder setApplicationInfoNativeLibraryRootDir(String dir) {
+ mPkg.applicationInfo.nativeLibraryRootDir = dir;
+ return this;
+ }
+
+ PackageBuilder setStaticSharedLib(String staticSharedLibName, long staticSharedLibVersion) {
+ mPkg.staticSharedLibVersion = staticSharedLibVersion;
+ mPkg.staticSharedLibName = staticSharedLibName;
+ return this;
+ }
+
+ PackageBuilder setManifestPackageName(String manifestPackageName) {
+ mPkg.manifestPackageName = manifestPackageName;
+ return this;
+ }
+
+ PackageBuilder setVersionCodeMajor(int versionCodeMajor) {
+ mPkg.mVersionCodeMajor = versionCodeMajor;
+ return this;
+ }
+
+ PackageBuilder setVersionCode(int versionCode) {
+ mPkg.mVersionCode = versionCode;
+ return this;
+ }
+
+ PackageBuilder addSplitCodePath(String splitCodePath) {
+ mPkg.splitCodePaths =
+ ArrayUtils.appendElement(String.class, mPkg.splitCodePaths, splitCodePath);
+ return this;
+ }
+
+ PackageBuilder setApplicationInfoVolumeUuid(String volumeUuid) {
+ mPkg.applicationInfo.volumeUuid = volumeUuid;
+ return this;
+ }
+
+ PackageBuilder addLibraryName(String libraryName) {
+ mPkg.libraryNames = ArrayUtils.add(mPkg.libraryNames, libraryName);
+ return this;
+ }
+
+ PackageBuilder setRealPackageName(String realPackageName) {
+ mPkg.mRealPackage = realPackageName;
+ return this;
+ }
+
+ PackageBuilder setCpuAbiOVerride(String cpuAbiOverride) {
+ mPkg.cpuAbiOverride = cpuAbiOverride;
+ return this;
+ }
+
+ PackageBuilder addPermissionRequest(String permissionName) {
+ mPkg.requestedPermissions.add(permissionName);
+ return this;
+ }
+
+ PackageParser.Package build() {
+ return mPkg;
+ }
+
+ public PackageBuilder addApplicationInfoFlag(int flag) {
+ mPkg.applicationInfo.flags |= flag;
+ return this;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 13a8eb1..e33d8ca 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
@@ -557,6 +558,9 @@
pkg.mRequiredForAllUsers = true;
pkg.visibleToInstantApps = true;
pkg.use32bitAbi = true;
+ pkg.mForceQueryable = true;
+ pkg.mQueriesPackages = new ArrayList<>(Arrays.asList("foo27"));
+ pkg.mQueriesIntents = new ArrayList<>(Arrays.asList(new Intent("foo28")));
}
private static void assertAllFieldsExist(PackageParser.Package pkg) throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
new file mode 100644
index 0000000..b42cfd8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2019 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.pm;
+
+import android.content.pm.PackageUserState;
+import android.util.SparseArray;
+
+import java.io.File;
+import java.util.List;
+
+class PackageSettingBuilder {
+ private String mName;
+ private String mRealName;
+ private String mCodePath;
+ private String mResourcePath;
+ private String mLegacyNativeLibraryPathString;
+ private String mPrimaryCpuAbiString;
+ private String mSecondaryCpuAbiString;
+ private String mCpuAbiOverrideString;
+ private long mPVersionCode;
+ private int mPkgFlags;
+ private int mPrivateFlags;
+ private String mParentPackageName;
+ private List<String> mChildPackageNames;
+ private int mSharedUserId;
+ private String[] mUsesStaticLibraries;
+ private long[] mUsesStaticLibrariesVersions;
+ private String mVolumeUuid;
+ private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
+
+ public PackageSettingBuilder setName(String name) {
+ this.mName = name;
+ return this;
+ }
+
+ public PackageSettingBuilder setRealName(String realName) {
+ this.mRealName = realName;
+ return this;
+ }
+
+ public PackageSettingBuilder setCodePath(String codePath) {
+ this.mCodePath = codePath;
+ return this;
+ }
+
+ public PackageSettingBuilder setResourcePath(String resourcePath) {
+ this.mResourcePath = resourcePath;
+ return this;
+ }
+
+ public PackageSettingBuilder setLegacyNativeLibraryPathString(
+ String legacyNativeLibraryPathString) {
+ this.mLegacyNativeLibraryPathString = legacyNativeLibraryPathString;
+ return this;
+ }
+
+ public PackageSettingBuilder setPrimaryCpuAbiString(String primaryCpuAbiString) {
+ this.mPrimaryCpuAbiString = primaryCpuAbiString;
+ return this;
+ }
+
+ public PackageSettingBuilder setSecondaryCpuAbiString(String secondaryCpuAbiString) {
+ this.mSecondaryCpuAbiString = secondaryCpuAbiString;
+ return this;
+ }
+
+ public PackageSettingBuilder setCpuAbiOverrideString(String cpuAbiOverrideString) {
+ this.mCpuAbiOverrideString = cpuAbiOverrideString;
+ return this;
+ }
+
+ public PackageSettingBuilder setPVersionCode(long pVersionCode) {
+ this.mPVersionCode = pVersionCode;
+ return this;
+ }
+
+ public PackageSettingBuilder setPkgFlags(int pkgFlags) {
+ this.mPkgFlags = pkgFlags;
+ return this;
+ }
+
+ public PackageSettingBuilder setPrivateFlags(int privateFlags) {
+ this.mPrivateFlags = privateFlags;
+ return this;
+ }
+
+ public PackageSettingBuilder setParentPackageName(String parentPackageName) {
+ this.mParentPackageName = parentPackageName;
+ return this;
+ }
+
+ public PackageSettingBuilder setChildPackageNames(List<String> childPackageNames) {
+ this.mChildPackageNames = childPackageNames;
+ return this;
+ }
+
+ public PackageSettingBuilder setSharedUserId(int sharedUserId) {
+ this.mSharedUserId = sharedUserId;
+ return this;
+ }
+
+ public PackageSettingBuilder setUsesStaticLibraries(String[] usesStaticLibraries) {
+ this.mUsesStaticLibraries = usesStaticLibraries;
+ return this;
+ }
+
+ public PackageSettingBuilder setUsesStaticLibrariesVersions(
+ long[] usesStaticLibrariesVersions) {
+ this.mUsesStaticLibrariesVersions = usesStaticLibrariesVersions;
+ return this;
+ }
+
+ public PackageSettingBuilder setVolumeUuid(String volumeUuid) {
+ this.mVolumeUuid = volumeUuid;
+ return this;
+ }
+
+ public PackageSettingBuilder setInstantAppUserState(int userId, boolean isInstant) {
+ if (mUserStates.indexOfKey(userId) < 0) {
+ mUserStates.put(userId, new PackageUserState());
+ }
+ mUserStates.get(userId).instantApp = isInstant;
+ return this;
+ }
+
+ public PackageSetting build() {
+ final PackageSetting packageSetting = new PackageSetting(mName, mRealName,
+ new File(mCodePath), new File(mResourcePath),
+ mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString,
+ mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mParentPackageName,
+ mChildPackageNames, mSharedUserId, mUsesStaticLibraries,
+ mUsesStaticLibrariesVersions);
+ packageSetting.volumeUuid = this.mVolumeUuid;
+ for (int i = 0; i < mUserStates.size(); i++) {
+ packageSetting.setUserState(mUserStates.keyAt(i), mUserStates.valueAt(i));
+ }
+ return packageSetting;
+
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
new file mode 100644
index 0000000..34a3f86
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2019 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.pm;
+
+import android.content.pm.PackageParser;
+import android.os.UserHandle;
+
+class ScanRequestBuilder {
+ private final PackageParser.Package mPkg;
+ private PackageParser.Package mOldPkg;
+ private SharedUserSetting mSharedUserSetting;
+ private PackageSetting mPkgSetting;
+ private PackageSetting mDisabledPkgSetting;
+ private PackageSetting mOriginalPkgSetting;
+ private String mRealPkgName;
+ private int mParseFlags;
+ private int mScanFlags;
+ private UserHandle mUser;
+ private boolean mIsPlatformPackage;
+
+ ScanRequestBuilder(PackageParser.Package pkg) {
+ this.mPkg = pkg;
+ }
+
+ public ScanRequestBuilder setOldPkg(PackageParser.Package oldPkg) {
+ this.mOldPkg = oldPkg;
+ return this;
+ }
+
+ public ScanRequestBuilder setSharedUserSetting(SharedUserSetting sharedUserSetting) {
+ this.mSharedUserSetting = sharedUserSetting;
+ return this;
+ }
+
+ public ScanRequestBuilder setPkgSetting(PackageSetting pkgSetting) {
+ this.mPkgSetting = pkgSetting;
+ return this;
+ }
+
+ public ScanRequestBuilder setDisabledPkgSetting(PackageSetting disabledPkgSetting) {
+ this.mDisabledPkgSetting = disabledPkgSetting;
+ return this;
+ }
+
+ public ScanRequestBuilder setOriginalPkgSetting(PackageSetting originalPkgSetting) {
+ this.mOriginalPkgSetting = originalPkgSetting;
+ return this;
+ }
+
+ public ScanRequestBuilder setRealPkgName(String realPkgName) {
+ this.mRealPkgName = realPkgName;
+ return this;
+ }
+
+ public ScanRequestBuilder setParseFlags(int parseFlags) {
+ this.mParseFlags = parseFlags;
+ return this;
+ }
+
+ public ScanRequestBuilder addParseFlag(int parseFlag) {
+ this.mParseFlags |= parseFlag;
+ return this;
+ }
+
+ public ScanRequestBuilder setScanFlags(int scanFlags) {
+ this.mScanFlags = scanFlags;
+ return this;
+ }
+
+ public ScanRequestBuilder addScanFlag(int scanFlag) {
+ this.mScanFlags |= scanFlag;
+ return this;
+ }
+
+ public ScanRequestBuilder setUser(UserHandle user) {
+ this.mUser = user;
+ return this;
+ }
+
+ public ScanRequestBuilder setIsPlatformPackage(boolean isPlatformPackage) {
+ this.mIsPlatformPackage = isPlatformPackage;
+ return this;
+ }
+
+ PackageManagerService.ScanRequest build() {
+ return new PackageManagerService.ScanRequest(
+ mPkg, mSharedUserSetting, mOldPkg, mPkgSetting, mDisabledPkgSetting,
+ mOriginalPkgSetting, mRealPkgName, mParseFlags, mScanFlags, mIsPlatformPackage,
+ mUser);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
new file mode 100644
index 0000000..cc70ef8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2019 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.pm;
+
+import static android.content.pm.SharedLibraryInfo.TYPE_DYNAMIC;
+import static android.content.pm.SharedLibraryInfo.TYPE_STATIC;
+import static android.content.pm.SharedLibraryInfo.VERSION_UNDEFINED;
+
+import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE;
+import static com.android.server.pm.PackageManagerService.SCAN_NEW_INSTALL;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.collection.IsArrayContainingInOrder.arrayContaining;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertNotSame;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.SharedLibraryInfo;
+import android.os.Environment;
+import android.os.UserHandle;
+import android.os.UserManagerInternal;
+import android.platform.test.annotations.Presubmit;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.File;
+
+@RunWith(MockitoJUnitRunner.class)
+@Presubmit
+public class ScanTests {
+
+ private static final String DUMMY_PACKAGE_NAME = "some.app.to.test";
+
+ @Mock
+ PackageAbiHelper mMockPackageAbiHelper;
+ @Mock
+ UserManagerInternal mMockUserManager;
+
+ @Before
+ public void setupDefaultUser() {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+ }
+
+ @Test
+ public void newInstallSimpleAllNominal() throws Exception {
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
+ .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+ assertThat(scanResult.existingSettingCopied, is(false));
+ verify(mMockPackageAbiHelper, never()).derivePackageAbi(any(PackageParser.Package.class),
+ anyString() /*abioverride*/, anyBoolean() /*extractNativeLibs*/);
+ verify(mMockPackageAbiHelper).setNativeLibraryPaths(
+ scanResult.pkgSetting.pkg, PackageManagerService.sAppLib32InstallDir);
+ }
+
+ @Test
+ public void newInstallForAllUsers() throws Exception {
+ final int[] userIds = {0, 10, 11};
+ when(mMockUserManager.getUserIds()).thenReturn(userIds);
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setRealPkgName(null)
+ .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
+ .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+ .build();
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ for (int uid : userIds) {
+ assertThat(scanResult.pkgSetting.readUserState(uid).installed, is(true));
+ }
+ }
+
+ @Test
+ public void installRealPackageName() throws Exception {
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setRealPkgName("com.package.real")
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.pkgSetting.realName, is("com.package.real"));
+
+ final PackageManagerService.ScanRequest scanRequestNoRealPkg =
+ createBasicScanRequestBuilder(
+ createBasicPackage(DUMMY_PACKAGE_NAME)
+ .setRealPackageName("com.package.real").build())
+ .build();
+
+ final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
+ assertThat(scanResultNoReal.pkgSetting.realName, nullValue());
+ }
+
+ @Test
+ public void updateSimpleNominal() throws Exception {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+ final PackageSetting pkgSetting = createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setPrimaryCpuAbiString("primaryCpuAbi")
+ .setSecondaryCpuAbiString("secondaryCpuAbi")
+ .build();
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+ .setPkgSetting(pkgSetting)
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.existingSettingCopied, is(true));
+
+ // ensure we don't overwrite the existing pkgSetting, in case something post-scan fails
+ assertNotSame(pkgSetting, scanResult.pkgSetting);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+
+ assertThat(scanResult.pkgSetting.primaryCpuAbiString, is("primaryCpuAbi"));
+ assertThat(scanResult.pkgSetting.secondaryCpuAbiString, is("secondaryCpuAbi"));
+ assertThat(scanResult.pkgSetting.cpuAbiOverrideString, nullValue());
+
+ verify(mMockPackageAbiHelper, never()).derivePackageAbi(any(PackageParser.Package.class),
+ anyString() /*abioverride*/, anyBoolean() /*extractNativeLibs*/);
+ verify(mMockPackageAbiHelper).setNativeLibraryPaths(
+ scanResult.pkgSetting.pkg, PackageManagerService.sAppLib32InstallDir);
+ }
+
+ @Test
+ public void updateInstantSimpleNominal() throws Exception {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+ final PackageSetting existingPkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setInstantAppUserState(0, true)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setPkgSetting(existingPkgSetting)
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
+ }
+
+ @Test
+ public void installStaticSharedLibrary() throws Exception {
+ final PackageParser.Package pkg = createBasicPackage("static.lib.pkg.123")
+ .setStaticSharedLib("static.lib", 123L)
+ .setManifestPackageName("static.lib.pkg")
+ .setVersionCodeMajor(1)
+ .setVersionCode(234)
+ .setBaseCodePath("/some/path.apk")
+ .addSplitCodePath("/some/other/path.apk")
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(
+ pkg).setUser(UserHandle.of(0)).build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.staticSharedLibraryInfo.getPackageName(), is("static.lib.pkg.123"));
+ assertThat(scanResult.staticSharedLibraryInfo.getName(), is("static.lib"));
+ assertThat(scanResult.staticSharedLibraryInfo.getLongVersion(), is(123L));
+ assertThat(scanResult.staticSharedLibraryInfo.getType(), is(TYPE_STATIC));
+ assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getPackageName(),
+ is("static.lib.pkg"));
+ assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
+ is(pkg.getLongVersionCode()));
+ assertThat(scanResult.staticSharedLibraryInfo.getAllCodePaths(),
+ hasItems("/some/path.apk", "/some/other/path.apk"));
+ assertThat(scanResult.staticSharedLibraryInfo.getDependencies(), nullValue());
+ assertThat(scanResult.staticSharedLibraryInfo.getDependentPackages(), empty());
+ }
+
+ @Test
+ public void installDynamicLibraries() throws Exception {
+ final PackageParser.Package pkg = createBasicPackage("dynamic.lib.pkg")
+ .setManifestPackageName("dynamic.lib.pkg")
+ .addLibraryName("liba")
+ .addLibraryName("libb")
+ .setVersionCodeMajor(1)
+ .setVersionCode(234)
+ .setBaseCodePath("/some/path.apk")
+ .addSplitCodePath("/some/other/path.apk")
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ final SharedLibraryInfo dynamicLib0 = scanResult.dynamicSharedLibraryInfos.get(0);
+ assertThat(dynamicLib0.getPackageName(), is("dynamic.lib.pkg"));
+ assertThat(dynamicLib0.getName(), is("liba"));
+ assertThat(dynamicLib0.getLongVersion(), is((long) VERSION_UNDEFINED));
+ assertThat(dynamicLib0.getType(), is(TYPE_DYNAMIC));
+ assertThat(dynamicLib0.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
+ assertThat(dynamicLib0.getDeclaringPackage().getLongVersionCode(),
+ is(pkg.getLongVersionCode()));
+ assertThat(dynamicLib0.getAllCodePaths(),
+ hasItems("/some/path.apk", "/some/other/path.apk"));
+ assertThat(dynamicLib0.getDependencies(), nullValue());
+ assertThat(dynamicLib0.getDependentPackages(), empty());
+
+ final SharedLibraryInfo dynamicLib1 = scanResult.dynamicSharedLibraryInfos.get(1);
+ assertThat(dynamicLib1.getPackageName(), is("dynamic.lib.pkg"));
+ assertThat(dynamicLib1.getName(), is("libb"));
+ assertThat(dynamicLib1.getLongVersion(), is((long) VERSION_UNDEFINED));
+ assertThat(dynamicLib1.getType(), is(TYPE_DYNAMIC));
+ assertThat(dynamicLib1.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
+ assertThat(dynamicLib1.getDeclaringPackage().getLongVersionCode(),
+ is(pkg.getLongVersionCode()));
+ assertThat(dynamicLib1.getAllCodePaths(),
+ hasItems("/some/path.apk", "/some/other/path.apk"));
+ assertThat(dynamicLib1.getDependencies(), nullValue());
+ assertThat(dynamicLib1.getDependentPackages(), empty());
+ }
+
+ @Test
+ public void volumeUuidChangesOnUpdate() throws Exception {
+ final PackageSetting pkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setVolumeUuid("someUuid")
+ .build();
+
+ final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+ .setApplicationInfoVolumeUuid("someNewUuid")
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(
+ new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build());
+
+ assertThat(scanResult.pkgSetting.volumeUuid, is("someNewUuid"));
+ }
+
+ @Test
+ public void scanFirstBoot_derivesAbis() throws Exception {
+ final PackageSetting pkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build();
+
+ final PackageParser.Package basicPackage =
+ createBasicPackage(DUMMY_PACKAGE_NAME)
+ .setCpuAbiOVerride("testOverride")
+ .build();
+
+
+ executeScan(new ScanRequestBuilder(basicPackage)
+ .setPkgSetting(pkgSetting)
+ .addScanFlag(SCAN_FIRST_BOOT_OR_UPGRADE)
+ .build());
+
+ verify(mMockPackageAbiHelper).derivePackageAbi(basicPackage, "testOverride", true);
+ }
+
+ @Test
+ public void scanWithOriginalPkgSetting_packageNameChanges() throws Exception {
+ final PackageSetting originalPkgSetting =
+ createBasicPackageSettingBuilder("original.package").build();
+
+ final PackageParser.Package basicPackage =
+ createBasicPackage(DUMMY_PACKAGE_NAME)
+ .build();
+
+
+ final PackageManagerService.ScanResult result =
+ executeScan(new ScanRequestBuilder(basicPackage)
+ .setOriginalPkgSetting(originalPkgSetting)
+ .build());
+
+ assertThat(result.request.pkg.packageName, is("original.package"));
+ }
+
+ @Test
+ public void updateInstant_changeToFull() throws Exception {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+ final PackageSetting existingPkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setInstantAppUserState(0, true)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setPkgSetting(existingPkgSetting)
+ .addScanFlag(SCAN_AS_FULL_APP)
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+ }
+
+ @Test
+ public void updateFull_changeToInstant() throws Exception {
+ when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+ final PackageSetting existingPkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setInstantAppUserState(0, false)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setPkgSetting(existingPkgSetting)
+ .addScanFlag(SCAN_AS_INSTANT_APP)
+ .build();
+
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
+ }
+
+ @Test
+ public void updateSystemApp_applicationInfoFlagSet() throws Exception {
+ final PackageSetting existingPkgSetting =
+ createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+ .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+ .setPkgSetting(existingPkgSetting)
+ .setDisabledPkgSetting(existingPkgSetting)
+ .addScanFlag(SCAN_NEW_INSTALL)
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.request.pkg.applicationInfo.flags,
+ hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
+ }
+
+ @Test
+ public void factoryTestFlagSet() throws Exception {
+ final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+ .addPermissionRequest(Manifest.permission.FACTORY_TEST)
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
+ createBasicScanRequestBuilder(basicPackage).build(),
+ new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
+ true /*isUnderFactoryTest*/,
+ System.currentTimeMillis());
+
+ assertThat(scanResult.request.pkg.applicationInfo.flags,
+ hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
+ }
+
+ @Test
+ public void scanSystemApp_isOrphanedTrue() throws Exception {
+ final PackageParser.Package pkg = createBasicPackage(DUMMY_PACKAGE_NAME)
+ .addApplicationInfoFlag(ApplicationInfo.FLAG_SYSTEM)
+ .build();
+
+ final PackageManagerService.ScanRequest scanRequest =
+ createBasicScanRequestBuilder(pkg)
+ .build();
+
+ final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+ assertThat(scanResult.pkgSetting.isOrphaned, is(true));
+ }
+
+ private static Matcher<Integer> hasFlag(final int flag) {
+ return new BaseMatcher<Integer>() {
+ @Override public void describeTo(Description description) {
+ description.appendText("flags ");
+ }
+
+ @Override public boolean matches(Object item) {
+ return ((int) item & flag) != 0;
+ }
+
+ @Override
+ public void describeMismatch(Object item, Description mismatchDescription) {
+ mismatchDescription
+ .appendValue(item)
+ .appendText(" does not contain flag ")
+ .appendValue(flag);
+ }
+ };
+ }
+
+ private PackageManagerService.ScanResult executeScan(
+ PackageManagerService.ScanRequest scanRequest) throws PackageManagerException {
+ return PackageManagerService.scanPackageOnlyLI(
+ scanRequest,
+ new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
+ false /*isUnderFactoryTest*/,
+ System.currentTimeMillis());
+ }
+
+ private static String createResourcePath(String packageName) {
+ return "/data/app/" + packageName + "-randompath/base.apk";
+ }
+
+ private static String createCodePath(String packageName) {
+ return "/data/app/" + packageName + "-randompath";
+ }
+
+ private static PackageSettingBuilder createBasicPackageSettingBuilder(String packageName) {
+ return new PackageSettingBuilder()
+ .setName(packageName)
+ .setCodePath(createCodePath(packageName))
+ .setResourcePath(createResourcePath(packageName));
+ }
+
+ private static ScanRequestBuilder createBasicScanRequestBuilder(PackageParser.Package pkg) {
+ return new ScanRequestBuilder(pkg)
+ .setUser(UserHandle.of(0));
+ }
+
+
+ private static PackageBuilder createBasicPackage(String packageName) {
+ return new PackageBuilder(packageName)
+ .setCodePath("/data/tmp/randompath")
+ .setApplicationInfoCodePath(createCodePath(packageName))
+ .setApplicationInfoResourcePath(createResourcePath(packageName))
+ .setApplicationInfoVolumeUuid("volumeUuid")
+ .setBaseCodePath("/data/tmp/randompath/base.apk")
+ .addUsesStaticLibrary("some.static.library", 234L)
+ .addUsesStaticLibrary("some.other.static.library", 456L)
+ .setApplicationInfoNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
+ .setVersionCodeMajor(1)
+ .setVersionCode(2345);
+ }
+
+ private static void assertBasicPackageScanResult(
+ PackageManagerService.ScanResult scanResult, String packageName, boolean isInstant) {
+ assertThat(scanResult.success, is(true));
+
+ final PackageSetting pkgSetting = scanResult.pkgSetting;
+ assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
+
+ final ApplicationInfo applicationInfo = pkgSetting.pkg.applicationInfo;
+ verifyBasicApplicationInfo(scanResult, applicationInfo);
+
+ }
+
+ private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult,
+ String packageName, boolean isInstant, PackageSetting pkgSetting) {
+ assertThat(pkgSetting.pkg.packageName, is(packageName));
+ assertThat(pkgSetting.getInstantApp(0), is(isInstant));
+ assertThat(pkgSetting.usesStaticLibraries,
+ arrayContaining("some.static.library", "some.other.static.library"));
+ assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
+ assertThat(pkgSetting.pkg, is(scanResult.request.pkg));
+ assertThat(pkgSetting.pkg.mExtras, is(pkgSetting));
+ assertThat(pkgSetting.legacyNativeLibraryPathString,
+ is("/data/tmp/randompath/base.apk:/lib"));
+ assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName))));
+ assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName))));
+ assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
+ }
+
+ private static void verifyBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
+ ApplicationInfo applicationInfo) {
+ assertThat(applicationInfo.processName, is(scanResult.request.pkg.packageName));
+
+ final int uid = applicationInfo.uid;
+ assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM));
+
+ final String calculatedCredentialId = Environment.getDataUserCePackageDirectory(
+ applicationInfo.volumeUuid, UserHandle.USER_SYSTEM,
+ scanResult.request.pkg.packageName).getAbsolutePath();
+ assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
+ assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 26cd63c..cd292b2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -25,6 +25,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
@@ -35,10 +36,12 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import android.os.Binder;
@@ -79,6 +82,7 @@
// Hold the lock to protect the stubbing from being accessed by other threads.
spyOn(mWm.mRoot);
doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
+ doReturn(mDisplayContent).when(mWm.mRoot).getDisplayContent(anyInt());
}
when(mMockRunner.asBinder()).thenReturn(new Binder());
mController = new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
@@ -135,7 +139,7 @@
hiddenAppWindow.setHidden(true);
mDisplayContent.getConfiguration().windowConfiguration.setRotation(
mDisplayContent.getRotation());
- mController.initialize(mDisplayContent, ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+ mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray());
// Ensure that we are animating the target activity as well
assertTrue(mController.isAnimatingTask(homeAppWindow.getTask()));
@@ -144,7 +148,7 @@
}
@Test
- public void testCancelAnimationWithScreenShot() throws Exception {
+ public void testDeferCancelAnimation() throws Exception {
mWm.setRecentsAnimationController(mController);
final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
@@ -156,8 +160,31 @@
mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
assertTrue(mController.isAnimatingTask(appWindow.getTask()));
- mController.setCancelWithDeferredScreenshotLocked(true);
- mController.cancelAnimationWithScreenShot();
+ mController.setDeferredCancel(true /* deferred */, false /* screenshot */);
+ mController.cancelAnimationWithScreenshot(false /* screenshot */);
+ verify(mMockRunner).onAnimationCanceled(false /* deferredWithScreenshot */);
+ assertNull(mController.mRecentScreenshotAnimator);
+
+ // Simulate the app transition finishing
+ mController.mAppTransitionListener.onAppTransitionStartingLocked(0, 0, 0, 0);
+ verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
+ }
+
+ @Test
+ public void testDeferCancelAnimationWithScreenShot() throws Exception {
+ mWm.setRecentsAnimationController(mController);
+ final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
+ appWindow.addWindow(win1);
+ assertEquals(appWindow.getTask().getTopVisibleAppToken(), appWindow);
+ assertEquals(appWindow.findMainWindow(), win1);
+
+ mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
+ assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+
+ mController.setDeferredCancel(true /* deferred */, true /* screenshot */);
+ mController.cancelAnimationWithScreenshot(true /* screenshot */);
verify(mMockRunner).onAnimationCanceled(true /* deferredWithScreenshot */);
assertNotNull(mController.mRecentScreenshotAnimator);
assertTrue(mController.mRecentScreenshotAnimator.isAnimating());
@@ -185,7 +212,7 @@
// Assume appWindow transition should animate when no
// IRecentsAnimationController#setCancelWithDeferredScreenshot called.
- assertFalse(mController.shouldCancelWithDeferredScreenshot());
+ assertFalse(mController.shouldDeferCancelWithScreenshot());
assertTrue(appWindow.shouldAnimate(TRANSIT_ACTIVITY_CLOSE));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 9630b7d..0e119e3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -274,12 +274,13 @@
// Assume recents animation already started, set a state that cancel recents animation
// with screenshot.
- doReturn(true).when(mRecentsAnimationController).shouldCancelWithDeferredScreenshot();
+ doReturn(true).when(mRecentsAnimationController).shouldDeferCancelUntilNextTransition();
+ doReturn(true).when(mRecentsAnimationController).shouldDeferCancelWithScreenshot();
// Start another fullscreen activity.
fullscreenStack2.moveToFront("Activity start");
- // Ensure that the recents animation was canceled by cancelOnNextTransitionStart().
- verify(mRecentsAnimationController, times(1)).cancelOnNextTransitionStart();
+ // Ensure that the recents animation was canceled by setCancelOnNextTransitionStart().
+ verify(mRecentsAnimationController, times(1)).setCancelOnNextTransitionStart();
}
@Test
@@ -315,7 +316,7 @@
// Ensure that the recents animation was NOT canceled
verify(mService.mWindowManager, times(0)).cancelRecentsAnimationSynchronously(
eq(REORDER_KEEP_IN_PLACE), any());
- verify(mRecentsAnimationController, times(0)).cancelOnNextTransitionStart();
+ verify(mRecentsAnimationController, times(0)).setCancelOnNextTransitionStart();
}
@Test
diff --git a/startop/apps/test/Android.bp b/startop/apps/test/Android.bp
index 7a1678a..a4906d7 100644
--- a/startop/apps/test/Android.bp
+++ b/startop/apps/test/Android.bp
@@ -23,4 +23,5 @@
"src/FrameLayoutInflationActivity.java",
"src/TextViewInflationActivity.java",
],
+ platform_apis: true,
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 91bea5f..4016c5c 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3029,6 +3029,23 @@
"is_opportunistic_subscription_bool";
/**
+ * Configs used by the IMS stack.
+ */
+ public static final class Ims {
+ /** Prefix of all Ims.KEY_* constants. */
+ public static final String KEY_PREFIX = "ims.";
+
+ //TODO: Add configs related to IMS.
+
+ private Ims() {}
+
+ private static PersistableBundle getDefaults() {
+ PersistableBundle defaults = new PersistableBundle();
+ return defaults;
+ }
+ }
+
+ /**
* A list of 4 GSM RSSI thresholds above which a signal level is considered POOR,
* MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting.
*
@@ -3463,6 +3480,7 @@
-89, /* SIGNAL_STRENGTH_GREAT */
});
sDefaults.putBoolean(KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
+ sDefaults.putAll(Ims.getDefaults());
}
/**
@@ -3659,4 +3677,75 @@
return ICarrierConfigLoader.Stub
.asInterface(ServiceManager.getService(Context.CARRIER_CONFIG_SERVICE));
}
+
+ /**
+ * Gets the configuration values for a component using its prefix.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param prefix prefix of the component.
+ * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
+ *
+ * @see #getConfigForSubId
+ */
+ @Nullable
+ public PersistableBundle getConfigByComponentForSubId(String prefix, int subId) {
+ PersistableBundle configs = getConfigForSubId(subId);
+
+ if (configs == null) {
+ return null;
+ }
+
+ PersistableBundle ret = new PersistableBundle();
+ for (String configKey : configs.keySet()) {
+ if (configKey.startsWith(prefix)) {
+ addConfig(configKey, configs.get(configKey), ret);
+ }
+ }
+
+ return ret;
+ }
+
+ private void addConfig(String key, Object value, PersistableBundle configs) {
+ if (value instanceof String) {
+ configs.putString(key, (String) value);
+ }
+
+ if (value instanceof String[]) {
+ configs.putStringArray(key, (String[]) value);
+ }
+
+ if (value instanceof Integer) {
+ configs.putInt(key, (Integer) value);
+ }
+
+ if (value instanceof Long) {
+ configs.putLong(key, (Long) value);
+ }
+
+ if (value instanceof Double) {
+ configs.putDouble(key, (Double) value);
+ }
+
+ if (value instanceof Boolean) {
+ configs.putBoolean(key, (Boolean) value);
+ }
+
+ if (value instanceof int[]) {
+ configs.putIntArray(key, (int[]) value);
+ }
+
+ if (value instanceof double[]) {
+ configs.putDoubleArray(key, (double[]) value);
+ }
+
+ if (value instanceof boolean[]) {
+ configs.putBooleanArray(key, (boolean[]) value);
+ }
+
+ if (value instanceof long[]) {
+ configs.putLongArray(key, (long[]) value);
+ }
+ }
}
diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java
index 8c686f7..8e1324b 100644
--- a/telephony/java/android/telephony/ims/ImsException.java
+++ b/telephony/java/android/telephony/ims/ImsException.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.pm.PackageManager;
+import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import java.lang.annotation.Retention;
@@ -55,12 +56,23 @@
*/
public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2;
+ /**
+ * The subscription ID associated with this operation is invalid or not active.
+ * <p>
+ * This is a configuration error and there should be no retry. The subscription used for this
+ * operation is either invalid or has become inactive. The active subscriptions can be queried
+ * with {@link SubscriptionManager#getActiveSubscriptionInfoList()}.
+ * @hide
+ */
+ public static final int CODE_ERROR_INVALID_SUBSCRIPTION = 3;
+
/**@hide*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "CODE_ERROR_", value = {
CODE_ERROR_UNSPECIFIED,
CODE_ERROR_SERVICE_UNAVAILABLE,
- CODE_ERROR_UNSUPPORTED_OPERATION
+ CODE_ERROR_UNSUPPORTED_OPERATION,
+ CODE_ERROR_INVALID_SUBSCRIPTION
})
public @interface ImsErrorCode {}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index be58723..a1a7fcc 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -31,6 +31,7 @@
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
import android.telephony.AccessNetworkConstants;
import android.telephony.SubscriptionManager;
import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -375,6 +376,13 @@
c.setExecutor(executor);
try {
getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException | IllegalStateException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
@@ -390,8 +398,6 @@
* @param c The {@link RegistrationCallback} to be removed.
* @see SubscriptionManager.OnSubscriptionsChangedListener
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
- * @throws IllegalArgumentException if the subscription ID associated with this callback is
- * invalid.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
@@ -445,6 +451,13 @@
c.setExecutor(executor);
try {
getITelephony().registerMmTelCapabilityCallback(mSubId, c.getBinder());
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
} catch (IllegalStateException e) {
@@ -460,8 +473,6 @@
* inactive subscription, it will result in a no-op.
* @param c The MmTel {@link CapabilityCallback} to be removed.
* @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
- * @throws IllegalArgumentException if the subscription ID associated with this callback is
- * invalid.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
@@ -482,12 +493,9 @@
* be enabled as long as the carrier has provisioned these services for the specified
* subscription. Other IMS services (SMS/UT) are not affected by this user setting and depend on
* carrier requirements.
- *
- * Modifying this value may also trigger an IMS registration or deregistration, depending on
- * whether or not the new value is enabled or disabled.
- *
+ * <p>
* Note: If the carrier configuration for advanced calling is not editable or hidden, this
- * method will do nothing and will instead always use the default value.
+ * method will always return the default value.
*
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
* @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL
@@ -495,12 +503,21 @@
* @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
* @see #setAdvancedCallingSettingEnabled(boolean)
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @return true if the user's setting for advanced calling is enabled, false otherwise.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isAdvancedCallingSettingEnabled() {
try {
return getITelephony().isAdvancedCallingSettingEnabled(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -526,12 +543,20 @@
* @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
* @see #isAdvancedCallingSettingEnabled()
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setAdvancedCallingSettingEnabled(boolean isEnabled) {
try {
getITelephony().setAdvancedCallingSettingEnabled(mSubId, isEnabled);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -597,6 +622,9 @@
/**
* The user's setting for whether or not they have enabled the "Video Calling" setting.
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @return true if the user’s “Video Calling” setting is currently enabled.
* @see #setVtSettingEnabled(boolean)
*/
@@ -604,6 +632,13 @@
public boolean isVtSettingEnabled() {
try {
return getITelephony().isVtSettingEnabled(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -611,13 +646,22 @@
/**
* Change the user's setting for Video Telephony and enable the Video Telephony capability.
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #isVtSettingEnabled()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVtSettingEnabled(boolean isEnabled) {
try {
getITelephony().setVtSettingEnabled(mSubId, isEnabled);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -625,12 +669,22 @@
/**
* @return true if the user's setting for Voice over WiFi is enabled and false if it is not.
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #setVoWiFiSettingEnabled(boolean)
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isVoWiFiSettingEnabled() {
try {
return getITelephony().isVoWiFiSettingEnabled(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -638,6 +692,9 @@
/**
* Sets the user's setting for whether or not Voice over WiFi is enabled.
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @param isEnabled true if the user's setting for Voice over WiFi is enabled, false otherwise=
* @see #isVoWiFiSettingEnabled()
*/
@@ -645,13 +702,23 @@
public void setVoWiFiSettingEnabled(boolean isEnabled) {
try {
getITelephony().setVoWiFiSettingEnabled(mSubId, isEnabled);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
+ * Returns the user's voice over WiFi roaming setting associated with the current subscription.
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @return true if the user's setting for Voice over WiFi while roaming is enabled, false
* if disabled.
* @see #setVoWiFiRoamingSettingEnabled(boolean)
@@ -660,6 +727,13 @@
public boolean isVoWiFiRoamingSettingEnabled() {
try {
return getITelephony().isVoWiFiRoamingSettingEnabled(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -667,15 +741,24 @@
/**
* Change the user's setting for Voice over WiFi while roaming.
+ *
* @param isEnabled true if the user's setting for Voice over WiFi while roaming is enabled,
* false otherwise.
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #isVoWiFiRoamingSettingEnabled()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingSettingEnabled(boolean isEnabled) {
try {
getITelephony().setVoWiFiRoamingSettingEnabled(mSubId, isEnabled);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -691,19 +774,31 @@
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #setVoWiFiSettingEnabled(boolean)
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiNonPersistent(boolean isCapable, int mode) {
try {
getITelephony().setVoWiFiNonPersistent(mSubId, isCapable, mode);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
+ * Returns the user's voice over WiFi Roaming mode setting associated with the device.
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @return The Voice over WiFi Mode preference set by the user, which can be one of the
* following:
* - {@link #WIFI_MODE_WIFI_ONLY}
@@ -715,6 +810,13 @@
public @WiFiCallingMode int getVoWiFiModeSetting() {
try {
return getITelephony().getVoWiFiModeSetting(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -727,13 +829,21 @@
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #getVoWiFiModeSetting()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiModeSetting(@WiFiCallingMode int mode) {
try {
getITelephony().setVoWiFiModeSetting(mSubId, mode);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -748,12 +858,21 @@
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #setVoWiFiRoamingSettingEnabled(boolean)
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @WiFiCallingMode int getVoWiFiRoamingModeSetting() {
try {
return getITelephony().getVoWiFiRoamingModeSetting(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -768,13 +887,21 @@
* - {@link #WIFI_MODE_WIFI_ONLY}
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see #getVoWiFiRoamingModeSetting()
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) {
try {
getITelephony().setVoWiFiRoamingModeSetting(mSubId, mode);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -787,13 +914,21 @@
* {@link android.provider.Settings.Secure#RTT_CALLING_MODE}, which is the global user setting
* for RTT. That value is enabled/disabled separately by the user through the Accessibility
* settings.
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @param isEnabled if true RTT should be enabled during calls made on this subscription.
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setRttCapabilitySetting(boolean isEnabled) {
try {
getITelephony().setRttCapabilitySetting(mSubId, isEnabled);
- return;
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -801,6 +936,9 @@
/**
* @return true if TTY over VoLTE is supported
+ *
+ * @throws IllegalArgumentException if the subscription associated with this operation is not
+ * active (SIM is not inserted, ESIM inactive) or invalid.
* @see android.telecom.TelecomManager#getCurrentTtyMode
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
*/
@@ -808,6 +946,13 @@
boolean isTtyOverVolteEnabled() {
try {
return getITelephony().isTtyOverVolteEnabled(mSubId);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+ // Rethrow as runtime error to keep API compatible.
+ throw new IllegalArgumentException(e.getMessage());
+ } else {
+ throw new RuntimeException(e.getMessage());
+ }
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
index 4433c1c..53e4596 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
@@ -17,6 +17,8 @@
package android.telephony.ims.aidl;
+import android.os.PersistableBundle;
+
import android.telephony.ims.aidl.IImsConfigCallback;
import com.android.ims.ImsConfigListener;
@@ -37,4 +39,5 @@
int setConfigInt(int item, int value);
// Return result code defined in ImsConfig#OperationStatusConstants
int setConfigString(int item, String value);
+ void updateImsCarrierConfigs(in PersistableBundle bundle);
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index 321bfff..91b0a43 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.content.Context;
+import android.os.PersistableBundle;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.telephony.ims.aidl.IImsConfig;
@@ -182,6 +183,11 @@
return retVal;
}
+ @Override
+ public void updateImsCarrierConfigs(PersistableBundle bundle) throws RemoteException {
+ getImsConfigImpl().updateImsCarrierConfigs(bundle);
+ }
+
private ImsConfigImplBase getImsConfigImpl() throws RemoteException {
ImsConfigImplBase ref = mImsConfigImplBaseWeakReference.get();
if (ref == null) {
@@ -387,4 +393,11 @@
// Base Implementation - To be overridden.
return null;
}
+
+ /**
+ * @hide
+ */
+ public void updateImsCarrierConfigs(PersistableBundle bundle) {
+ // Base Implementation - Should be overridden
+ }
}
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 11150dd..b725920 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -386,6 +386,9 @@
manifest_action["package-verifier"];
manifest_action["meta-data"] = meta_data_action;
manifest_action["uses-split"].Action(RequiredNameIsJavaPackage);
+ manifest_action["queries"]["package"].Action(RequiredNameIsJavaPackage);
+ manifest_action["queries"]["intent"] = intent_filter_action;
+ // TODO: more complicated component name tag
manifest_action["key-sets"]["key-set"]["public-key"];
manifest_action["key-sets"]["upgrade-key-set"];
diff --git a/tools/preload2/Android.bp b/tools/preload2/Android.bp
deleted file mode 100644
index 5809421..0000000
--- a/tools/preload2/Android.bp
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (C) 2015 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.
-
-java_library_host {
- name: "preload2",
-
- srcs: ["src/**/*.java"],
-
- // To connect to devices (and take hprof dumps).
- static_libs: [
- "ddmlib-prebuilt",
- "tools-common-prebuilt",
-
- // To process hprof dumps.
- "perflib-prebuilt",
-
- "trove-prebuilt",
- "guavalib",
-
- // For JDWP access we use the framework in the JDWP tests from Apache Harmony, for
- // convenience (and to not depend on internal JDK APIs).
- "apache-harmony-jdwp-tests",
- "junit",
- ],
-
- // Copy to build artifacts
- dist: {
- targets: [
- "dist_files",
- ],
- },
-}
-
-// Copy the preload-tool shell script to the host's bin directory.
-sh_binary_host {
- name: "preload-tool",
- src: "preload-tool",
- required: ["preload2"],
-}
diff --git a/tools/preload2/preload-tool b/tools/preload2/preload-tool
deleted file mode 100644
index 322b62f..0000000
--- a/tools/preload2/preload-tool
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2015 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.
-
-# This script is used on the host only. It uses a common subset
-# shell dialect that should work well. It is partially derived
-# from art/tools/art.
-
-function follow_links() {
- if [ z"$BASH_SOURCE" != z ]; then
- file="$BASH_SOURCE"
- else
- file="$0"
- fi
- while [ -h "$file" ]; do
- # On Mac OS, readlink -f doesn't work.
- file="$(readlink "$file")"
- done
- echo "$file"
-}
-
-
-PROG_NAME="$(follow_links)"
-PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-ANDROID_ROOT=$PROG_DIR/..
-
-java -cp $ANDROID_ROOT/framework/preload2.jar com.android.preload.Main $@
diff --git a/tools/preload2/src/com/android/preload/ClientUtils.java b/tools/preload2/src/com/android/preload/ClientUtils.java
deleted file mode 100644
index 71ef025..0000000
--- a/tools/preload2/src/com/android/preload/ClientUtils.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload;
-
-import com.android.ddmlib.AndroidDebugBridge;
-import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-
-/**
- * Helper class for common communication with a Client (the ddms name for a running application).
- *
- * Instances take a default timeout parameter that's applied to all functions without explicit
- * timeout. Timeouts are in milliseconds.
- */
-public class ClientUtils {
-
- private int defaultTimeout;
-
- public ClientUtils() {
- this(10000);
- }
-
- public ClientUtils(int defaultTimeout) {
- this.defaultTimeout = defaultTimeout;
- }
-
- /**
- * Shortcut for findClient with default timeout.
- */
- public Client findClient(IDevice device, String processName, int processPid) {
- return findClient(device, processName, processPid, defaultTimeout);
- }
-
- /**
- * Find the client with the given process name or process id. The name takes precedence over
- * the process id (if valid). Stop looking after the given timeout.
- *
- * @param device The device to communicate with.
- * @param processName The name of the process. May be null.
- * @param processPid The pid of the process. Values less than or equal to zero are ignored.
- * @param timeout The amount of milliseconds to wait, at most.
- * @return The client, if found. Otherwise null.
- */
- public Client findClient(IDevice device, String processName, int processPid, int timeout) {
- WaitForClient wfc = new WaitForClient(device, processName, processPid, timeout);
- return wfc.get();
- }
-
- /**
- * Shortcut for findAllClients with default timeout.
- */
- public Client[] findAllClients(IDevice device) {
- return findAllClients(device, defaultTimeout);
- }
-
- /**
- * Retrieve all clients known to the given device. Wait at most the given timeout.
- *
- * @param device The device to investigate.
- * @param timeout The amount of milliseconds to wait, at most.
- * @return An array of clients running on the given device. May be null depending on the
- * device implementation.
- */
- public Client[] findAllClients(IDevice device, int timeout) {
- if (device.hasClients()) {
- return device.getClients();
- }
- WaitForClients wfc = new WaitForClients(device, timeout);
- return wfc.get();
- }
-
- private static class WaitForClient implements IClientChangeListener {
-
- private IDevice device;
- private String processName;
- private int processPid;
- private long timeout;
- private Client result;
-
- public WaitForClient(IDevice device, String processName, int processPid, long timeout) {
- this.device = device;
- this.processName = processName;
- this.processPid = processPid;
- this.timeout = timeout;
- this.result = null;
- }
-
- public Client get() {
- synchronized (this) {
- AndroidDebugBridge.addClientChangeListener(this);
-
- // Maybe it's already there.
- if (result == null) {
- result = searchForClient(device);
- }
-
- if (result == null) {
- try {
- wait(timeout);
- } catch (InterruptedException e) {
- // Note: doesn't guard for spurious wakeup.
- }
- }
- }
-
- AndroidDebugBridge.removeClientChangeListener(this);
- return result;
- }
-
- private Client searchForClient(IDevice device) {
- if (processName != null) {
- Client tmp = device.getClient(processName);
- if (tmp != null) {
- return tmp;
- }
- }
- if (processPid > 0) {
- String name = device.getClientName(processPid);
- if (name != null && !name.isEmpty()) {
- Client tmp = device.getClient(name);
- if (tmp != null) {
- return tmp;
- }
- }
- }
- if (processPid > 0) {
- // Try manual search.
- for (Client cl : device.getClients()) {
- if (cl.getClientData().getPid() == processPid
- && cl.getClientData().getClientDescription() != null) {
- return cl;
- }
- }
- }
- return null;
- }
-
- private boolean isTargetClient(Client c) {
- if (processPid > 0 && c.getClientData().getPid() == processPid) {
- return true;
- }
- if (processName != null
- && processName.equals(c.getClientData().getClientDescription())) {
- return true;
- }
- return false;
- }
-
- @Override
- public void clientChanged(Client arg0, int arg1) {
- synchronized (this) {
- if ((arg1 & Client.CHANGE_INFO) != 0 && (arg0.getDevice() == device)) {
- if (isTargetClient(arg0)) {
- result = arg0;
- notifyAll();
- }
- }
- }
- }
- }
-
- private static class WaitForClients implements IClientChangeListener {
-
- private IDevice device;
- private long timeout;
-
- public WaitForClients(IDevice device, long timeout) {
- this.device = device;
- this.timeout = timeout;
- }
-
- public Client[] get() {
- synchronized (this) {
- AndroidDebugBridge.addClientChangeListener(this);
-
- if (device.hasClients()) {
- return device.getClients();
- }
-
- try {
- wait(timeout); // Note: doesn't guard for spurious wakeup.
- } catch (InterruptedException exc) {
- }
-
- // We will be woken up when the first client data arrives. Sleep a little longer
- // to give (hopefully all of) the rest of the clients a chance to become available.
- // Note: a loop with timeout is brittle as well and complicated, just accept this
- // for now.
- try {
- Thread.sleep(500);
- } catch (InterruptedException exc) {
- }
- }
-
- AndroidDebugBridge.removeClientChangeListener(this);
-
- return device.getClients();
- }
-
- @Override
- public void clientChanged(Client arg0, int arg1) {
- synchronized (this) {
- if ((arg1 & Client.CHANGE_INFO) != 0 && (arg0.getDevice() == device)) {
- notifyAll();
- }
- }
- }
- }
-}
diff --git a/tools/preload2/src/com/android/preload/DeviceUtils.java b/tools/preload2/src/com/android/preload/DeviceUtils.java
deleted file mode 100644
index 18cab7b..0000000
--- a/tools/preload2/src/com/android/preload/DeviceUtils.java
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload;
-
-import com.android.ddmlib.AdbCommandRejectedException;
-import com.android.ddmlib.AndroidDebugBridge;
-import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
-import com.android.preload.classdataretrieval.hprof.Hprof;
-import com.android.ddmlib.DdmPreferences;
-import com.android.ddmlib.IDevice;
-import com.android.ddmlib.IShellOutputReceiver;
-import com.android.ddmlib.SyncException;
-import com.android.ddmlib.TimeoutException;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Date;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Helper class for some device routines.
- */
-public class DeviceUtils {
-
- // Locations
- private static final String PRELOADED_CLASSES_FILE = "/etc/preloaded-classes";
- // Shell commands
- private static final String CREATE_EMPTY_PRELOADED_CMD = "touch " + PRELOADED_CLASSES_FILE;
- private static final String DELETE_CACHE_CMD = "rm /data/dalvik-cache/*/*boot.art";
- private static final String DELETE_PRELOADED_CMD = "rm " + PRELOADED_CLASSES_FILE;
- private static final String READ_PRELOADED_CMD = "cat " + PRELOADED_CLASSES_FILE;
- private static final String START_SHELL_CMD = "start";
- private static final String STOP_SHELL_CMD = "stop";
- private static final String REMOUNT_SYSTEM_CMD = "mount -o rw,remount /system";
- private static final String UNSET_BOOTCOMPLETE_CMD = "setprop dev.bootcomplete \"0\"";
-
- public static void init(int debugPort) {
- DdmPreferences.setSelectedDebugPort(debugPort);
-
- Hprof.init();
-
- AndroidDebugBridge.init(true);
-
- AndroidDebugBridge.createBridge();
- }
-
- /**
- * Run a command in the shell on the device.
- */
- public static void doShell(IDevice device, String cmdline, long timeout, TimeUnit unit) {
- doShell(device, cmdline, new NullShellOutputReceiver(), timeout, unit);
- }
-
- /**
- * Run a command in the shell on the device. Collects and returns the console output.
- */
- public static String doShellReturnString(IDevice device, String cmdline, long timeout,
- TimeUnit unit) {
- CollectStringShellOutputReceiver rec = new CollectStringShellOutputReceiver();
- doShell(device, cmdline, rec, timeout, unit);
- return rec.toString();
- }
-
- /**
- * Run a command in the shell on the device, directing all output to the given receiver.
- */
- public static void doShell(IDevice device, String cmdline, IShellOutputReceiver receiver,
- long timeout, TimeUnit unit) {
- try {
- device.executeShellCommand(cmdline, receiver, timeout, unit);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- /**
- * Run am start on the device.
- */
- public static void doAMStart(IDevice device, String name, String activity) {
- doShell(device, "am start -n " + name + " /." + activity, 30, TimeUnit.SECONDS);
- }
-
- /**
- * Find the device with the given serial. Give up after the given timeout (in milliseconds).
- */
- public static IDevice findDevice(String serial, int timeout) {
- WaitForDevice wfd = new WaitForDevice(serial, timeout);
- return wfd.get();
- }
-
- /**
- * Get all devices ddms knows about. Wait at most for the given timeout.
- */
- public static IDevice[] findDevices(int timeout) {
- WaitForDevice wfd = new WaitForDevice(null, timeout);
- wfd.get();
- return AndroidDebugBridge.getBridge().getDevices();
- }
-
- /**
- * Return the build type of the given device. This is the value of the "ro.build.type"
- * system property.
- */
- public static String getBuildType(IDevice device) {
- try {
- Future<String> buildType = device.getSystemProperty("ro.build.type");
- return buildType.get(500, TimeUnit.MILLISECONDS);
- } catch (Exception e) {
- }
- return null;
- }
-
- /**
- * Check whether the given device has a pre-optimized boot image. More precisely, checks
- * whether /system/framework/ * /boot.art exists.
- */
- public static boolean hasPrebuiltBootImage(IDevice device) {
- String ret =
- doShellReturnString(device, "ls /system/framework/*/boot.art", 500, TimeUnit.MILLISECONDS);
-
- return !ret.contains("No such file or directory");
- }
-
- /**
- * Write over the preloaded-classes file with an empty or existing file and regenerate the boot
- * image as necessary.
- *
- * @param device
- * @param pcFile
- * @param bootTimeout
- * @throws AdbCommandRejectedException
- * @throws IOException
- * @throws TimeoutException
- * @throws SyncException
- * @return true if successfully overwritten, false otherwise
- */
- public static boolean overwritePreloaded(IDevice device, File pcFile, long bootTimeout)
- throws AdbCommandRejectedException, IOException, TimeoutException, SyncException {
- boolean writeEmpty = (pcFile == null);
- if (writeEmpty) {
- // Check if the preloaded-classes file is already empty.
- String oldContent =
- doShellReturnString(device, READ_PRELOADED_CMD, 1, TimeUnit.SECONDS);
- if (oldContent.trim().equals("")) {
- System.out.println("Preloaded-classes already empty.");
- return true;
- }
- }
-
- // Stop the system server etc.
- doShell(device, STOP_SHELL_CMD, 1, TimeUnit.SECONDS);
- // Remount the read-only system partition
- doShell(device, REMOUNT_SYSTEM_CMD, 1, TimeUnit.SECONDS);
- // Delete the preloaded-classes file
- doShell(device, DELETE_PRELOADED_CMD, 1, TimeUnit.SECONDS);
- // Delete the dalvik cache files
- doShell(device, DELETE_CACHE_CMD, 1, TimeUnit.SECONDS);
- if (writeEmpty) {
- // Write an empty preloaded-classes file
- doShell(device, CREATE_EMPTY_PRELOADED_CMD, 500, TimeUnit.MILLISECONDS);
- } else {
- // Push the new preloaded-classes file
- device.pushFile(pcFile.getAbsolutePath(), PRELOADED_CLASSES_FILE);
- }
- // Manually reset the boot complete flag
- doShell(device, UNSET_BOOTCOMPLETE_CMD, 1, TimeUnit.SECONDS);
- // Restart system server on the device
- doShell(device, START_SHELL_CMD, 1, TimeUnit.SECONDS);
- // Wait for the boot complete flag and return the outcome.
- return waitForBootComplete(device, bootTimeout);
- }
-
- private static boolean waitForBootComplete(IDevice device, long timeout) {
- // Do a loop checking each second whether bootcomplete. Wait for at most the given
- // threshold.
- Date startDate = new Date();
- for (;;) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // Ignore spurious wakeup.
- }
- // Check whether bootcomplete.
- String ret =
- doShellReturnString(device, "getprop dev.bootcomplete", 500, TimeUnit.MILLISECONDS);
- if (ret.trim().equals("1")) {
- break;
- }
- System.out.println("Still not booted: " + ret);
-
- // Check whether we timed out. This is a simplistic check that doesn't take into account
- // things like switches in time.
- Date endDate = new Date();
- long seconds =
- TimeUnit.SECONDS.convert(endDate.getTime() - startDate.getTime(), TimeUnit.MILLISECONDS);
- if (seconds > timeout) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Enable method-tracing on device. The system should be restarted after this.
- */
- public static void enableTracing(IDevice device) {
- // Disable selinux.
- doShell(device, "setenforce 0", 100, TimeUnit.MILLISECONDS);
-
- // Make the profile directory world-writable.
- doShell(device, "chmod 777 /data/dalvik-cache/profiles", 100, TimeUnit.MILLISECONDS);
-
- // Enable streaming method tracing with a small 1K buffer.
- doShell(device, "setprop dalvik.vm.method-trace true", 100, TimeUnit.MILLISECONDS);
- doShell(device, "setprop dalvik.vm.method-trace-file "
- + "/data/dalvik-cache/profiles/zygote.trace.bin", 100, TimeUnit.MILLISECONDS);
- doShell(device, "setprop dalvik.vm.method-trace-file-siz 1024", 100, TimeUnit.MILLISECONDS);
- doShell(device, "setprop dalvik.vm.method-trace-stream true", 100, TimeUnit.MILLISECONDS);
- }
-
- private static class NullShellOutputReceiver implements IShellOutputReceiver {
- @Override
- public boolean isCancelled() {
- return false;
- }
-
- @Override
- public void flush() {}
-
- @Override
- public void addOutput(byte[] arg0, int arg1, int arg2) {}
- }
-
- private static class CollectStringShellOutputReceiver implements IShellOutputReceiver {
-
- private StringBuilder builder = new StringBuilder();
-
- @Override
- public String toString() {
- String ret = builder.toString();
- // Strip trailing newlines. They are especially ugly because adb uses DOS line endings.
- while (ret.endsWith("\r") || ret.endsWith("\n")) {
- ret = ret.substring(0, ret.length() - 1);
- }
- return ret;
- }
-
- @Override
- public void addOutput(byte[] arg0, int arg1, int arg2) {
- builder.append(new String(arg0, arg1, arg2));
- }
-
- @Override
- public void flush() {}
-
- @Override
- public boolean isCancelled() {
- return false;
- }
- }
-
- private static class WaitForDevice {
-
- private String serial;
- private long timeout;
- private IDevice device;
-
- public WaitForDevice(String serial, long timeout) {
- this.serial = serial;
- this.timeout = timeout;
- device = null;
- }
-
- public IDevice get() {
- if (device == null) {
- WaitForDeviceListener wfdl = new WaitForDeviceListener(serial);
- synchronized (wfdl) {
- AndroidDebugBridge.addDeviceChangeListener(wfdl);
-
- // Check whether we already know about this device.
- IDevice[] devices = AndroidDebugBridge.getBridge().getDevices();
- if (serial != null) {
- for (IDevice d : devices) {
- if (serial.equals(d.getSerialNumber())) {
- // Only accept if there are clients already. Else wait for the callback informing
- // us that we now have clients.
- if (d.hasClients()) {
- device = d;
- }
-
- break;
- }
- }
- } else {
- if (devices.length > 0) {
- device = devices[0];
- }
- }
-
- if (device == null) {
- try {
- wfdl.wait(timeout);
- } catch (InterruptedException e) {
- // Ignore spurious wakeups.
- }
- device = wfdl.getDevice();
- }
-
- AndroidDebugBridge.removeDeviceChangeListener(wfdl);
- }
- }
-
- if (device != null) {
- // Wait for clients.
- WaitForClientsListener wfcl = new WaitForClientsListener(device);
- synchronized (wfcl) {
- AndroidDebugBridge.addDeviceChangeListener(wfcl);
-
- if (!device.hasClients()) {
- try {
- wfcl.wait(timeout);
- } catch (InterruptedException e) {
- // Ignore spurious wakeups.
- }
- }
-
- AndroidDebugBridge.removeDeviceChangeListener(wfcl);
- }
- }
-
- return device;
- }
-
- private static class WaitForDeviceListener implements IDeviceChangeListener {
-
- private String serial;
- private IDevice device;
-
- public WaitForDeviceListener(String serial) {
- this.serial = serial;
- }
-
- public IDevice getDevice() {
- return device;
- }
-
- @Override
- public void deviceChanged(IDevice arg0, int arg1) {
- // We may get a device changed instead of connected. Handle like a connection.
- deviceConnected(arg0);
- }
-
- @Override
- public void deviceConnected(IDevice arg0) {
- if (device != null) {
- // Ignore updates.
- return;
- }
-
- if (serial == null || serial.equals(arg0.getSerialNumber())) {
- device = arg0;
- synchronized (this) {
- notifyAll();
- }
- }
- }
-
- @Override
- public void deviceDisconnected(IDevice arg0) {
- // Ignore disconnects.
- }
-
- }
-
- private static class WaitForClientsListener implements IDeviceChangeListener {
-
- private IDevice myDevice;
-
- public WaitForClientsListener(IDevice myDevice) {
- this.myDevice = myDevice;
- }
-
- @Override
- public void deviceChanged(IDevice arg0, int arg1) {
- if (arg0 == myDevice && (arg1 & IDevice.CHANGE_CLIENT_LIST) != 0) {
- // Got a client list, done here.
- synchronized (this) {
- notifyAll();
- }
- }
- }
-
- @Override
- public void deviceConnected(IDevice arg0) {
- }
-
- @Override
- public void deviceDisconnected(IDevice arg0) {
- }
-
- }
- }
-
-}
diff --git a/tools/preload2/src/com/android/preload/DumpData.java b/tools/preload2/src/com/android/preload/DumpData.java
deleted file mode 100644
index d997224..0000000
--- a/tools/preload2/src/com/android/preload/DumpData.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload;
-
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Holds the collected data for a process.
- */
-public class DumpData {
- /**
- * Name of the package (=application).
- */
- String packageName;
-
- /**
- * A map of class name to a string for the classloader. This may be a toString equivalent,
- * or just a unique ID.
- */
- Map<String, String> dumpData;
-
- /**
- * The Date when this data was captured. Mostly for display purposes.
- */
- Date date;
-
- /**
- * A cached value for the number of boot classpath classes (classloader value in dumpData is
- * null).
- */
- int bcpClasses;
-
- public DumpData(String packageName, Map<String, String> dumpData, Date date) {
- this.packageName = packageName;
- this.dumpData = dumpData;
- this.date = date;
-
- countBootClassPath();
- }
-
- public String getPackageName() {
- return packageName;
- }
-
- public Date getDate() {
- return date;
- }
-
- public Map<String, String> getDumpData() {
- return dumpData;
- }
-
- public void countBootClassPath() {
- bcpClasses = 0;
- for (Map.Entry<String, String> e : dumpData.entrySet()) {
- if (e.getValue() == null) {
- bcpClasses++;
- }
- }
- }
-
- // Return an inverted mapping.
- public Map<String, Set<String>> invertData() {
- Map<String, Set<String>> ret = new HashMap<>();
- for (Map.Entry<String, String> e : dumpData.entrySet()) {
- if (!ret.containsKey(e.getValue())) {
- ret.put(e.getValue(), new HashSet<String>());
- }
- ret.get(e.getValue()).add(e.getKey());
- }
- return ret;
- }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/DumpDataIO.java b/tools/preload2/src/com/android/preload/DumpDataIO.java
deleted file mode 100644
index 28625c5..0000000
--- a/tools/preload2/src/com/android/preload/DumpDataIO.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.DefaultHandler;
-
-import java.io.File;
-import java.io.FileReader;
-import java.text.DateFormat;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-/**
- * Helper class for serialization and deserialization of a collection of DumpData objects to XML.
- */
-public class DumpDataIO {
-
- /**
- * Serialize the given collection to an XML document. Returns the produced string.
- */
- public static String serialize(Collection<DumpData> data) {
- // We'll do this by hand, constructing a DOM or similar is too complicated for our simple
- // use case.
-
- StringBuilder sb = new StringBuilder();
- sb.append("<preloaded-classes-data>\n");
-
- for (DumpData d : data) {
- serialize(d, sb);
- }
-
- sb.append("</preloaded-classes-data>\n");
- return sb.toString();
- }
-
- private static void serialize(DumpData d, StringBuilder sb) {
- sb.append("<data package=\"" + d.packageName + "\" date=\"" +
- DateFormat.getDateTimeInstance().format(d.date) +"\">\n");
-
- for (Map.Entry<String, String> e : d.dumpData.entrySet()) {
- sb.append("<class name=\"" + e.getKey() + "\" classloader=\"" + e.getValue() + "\"/>\n");
- }
-
- sb.append("</data>\n");
- }
-
- /**
- * Load a collection of DumpData objects from the given file.
- */
- public static Collection<DumpData> deserialize(File f) throws Exception {
- // Use SAX parsing. Our format is very simple. Don't do any schema validation or such.
-
- SAXParserFactory spf = SAXParserFactory.newInstance();
- spf.setNamespaceAware(false);
- SAXParser saxParser = spf.newSAXParser();
-
- XMLReader xmlReader = saxParser.getXMLReader();
- DumpDataContentHandler ddch = new DumpDataContentHandler();
- xmlReader.setContentHandler(ddch);
- xmlReader.parse(new InputSource(new FileReader(f)));
-
- return ddch.data;
- }
-
- private static class DumpDataContentHandler extends DefaultHandler {
- Collection<DumpData> data = new LinkedList<DumpData>();
- DumpData openData = null;
-
- @Override
- public void startElement(String uri, String localName, String qName, Attributes attributes)
- throws SAXException {
- if (qName.equals("data")) {
- if (openData != null) {
- throw new IllegalStateException();
- }
- String pkg = attributes.getValue("package");
- String dateString = attributes.getValue("date");
-
- if (pkg == null || dateString == null) {
- throw new IllegalArgumentException();
- }
-
- try {
- Date date = DateFormat.getDateTimeInstance().parse(dateString);
- openData = new DumpData(pkg, new HashMap<String, String>(), date);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- } else if (qName.equals("class")) {
- if (openData == null) {
- throw new IllegalStateException();
- }
- String className = attributes.getValue("name");
- String classLoader = attributes.getValue("classloader");
-
- if (className == null || classLoader == null) {
- throw new IllegalArgumentException();
- }
-
- openData.dumpData.put(className, classLoader.equals("null") ? null : classLoader);
- }
- }
-
- @Override
- public void endElement(String uri, String localName, String qName) throws SAXException {
- if (qName.equals("data")) {
- if (openData == null) {
- throw new IllegalStateException();
- }
- openData.countBootClassPath();
-
- data.add(openData);
- openData = null;
- }
- }
- }
-}
diff --git a/tools/preload2/src/com/android/preload/DumpTableModel.java b/tools/preload2/src/com/android/preload/DumpTableModel.java
deleted file mode 100644
index d97cbf0..0000000
--- a/tools/preload2/src/com/android/preload/DumpTableModel.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.table.AbstractTableModel;
-
-/**
- * A table model for collected DumpData. This is both the internal storage as well as the model
- * for display.
- */
-public class DumpTableModel extends AbstractTableModel {
-
- private List<DumpData> data = new ArrayList<DumpData>();
-
- public void addData(DumpData d) {
- data.add(d);
- fireTableRowsInserted(data.size() - 1, data.size() - 1);
- }
-
- public void clear() {
- int size = data.size();
- if (size > 0) {
- data.clear();
- fireTableRowsDeleted(0, size - 1);
- }
- }
-
- public List<DumpData> getData() {
- return data;
- }
-
- @Override
- public int getRowCount() {
- return data.size();
- }
-
- @Override
- public int getColumnCount() {
- return 4;
- }
-
- @Override
- public String getColumnName(int column) {
- switch (column) {
- case 0:
- return "Package";
- case 1:
- return "Date";
- case 2:
- return "# All Classes";
- case 3:
- return "# Boot Classpath Classes";
-
- default:
- throw new IndexOutOfBoundsException(String.valueOf(column));
- }
- }
-
- @Override
- public Object getValueAt(int rowIndex, int columnIndex) {
- DumpData d = data.get(rowIndex);
- switch (columnIndex) {
- case 0:
- return d.packageName;
- case 1:
- return d.date;
- case 2:
- return d.dumpData.size();
- case 3:
- return d.bcpClasses;
-
- default:
- throw new IndexOutOfBoundsException(String.valueOf(columnIndex));
- }
- }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/Main.java b/tools/preload2/src/com/android/preload/Main.java
deleted file mode 100644
index 2265e95..0000000
--- a/tools/preload2/src/com/android/preload/Main.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.actions.ClearTableAction;
-import com.android.preload.actions.ComputeThresholdAction;
-import com.android.preload.actions.ComputeThresholdXAction;
-import com.android.preload.actions.DeviceSpecific;
-import com.android.preload.actions.ExportAction;
-import com.android.preload.actions.ImportAction;
-import com.android.preload.actions.ReloadListAction;
-import com.android.preload.actions.RunMonkeyAction;
-import com.android.preload.actions.ScanAllPackagesAction;
-import com.android.preload.actions.ScanPackageAction;
-import com.android.preload.actions.ShowDataAction;
-import com.android.preload.actions.WritePreloadedClassesAction;
-import com.android.preload.classdataretrieval.ClassDataRetriever;
-import com.android.preload.classdataretrieval.hprof.Hprof;
-import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever;
-import com.android.preload.ui.IUI;
-import com.android.preload.ui.SequenceUI;
-import com.android.preload.ui.SwingUI;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-
-import javax.swing.Action;
-import javax.swing.DefaultListModel;
-
-public class Main {
-
- /**
- * Enable tracing mode. This is a work-in-progress to derive compiled-methods data, so it is
- * off for now.
- */
- public final static boolean ENABLE_TRACING = false;
-
- /**
- * Ten-second timeout.
- */
- public final static int DEFAULT_TIMEOUT_MILLIS = 10 * 1000;
-
- /**
- * Hprof timeout. Two minutes.
- */
- public final static int HPROF_TIMEOUT_MILLIS = 120 * 1000;
-
- private IDevice device;
- private static ClientUtils clientUtils;
-
- private DumpTableModel dataTableModel;
- private DefaultListModel<Client> clientListModel;
-
- private IUI ui;
-
- // Actions that need to be updated once a device is selected.
- private Collection<DeviceSpecific> deviceSpecificActions;
-
- // Current main instance.
- private static Main top;
- private static boolean useJdwpClassDataRetriever = false;
-
- public final static String CLASS_PRELOAD_BLACKLIST = "android.app.AlarmManager$" + "|"
- + "android.app.SearchManager$" + "|" + "android.os.FileObserver$" + "|"
- + "com.android.server.PackageManagerService\\$AppDirObserver$" + "|" +
-
-
- // Threads
- "android.os.AsyncTask$" + "|" + "android.pim.ContactsAsyncHelper$" + "|"
- + "android.webkit.WebViewClassic\\$1$" + "|" + "java.lang.ProcessManager$" + "|"
- + "(.*\\$NoPreloadHolder$)";
-
- public final static String SCAN_ALL_CMD = "scan-all";
- public final static String SCAN_PACKAGE_CMD = "scan";
- public final static String COMPUTE_FILE_CMD = "comp";
- public final static String EXPORT_CMD = "export";
- public final static String IMPORT_CMD = "import";
- public final static String WRITE_CMD = "write";
-
- /**
- * @param args
- */
- public static void main(String[] args) {
- Main m;
- if (args.length > 0 && args[0].equals("--seq")) {
- m = createSequencedMain(args);
- } else {
- m = new Main(new SwingUI());
- }
-
- top = m;
- m.startUp();
- }
-
- public Main(IUI ui) {
- this.ui = ui;
-
- clientListModel = new DefaultListModel<Client>();
- dataTableModel = new DumpTableModel();
-
- clientUtils = new ClientUtils(DEFAULT_TIMEOUT_MILLIS); // Client utils with 10s timeout.
-
- List<Action> actions = new ArrayList<Action>();
- actions.add(new ReloadListAction(clientUtils, null, clientListModel));
- actions.add(new ClearTableAction(dataTableModel));
- actions.add(new RunMonkeyAction(null, dataTableModel));
- actions.add(new ScanPackageAction(clientUtils, null, dataTableModel));
- actions.add(new ScanAllPackagesAction(clientUtils, null, dataTableModel));
- actions.add(new ComputeThresholdAction("Compute preloaded-classes", dataTableModel, 2,
- CLASS_PRELOAD_BLACKLIST));
- actions.add(new ComputeThresholdAction("Compute compiled-classes", dataTableModel, 1,
- null));
- actions.add(new ComputeThresholdXAction("Compute(X)", dataTableModel,
- CLASS_PRELOAD_BLACKLIST));
- actions.add(new WritePreloadedClassesAction(clientUtils, null, dataTableModel));
- actions.add(new ShowDataAction(dataTableModel));
- actions.add(new ImportAction(dataTableModel));
- actions.add(new ExportAction(dataTableModel));
-
- deviceSpecificActions = new ArrayList<DeviceSpecific>();
- for (Action a : actions) {
- if (a instanceof DeviceSpecific) {
- deviceSpecificActions.add((DeviceSpecific)a);
- }
- }
-
- ui.prepare(clientListModel, dataTableModel, actions);
- }
-
- /**
- * @param args
- * @return
- */
- private static Main createSequencedMain(String[] args) {
- SequenceUI ui = new SequenceUI();
- Main main = new Main(ui);
-
- Iterator<String> it = Arrays.asList(args).iterator();
- it.next(); // --seq
- // Setup
- ui.choice("#" + it.next()); // Device.
- ui.confirmNo(); // Prepare: no.
- // Actions
- try {
- while (it.hasNext()) {
- String op = it.next();
- // Operation: Scan a single package
- if (SCAN_PACKAGE_CMD.equals(op)) {
- System.out.println("Scanning package.");
- ui.action(ScanPackageAction.class);
- ui.client(it.next());
- // Operation: Scan all packages
- } else if (SCAN_ALL_CMD.equals(op)) {
- System.out.println("Scanning all packages.");
- ui.action(ScanAllPackagesAction.class);
- // Operation: Export the output to a file
- } else if (EXPORT_CMD.equals(op)) {
- System.out.println("Exporting data.");
- ui.action(ExportAction.class);
- ui.output(new File(it.next()));
- // Operation: Import the input from a file or directory
- } else if (IMPORT_CMD.equals(op)) {
- System.out.println("Importing data.");
- File file = new File(it.next());
- if (!file.exists()) {
- throw new RuntimeException(
- String.format("File does not exist, %s.", file.getAbsolutePath()));
- } else if (file.isFile()) {
- ui.action(ImportAction.class);
- ui.input(file);
- } else if (file.isDirectory()) {
- for (File content : file.listFiles()) {
- ui.action(ImportAction.class);
- ui.input(content);
- }
- }
- // Operation: Compute preloaded classes with specific threshold
- } else if (COMPUTE_FILE_CMD.equals(op)) {
- System.out.println("Compute preloaded classes.");
- ui.action(ComputeThresholdXAction.class);
- ui.input(it.next());
- ui.confirmYes();
- ui.output(new File(it.next()));
- // Operation: Write preloaded classes from a specific file
- } else if (WRITE_CMD.equals(op)) {
- System.out.println("Writing preloaded classes.");
- ui.action(WritePreloadedClassesAction.class);
- ui.input(new File(it.next()));
- }
- }
- } catch (NoSuchElementException e) {
- System.out.println("Failed to parse action sequence correctly.");
- throw e;
- }
-
- return main;
- }
-
- public static IUI getUI() {
- return top.ui;
- }
-
- public static ClassDataRetriever getClassDataRetriever() {
- if (useJdwpClassDataRetriever) {
- return new JDWPClassDataRetriever();
- } else {
- return new Hprof(HPROF_TIMEOUT_MILLIS);
- }
- }
-
- public IDevice getDevice() {
- return device;
- }
-
- public void setDevice(IDevice device) {
- this.device = device;
- for (DeviceSpecific ds : deviceSpecificActions) {
- ds.setDevice(device);
- }
- }
-
- public DefaultListModel<Client> getClientListModel() {
- return clientListModel;
- }
-
- static class DeviceWrapper {
- IDevice device;
-
- public DeviceWrapper(IDevice d) {
- device = d;
- }
-
- @Override
- public String toString() {
- return device.getName() + " (#" + device.getSerialNumber() + ")";
- }
- }
-
- private void startUp() {
- getUI().showWaitDialog();
- initDevice();
-
- // Load clients.
- new ReloadListAction(clientUtils, getDevice(), clientListModel).run();
-
- getUI().hideWaitDialog();
- getUI().ready();
- }
-
- private void initDevice() {
- DeviceUtils.init(DEFAULT_TIMEOUT_MILLIS);
-
- IDevice devices[] = DeviceUtils.findDevices(DEFAULT_TIMEOUT_MILLIS);
- if (devices == null || devices.length == 0) {
- throw new RuntimeException("Could not find any devices...");
- }
-
- getUI().hideWaitDialog();
-
- DeviceWrapper deviceWrappers[] = new DeviceWrapper[devices.length];
- for (int i = 0; i < devices.length; i++) {
- deviceWrappers[i] = new DeviceWrapper(devices[i]);
- }
-
- DeviceWrapper ret = Main.getUI().showChoiceDialog("Choose a device", "Choose device",
- deviceWrappers);
- if (ret != null) {
- setDevice(ret.device);
- } else {
- System.exit(0);
- }
-
- boolean prepare = Main.getUI().showConfirmDialog("Prepare device?",
- "Do you want to prepare the device? This is highly recommended.");
- if (prepare) {
- String buildType = DeviceUtils.getBuildType(device);
- if (buildType == null || (!buildType.equals("userdebug") && !buildType.equals("eng"))) {
- Main.getUI().showMessageDialog("Need a userdebug or eng build! (Found " + buildType
- + ")");
- return;
- }
- if (DeviceUtils.hasPrebuiltBootImage(device)) {
- Main.getUI().showMessageDialog("Cannot prepare a device with pre-optimized boot "
- + "image!");
- return;
- }
-
- if (ENABLE_TRACING) {
- DeviceUtils.enableTracing(device);
- }
-
- Main.getUI().showMessageDialog("The device will reboot. This will potentially take a "
- + "long time. Please be patient.");
- boolean success = false;
- try {
- success = DeviceUtils.overwritePreloaded(device, null, 15 * 60);
- } catch (Exception e) {
- System.err.println(e);
- } finally {
- if (!success) {
- Main.getUI().showMessageDialog(
- "Removing preloaded-classes failed unexpectedly!");
- }
- }
- }
- }
-
- public static Map<String, String> findAndGetClassData(IDevice device, String packageName)
- throws Exception {
- Client client = clientUtils.findClient(device, packageName, -1);
- if (client == null) {
- throw new RuntimeException("Could not find client...");
- }
- System.out.println("Found client: " + client);
-
- return getClassDataRetriever().getClassData(client);
- }
-
-}
diff --git a/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java b/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
deleted file mode 100644
index 5787d85..0000000
--- a/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.Main;
-import java.awt.event.ActionEvent;
-
-import javax.swing.AbstractAction;
-
-public abstract class AbstractThreadedAction extends AbstractAction implements Runnable {
-
- protected AbstractThreadedAction(String title) {
- super(title);
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (Main.getUI().isSingleThreaded()) {
- run();
- } else {
- new Thread(this).start();
- }
- }
-
-}
diff --git a/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java b/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java
deleted file mode 100644
index 7906417..0000000
--- a/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.IDevice;
-
-import java.awt.event.ActionEvent;
-
-public abstract class AbstractThreadedDeviceSpecificAction extends AbstractThreadedAction
- implements DeviceSpecific {
-
- protected IDevice device;
-
- protected AbstractThreadedDeviceSpecificAction(String title, IDevice device) {
- super(title);
- this.device = device;
- }
-
- @Override
- public void setDevice(IDevice device) {
- this.device = device;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (device == null) {
- return;
- }
- super.actionPerformed(e);
- }
-}
diff --git a/tools/preload2/src/com/android/preload/actions/ClearTableAction.java b/tools/preload2/src/com/android/preload/actions/ClearTableAction.java
deleted file mode 100644
index c0e4795..0000000
--- a/tools/preload2/src/com/android/preload/actions/ClearTableAction.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.DumpTableModel;
-
-import java.awt.event.ActionEvent;
-
-import javax.swing.AbstractAction;
-
-public class ClearTableAction extends AbstractAction {
- private final DumpTableModel dataTableModel;
-
- public ClearTableAction(DumpTableModel dataTableModel) {
- super("Clear");
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- dataTableModel.clear();
- }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java b/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
deleted file mode 100644
index 3a7f7f7..0000000
--- a/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.regex.Pattern;
-
-import javax.swing.AbstractAction;
-
-/**
- * Compute an intersection of classes from the given data. A class is in the intersection if it
- * appears in at least the number of threshold given packages. An optional blacklist can be
- * used to filter classes from the intersection.
- */
-public class ComputeThresholdAction extends AbstractThreadedAction {
- protected int threshold;
- private Pattern blacklist;
- private DumpTableModel dataTableModel;
-
- /**
- * Create an action with the given parameters. The blacklist is a regular expression
- * that filters classes.
- */
- public ComputeThresholdAction(String name, DumpTableModel dataTableModel, int threshold,
- String blacklist) {
- super(name);
- this.dataTableModel = dataTableModel;
- this.threshold = threshold;
- if (blacklist != null) {
- this.blacklist = Pattern.compile(blacklist);
- }
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- List<DumpData> data = dataTableModel.getData();
- if (data.size() == 0) {
- Main.getUI().showMessageDialog("No data available, please scan packages or run "
- + "monkeys.");
- return;
- }
- if (data.size() == 1) {
- Main.getUI().showMessageDialog("Cannot compute list from only one data set, please "
- + "scan packages or run monkeys.");
- return;
- }
-
- super.actionPerformed(e);
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
-
- Map<String, Set<String>> uses = new HashMap<String, Set<String>>();
- for (DumpData d : dataTableModel.getData()) {
- Main.getUI().updateWaitDialog("Merging " + d.getPackageName());
- updateClassUse(d.getPackageName(), uses, getBootClassPathClasses(d.getDumpData()));
- }
-
- Main.getUI().updateWaitDialog("Computing thresholded set");
- Set<String> result = fromThreshold(uses, blacklist, threshold);
- Main.getUI().hideWaitDialog();
-
- boolean ret = Main.getUI().showConfirmDialog("Computed a set with " + result.size()
- + " classes, would you like to save to disk?", "Save?");
- if (ret) {
- File f = Main.getUI().showSaveDialog();
- if (f != null) {
- saveSet(result, f);
- }
- }
- }
-
- private Set<String> fromThreshold(Map<String, Set<String>> classUses, Pattern blacklist,
- int threshold) {
- TreeSet<String> ret = new TreeSet<>(); // TreeSet so it's nicely ordered by name.
-
- for (Map.Entry<String, Set<String>> e : classUses.entrySet()) {
- if (e.getValue().size() >= threshold) {
- if (blacklist == null || !blacklist.matcher(e.getKey()).matches()) {
- ret.add(e.getKey());
- }
- }
- }
-
- return ret;
- }
-
- private static void updateClassUse(String pkg, Map<String, Set<String>> classUses,
- Set<String> classes) {
- for (String className : classes) {
- Set<String> old = classUses.get(className);
- if (old == null) {
- classUses.put(className, new HashSet<String>());
- }
- classUses.get(className).add(pkg);
- }
- }
-
- private static Set<String> getBootClassPathClasses(Map<String, String> source) {
- Set<String> ret = new HashSet<>();
- for (Map.Entry<String, String> e : source.entrySet()) {
- if (e.getValue() == null) {
- ret.add(e.getKey());
- }
- }
- return ret;
- }
-
- private static void saveSet(Set<String> result, File f) {
- try {
- PrintWriter out = new PrintWriter(f);
- for (String s : result) {
- out.println(s);
- }
- out.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java b/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java
deleted file mode 100644
index 3ec0a4c..0000000
--- a/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-public class ComputeThresholdXAction extends ComputeThresholdAction {
-
- public ComputeThresholdXAction(String name, DumpTableModel dataTableModel,
- String blacklist) {
- super(name, dataTableModel, 1, blacklist);
- }
-
- @Override
- public void run() {
- String value = Main.getUI().showInputDialog("Threshold?");
-
- if (value != null) {
- try {
- threshold = Integer.parseInt(value);
- super.run();
- } catch (Exception exc) {
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java b/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java
deleted file mode 100644
index 35a8f26..0000000
--- a/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.IDevice;
-
-/**
- * Marks an action as being device-specific. The user must set the device through the specified
- * method if the device selection changes.
- *
- * Implementors must tolerate a null device (for example, with a no-op). This includes calling
- * any methods before setDevice has been called.
- */
-public interface DeviceSpecific {
-
- /**
- * Set the device that should be used. Note that there is no restriction on calling other
- * methods of the implementor before a setDevice call. Neither is device guaranteed to be
- * non-null.
- *
- * @param device The device to use going forward.
- */
- public void setDevice(IDevice device);
-}
diff --git a/tools/preload2/src/com/android/preload/actions/ExportAction.java b/tools/preload2/src/com/android/preload/actions/ExportAction.java
deleted file mode 100644
index 848a568..0000000
--- a/tools/preload2/src/com/android/preload/actions/ExportAction.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.DumpDataIO;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.io.PrintWriter;
-
-public class ExportAction extends AbstractThreadedAction {
- private File lastSaveFile;
- private DumpTableModel dataTableModel;
-
- public ExportAction(DumpTableModel dataTableModel) {
- super("Export data");
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- lastSaveFile = Main.getUI().showSaveDialog();
- if (lastSaveFile != null) {
- super.actionPerformed(e);
- }
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
-
- String serialized = DumpDataIO.serialize(dataTableModel.getData());
-
- if (serialized != null) {
- try {
- PrintWriter out = new PrintWriter(lastSaveFile);
- out.println(serialized);
- out.close();
-
- Main.getUI().hideWaitDialog();
- } catch (Exception e) {
- Main.getUI().hideWaitDialog();
- Main.getUI().showMessageDialog("Failed writing: " + e.getMessage());
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ImportAction.java b/tools/preload2/src/com/android/preload/actions/ImportAction.java
deleted file mode 100644
index bfeeb83..0000000
--- a/tools/preload2/src/com/android/preload/actions/ImportAction.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.DumpData;
-import com.android.preload.DumpDataIO;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.util.Collection;
-
-import javax.swing.AbstractAction;
-
-public class ImportAction extends AbstractThreadedAction {
- private File[] lastOpenFiles;
- private DumpTableModel dataTableModel;
-
- public ImportAction(DumpTableModel dataTableModel) {
- super("Import data");
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- lastOpenFiles = Main.getUI().showOpenDialog(true);
- if (lastOpenFiles != null) {
- super.actionPerformed(e);
- }
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
-
- try {
- for (File f : lastOpenFiles) {
- try {
- Collection<DumpData> data = DumpDataIO.deserialize(f);
-
- for (DumpData d : data) {
- dataTableModel.addData(d);
- }
- } catch (Exception e) {
- Main.getUI().showMessageDialog("Failed reading: " + e.getMessage());
- }
- }
- } finally {
- Main.getUI().hideWaitDialog();
- }
-
- }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ReloadListAction.java b/tools/preload2/src/com/android/preload/actions/ReloadListAction.java
deleted file mode 100644
index 29f0557..0000000
--- a/tools/preload2/src/com/android/preload/actions/ReloadListAction.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.ClientUtils;
-
-import java.util.Arrays;
-import java.util.Comparator;
-
-import javax.swing.DefaultListModel;
-
-public class ReloadListAction extends AbstractThreadedDeviceSpecificAction {
-
- private ClientUtils clientUtils;
- private final DefaultListModel<Client> clientListModel;
-
- public ReloadListAction(ClientUtils utils, IDevice device,
- DefaultListModel<Client> clientListModel) {
- super("Reload", device);
- this.clientUtils = utils;
- this.clientListModel = clientListModel;
- }
-
- @Override
- public void run() {
- Client[] clients = clientUtils.findAllClients(device);
- if (clients != null) {
- Arrays.sort(clients, new ClientComparator());
- }
- clientListModel.removeAllElements();
- for (Client c : clients) {
- clientListModel.addElement(c);
- }
- }
-
- private static class ClientComparator implements Comparator<Client> {
-
- @Override
- public int compare(Client o1, Client o2) {
- String s1 = o1.getClientData().getClientDescription();
- String s2 = o2.getClientData().getClientDescription();
-
- if (s1 == null || s2 == null) {
- // Not good, didn't get all data?
- return (s1 == null) ? -1 : 1;
- }
-
- return s1.compareTo(s2);
- }
-
- }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java b/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
deleted file mode 100644
index 29464fc..0000000
--- a/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.IDevice;
-import com.android.preload.DeviceUtils;
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.event.ActionEvent;
-import java.util.Date;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import javax.swing.AbstractAction;
-
-public class RunMonkeyAction extends AbstractAction implements DeviceSpecific {
-
- private final static String DEFAULT_MONKEY_PACKAGES =
- "com.android.calendar,com.android.gallery3d";
-
- private IDevice device;
- private DumpTableModel dataTableModel;
-
- public RunMonkeyAction(IDevice device, DumpTableModel dataTableModel) {
- super("Run monkey");
- this.device = device;
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void setDevice(IDevice device) {
- this.device = device;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- String packages = Main.getUI().showInputDialog("Please enter packages name to run with"
- + " the monkey, or leave empty for default.");
- if (packages == null) {
- return;
- }
- if (packages.isEmpty()) {
- packages = DEFAULT_MONKEY_PACKAGES;
- }
- Runnable r = new RunMonkeyRunnable(packages);
- if (Main.getUI().isSingleThreaded()) {
- r.run();
- } else {
- new Thread(r).start();
- }
- }
-
- private class RunMonkeyRunnable implements Runnable {
-
- private String packages;
- private final static int ITERATIONS = 1000;
-
- public RunMonkeyRunnable(String packages) {
- this.packages = packages;
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
-
- try {
- String pkgs[] = packages.split(",");
-
- for (String pkg : pkgs) {
- Main.getUI().updateWaitDialog("Running monkey on " + pkg);
-
- try {
- // Stop running app.
- forceStop(pkg);
-
- // Little bit of breather here.
- try {
- Thread.sleep(1000);
- } catch (Exception e) {
- }
-
- DeviceUtils.doShell(device, "monkey -p " + pkg + " " + ITERATIONS, 1,
- TimeUnit.MINUTES);
-
- Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg);
- Map<String, String> data = Main.findAndGetClassData(device, pkg);
- DumpData dumpData = new DumpData(pkg, data, new Date());
- dataTableModel.addData(dumpData);
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- // Stop running app.
- forceStop(pkg);
- }
- }
- } finally {
- Main.getUI().hideWaitDialog();
- }
- }
-
- private void forceStop(String packageName) {
- // Stop running app.
- DeviceUtils.doShell(device, "force-stop " + packageName, 5, TimeUnit.SECONDS);
- DeviceUtils.doShell(device, "kill " + packageName, 5, TimeUnit.SECONDS);
- DeviceUtils.doShell(device, "kill `pid " + packageName + "`", 5, TimeUnit.SECONDS);
- }
- }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java b/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java
deleted file mode 100644
index d74b8a3..0000000
--- a/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.ClientUtils;
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.util.Date;
-import java.util.Map;
-
-public class ScanAllPackagesAction extends AbstractThreadedDeviceSpecificAction {
-
- private ClientUtils clientUtils;
- private DumpTableModel dataTableModel;
-
- public ScanAllPackagesAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) {
- super("Scan all packages", device);
- this.clientUtils = utils;
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
-
- try {
- Client[] clients = clientUtils.findAllClients(device);
- for (Client c : clients) {
- String pkg = c.getClientData().getClientDescription();
- Main.getUI().showWaitDialog();
- Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg);
-
- try {
- Map<String, String> data = Main.getClassDataRetriever().getClassData(c);
- DumpData dumpData = new DumpData(pkg, data, new Date());
- dataTableModel.addData(dumpData);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- } finally {
- Main.getUI().hideWaitDialog();
- }
- }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java b/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java
deleted file mode 100644
index 98492bd..0000000
--- a/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.ClientUtils;
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.util.Date;
-import java.util.Map;
-
-public class ScanPackageAction extends AbstractThreadedDeviceSpecificAction {
-
- private ClientUtils clientUtils;
- private DumpTableModel dataTableModel;
-
- public ScanPackageAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) {
- super("Scan package", device);
- this.clientUtils = utils;
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
-
- try {
- Client client = Main.getUI().getSelectedClient();
- if (client != null) {
- work(client);
- } else {
- Client[] clients = clientUtils.findAllClients(device);
- if (clients.length > 0) {
- ClientWrapper[] clientWrappers = new ClientWrapper[clients.length];
- for (int i = 0; i < clientWrappers.length; i++) {
- clientWrappers[i] = new ClientWrapper(clients[i]);
- }
- Main.getUI().hideWaitDialog();
-
- ClientWrapper ret = Main.getUI().showChoiceDialog("Choose a package to scan",
- "Choose package",
- clientWrappers);
- if (ret != null) {
- work(ret.client);
- }
- }
- }
- } finally {
- Main.getUI().hideWaitDialog();
- }
- }
-
- private void work(Client c) {
- String pkg = c.getClientData().getClientDescription();
- Main.getUI().showWaitDialog();
- Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg);
-
- try {
- Map<String, String> data = Main.findAndGetClassData(device, pkg);
- DumpData dumpData = new DumpData(pkg, data, new Date());
- dataTableModel.addData(dumpData);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- private static class ClientWrapper {
- private Client client;
-
- public ClientWrapper(Client c) {
- client = c;
- }
-
- @Override
- public String toString() {
- return client.getClientData().getClientDescription() + " (pid "
- + client.getClientData().getPid() + ")";
- }
- }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ShowDataAction.java b/tools/preload2/src/com/android/preload/actions/ShowDataAction.java
deleted file mode 100644
index 2bb175f..0000000
--- a/tools/preload2/src/com/android/preload/actions/ShowDataAction.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.BorderLayout;
-import java.awt.event.ActionEvent;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.swing.AbstractAction;
-import javax.swing.JFrame;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
-
-public class ShowDataAction extends AbstractAction {
- private DumpTableModel dataTableModel;
-
- public ShowDataAction(DumpTableModel dataTableModel) {
- super("Show data");
- this.dataTableModel = dataTableModel;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- // TODO(agampe): Auto-generated method stub
- int selRow = Main.getUI().getSelectedDataTableRow();
- if (selRow != -1) {
- DumpData data = dataTableModel.getData().get(selRow);
- Map<String, Set<String>> inv = data.invertData();
-
- StringBuilder builder = new StringBuilder();
-
- // First bootclasspath.
- add(builder, "Boot classpath:", inv.get(null));
-
- // Now everything else.
- for (String k : inv.keySet()) {
- if (k != null) {
- builder.append("==================\n\n");
- add(builder, k, inv.get(k));
- }
- }
-
- JFrame newFrame = new JFrame(data.getPackageName() + " " + data.getDate());
- newFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
- newFrame.getContentPane().add(new JScrollPane(new JTextArea(builder.toString())),
- BorderLayout.CENTER);
- newFrame.setSize(800, 600);
- newFrame.setLocationRelativeTo(null);
- newFrame.setVisible(true);
- }
- }
-
- private void add(StringBuilder builder, String head, Set<String> set) {
- builder.append(head);
- builder.append('\n');
- addSet(builder, set);
- builder.append('\n');
- }
-
- private void addSet(StringBuilder builder, Set<String> set) {
- if (set == null) {
- builder.append(" NONE\n");
- return;
- }
- List<String> sorted = new ArrayList<>(set);
- Collections.sort(sorted);
- for (String s : sorted) {
- builder.append(s);
- builder.append('\n');
- }
- }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java b/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java
deleted file mode 100644
index 9b97f11..0000000
--- a/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.actions;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.ClientUtils;
-import com.android.preload.DeviceUtils;
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.util.Date;
-import java.util.Map;
-
-public class WritePreloadedClassesAction extends AbstractThreadedDeviceSpecificAction {
- private File preloadedClassFile;
-
- public WritePreloadedClassesAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) {
- super("Write preloaded classes action", device);
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- File[] files = Main.getUI().showOpenDialog(true);
- if (files != null && files.length > 0) {
- preloadedClassFile = files[0];
- super.actionPerformed(e);
- }
- }
-
- @Override
- public void run() {
- Main.getUI().showWaitDialog();
- try {
- // Write the new file with a 5-minute timeout
- DeviceUtils.overwritePreloaded(device, preloadedClassFile, 5 * 60);
- } catch (Exception e) {
- System.err.println(e);
- } finally {
- Main.getUI().hideWaitDialog();
- }
- }
-}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java b/tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java
deleted file mode 100644
index f04360f..0000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.classdataretrieval;
-
-import com.android.ddmlib.Client;
-
-import java.util.Map;
-
-/**
- * Retrieve a class-to-classloader map for loaded classes from the client.
- */
-public interface ClassDataRetriever {
-
- public Map<String, String> getClassData(Client client);
-}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java
deleted file mode 100644
index 8d797ee..0000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.classdataretrieval.hprof;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData.IHprofDumpHandler;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class GeneralHprofDumpHandler implements IHprofDumpHandler {
-
- private List<IHprofDumpHandler> handlers = new ArrayList<>();
-
- public void addHandler(IHprofDumpHandler h) {
- synchronized (handlers) {
- handlers.add(h);
- }
- }
-
- public void removeHandler(IHprofDumpHandler h) {
- synchronized (handlers) {
- handlers.remove(h);
- }
- }
-
- private List<IHprofDumpHandler> getIterationList() {
- synchronized (handlers) {
- return new ArrayList<>(handlers);
- }
- }
-
- @Override
- public void onEndFailure(Client arg0, String arg1) {
- List<IHprofDumpHandler> iterList = getIterationList();
- for (IHprofDumpHandler h : iterList) {
- h.onEndFailure(arg0, arg1);
- }
- }
-
- @Override
- public void onSuccess(String arg0, Client arg1) {
- List<IHprofDumpHandler> iterList = getIterationList();
- for (IHprofDumpHandler h : iterList) {
- h.onSuccess(arg0, arg1);
- }
- }
-
- @Override
- public void onSuccess(byte[] arg0, Client arg1) {
- List<IHprofDumpHandler> iterList = getIterationList();
- for (IHprofDumpHandler h : iterList) {
- h.onSuccess(arg0, arg1);
- }
- }
- }
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java
deleted file mode 100644
index 84ec8b7..0000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.classdataretrieval.hprof;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData;
-import com.android.ddmlib.ClientData.IHprofDumpHandler;
-import com.android.preload.classdataretrieval.ClassDataRetriever;
-import com.android.preload.ui.NullProgressMonitor;
-import com.android.tools.perflib.captures.MemoryMappedFileBuffer;
-import com.android.tools.perflib.heap.ClassObj;
-import com.android.tools.perflib.heap.Queries;
-import com.android.tools.perflib.heap.Snapshot;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-public class Hprof implements ClassDataRetriever {
-
- private static GeneralHprofDumpHandler hprofHandler;
-
- public static void init() {
- synchronized(Hprof.class) {
- if (hprofHandler == null) {
- ClientData.setHprofDumpHandler(hprofHandler = new GeneralHprofDumpHandler());
- }
- }
- }
-
- public static File doHprof(Client client, int timeout) {
- GetHprof gh = new GetHprof(client, timeout);
- return gh.get();
- }
-
- /**
- * Return a map of class names to class-loader names derived from the hprof dump.
- *
- * @param hprofLocalFile
- */
- public static Map<String, String> analyzeHprof(File hprofLocalFile) throws Exception {
- Snapshot snapshot = Snapshot.createSnapshot(new MemoryMappedFileBuffer(hprofLocalFile));
-
- Map<String, Set<ClassObj>> classes = Queries.classes(snapshot, null);
- Map<String, String> retValue = new HashMap<String, String>();
- for (Map.Entry<String, Set<ClassObj>> e : classes.entrySet()) {
- for (ClassObj c : e.getValue()) {
- String cl = c.getClassLoader() == null ? null : c.getClassLoader().toString();
- String cName = c.getClassName();
- int aDepth = 0;
- while (cName.endsWith("[]")) {
- cName = cName.substring(0, cName.length()-2);
- aDepth++;
- }
- String newName = transformPrimitiveClass(cName);
- if (aDepth > 0) {
- // Need to use kind-a descriptor syntax. If it was transformed, it is primitive.
- if (newName.equals(cName)) {
- newName = "L" + newName + ";";
- }
- for (int i = 0; i < aDepth; i++) {
- newName = "[" + newName;
- }
- }
- retValue.put(newName, cl);
- }
- }
-
- // Free up memory.
- snapshot.dispose();
-
- return retValue;
- }
-
- private static Map<String, String> primitiveMapping;
-
- static {
- primitiveMapping = new HashMap<>();
- primitiveMapping.put("boolean", "Z");
- primitiveMapping.put("byte", "B");
- primitiveMapping.put("char", "C");
- primitiveMapping.put("double", "D");
- primitiveMapping.put("float", "F");
- primitiveMapping.put("int", "I");
- primitiveMapping.put("long", "J");
- primitiveMapping.put("short", "S");
- primitiveMapping.put("void", "V");
- }
-
- private static String transformPrimitiveClass(String name) {
- String rep = primitiveMapping.get(name);
- if (rep != null) {
- return rep;
- }
- return name;
- }
-
- private static class GetHprof implements IHprofDumpHandler {
-
- private File target;
- private long timeout;
- private Client client;
-
- public GetHprof(Client client, long timeout) {
- this.client = client;
- this.timeout = timeout;
- }
-
- public File get() {
- synchronized (this) {
- hprofHandler.addHandler(this);
- client.dumpHprof();
- if (target == null) {
- try {
- wait(timeout);
- } catch (Exception e) {
- System.out.println(e);
- }
- }
- }
-
- hprofHandler.removeHandler(this);
- return target;
- }
-
- private void wakeUp() {
- synchronized (this) {
- notifyAll();
- }
- }
-
- @Override
- public void onEndFailure(Client arg0, String arg1) {
- System.out.println("GetHprof.onEndFailure");
- if (client == arg0) {
- wakeUp();
- }
- }
-
- private static File createTargetFile() {
- try {
- return File.createTempFile("ddms", ".hprof");
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void onSuccess(String arg0, Client arg1) {
- System.out.println("GetHprof.onSuccess");
- if (client == arg1) {
- try {
- target = createTargetFile();
- arg1.getDevice().getSyncService().pullFile(arg0,
- target.getAbsoluteFile().toString(), new NullProgressMonitor());
- } catch (Exception e) {
- if (target != null) {
- target.delete();
- }
- e.printStackTrace();
- target = null;
- }
- wakeUp();
- }
- }
-
- @Override
- public void onSuccess(byte[] arg0, Client arg1) {
- System.out.println("GetHprof.onSuccess");
- if (client == arg1) {
- try {
- target = createTargetFile();
- BufferedOutputStream out =
- new BufferedOutputStream(new FileOutputStream(target));
- out.write(arg0);
- out.close();
- } catch (Exception e) {
- if (target != null) {
- target.delete();
- }
- e.printStackTrace();
- target = null;
- }
- wakeUp();
- }
- }
- }
-
- private int timeout;
-
- public Hprof(int timeout) {
- this.timeout = timeout;
- }
-
- @Override
- public Map<String, String> getClassData(Client client) {
- File hprofLocalFile = Hprof.doHprof(client, timeout);
- if (hprofLocalFile == null) {
- throw new RuntimeException("Failed getting dump...");
- }
- System.out.println("Dump file is " + hprofLocalFile);
-
- try {
- return analyzeHprof(hprofLocalFile);
- } catch (Exception e) {
- throw new RuntimeException(e);
- } finally {
- hprofLocalFile.delete();
- }
- }
-}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java
deleted file mode 100644
index dbd4c89..0000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.classdataretrieval.jdwp;
-
-import com.android.ddmlib.Client;
-import com.android.preload.classdataretrieval.ClassDataRetriever;
-
-import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
-import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
-import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
-import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
-import org.apache.harmony.jpda.tests.jdwp.share.JDWPTestCase;
-import org.apache.harmony.jpda.tests.jdwp.share.JDWPUnitDebuggeeWrapper;
-import org.apache.harmony.jpda.tests.share.JPDALogWriter;
-import org.apache.harmony.jpda.tests.share.JPDATestOptions;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class JDWPClassDataRetriever extends JDWPTestCase implements ClassDataRetriever {
-
- private final Client client;
-
- public JDWPClassDataRetriever() {
- this(null);
- }
-
- public JDWPClassDataRetriever(Client client) {
- this.client = client;
- }
-
-
- @Override
- protected String getDebuggeeClassName() {
- return "<unset>";
- }
-
- @Override
- public Map<String, String> getClassData(Client client) {
- return new JDWPClassDataRetriever(client).retrieve();
- }
-
- private Map<String, String> retrieve() {
- if (client == null) {
- throw new IllegalStateException();
- }
-
- settings = createTestOptions("localhost:" + String.valueOf(client.getDebuggerListenPort()));
- settings.setDebuggeeSuspend("n");
-
- logWriter = new JPDALogWriter(System.out, "", false);
-
- try {
- internalSetUp();
-
- return retrieveImpl();
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- } finally {
- internalTearDown();
- }
- }
-
- private Map<String, String> retrieveImpl() {
- try {
- // Suspend the app.
- {
- CommandPacket packet = new CommandPacket(
- JDWPCommands.VirtualMachineCommandSet.CommandSetID,
- JDWPCommands.VirtualMachineCommandSet.SuspendCommand);
- ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
- if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
- return null;
- }
- }
-
- // List all classes.
- CommandPacket packet = new CommandPacket(
- JDWPCommands.VirtualMachineCommandSet.CommandSetID,
- JDWPCommands.VirtualMachineCommandSet.AllClassesCommand);
- ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
-
- if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
- return null;
- }
-
- int classCount = reply.getNextValueAsInt();
- System.out.println("Runtime reported " + classCount + " classes.");
-
- Map<Long, String> classes = new HashMap<Long, String>();
- Map<Long, String> arrayClasses = new HashMap<Long, String>();
-
- for (int i = 0; i < classCount; i++) {
- byte refTypeTag = reply.getNextValueAsByte();
- long typeID = reply.getNextValueAsReferenceTypeID();
- String signature = reply.getNextValueAsString();
- /* int status = */ reply.getNextValueAsInt();
-
- switch (refTypeTag) {
- case JDWPConstants.TypeTag.CLASS:
- case JDWPConstants.TypeTag.INTERFACE:
- classes.put(typeID, signature);
- break;
-
- case JDWPConstants.TypeTag.ARRAY:
- arrayClasses.put(typeID, signature);
- break;
- }
- }
-
- Map<String, String> result = new HashMap<String, String>();
-
- // Parse all classes.
- for (Map.Entry<Long, String> entry : classes.entrySet()) {
- long typeID = entry.getKey();
- String signature = entry.getValue();
-
- if (!checkClass(typeID, signature, result)) {
- System.err.println("Issue investigating " + signature);
- }
- }
-
- // For arrays, look at the leaf component type.
- for (Map.Entry<Long, String> entry : arrayClasses.entrySet()) {
- long typeID = entry.getKey();
- String signature = entry.getValue();
-
- if (!checkArrayClass(typeID, signature, result)) {
- System.err.println("Issue investigating " + signature);
- }
- }
-
- return result;
- } finally {
- // Resume the app.
- {
- CommandPacket packet = new CommandPacket(
- JDWPCommands.VirtualMachineCommandSet.CommandSetID,
- JDWPCommands.VirtualMachineCommandSet.ResumeCommand);
- /* ReplyPacket reply = */ debuggeeWrapper.vmMirror.performCommand(packet);
- }
- }
- }
-
- private boolean checkClass(long typeID, String signature, Map<String, String> result) {
- CommandPacket packet = new CommandPacket(
- JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
- JDWPCommands.ReferenceTypeCommandSet.ClassLoaderCommand);
- packet.setNextValueAsReferenceTypeID(typeID);
- ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
- if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
- return false;
- }
-
- long classLoaderID = reply.getNextValueAsObjectID();
-
- // TODO: Investigate the classloader to have a better string?
- String classLoaderString = (classLoaderID == 0) ? null : String.valueOf(classLoaderID);
-
- result.put(getClassName(signature), classLoaderString);
-
- return true;
- }
-
- private boolean checkArrayClass(long typeID, String signature, Map<String, String> result) {
- // Classloaders of array classes are the same as the component class'.
- CommandPacket packet = new CommandPacket(
- JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
- JDWPCommands.ReferenceTypeCommandSet.ClassLoaderCommand);
- packet.setNextValueAsReferenceTypeID(typeID);
- ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
- if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
- return false;
- }
-
- long classLoaderID = reply.getNextValueAsObjectID();
-
- // TODO: Investigate the classloader to have a better string?
- String classLoaderString = (classLoaderID == 0) ? null : String.valueOf(classLoaderID);
-
- // For array classes, we *need* the signature directly.
- result.put(signature, classLoaderString);
-
- return true;
- }
-
- private static String getClassName(String signature) {
- String withoutLAndSemicolon = signature.substring(1, signature.length() - 1);
- return withoutLAndSemicolon.replace('/', '.');
- }
-
-
- private static JPDATestOptions createTestOptions(String address) {
- JPDATestOptions options = new JPDATestOptions();
- options.setAttachConnectorKind();
- options.setTimeout(1000);
- options.setWaitingTime(1000);
- options.setTransportAddress(address);
- return options;
- }
-
- @Override
- protected JDWPUnitDebuggeeWrapper createDebuggeeWrapper() {
- return new PreloadDebugeeWrapper(settings, logWriter);
- }
-}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java
deleted file mode 100644
index b9df6d0..0000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.classdataretrieval.jdwp;
-
-import org.apache.harmony.jpda.tests.framework.LogWriter;
-import org.apache.harmony.jpda.tests.jdwp.share.JDWPManualDebuggeeWrapper;
-import org.apache.harmony.jpda.tests.share.JPDATestOptions;
-
-import java.io.IOException;
-
-public class PreloadDebugeeWrapper extends JDWPManualDebuggeeWrapper {
-
- public PreloadDebugeeWrapper(JPDATestOptions options, LogWriter writer) {
- super(options, writer);
- }
-
- @Override
- protected Process launchProcess(String cmdLine) throws IOException {
- return null;
- }
-
- @Override
- protected void WaitForProcessExit(Process process) {
- }
-
-}
diff --git a/tools/preload2/src/com/android/preload/ui/IUI.java b/tools/preload2/src/com/android/preload/ui/IUI.java
deleted file mode 100644
index 9371463..0000000
--- a/tools/preload2/src/com/android/preload/ui/IUI.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.android.preload.ui;
-
-import com.android.ddmlib.Client;
-import java.io.File;
-import java.util.List;
-import javax.swing.Action;
-import javax.swing.ListModel;
-import javax.swing.table.TableModel;
-
-/**
- * UI abstraction for the tool. This allows a graphical mode, command line mode,
- * or silent mode.
- */
-public interface IUI {
-
- void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
- List<Action> actions);
-
- void ready();
-
- boolean isSingleThreaded();
-
- Client getSelectedClient();
-
- int getSelectedDataTableRow();
-
- void showWaitDialog();
-
- void updateWaitDialog(String s);
-
- void hideWaitDialog();
-
- void showMessageDialog(String s);
-
- boolean showConfirmDialog(String title, String message);
-
- String showInputDialog(String message);
-
- <T> T showChoiceDialog(String title, String message, T[] choices);
-
- File showSaveDialog();
-
- File[] showOpenDialog(boolean multi);
-
-}
diff --git a/tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java b/tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java
deleted file mode 100644
index f45aad0..0000000
--- a/tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.ui;
-
-import com.android.ddmlib.SyncService.ISyncProgressMonitor;
-
-public class NullProgressMonitor implements ISyncProgressMonitor {
-
- @Override
- public void advance(int arg0) {}
-
- @Override
- public boolean isCanceled() {
- return false;
- }
-
- @Override
- public void start(int arg0) {}
-
- @Override
- public void startSubTask(String arg0) {}
-
- @Override
- public void stop() {}
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/ui/SequenceUI.java b/tools/preload2/src/com/android/preload/ui/SequenceUI.java
deleted file mode 100644
index dc6a4f3..0000000
--- a/tools/preload2/src/com/android/preload/ui/SequenceUI.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package com.android.preload.ui;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData;
-import java.io.File;
-import java.util.LinkedList;
-import java.util.List;
-import javax.swing.Action;
-import javax.swing.ListModel;
-import javax.swing.table.TableModel;
-
-public class SequenceUI implements IUI {
-
- private ListModel<Client> clientListModel;
- @SuppressWarnings("unused")
- private TableModel dataTableModel;
- private List<Action> actions;
-
- private List<Object> sequence = new LinkedList<>();
-
- public SequenceUI() {
- }
-
- @Override
- public boolean isSingleThreaded() {
- return true;
- }
-
- @Override
- public void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
- List<Action> actions) {
- this.clientListModel = clientListModel;
- this.dataTableModel = dataTableModel;
- this.actions = actions;
- }
-
- public SequenceUI action(Action a) {
- sequence.add(a);
- return this;
- }
-
- public SequenceUI action(Class<? extends Action> actionClass) {
- for (Action a : actions) {
- if (actionClass.equals(a.getClass())) {
- sequence.add(a);
- return this;
- }
- }
- throw new IllegalArgumentException("No action of class " + actionClass + " found.");
- }
-
- public SequenceUI confirmYes() {
- sequence.add(Boolean.TRUE);
- return this;
- }
-
- public SequenceUI confirmNo() {
- sequence.add(Boolean.FALSE);
- return this;
- }
-
- public SequenceUI input(String input) {
- sequence.add(input);
- return this;
- }
-
- public SequenceUI input(File... f) {
- sequence.add(f);
- return this;
- }
-
- public SequenceUI output(File f) {
- sequence.add(f);
- return this;
- }
-
- public SequenceUI tableRow(int i) {
- sequence.add(i);
- return this;
- }
-
- private class ClientSelector {
- private String pkg;
-
- public ClientSelector(String pkg) {
- this.pkg = pkg;
- }
-
- public Client getClient() {
- for (int i = 0; i < clientListModel.getSize(); i++) {
- ClientData cd = clientListModel.getElementAt(i).getClientData();
- if (cd != null) {
- String s = cd.getClientDescription();
- if (pkg.equals(s)) {
- return clientListModel.getElementAt(i);
- }
- }
- }
- throw new RuntimeException("Didn't find client " + pkg);
- }
- }
-
- public SequenceUI client(String pkg) {
- sequence.add(new ClientSelector(pkg));
- return this;
- }
-
- public SequenceUI choice(String pattern) {
- sequence.add(pattern);
- return this;
- }
-
- @Override
- public void ready() {
- // Run the actions.
- // No iterator or foreach loop as the sequence will be emptied while running.
- try {
- while (!sequence.isEmpty()) {
- Object next = sequence.remove(0);
- if (next instanceof Action) {
- ((Action)next).actionPerformed(null);
- } else {
- throw new IllegalStateException("Didn't expect a non-action: " + next);
- }
- }
- } catch (Exception e) {
- e.printStackTrace(System.out);
- }
-
- // Now shut down.
- System.exit(0);
- }
-
- @Override
- public Client getSelectedClient() {
- Object next = sequence.remove(0);
- if (next instanceof ClientSelector) {
- return ((ClientSelector)next).getClient();
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
- @Override
- public int getSelectedDataTableRow() {
- Object next = sequence.remove(0);
- if (next instanceof Integer) {
- return ((Integer)next).intValue();
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
- @Override
- public void showWaitDialog() {
- }
-
- @Override
- public void updateWaitDialog(String s) {
- System.out.println(s);
- }
-
- @Override
- public void hideWaitDialog() {
- }
-
- @Override
- public void showMessageDialog(String s) {
- System.out.println(s);
- }
-
- @Override
- public boolean showConfirmDialog(String title, String message) {
- Object next = sequence.remove(0);
- if (next instanceof Boolean) {
- return ((Boolean)next).booleanValue();
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
- @Override
- public String showInputDialog(String message) {
- Object next = sequence.remove(0);
- if (next instanceof String) {
- return (String)next;
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
- @Override
- public <T> T showChoiceDialog(String title, String message, T[] choices) {
- Object next = sequence.remove(0);
- if (next instanceof String) {
- String s = (String)next;
- for (T t : choices) {
- if (t.toString().contains(s)) {
- return t;
- }
- }
- return null;
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
- @Override
- public File showSaveDialog() {
- Object next = sequence.remove(0);
- if (next instanceof File) {
- System.out.println(next);
- return (File)next;
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
- @Override
- public File[] showOpenDialog(boolean multi) {
- Object next = sequence.remove(0);
- if (next instanceof File[]) {
- return (File[])next;
- }
- throw new IllegalStateException("Unexpected: " + next);
- }
-
-}
diff --git a/tools/preload2/src/com/android/preload/ui/SwingUI.java b/tools/preload2/src/com/android/preload/ui/SwingUI.java
deleted file mode 100644
index cab3744..0000000
--- a/tools/preload2/src/com/android/preload/ui/SwingUI.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright (C) 2015 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.preload.ui;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.io.File;
-import java.util.List;
-
-import javax.swing.Action;
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.JDialog;
-import javax.swing.JFileChooser;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JOptionPane;
-import javax.swing.JProgressBar;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.JToolBar;
-import javax.swing.ListModel;
-import javax.swing.SwingUtilities;
-import javax.swing.table.TableModel;
-
-public class SwingUI extends JFrame implements IUI {
-
- private JList<Client> clientList;
- private JTable dataTable;
-
- // Shared file chooser, means the directory is retained.
- private JFileChooser jfc;
-
- public SwingUI() {
- super("Preloaded-classes computation");
- }
-
- @Override
- public boolean isSingleThreaded() {
- return false;
- }
-
- @Override
- public void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
- List<Action> actions) {
- getContentPane().add(new JScrollPane(clientList = new JList<Client>(clientListModel)),
- BorderLayout.WEST);
- clientList.setCellRenderer(new ClientListCellRenderer());
- // clientList.addListSelectionListener(listener);
-
- dataTable = new JTable(dataTableModel);
- getContentPane().add(new JScrollPane(dataTable), BorderLayout.CENTER);
-
- JToolBar toolbar = new JToolBar(JToolBar.HORIZONTAL);
- for (Action a : actions) {
- if (a == null) {
- toolbar.addSeparator();
- } else {
- toolbar.add(a);
- }
- }
- getContentPane().add(toolbar, BorderLayout.PAGE_START);
-
- setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- setBounds(100, 100, 800, 600);
-
- setVisible(true);
- }
-
- @Override
- public void ready() {
- }
-
- @Override
- public Client getSelectedClient() {
- return clientList.getSelectedValue();
- }
-
- @Override
- public int getSelectedDataTableRow() {
- return dataTable.getSelectedRow();
- }
-
- private JDialog currentWaitDialog = null;
-
- @Override
- public void showWaitDialog() {
- if (currentWaitDialog == null) {
- currentWaitDialog = new JDialog(this, "Please wait...", true);
- currentWaitDialog.getContentPane().add(new JLabel("Please be patient."),
- BorderLayout.CENTER);
- JProgressBar progress = new JProgressBar(JProgressBar.HORIZONTAL);
- progress.setIndeterminate(true);
- currentWaitDialog.getContentPane().add(progress, BorderLayout.SOUTH);
- currentWaitDialog.setSize(200, 100);
- currentWaitDialog.setLocationRelativeTo(null);
- showWaitDialogLater();
- }
- }
-
- private void showWaitDialogLater() {
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(true); // This is blocking.
- }
- }
- });
- }
-
- @Override
- public void updateWaitDialog(String s) {
- if (currentWaitDialog != null) {
- ((JLabel) currentWaitDialog.getContentPane().getComponent(0)).setText(s);
- Dimension prefSize = currentWaitDialog.getPreferredSize();
- Dimension curSize = currentWaitDialog.getSize();
- if (prefSize.width > curSize.width || prefSize.height > curSize.height) {
- currentWaitDialog.setSize(Math.max(prefSize.width, curSize.width),
- Math.max(prefSize.height, curSize.height));
- currentWaitDialog.invalidate();
- }
- }
- }
-
- @Override
- public void hideWaitDialog() {
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- currentWaitDialog = null;
- }
- }
-
- @Override
- public void showMessageDialog(String s) {
- // Hide the wait dialog...
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- }
-
- try {
- JOptionPane.showMessageDialog(this, s);
- } finally {
- // And reshow it afterwards...
- if (currentWaitDialog != null) {
- showWaitDialogLater();
- }
- }
- }
-
- @Override
- public boolean showConfirmDialog(String title, String message) {
- // Hide the wait dialog...
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- }
-
- try {
- return JOptionPane.showConfirmDialog(this, title, message, JOptionPane.YES_NO_OPTION)
- == JOptionPane.YES_OPTION;
- } finally {
- // And reshow it afterwards...
- if (currentWaitDialog != null) {
- showWaitDialogLater();
- }
- }
- }
-
- @Override
- public String showInputDialog(String message) {
- // Hide the wait dialog...
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- }
-
- try {
- return JOptionPane.showInputDialog(message);
- } finally {
- // And reshow it afterwards...
- if (currentWaitDialog != null) {
- showWaitDialogLater();
- }
- }
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public <T> T showChoiceDialog(String title, String message, T[] choices) {
- // Hide the wait dialog...
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- }
-
- try{
- return (T)JOptionPane.showInputDialog(this,
- title,
- message,
- JOptionPane.QUESTION_MESSAGE,
- null,
- choices,
- choices[0]);
- } finally {
- // And reshow it afterwards...
- if (currentWaitDialog != null) {
- showWaitDialogLater();
- }
- }
- }
-
- @Override
- public File showSaveDialog() {
- // Hide the wait dialog...
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- }
-
- try{
- if (jfc == null) {
- jfc = new JFileChooser();
- }
-
- int ret = jfc.showSaveDialog(this);
- if (ret == JFileChooser.APPROVE_OPTION) {
- return jfc.getSelectedFile();
- } else {
- return null;
- }
- } finally {
- // And reshow it afterwards...
- if (currentWaitDialog != null) {
- showWaitDialogLater();
- }
- }
- }
-
- @Override
- public File[] showOpenDialog(boolean multi) {
- // Hide the wait dialog...
- if (currentWaitDialog != null) {
- currentWaitDialog.setVisible(false);
- }
-
- try{
- if (jfc == null) {
- jfc = new JFileChooser();
- }
-
- jfc.setMultiSelectionEnabled(multi);
- int ret = jfc.showOpenDialog(this);
- if (ret == JFileChooser.APPROVE_OPTION) {
- return jfc.getSelectedFiles();
- } else {
- return null;
- }
- } finally {
- // And reshow it afterwards...
- if (currentWaitDialog != null) {
- showWaitDialogLater();
- }
- }
- }
-
- private class ClientListCellRenderer extends DefaultListCellRenderer {
-
- @Override
- public Component getListCellRendererComponent(JList<?> list, Object value, int index,
- boolean isSelected, boolean cellHasFocus) {
- ClientData cd = ((Client) value).getClientData();
- String s = cd.getClientDescription() + " (pid " + cd.getPid() + ")";
- return super.getListCellRendererComponent(list, s, index, isSelected, cellHasFocus);
- }
- }
-}