Work on issue #36891897: Need to ensure foreground services can't...
...hide themselves
The activity manager now keeps track of all apps that are running
foreground services and builds a notification showing them to the
user. We ensure they are shown to the user for at least 30 seconds
(configurable). If foreground services are executed while the
screen is off, their apps will be shown to the user for at least
30 seconds after the screen turns back on.
While doing this I am also adding a new process state to distinguish
between "important background" stuff that should bypass bg check vs.
ones that don't. By default, these now no longer bypass bg check,
which is really the expected (and documented) behavior. There is a
new bind flag to allow them to bypass bg check, which is currently
only used by the IME.
Also add some new job scheduler commands that will be used to
write new tests cases for jobs timing out.
Bug: 36891897
Test: manual
Change-Id: Ied3f7b56444254513fd776f06b88bc0e54704958
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2230472..6bc59fc 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -458,42 +458,45 @@
/** @hide Process is important to the user, but not something they are aware of. */
public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 7;
+ /** @hide Process is in the background transient so we will try to keep running. */
+ public static final int PROCESS_STATE_TRANSIENT_BACKGROUND = 8;
+
/** @hide Process is in the background running a backup/restore operation. */
- public static final int PROCESS_STATE_BACKUP = 8;
+ public static final int PROCESS_STATE_BACKUP = 9;
/** @hide Process is in the background, but it can't restore its state so we want
* to try to avoid killing it. */
- public static final int PROCESS_STATE_HEAVY_WEIGHT = 9;
+ public static final int PROCESS_STATE_HEAVY_WEIGHT = 10;
/** @hide Process is in the background running a service. Unlike oom_adj, this level
* is used for both the normal running in background state and the executing
* operations state. */
- public static final int PROCESS_STATE_SERVICE = 10;
+ public static final int PROCESS_STATE_SERVICE = 11;
/** @hide Process is in the background running a receiver. Note that from the
* perspective of oom_adj receivers run at a higher foreground level, but for our
* prioritization here that is not necessary and putting them below services means
* many fewer changes in some process states as they receive broadcasts. */
- public static final int PROCESS_STATE_RECEIVER = 11;
+ public static final int PROCESS_STATE_RECEIVER = 12;
/** @hide Process is in the background but hosts the home activity. */
- public static final int PROCESS_STATE_HOME = 12;
+ public static final int PROCESS_STATE_HOME = 13;
/** @hide Process is in the background but hosts the last shown activity. */
- public static final int PROCESS_STATE_LAST_ACTIVITY = 13;
+ public static final int PROCESS_STATE_LAST_ACTIVITY = 14;
/** @hide Process is being cached for later use and contains activities. */
- public static final int PROCESS_STATE_CACHED_ACTIVITY = 14;
+ public static final int PROCESS_STATE_CACHED_ACTIVITY = 15;
/** @hide Process is being cached for later use and is a client of another cached
* process that contains activities. */
- public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 15;
+ public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 16;
/** @hide Process is being cached for later use and is empty. */
- public static final int PROCESS_STATE_CACHED_EMPTY = 16;
+ public static final int PROCESS_STATE_CACHED_EMPTY = 17;
/** @hide Process does not exist. */
- public static final int PROCESS_STATE_NONEXISTENT = 17;
+ public static final int PROCESS_STATE_NONEXISTENT = 18;
/** @hide The lowest process state number */
public static final int MIN_PROCESS_STATE = PROCESS_STATE_PERSISTENT;
@@ -503,7 +506,7 @@
/** @hide Should this process state be considered a background state? */
public static final boolean isProcStateBackground(int procState) {
- return procState >= PROCESS_STATE_BACKUP;
+ return procState >= PROCESS_STATE_TRANSIENT_BACKGROUND;
}
/** @hide requestType for assist context: only basic information. */
@@ -3233,7 +3236,7 @@
return IMPORTANCE_SERVICE;
} else if (procState > PROCESS_STATE_HEAVY_WEIGHT) {
return IMPORTANCE_CANT_SAVE_STATE;
- } else if (procState >= PROCESS_STATE_IMPORTANT_BACKGROUND) {
+ } else if (procState >= PROCESS_STATE_TRANSIENT_BACKGROUND) {
return IMPORTANCE_PERCEPTIBLE;
} else if (procState >= PROCESS_STATE_IMPORTANT_FOREGROUND) {
return IMPORTANCE_VISIBLE;
@@ -3290,7 +3293,7 @@
} else if (importance > IMPORTANCE_CANT_SAVE_STATE) {
return PROCESS_STATE_HEAVY_WEIGHT;
} else if (importance >= IMPORTANCE_PERCEPTIBLE) {
- return PROCESS_STATE_IMPORTANT_BACKGROUND;
+ return PROCESS_STATE_TRANSIENT_BACKGROUND;
} else if (importance >= IMPORTANCE_VISIBLE) {
return PROCESS_STATE_IMPORTANT_FOREGROUND;
} else if (importance >= IMPORTANCE_TOP_SLEEPING) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2e2d444..bf7af20 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -323,6 +323,12 @@
public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0080;
/**
+ * @hide Flag for {@link #bindService}: like {@link #BIND_NOT_FOREGROUND}, but puts it
+ * up in to the important background state (instead of transient).
+ */
+ public static final int BIND_IMPORTANT_BACKGROUND = 0x00800000;
+
+ /**
* @hide Flag for {@link #bindService}: allows application hosting service to manage whitelists
* such as temporary allowing a {@code PendingIntent} to bypass Power Save mode.
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 95be39b..f215ae7 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -724,6 +724,19 @@
"android.settings.APPLICATION_DETAILS_SETTINGS";
/**
+ * Activity Action: Show list of applications that have been running
+ * foreground services (to the user "running in the background").
+ * <p>
+ * Input: Extras "packages" is a string array of package names.
+ * <p>
+ * Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_FOREGROUND_SERVICES_SETTINGS =
+ "android.settings.FOREGROUND_SERVICES_SETTINGS";
+
+ /**
* Activity Action: Show screen for controlling which apps can ignore battery optimizations.
* <p>
* Input: Nothing.
@@ -8980,13 +8993,30 @@
* Activity manager specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
- * "enforce_bg_check=true,max_cached_processes=24"
+ * "gc_timeout=5000,max_cached_processes=24"
*
* The following keys are supported:
*
* <pre>
- * enforce_bg_check (boolean)
* max_cached_processes (int)
+ * background_settle_time (long)
+ * foreground_service_ui_min_time (long)
+ * content_provider_retain_time (long)
+ * gc_timeout (long)
+ * gc_min_interval (long)
+ * full_pss_min_interval (long)
+ * full_pss_lowered_interval (long)
+ * power_check_delay (long)
+ * wake_lock_min_check_duration (long)
+ * cpu_min_check_duration (long)
+ * service_usage_interaction_time (long)
+ * usage_stats_interaction_interval (long)
+ * service_restart_duration (long)
+ * service_reset_run_duration (long)
+ * service_restart_duration_factor (int)
+ * service_min_restart_time_between (long)
+ * service_max_inactivity (long)
+ * service_bg_start_timeout (long)
* </pre>
*
* <p>
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index 8c2c236..9470668 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -86,6 +86,7 @@
STATE_TOP, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
STATE_BACKUP, // ActivityManager.PROCESS_STATE_BACKUP
STATE_HEAVY_WEIGHT, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
STATE_SERVICE, // ActivityManager.PROCESS_STATE_SERVICE
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index ef20750..fef85da 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -45,6 +45,7 @@
public static String ALERTS = "ALERTS";
public static String RETAIL_MODE = "RETAIL_MODE";
public static String USB = "USB";
+ public static String FOREGROUND_SERVICE = "FOREGROUND_SERVICE";
public static void createAll(Context context) {
final NotificationManager nm = context.getSystemService(NotificationManager.class);
@@ -125,6 +126,11 @@
context.getString(R.string.notification_channel_usb),
NotificationManager.IMPORTANCE_MIN));
+ channelsList.add(new NotificationChannel(
+ FOREGROUND_SERVICE,
+ context.getString(R.string.notification_channel_foreground_service),
+ NotificationManager.IMPORTANCE_MIN));
+
nm.createNotificationChannels(channelsList);
}
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 35b12ff..e633d66 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -644,6 +644,29 @@
<!-- Text shown when viewing channel settings for notifications related to a usb connection -->
<string name="notification_channel_usb">USB connection</string>
+ <!-- Text shown when viewing channel settings for notifications related to running foreground
+ services [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_foreground_service">Apps running in background</string>
+
+ <!-- Label for foreground service notification when one app is running. [CHAR LIMIT=NONE] -->
+ <string name="foreground_service_app_in_background"><xliff:g id="app_name">%1$s</xliff:g> is
+ running in the background</string>
+
+ <!-- Label for foreground service notification when multiple apps are running.
+ [CHAR LIMIT=NONE] -->
+ <string name="foreground_service_apps_in_background"><xliff:g id="number">%1$d</xliff:g> apps
+ are running in the background</string>
+
+ <!-- Content for foreground service notification when one app is running.
+ [CHAR LIMIT=NONE] -->
+ <string name="foreground_service_tap_for_details">Tap for details on battery and
+ data usage</string>
+
+ <!-- Separator for foreground service notification content listing all apps when there
+ are multiple apps running [CHAR LIMIT=NONE] -->
+ <string name="foreground_service_multiple_separator"><xliff:g id="left_side">%1$s</xliff:g>,
+ <xliff:g id="right_side">%2$s</xliff:g></string>
+
<!-- Displayed to the user to tell them that they have started up the phone in "safe mode" -->
<string name="safeMode">Safe mode</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1e529da7..5c17788 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2969,6 +2969,12 @@
<java-symbol type="string" name="notification_channel_usb" />
<java-symbol type="string" name="config_defaultAutofillService" />
+ <java-symbol type="string" name="notification_channel_foreground_service" />
+ <java-symbol type="string" name="foreground_service_app_in_background" />
+ <java-symbol type="string" name="foreground_service_apps_in_background" />
+ <java-symbol type="string" name="foreground_service_tap_for_details" />
+ <java-symbol type="string" name="foreground_service_multiple_separator" />
+
<!-- ETWS primary messages -->
<java-symbol type="string" name="etws_primary_default_message_earthquake" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index bf39bc4..490bee4 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -539,6 +539,17 @@
</intent-filter>
</activity>
+ <activity android:name=".ForegroundServicesDialog"
+ android:process=":fgservices"
+ android:excludeFromRecents="true"
+ android:launchMode="singleTop"
+ android:theme="@*android:style/Theme.DeviceDefault.Settings.Dialog">
+ <intent-filter android:priority="1">
+ <action android:name="android.settings.FOREGROUND_SERVICES_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<!-- Doze with notifications, run in main sysui process for every user -->
<service
android:name=".doze.DozeService"
diff --git a/packages/SystemUI/res/layout/foreground_service_item.xml b/packages/SystemUI/res/layout/foreground_service_item.xml
new file mode 100644
index 0000000..0a1dea0
--- /dev/null
+++ b/packages/SystemUI/res/layout/foreground_service_item.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/app_icon"
+ android:layout_width="@android:dimen/app_icon_size"
+ android:layout_height="@android:dimen/app_icon_size"
+ android:layout_marginEnd="8dp"
+ android:scaleType="centerInside"
+ android:contentDescription="@null" />
+
+ <TextView
+ android:id="@+id/app_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal|center_vertical"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textAlignment="viewStart" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/foreground_service_title.xml b/packages/SystemUI/res/layout/foreground_service_title.xml
new file mode 100644
index 0000000..b5434b2
--- /dev/null
+++ b/packages/SystemUI/res/layout/foreground_service_title.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:gravity="center_vertical"
+ android:paddingTop="?android:attr/listPreferredItemPaddingStart"
+ android:paddingBottom="16dp"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+ <com.android.internal.widget.DialogTitle style="?android:attr/textAppearanceLarge"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart"
+ android:text="@string/running_foreground_services_title" />
+ <TextView style="?android:attr/textAppearanceSmall"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:textAlignment="viewStart"
+ android:text="@string/running_foreground_services_msg" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 9097c53..bf70c5a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2030,4 +2030,10 @@
<!-- Do Not Disturb button to change the current settings [CHAR LIMIT=20] -->
<string name="qs_dnd_replace">Replace</string>
+ <!-- Title of the "running foreground services" dialog. [CHAR LIMIT=NONE] -->
+ <string name="running_foreground_services_title">Apps running in background</string>
+
+ <!-- Title of the "running foreground services" dialog. [CHAR LIMIT=NONE] -->
+ <string name="running_foreground_services_msg">Tap for details on battery and data usage</string>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java b/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
new file mode 100644
index 0000000..086e5e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
@@ -0,0 +1,204 @@
+/*
+ * 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.systemui;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+
+/**
+ * Show a list of currently running foreground services (supplied by the caller)
+ * that the user can tap through to their application details.
+ */
+public final class ForegroundServicesDialog extends AlertActivity implements
+ AdapterView.OnItemSelectedListener, DialogInterface.OnClickListener,
+ AlertController.AlertParams.OnPrepareListViewListener {
+
+ private static final String TAG = "ForegroundServicesDialog";
+
+ LayoutInflater mInflater;
+
+ private MetricsLogger mMetricsLogger;
+
+ private String[] mPackages;
+ private PackageItemAdapter mAdapter;
+
+ private DialogInterface.OnClickListener mAppClickListener =
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ String pkg = mPackages[which];
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.setData(Uri.fromParts("package", pkg, null));
+ startActivity(intent);
+ finish();
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Dependency.initDependencies(getApplicationContext());
+
+ mMetricsLogger = Dependency.get(MetricsLogger.class);
+
+ mInflater = LayoutInflater.from(this);
+
+ mAdapter = new PackageItemAdapter(this);
+
+ final AlertController.AlertParams p = mAlertParams;
+ p.mAdapter = mAdapter;
+ p.mOnClickListener = mAppClickListener;
+ p.mCustomTitleView = mInflater.inflate(R.layout.foreground_service_title, null);
+ p.mIsSingleChoice = true;
+ p.mOnItemSelectedListener = this;
+ p.mPositiveButtonText = getString(com.android.internal.R.string.done_label);
+ p.mPositiveButtonListener = this;
+ p.mOnPrepareListViewListener = this;
+
+ updateApps(getIntent());
+ if (mPackages == null) {
+ Log.w(TAG, "No packages supplied");
+ finish();
+ return;
+ }
+
+ setupAlert();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mMetricsLogger.visible(MetricsProto.MetricsEvent.RUNNING_BACKGROUND_APPS_DIALOG);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mMetricsLogger.hidden(MetricsProto.MetricsEvent.RUNNING_BACKGROUND_APPS_DIALOG);
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ updateApps(intent);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+
+ // This is a transient dialog, if the user leaves it then it goes away,
+ // they can return back to it from the notification.
+ if (!isChangingConfigurations()) {
+ finish();
+ }
+ }
+
+ void updateApps(Intent intent) {
+ mPackages = intent.getStringArrayExtra("packages");
+ if (mPackages != null) {
+ mAdapter.setPackages(mPackages);
+ }
+ }
+
+ public void onPrepareListView(ListView listView) {
+ }
+
+ /*
+ * On click of Ok/Cancel buttons
+ */
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+
+ public void onItemSelected(AdapterView parent, View view, int position, long id) {
+ }
+
+ public void onNothingSelected(AdapterView parent) {
+ }
+
+ static private class PackageItemAdapter extends ArrayAdapter<ApplicationInfo> {
+ final PackageManager mPm;
+ final LayoutInflater mInflater;
+
+ public PackageItemAdapter(Context context) {
+ super(context, R.layout.foreground_service_item);
+ mPm = context.getPackageManager();
+ mInflater = LayoutInflater.from(context);
+ }
+
+ public void setPackages(String[] packages) {
+ clear();
+
+ ArrayList<ApplicationInfo> apps = new ArrayList<>();
+ for (int i = 0; i < packages.length; i++) {
+ try {
+ apps.add(mPm.getApplicationInfo(packages[i],
+ PackageManager.MATCH_KNOWN_PACKAGES));
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ }
+
+ apps.sort(new ApplicationInfo.DisplayNameComparator(mPm));
+ addAll(apps);
+ }
+
+ public @NonNull
+ View getView(int position, @Nullable View convertView,
+ @NonNull ViewGroup parent) {
+ final View view;
+ if (convertView == null) {
+ view = mInflater.inflate(R.layout.foreground_service_item, parent, false);
+ } else {
+ view = convertView;
+ }
+
+ ImageView icon = view.findViewById(R.id.app_icon);
+ icon.setImageDrawable(getItem(position).loadIcon(mPm));
+
+ TextView label = view.findViewById(R.id.app_name);
+ label.setText(getItem(position).loadLabel(mPm));
+
+ return view;
+ }
+ }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index cc6e435..ff99b19 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3952,6 +3952,11 @@
// internal platform metrics use.
RESERVED_FOR_LOGBUILDER_UID = 943;
+ // OPEN: Running background apps notification > List of background apps
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: O
+ RUNNING_BACKGROUND_APPS_DIALOG = 944;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 65cc17e..53b3fe9 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -176,6 +176,10 @@
// Inform the user their phone recently shut down due to high temperature
NOTE_THERMAL_SHUTDOWN = 39;
+ // Tell the user about currently running foreground services
+ // Package: android
+ NOTE_FOREGROUND_SERVICES = 40;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index 9d3d531..e1756d1 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -371,6 +371,14 @@
doPrint = true;
} else if (args[i].equals("-f") || args[i].equals("--file")) {
doFile = true;
+ } else if (args[i].equals("-h") || args[i].equals("--help")) {
+ pw.println("Dropbox (dropbox) dump options:");
+ pw.println(" [-h|--help] [-p|--print] [-f|--file] [timestamp]");
+ pw.println(" -h|--help: print this help");
+ pw.println(" -p|--print: print full contents of each entry");
+ pw.println(" -f|--file: print path of each entry's file");
+ pw.println(" [timestamp] optionally filters to only those entries.");
+ return;
} else if (args[i].startsWith("-")) {
out.append("Unknown argument: ").append(args[i]).append("\n");
} else {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 8ad3d23..20a6d14 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -212,6 +212,7 @@
Context.BIND_AUTO_CREATE
| Context.BIND_NOT_VISIBLE
| Context.BIND_NOT_FOREGROUND
+ | Context.BIND_IMPORTANT_BACKGROUND
| Context.BIND_SHOWING_UI;
/**
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d008c5e..5edf19a 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -31,10 +31,12 @@
import android.app.ActivityThread;
import android.app.AppOpsManager;
+import android.app.NotificationManager;
import android.app.ServiceStartArgs;
import android.content.IIntentSender;
import android.content.IntentSender;
import android.content.pm.ParceledListSlice;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.DeadObjectException;
@@ -43,10 +45,14 @@
import android.os.RemoteCallback;
import android.os.SystemProperties;
import android.os.TransactionTooLargeException;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
+import com.android.internal.R;
import com.android.internal.app.procstats.ServiceState;
+import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.FastPrintWriter;
@@ -101,32 +107,6 @@
// calling startForeground() before we ANR + stop it.
static final int SERVICE_START_FOREGROUND_TIMEOUT = 5*1000;
- // How long a service needs to be running until restarting its process
- // is no longer considered to be a relaunch of the service.
- static final int SERVICE_RESTART_DURATION = 1*1000;
-
- // How long a service needs to be running until it will start back at
- // SERVICE_RESTART_DURATION after being killed.
- static final int SERVICE_RESET_RUN_DURATION = 60*1000;
-
- // Multiplying factor to increase restart duration time by, for each time
- // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
- static final int SERVICE_RESTART_DURATION_FACTOR = 4;
-
- // The minimum amount of time between restarting services that we allow.
- // That is, when multiple services are restarting, we won't allow each
- // to restart less than this amount of time from the last one.
- static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
-
- // Maximum amount of time for there to be no activity on a service before
- // we consider it non-essential and allow its process to go on the
- // LRU background list.
- static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
-
- // How long we wait for a background started service to stop itself before
- // allowing the next pending start to run.
- static final int BG_START_TIMEOUT = 15*1000;
-
final ActivityManagerService mAm;
// Maximum number of services that we allow to start in the background
@@ -162,6 +142,11 @@
/** Temporary list for holding the results of calls to {@link #collectPackageServicesLocked} */
private ArrayList<ServiceRecord> mTmpCollectionResults = null;
+ /**
+ * For keeping ActiveForegroundApps retaining state while the screen is off.
+ */
+ boolean mScreenOn = true;
+
/** Amount of time to allow a last ANR message to exist before freeing the memory. */
static final int LAST_ANR_LIFETIME_DURATION_MSECS = 2 * 60 * 60 * 1000; // Two hours
@@ -176,9 +161,23 @@
};
/**
+ * Information about an app that is currently running one or more foreground services.
+ * (This mapps directly to the running apps we show in the notification.)
+ */
+ static final class ActiveForegroundApp {
+ String mPackageName;
+ CharSequence mLabel;
+ boolean mShownWhileScreenOn;
+ long mStartTime;
+ long mStartVisibleTime;
+ long mEndTime;
+ int mNumActive;
+ }
+
+ /**
* Information about services for a single user.
*/
- class ServiceMap extends Handler {
+ final class ServiceMap extends Handler {
final int mUserId;
final ArrayMap<ComponentName, ServiceRecord> mServicesByName = new ArrayMap<>();
final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent = new ArrayMap<>();
@@ -196,7 +195,11 @@
final ArrayList<ServiceRecord> mStartingBackground = new ArrayList<>();
+ final ArrayMap<String, ActiveForegroundApp> mActiveForegroundApps = new ArrayMap<>();
+ boolean mActiveForegroundAppsChanged;
+
static final int MSG_BG_START_TIMEOUT = 1;
+ static final int MSG_UPDATE_FOREGROUND_APPS = 2;
ServiceMap(Looper looper, int userId) {
super(looper);
@@ -211,6 +214,9 @@
rescheduleDelayedStartsLocked();
}
} break;
+ case MSG_UPDATE_FOREGROUND_APPS: {
+ updateForegroundApps(this);
+ } break;
}
}
@@ -528,7 +534,7 @@
if (r.startRequested && addToStarting) {
boolean first = smap.mStartingBackground.size() == 0;
smap.mStartingBackground.add(r);
- r.startingBgTimeout = SystemClock.uptimeMillis() + BG_START_TIMEOUT;
+ r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;
if (DEBUG_DELAYED_SERVICE) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
@@ -716,6 +722,171 @@
}
}
+ void updateForegroundApps(ServiceMap smap) {
+ // This is called from the handler without the lock held.
+ ArrayList<ActiveForegroundApp> active = null;
+ synchronized (mAm) {
+ final long now = SystemClock.elapsedRealtime();
+ final long nowPlusMin = now + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME;
+ if (smap != null) {
+ for (int i = smap.mActiveForegroundApps.size()-1; i >= 0; i--) {
+ ActiveForegroundApp aa = smap.mActiveForegroundApps.valueAt(i);
+ if (aa.mEndTime != 0 && (mScreenOn || aa.mShownWhileScreenOn)) {
+ if (aa.mEndTime < (aa.mStartVisibleTime
+ + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME)) {
+ // Check to see if this should still be displayed... we continue
+ // until it has been shown for at least the timeout duration.
+ if (nowPlusMin >= aa.mStartVisibleTime) {
+ // All over!
+ smap.mActiveForegroundApps.removeAt(i);
+ smap.mActiveForegroundAppsChanged = true;
+ continue;
+ }
+ } else {
+ // This was up for longer than the timeout, so just remove immediately.
+ smap.mActiveForegroundApps.removeAt(i);
+ smap.mActiveForegroundAppsChanged = true;
+ continue;
+ }
+ }
+ if (active == null) {
+ active = new ArrayList<>();
+ }
+ active.add(aa);
+ }
+ }
+ if (!smap.mActiveForegroundAppsChanged) {
+ return;
+ }
+ smap.mActiveForegroundAppsChanged = false;
+ }
+
+ final NotificationManager nm = (NotificationManager) mAm.mContext.getSystemService(
+ Context.NOTIFICATION_SERVICE);
+ final Context context = mAm.mContext;
+
+ if (active != null) {
+ for (int i = 0; i < active.size(); i++) {
+ ActiveForegroundApp aa = active.get(i);
+ if (aa.mLabel == null) {
+ PackageManager pm = context.getPackageManager();
+ try {
+ ApplicationInfo ai = pm.getApplicationInfoAsUser(aa.mPackageName,
+ PackageManager.MATCH_KNOWN_PACKAGES, smap.mUserId);
+ aa.mLabel = ai.loadLabel(pm);
+ } catch (PackageManager.NameNotFoundException e) {
+ aa.mLabel = aa.mPackageName;
+ }
+ }
+ }
+
+ Intent intent;
+ String title;
+ String msg;
+ if (active.size() == 1) {
+ intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.setData(Uri.fromParts("package", active.get(0).mPackageName, null));
+ title = context.getString(
+ R.string.foreground_service_app_in_background, active.get(0).mLabel);
+ msg = context.getString(R.string.foreground_service_tap_for_details);
+ } else {
+ intent = new Intent(Settings.ACTION_FOREGROUND_SERVICES_SETTINGS);
+ String[] pkgs = new String[active.size()];
+ for (int i = 0; i < active.size(); i++) {
+ pkgs[i] = active.get(i).mPackageName;
+ }
+ intent.putExtra("packages", pkgs);
+ title = context.getString(
+ R.string.foreground_service_apps_in_background, active.size());
+ msg = active.get(0).mLabel.toString();
+ for (int i = 1; i < active.size(); i++) {
+ msg = context.getString(R.string.foreground_service_multiple_separator,
+ msg, active.get(i).mLabel);
+ }
+ }
+ Notification.Builder n =
+ new Notification.Builder(context,
+ SystemNotificationChannels.FOREGROUND_SERVICE)
+ .setSmallIcon(R.drawable.ic_check_circle_24px)
+ .setOngoing(true)
+ .setShowWhen(false)
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(msg)
+ .setContentIntent(
+ PendingIntent.getActivityAsUser(context, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT,
+ null, new UserHandle(smap.mUserId)));
+ nm.notifyAsUser(null, SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
+ n.build(), new UserHandle(smap.mUserId));
+ } else {
+ nm.cancelAsUser(null, SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
+ new UserHandle(smap.mUserId));
+ }
+ }
+
+ private void requestUpdateActiveForegroundAppsLocked(ServiceMap smap, long time) {
+ Message msg = smap.obtainMessage(ServiceMap.MSG_UPDATE_FOREGROUND_APPS);
+ if (time != 0) {
+ smap.sendMessageAtTime(msg, time);
+ } else {
+ smap.mActiveForegroundAppsChanged = true;
+ smap.sendMessage(msg);
+ }
+ }
+
+ private void decActiveForegroundAppLocked(ServiceMap smap, ServiceRecord r) {
+ ActiveForegroundApp active = smap.mActiveForegroundApps.get(r.packageName);
+ if (active != null) {
+ active.mNumActive--;
+ if (active.mNumActive <= 0) {
+ active.mEndTime = SystemClock.elapsedRealtime();
+ if (active.mEndTime >= (active.mStartVisibleTime
+ + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME)) {
+ // Have been active for long enough that we will remove it immediately.
+ smap.mActiveForegroundApps.remove(r.packageName);
+ smap.mActiveForegroundAppsChanged = true;
+ requestUpdateActiveForegroundAppsLocked(smap, 0);
+ } else {
+ requestUpdateActiveForegroundAppsLocked(smap, active.mStartVisibleTime
+ + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME);
+ }
+ }
+ }
+ }
+
+ void updateScreenStateLocked(boolean screenOn) {
+ if (mScreenOn != screenOn) {
+ mScreenOn = screenOn;
+
+ // If screen is turning on, then we now reset the start time of any foreground
+ // services that were started while the screen was off.
+ if (screenOn) {
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ for (int i = mServiceMap.size()-1; i >= 0; i--) {
+ ServiceMap smap = mServiceMap.valueAt(i);
+ boolean changed = false;
+ for (int j = smap.mActiveForegroundApps.size()-1; j >= 0; j--) {
+ ActiveForegroundApp active = smap.mActiveForegroundApps.valueAt(j);
+ if (!active.mShownWhileScreenOn) {
+ changed = true;
+ active.mShownWhileScreenOn = mScreenOn;
+ active.mStartVisibleTime = nowElapsed;
+ if (active.mEndTime != 0) {
+ active.mEndTime = nowElapsed;
+ }
+ }
+ }
+ if (changed) {
+ requestUpdateActiveForegroundAppsLocked(smap,
+ nowElapsed + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME);
+ }
+ }
+ }
+ }
+ }
+
private void setServiceForegroundInnerLocked(ServiceRecord r, int id,
Notification notification, int flags) {
if (id != 0) {
@@ -770,7 +941,23 @@
}
notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
r.foregroundNoti = notification;
- r.isForeground = true;
+ if (!r.isForeground) {
+ final ServiceMap smap = getServiceMapLocked(r.userId);
+ if (smap != null) {
+ ActiveForegroundApp active = smap.mActiveForegroundApps.get(r.packageName);
+ if (active == null) {
+ active = new ActiveForegroundApp();
+ active.mPackageName = r.packageName;
+ active.mShownWhileScreenOn = mScreenOn;
+ active.mStartTime = active.mStartVisibleTime
+ = SystemClock.elapsedRealtime();
+ smap.mActiveForegroundApps.put(r.packageName, active);
+ requestUpdateActiveForegroundAppsLocked(smap, 0);
+ }
+ active.mNumActive++;
+ }
+ r.isForeground = true;
+ }
r.postNotification();
if (r.app != null) {
updateServiceForegroundLocked(r.app, true);
@@ -780,6 +967,10 @@
PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
} else {
if (r.isForeground) {
+ final ServiceMap smap = getServiceMapLocked(r.userId);
+ if (smap != null) {
+ decActiveForegroundAppLocked(smap, r);
+ }
r.isForeground = false;
if (r.app != null) {
mAm.updateLruProcessLocked(r.app, false, null);
@@ -1561,8 +1752,8 @@
if ((r.serviceInfo.applicationInfo.flags
&ApplicationInfo.FLAG_PERSISTENT) == 0) {
- long minDuration = SERVICE_RESTART_DURATION;
- long resetTime = SERVICE_RESET_RUN_DURATION;
+ long minDuration = mAm.mConstants.SERVICE_RESTART_DURATION;
+ long resetTime = mAm.mConstants.SERVICE_RESET_RUN_DURATION;
// Any delivered but not yet finished starts should be put back
// on the pending list.
@@ -1603,7 +1794,7 @@
r.restartCount = 1;
r.restartDelay = minDuration;
} else {
- r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
+ r.restartDelay *= mAm.mConstants.SERVICE_RESTART_DURATION_FACTOR;
if (r.restartDelay < minDuration) {
r.restartDelay = minDuration;
}
@@ -1617,13 +1808,12 @@
boolean repeat;
do {
repeat = false;
+ final long restartTimeBetween = mAm.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN;
for (int i=mRestartingServices.size()-1; i>=0; i--) {
ServiceRecord r2 = mRestartingServices.get(i);
- if (r2 != r && r.nextRestartTime
- >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
- && r.nextRestartTime
- < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
- r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
+ if (r2 != r && r.nextRestartTime >= (r2.nextRestartTime-restartTimeBetween)
+ && r.nextRestartTime < (r2.nextRestartTime+restartTimeBetween)) {
+ r.nextRestartTime = r2.nextRestartTime + restartTimeBetween;
r.restartDelay = r.nextRestartTime - now;
repeat = true;
break;
@@ -2174,6 +2364,9 @@
}
cancelForegroundNotificationLocked(r);
+ if (r.isForeground) {
+ decActiveForegroundAppLocked(smap, r);
+ }
r.isForeground = false;
r.foregroundId = 0;
r.foregroundNoti = null;
@@ -2612,6 +2805,22 @@
return didSomething;
}
+ void removeUninstalledPackageLocked(String packageName, int userId) {
+ ServiceMap smap = mServiceMap.get(userId);
+ if (smap != null && smap.mActiveForegroundApps.size() > 0) {
+ for (int i = smap.mActiveForegroundApps.size(); i >= 0; i--) {
+ ActiveForegroundApp aa = smap.mActiveForegroundApps.valueAt(i);
+ if (aa.mPackageName.equals(packageName)) {
+ smap.mActiveForegroundApps.removeAt(i);
+ smap.mActiveForegroundAppsChanged = true;
+ }
+ }
+ if (smap.mActiveForegroundAppsChanged) {
+ requestUpdateActiveForegroundAppsLocked(smap, 0);
+ }
+ }
+ }
+
void cleanUpRemovedTaskLocked(TaskRecord tr, ComponentName component, Intent baseIntent) {
ArrayList<ServiceRecord> services = new ArrayList<>();
ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(tr.userId);
@@ -3394,6 +3603,55 @@
}
}
+ if (matcher.all) {
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ final int[] users = mAm.mUserController.getUsers();
+ for (int user : users) {
+ boolean printedUser = false;
+ ServiceMap smap = mServiceMap.get(user);
+ if (smap == null) {
+ continue;
+ }
+ for (int i = smap.mActiveForegroundApps.size() - 1; i >= 0; i--) {
+ ActiveForegroundApp aa = smap.mActiveForegroundApps.valueAt(i);
+ if (dumpPackage != null && !dumpPackage.equals(aa.mPackageName)) {
+ continue;
+ }
+ if (!printedUser) {
+ printedUser = true;
+ printedAnything = true;
+ if (needSep) pw.println();
+ needSep = true;
+ pw.print("Active foreground apps - user ");
+ pw.print(user);
+ pw.println(":");
+ }
+ pw.print(" #");
+ pw.print(i);
+ pw.print(": ");
+ pw.println(aa.mPackageName);
+ if (aa.mLabel != null) {
+ pw.print(" mLabel=");
+ pw.println(aa.mLabel);
+ }
+ pw.print(" mNumActive=");
+ pw.print(aa.mNumActive);
+ pw.print(" mShownWhileScreenOn=");
+ pw.println(aa.mShownWhileScreenOn);
+ pw.print(" mStartTime=");
+ TimeUtils.formatDuration(aa.mStartTime - nowElapsed, pw);
+ pw.print(" mStartVisibleTime=");
+ TimeUtils.formatDuration(aa.mStartVisibleTime - nowElapsed, pw);
+ pw.println();
+ if (aa.mEndTime != 0) {
+ pw.print(" mEndTime=");
+ TimeUtils.formatDuration(aa.mEndTime - nowElapsed, pw);
+ pw.println();
+ }
+ }
+ }
+ }
+
if (!printedAnything) {
pw.println(" (nothing)");
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 55ee183..5749f31 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -20,25 +20,137 @@
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
-import android.os.SystemProperties;
import android.provider.Settings;
import android.util.KeyValueListParser;
import android.util.Slog;
import java.io.PrintWriter;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
+
/**
* Settings constants that can modify the activity manager's behavior.
*/
final class ActivityManagerConstants extends ContentObserver {
// Key names stored in the settings value.
private static final String KEY_MAX_CACHED_PROCESSES = "max_cached_processes";
+ private static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time";
+ private static final String KEY_FOREGROUND_SERVICE_UI_MIN_TIME
+ = "foreground_service_ui_min_time";
+ private static final String KEY_CONTENT_PROVIDER_RETAIN_TIME = "content_provider_retain_time";
+ private static final String KEY_GC_TIMEOUT = "gc_timeout";
+ private static final String KEY_GC_MIN_INTERVAL = "gc_min_interval";
+ private static final String KEY_FULL_PSS_MIN_INTERVAL = "full_pss_min_interval";
+ private static final String KEY_FULL_PSS_LOWERED_INTERVAL = "full_pss_lowered_interval";
+ private static final String KEY_POWER_CHECK_DELAY = "power_check_delay";
+ private static final String KEY_WAKE_LOCK_MIN_CHECK_DURATION = "wake_lock_min_check_duration";
+ private static final String KEY_CPU_MIN_CHECK_DURATION = "cpu_min_check_duration";
+ private static final String KEY_SERVICE_USAGE_INTERACTION_TIME
+ = "service_usage_interaction_time";
+ private static final String KEY_USAGE_STATS_INTERACTION_INTERVAL
+ = "usage_stats_interaction_interval";
+ static final String KEY_SERVICE_RESTART_DURATION = "service_restart_duration";
+ static final String KEY_SERVICE_RESET_RUN_DURATION = "service_reset_run_duration";
+ static final String KEY_SERVICE_RESTART_DURATION_FACTOR = "service_restart_duration_factor";
+ static final String KEY_SERVICE_MIN_RESTART_TIME_BETWEEN = "service_min_restart_time_between";
+ static final String KEY_MAX_SERVICE_INACTIVITY = "service_max_inactivity";
+ static final String KEY_BG_START_TIMEOUT = "service_bg_start_timeout";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
+ private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
+ private static final long DEFAULT_FOREGROUND_SERVICE_UI_MIN_TIME = 30*1000;
+ private static final long DEFAULT_CONTENT_PROVIDER_RETAIN_TIME = 20*1000;
+ private static final long DEFAULT_GC_TIMEOUT = 5*1000;
+ private static final long DEFAULT_GC_MIN_INTERVAL = 60*1000;
+ private static final long DEFAULT_FULL_PSS_MIN_INTERVAL = 10*60*1000;
+ private static final long DEFAULT_FULL_PSS_LOWERED_INTERVAL = 2*60*1000;
+ private static final long DEFAULT_POWER_CHECK_DELAY = (DEBUG_POWER_QUICK ? 2 : 15) * 60*1000;
+ private static final long DEFAULT_WAKE_LOCK_MIN_CHECK_DURATION
+ = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
+ private static final long DEFAULT_CPU_MIN_CHECK_DURATION
+ = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
+ private static final long DEFAULT_SERVICE_USAGE_INTERACTION_TIME = 30*60*1000;
+ private static final long DEFAULT_USAGE_STATS_INTERACTION_INTERVAL = 24*60*60*1000L;
+ private static final long DEFAULT_SERVICE_RESTART_DURATION = 1*1000;
+ private static final long DEFAULT_SERVICE_RESET_RUN_DURATION = 60*1000;
+ private static final int DEFAULT_SERVICE_RESTART_DURATION_FACTOR = 4;
+ private static final long DEFAULT_SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
+ private static final long DEFAULT_MAX_SERVICE_INACTIVITY = 30*60*1000;
+ private static final long DEFAULT_BG_START_TIMEOUT = 15*1000;
// Maximum number of cached processes we will allow.
public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
+ // This is the amount of time we allow an app to settle after it goes into the background,
+ // before we start restricting what it can do.
+ public long BACKGROUND_SETTLE_TIME = DEFAULT_BACKGROUND_SETTLE_TIME;
+
+ // The minimum time a foreground service will be shown as running in the notification UI.
+ public long FOREGROUND_SERVICE_UI_MIN_TIME = DEFAULT_FOREGROUND_SERVICE_UI_MIN_TIME;
+
+ // How long we will retain processes hosting content providers in the "last activity"
+ // state before allowing them to drop down to the regular cached LRU list. This is
+ // to avoid thrashing of provider processes under low memory situations.
+ long CONTENT_PROVIDER_RETAIN_TIME = DEFAULT_CONTENT_PROVIDER_RETAIN_TIME;
+
+ // How long to wait after going idle before forcing apps to GC.
+ long GC_TIMEOUT = DEFAULT_GC_TIMEOUT;
+
+ // The minimum amount of time between successive GC requests for a process.
+ long GC_MIN_INTERVAL = DEFAULT_GC_MIN_INTERVAL;
+
+ // The minimum amount of time between successive PSS requests for a process.
+ long FULL_PSS_MIN_INTERVAL = DEFAULT_FULL_PSS_MIN_INTERVAL;
+
+ // The minimum amount of time between successive PSS requests for a process
+ // when the request is due to the memory state being lowered.
+ long FULL_PSS_LOWERED_INTERVAL = DEFAULT_FULL_PSS_LOWERED_INTERVAL;
+
+ // The rate at which we check for apps using excessive power -- 15 mins.
+ long POWER_CHECK_DELAY = DEFAULT_POWER_CHECK_DELAY;
+
+ // The minimum sample duration we will allow before deciding we have
+ // enough data on wake locks to start killing things.
+ long WAKE_LOCK_MIN_CHECK_DURATION = DEFAULT_WAKE_LOCK_MIN_CHECK_DURATION;
+
+ // The minimum sample duration we will allow before deciding we have
+ // enough data on CPU usage to start killing things.
+ long CPU_MIN_CHECK_DURATION = DEFAULT_CPU_MIN_CHECK_DURATION;
+
+ // This is the amount of time an app needs to be running a foreground service before
+ // we will consider it to be doing interaction for usage stats.
+ long SERVICE_USAGE_INTERACTION_TIME = DEFAULT_SERVICE_USAGE_INTERACTION_TIME;
+
+ // Maximum amount of time we will allow to elapse before re-reporting usage stats
+ // interaction with foreground processes.
+ long USAGE_STATS_INTERACTION_INTERVAL = DEFAULT_USAGE_STATS_INTERACTION_INTERVAL;
+
+ // How long a service needs to be running until restarting its process
+ // is no longer considered to be a relaunch of the service.
+ public long SERVICE_RESTART_DURATION = DEFAULT_SERVICE_RESTART_DURATION;
+
+ // How long a service needs to be running until it will start back at
+ // SERVICE_RESTART_DURATION after being killed.
+ public long SERVICE_RESET_RUN_DURATION = DEFAULT_SERVICE_RESET_RUN_DURATION;
+
+ // Multiplying factor to increase restart duration time by, for each time
+ // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
+ public int SERVICE_RESTART_DURATION_FACTOR = DEFAULT_SERVICE_RESTART_DURATION_FACTOR;
+
+ // The minimum amount of time between restarting services that we allow.
+ // That is, when multiple services are restarting, we won't allow each
+ // to restart less than this amount of time from the last one.
+ public long SERVICE_MIN_RESTART_TIME_BETWEEN = DEFAULT_SERVICE_MIN_RESTART_TIME_BETWEEN;
+
+ // Maximum amount of time for there to be no activity on a service before
+ // we consider it non-essential and allow its process to go on the
+ // LRU background list.
+ public long MAX_SERVICE_INACTIVITY = DEFAULT_MAX_SERVICE_INACTIVITY;
+
+ // How long we wait for a background started service to stop itself before
+ // allowing the next pending start to run.
+ public long BG_START_TIMEOUT = DEFAULT_BG_START_TIMEOUT;
+
private final ActivityManagerService mService;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -111,6 +223,42 @@
}
MAX_CACHED_PROCESSES = mParser.getInt(KEY_MAX_CACHED_PROCESSES,
DEFAULT_MAX_CACHED_PROCESSES);
+ BACKGROUND_SETTLE_TIME = mParser.getLong(KEY_BACKGROUND_SETTLE_TIME,
+ DEFAULT_BACKGROUND_SETTLE_TIME);
+ FOREGROUND_SERVICE_UI_MIN_TIME = mParser.getLong(KEY_FOREGROUND_SERVICE_UI_MIN_TIME,
+ DEFAULT_FOREGROUND_SERVICE_UI_MIN_TIME);
+ CONTENT_PROVIDER_RETAIN_TIME = mParser.getLong(KEY_CONTENT_PROVIDER_RETAIN_TIME,
+ DEFAULT_CONTENT_PROVIDER_RETAIN_TIME);
+ GC_TIMEOUT = mParser.getLong(KEY_GC_TIMEOUT,
+ DEFAULT_GC_TIMEOUT);
+ GC_MIN_INTERVAL = mParser.getLong(KEY_GC_MIN_INTERVAL,
+ DEFAULT_GC_MIN_INTERVAL);
+ FULL_PSS_MIN_INTERVAL = mParser.getLong(KEY_FULL_PSS_MIN_INTERVAL,
+ DEFAULT_FULL_PSS_MIN_INTERVAL);
+ FULL_PSS_LOWERED_INTERVAL = mParser.getLong(KEY_FULL_PSS_LOWERED_INTERVAL,
+ DEFAULT_FULL_PSS_LOWERED_INTERVAL);
+ POWER_CHECK_DELAY = mParser.getLong(KEY_POWER_CHECK_DELAY,
+ DEFAULT_POWER_CHECK_DELAY);
+ WAKE_LOCK_MIN_CHECK_DURATION = mParser.getLong(KEY_WAKE_LOCK_MIN_CHECK_DURATION,
+ DEFAULT_WAKE_LOCK_MIN_CHECK_DURATION);
+ CPU_MIN_CHECK_DURATION = mParser.getLong(KEY_CPU_MIN_CHECK_DURATION,
+ DEFAULT_CPU_MIN_CHECK_DURATION);
+ SERVICE_USAGE_INTERACTION_TIME = mParser.getLong(KEY_SERVICE_USAGE_INTERACTION_TIME,
+ DEFAULT_SERVICE_USAGE_INTERACTION_TIME);
+ USAGE_STATS_INTERACTION_INTERVAL = mParser.getLong(KEY_USAGE_STATS_INTERACTION_INTERVAL,
+ DEFAULT_USAGE_STATS_INTERACTION_INTERVAL);
+ SERVICE_RESTART_DURATION = mParser.getLong(KEY_SERVICE_RESTART_DURATION,
+ DEFAULT_SERVICE_RESTART_DURATION);
+ SERVICE_RESET_RUN_DURATION = mParser.getLong(KEY_SERVICE_RESET_RUN_DURATION,
+ DEFAULT_SERVICE_RESET_RUN_DURATION);
+ SERVICE_RESTART_DURATION_FACTOR = mParser.getInt(KEY_SERVICE_RESTART_DURATION_FACTOR,
+ DEFAULT_SERVICE_RESTART_DURATION_FACTOR);
+ SERVICE_MIN_RESTART_TIME_BETWEEN = mParser.getLong(KEY_SERVICE_MIN_RESTART_TIME_BETWEEN,
+ DEFAULT_SERVICE_MIN_RESTART_TIME_BETWEEN);
+ MAX_SERVICE_INACTIVITY = mParser.getLong(KEY_MAX_SERVICE_INACTIVITY,
+ DEFAULT_MAX_SERVICE_INACTIVITY);
+ BG_START_TIMEOUT = mParser.getLong(KEY_BG_START_TIMEOUT,
+ DEFAULT_BG_START_TIMEOUT);
updateMaxCachedProcesses();
}
}
@@ -134,6 +282,42 @@
pw.print(" "); pw.print(KEY_MAX_CACHED_PROCESSES); pw.print("=");
pw.println(MAX_CACHED_PROCESSES);
+ pw.print(" "); pw.print(KEY_BACKGROUND_SETTLE_TIME); pw.print("=");
+ pw.println(BACKGROUND_SETTLE_TIME);
+ pw.print(" "); pw.print(KEY_FOREGROUND_SERVICE_UI_MIN_TIME); pw.print("=");
+ pw.println(FOREGROUND_SERVICE_UI_MIN_TIME);
+ pw.print(" "); pw.print(KEY_CONTENT_PROVIDER_RETAIN_TIME); pw.print("=");
+ pw.println(CONTENT_PROVIDER_RETAIN_TIME);
+ pw.print(" "); pw.print(KEY_GC_TIMEOUT); pw.print("=");
+ pw.println(GC_TIMEOUT);
+ pw.print(" "); pw.print(KEY_GC_MIN_INTERVAL); pw.print("=");
+ pw.println(GC_MIN_INTERVAL);
+ pw.print(" "); pw.print(KEY_FULL_PSS_MIN_INTERVAL); pw.print("=");
+ pw.println(FULL_PSS_MIN_INTERVAL);
+ pw.print(" "); pw.print(KEY_FULL_PSS_LOWERED_INTERVAL); pw.print("=");
+ pw.println(FULL_PSS_LOWERED_INTERVAL);
+ pw.print(" "); pw.print(KEY_POWER_CHECK_DELAY); pw.print("=");
+ pw.println(POWER_CHECK_DELAY);
+ pw.print(" "); pw.print(KEY_WAKE_LOCK_MIN_CHECK_DURATION); pw.print("=");
+ pw.println(WAKE_LOCK_MIN_CHECK_DURATION);
+ pw.print(" "); pw.print(KEY_CPU_MIN_CHECK_DURATION); pw.print("=");
+ pw.println(CPU_MIN_CHECK_DURATION);
+ pw.print(" "); pw.print(KEY_SERVICE_USAGE_INTERACTION_TIME); pw.print("=");
+ pw.println(SERVICE_USAGE_INTERACTION_TIME);
+ pw.print(" "); pw.print(KEY_USAGE_STATS_INTERACTION_INTERVAL); pw.print("=");
+ pw.println(USAGE_STATS_INTERACTION_INTERVAL);
+ pw.print(" "); pw.print(KEY_SERVICE_RESTART_DURATION); pw.print("=");
+ pw.println(SERVICE_RESTART_DURATION);
+ pw.print(" "); pw.print(KEY_SERVICE_RESET_RUN_DURATION); pw.print("=");
+ pw.println(SERVICE_RESET_RUN_DURATION);
+ pw.print(" "); pw.print(KEY_SERVICE_RESTART_DURATION_FACTOR); pw.print("=");
+ pw.println(SERVICE_RESTART_DURATION_FACTOR);
+ pw.print(" "); pw.print(KEY_SERVICE_MIN_RESTART_TIME_BETWEEN); pw.print("=");
+ pw.println(SERVICE_MIN_RESTART_TIME_BETWEEN);
+ pw.print(" "); pw.print(KEY_MAX_SERVICE_INACTIVITY); pw.print("=");
+ pw.println(MAX_SERVICE_INACTIVITY);
+ pw.print(" "); pw.print(KEY_BG_START_TIMEOUT); pw.print("=");
+ pw.println(BG_START_TIMEOUT);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 71ef230..d46a24b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -513,41 +513,12 @@
// before we decide it must be hung.
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
- // How long we will retain processes hosting content providers in the "last activity"
- // state before allowing them to drop down to the regular cached LRU list. This is
- // to avoid thrashing of provider processes under low memory situations.
- static final int CONTENT_PROVIDER_RETAIN_TIME = 20*1000;
-
// How long we wait for a launched process to attach to the activity manager
// before we decide it's never going to come up for real, when the process was
// started with a wrapper for instrumentation (such as Valgrind) because it
// could take much longer than usual.
static final int PROC_START_TIMEOUT_WITH_WRAPPER = 1200*1000;
- // How long to wait after going idle before forcing apps to GC.
- static final int GC_TIMEOUT = 5*1000;
-
- // The minimum amount of time between successive GC requests for a process.
- static final int GC_MIN_INTERVAL = 60*1000;
-
- // The minimum amount of time between successive PSS requests for a process.
- static final int FULL_PSS_MIN_INTERVAL = 10*60*1000;
-
- // The minimum amount of time between successive PSS requests for a process
- // when the request is due to the memory state being lowered.
- static final int FULL_PSS_LOWERED_INTERVAL = 2*60*1000;
-
- // The rate at which we check for apps using excessive power -- 15 mins.
- static final int POWER_CHECK_DELAY = (DEBUG_POWER_QUICK ? 2 : 15) * 60*1000;
-
- // The minimum sample duration we will allow before deciding we have
- // enough data on wake locks to start killing things.
- static final int WAKE_LOCK_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
-
- // The minimum sample duration we will allow before deciding we have
- // enough data on CPU usage to start killing things.
- static final int CPU_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
-
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;
@@ -558,18 +529,6 @@
// How long we wait until we timeout on key dispatching during instrumentation.
static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
- // This is the amount of time an app needs to be running a foreground service before
- // we will consider it to be doing interaction for usage stats.
- static final int SERVICE_USAGE_INTERACTION_TIME = 30*60*1000;
-
- // Maximum amount of time we will allow to elapse before re-reporting usage stats
- // interaction with foreground processes.
- static final long USAGE_STATS_INTERACTION_INTERVAL = 24*60*60*1000L;
-
- // This is the amount of time we allow an app to settle after it goes into the background,
- // before we start restricting what it can do.
- static final int BACKGROUND_SETTLE_TIME = 1*60*1000;
-
// How long to wait in getAssistContextExtras for the activity and foreground services
// to respond with the result.
static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500;
@@ -2147,7 +2106,7 @@
checkExcessivePowerUsageLocked(true);
removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
Message nmsg = obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
- sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
+ sendMessageDelayed(nmsg, mConstants.POWER_CHECK_DELAY);
}
} break;
case REPORT_MEM_USAGE_MSG: {
@@ -4259,7 +4218,7 @@
"Unable to set a higher trim level than current level");
}
if (!(level < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN ||
- app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND)) {
+ app.curProcState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)) {
throw new IllegalArgumentException("Unable to set a background trim level "
+ "on a foreground process");
}
@@ -5345,7 +5304,7 @@
memInfos.add(new ProcessMemInfo(rec.processName, rec.pid, rec.setAdj,
rec.setProcState, rec.adjType, rec.makeAdjReason()));
}
- if ((rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
+ if ((rec.lastLowMemory+mConstants.GC_MIN_INTERVAL) <= now) {
// The low memory report is overriding any current
// state for a GC request. Make sure to do
// heavy/important/visible/foreground processes first.
@@ -7103,7 +7062,7 @@
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
// Start looking for apps that are abusing wake locks.
Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
- mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
+ mHandler.sendMessageDelayed(nmsg, mConstants.POWER_CHECK_DELAY);
// Tell anyone interested that we are done booting!
SystemProperties.set("sys.boot_completed", "1");
@@ -12277,14 +12236,15 @@
}
void updateSleepIfNeededLocked() {
- if (mSleeping && !shouldSleepLocked()) {
+ final boolean shouldSleep = shouldSleepLocked();
+ if (mSleeping && !shouldSleep) {
mSleeping = false;
startTimeTrackingFocusedActivityLocked();
mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
mStackSupervisor.comeOutOfSleepIfNeededLocked();
sendNotifyVrManagerOfSleepState(false);
updateOomAdjLocked();
- } else if (!mSleeping && shouldSleepLocked()) {
+ } else if (!mSleeping && shouldSleep) {
mSleeping = true;
if (mCurAppTimeTracker != null) {
mCurAppTimeTracker.stop();
@@ -12298,7 +12258,20 @@
checkExcessivePowerUsageLocked(false);
mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
- mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
+ mHandler.sendMessageDelayed(nmsg, mConstants.POWER_CHECK_DELAY);
+ }
+
+ // Also update state in a special way for running foreground services UI.
+ switch (mWakefulness) {
+ case PowerManagerInternal.WAKEFULNESS_ASLEEP:
+ case PowerManagerInternal.WAKEFULNESS_DREAMING:
+ case PowerManagerInternal.WAKEFULNESS_DOZING:
+ mServices.updateScreenStateLocked(false);
+ break;
+ case PowerManagerInternal.WAKEFULNESS_AWAKE:
+ default:
+ mServices.updateScreenStateLocked(true);
+ break;
}
}
@@ -19034,6 +19007,8 @@
removeTasksByPackageNameLocked(ssp, userId);
+ mServices.removeUninstalledPackageLocked(ssp, userId);
+
// Hide the "unsupported display" dialog if necessary.
if (mUnsupportedDisplaySizeDialog != null && ssp.equals(
mUnsupportedDisplaySizeDialog.getPackageName())) {
@@ -20823,8 +20798,8 @@
if (adj > ProcessList.BACKUP_APP_ADJ) {
if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
adj = ProcessList.BACKUP_APP_ADJ;
- if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+ if (procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+ procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
}
app.adjType = "backup";
app.cached = false;
@@ -20856,7 +20831,7 @@
app.adjType = "cch-started-ui-services";
}
} else {
- if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {
+ if (now < (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
// This service has seen some activity within
// recent memory, so we will keep its process ahead
// of the background processes.
@@ -20921,8 +20896,7 @@
clientAdj = adj;
clientProcState = procState;
} else {
- if (now >= (s.lastActivity
- + ActiveServices.MAX_SERVICE_INACTIVITY)) {
+ if (now >= (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
// This service has not seen activity within
// recent memory, so allow it to drop to the
// LRU list if there is no other reason to keep
@@ -20968,7 +20942,8 @@
adjType = "service";
}
}
- if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+ if ((cr.flags & (Context.BIND_NOT_FOREGROUND
+ | Context.BIND_IMPORTANT_BACKGROUND)) == 0) {
// This will treat important bound services identically to
// the top app, which may behave differently than generic
// foreground work.
@@ -21012,6 +20987,12 @@
}
}
}
+ } else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
+ if (clientProcState <
+ ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+ clientProcState =
+ ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+ }
} else {
if (clientProcState <
ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
@@ -21150,7 +21131,8 @@
}
}
- if (app.lastProviderTime > 0 && (app.lastProviderTime+CONTENT_PROVIDER_RETAIN_TIME) > now) {
+ if (app.lastProviderTime > 0 &&
+ (app.lastProviderTime+mConstants.CONTENT_PROVIDER_RETAIN_TIME) > now) {
if (adj > ProcessList.PREVIOUS_APP_ADJ) {
adj = ProcessList.PREVIOUS_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
@@ -21172,6 +21154,7 @@
switch (procState) {
case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
+ case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
case ActivityManager.PROCESS_STATE_SERVICE:
// These all are longer-term states, so pull them up to the top
// of the background states, but not all the way to the top state.
@@ -21367,7 +21350,8 @@
void requestPssAllProcsLocked(long now, boolean always, boolean memLowered) {
if (!always) {
if (now < (mLastFullPssTime +
- (memLowered ? FULL_PSS_LOWERED_INTERVAL : FULL_PSS_MIN_INTERVAL))) {
+ (memLowered ? mConstants.FULL_PSS_LOWERED_INTERVAL
+ : mConstants.FULL_PSS_MIN_INTERVAL))) {
return;
}
}
@@ -21449,7 +21433,7 @@
while (mProcessesToGc.size() > 0) {
ProcessRecord proc = mProcessesToGc.remove(0);
if (proc.curRawAdj > ProcessList.PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) {
- if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
+ if ((proc.lastRequestedGc+mConstants.GC_MIN_INTERVAL)
<= SystemClock.uptimeMillis()) {
// To avoid spamming the system, we will GC processes one
// at a time, waiting a few seconds between each.
@@ -21492,10 +21476,10 @@
ProcessRecord proc = mProcessesToGc.get(0);
Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
- long when = proc.lastRequestedGc + GC_MIN_INTERVAL;
+ long when = proc.lastRequestedGc + mConstants.GC_MIN_INTERVAL;
long now = SystemClock.uptimeMillis();
- if (when < (now+GC_TIMEOUT)) {
- when = now + GC_TIMEOUT;
+ if (when < (now+mConstants.GC_TIMEOUT)) {
+ when = now + mConstants.GC_TIMEOUT;
}
mHandler.sendMessageAtTime(msg, when);
}
@@ -21528,7 +21512,7 @@
*/
final void scheduleAppGcLocked(ProcessRecord app) {
long now = SystemClock.uptimeMillis();
- if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
+ if ((app.lastRequestedGc+mConstants.GC_MIN_INTERVAL) > now) {
return;
}
if (!mProcessesToGc.contains(app)) {
@@ -21558,10 +21542,10 @@
final long uptimeSince = curUptime - mLastPowerCheckUptime;
mLastPowerCheckRealtime = curRealtime;
mLastPowerCheckUptime = curUptime;
- if (realtimeSince < WAKE_LOCK_MIN_CHECK_DURATION) {
+ if (realtimeSince < mConstants.WAKE_LOCK_MIN_CHECK_DURATION) {
doWakeKills = false;
}
- if (uptimeSince < CPU_MIN_CHECK_DURATION) {
+ if (uptimeSince < mConstants.CPU_MIN_CHECK_DURATION) {
doCpuKills = false;
}
int i = mLruProcesses.size();
@@ -21819,7 +21803,7 @@
app.procStateChanged = true;
}
} else if (app.reportedInteraction && (nowElapsed-app.interactionEventTime)
- > USAGE_STATS_INTERACTION_INTERVAL) {
+ > mConstants.USAGE_STATS_INTERACTION_INTERVAL) {
// For apps that sit around for a long time in the interactive state, we need
// to report this at least once a day so they don't go idle.
maybeUpdateUsageStatsLocked(app, nowElapsed);
@@ -21992,7 +21976,8 @@
app.fgInteractionTime = nowElapsed;
isInteraction = false;
} else {
- isInteraction = nowElapsed > app.fgInteractionTime + SERVICE_USAGE_INTERACTION_TIME;
+ isInteraction = nowElapsed > app.fgInteractionTime
+ + mConstants.SERVICE_USAGE_INTERACTION_TIME;
}
} else {
// If the app was being forced to the foreground, by say a Toast, then
@@ -22001,8 +21986,8 @@
&& app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
app.fgInteractionTime = 0;
}
- if (isInteraction && (!app.reportedInteraction
- || (nowElapsed-app.interactionEventTime) > USAGE_STATS_INTERACTION_INTERVAL)) {
+ if (isInteraction && (!app.reportedInteraction || (nowElapsed-app.interactionEventTime)
+ > mConstants.USAGE_STATS_INTERACTION_INTERVAL)) {
app.interactionEventTime = nowElapsed;
String[] packages = app.getPackageList();
if (packages != null) {
@@ -22518,7 +22503,8 @@
// the handler time base is uptime. All this means is that we may
// stop background uids later than we had intended, but that only
// happens because the device was sleeping so we are okay anyway.
- mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG, BACKGROUND_SETTLE_TIME);
+ mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
+ mConstants.BACKGROUND_SETTLE_TIME);
}
}
} else {
@@ -22623,7 +22609,7 @@
return;
}
final long nowElapsed = SystemClock.elapsedRealtime();
- final long maxBgTime = nowElapsed - BACKGROUND_SETTLE_TIME;
+ final long maxBgTime = nowElapsed - mConstants.BACKGROUND_SETTLE_TIME;
long nextTime = 0;
if (mLocalPowerManager != null) {
mLocalPowerManager.startUidChanges();
@@ -22648,7 +22634,7 @@
if (nextTime > 0) {
mHandler.removeMessages(IDLE_UIDS_MSG);
mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
- nextTime + BACKGROUND_SETTLE_TIME - nowElapsed);
+ nextTime + mConstants.BACKGROUND_SETTLE_TIME - nowElapsed);
}
}
}
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index cd37041..9b7a0c4 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -74,6 +74,9 @@
if ((flags&Context.BIND_NOT_FOREGROUND) != 0) {
sb.append("!FG ");
}
+ if ((flags&Context.BIND_IMPORTANT_BACKGROUND) != 0) {
+ sb.append("IMPB ");
+ }
if ((flags&Context.BIND_ABOVE_CLIENT) != 0) {
sb.append("ABCLT ");
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 0dc6788..80e7c75 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -373,6 +373,9 @@
case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
procState = "IMPB";
break;
+ case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
+ procState = "TRNB";
+ break;
case ActivityManager.PROCESS_STATE_BACKUP:
procState = "BKUP";
break;
@@ -482,6 +485,7 @@
PROC_MEM_TOP, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
PROC_MEM_IMPORTANT, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
PROC_MEM_IMPORTANT, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ PROC_MEM_IMPORTANT, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
PROC_MEM_IMPORTANT, // ActivityManager.PROCESS_STATE_BACKUP
PROC_MEM_IMPORTANT, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
PROC_MEM_SERVICE, // ActivityManager.PROCESS_STATE_SERVICE
@@ -502,6 +506,7 @@
PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_BACKUP
PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_SERVICE
@@ -522,6 +527,7 @@
PSS_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
PSS_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
PSS_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ PSS_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
PSS_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_BACKUP
PSS_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
PSS_SAME_SERVICE_INTERVAL, // ActivityManager.PROCESS_STATE_SERVICE
@@ -542,6 +548,7 @@
PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_BACKUP
PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_SERVICE
@@ -562,6 +569,7 @@
PSS_TEST_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_TOP_SLEEPING
PSS_TEST_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
PSS_TEST_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ PSS_TEST_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
PSS_TEST_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_BACKUP
PSS_TEST_SAME_IMPORTANT_INTERVAL, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
PSS_TEST_SAME_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_SERVICE
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index abb2b55..e2c1274 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -1916,7 +1916,8 @@
}
try {
- final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0, userId);
+ final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0,
+ userId != UserHandle.USER_ALL ? userId : UserHandle.USER_SYSTEM);
if (uid < 0) {
return JobSchedulerShellCommand.CMD_ERR_NO_PACKAGE;
}
@@ -1942,6 +1943,25 @@
return 0;
}
+ // Shell command infrastructure: immediately timeout currently executing jobs
+ int executeTimeoutCommand(PrintWriter pw, String pkgName, int userId,
+ boolean hasJobId, int jobId) {
+ if (DEBUG) {
+ Slog.v(TAG, "executeTimeoutCommand(): " + pkgName + "/" + userId + " " + jobId);
+ }
+
+ synchronized (mLock) {
+ boolean foundSome = false;
+ for (int i=0; i<mActiveServices.size(); i++) {
+ mActiveServices.get(i).timeoutIfExecutingLocked(pkgName, userId, hasJobId, jobId);
+ }
+ if (!foundSome) {
+ pw.println("No matching executing jobs found.");
+ }
+ }
+ return 0;
+ }
+
void setMonitorBattery(boolean enabled) {
synchronized (mLock) {
if (mBatteryController != null) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
index 1c31c3e..fdfb345 100644
--- a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -16,11 +16,11 @@
package com.android.server.job;
+import android.app.ActivityManager;
import android.app.AppGlobals;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.os.Binder;
-import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;
@@ -46,18 +46,20 @@
switch (cmd != null ? cmd : "") {
case "run":
return runJob(pw);
+ case "timeout":
+ return timeout(pw);
case "monitor-battery":
- return runMonitorBattery(pw);
+ return monitorBattery(pw);
case "get-battery-seq":
- return runGetBatterySeq(pw);
+ return getBatterySeq(pw);
case "get-battery-charging":
- return runGetBatteryCharging(pw);
+ return getBatteryCharging(pw);
case "get-battery-not-low":
- return runGetBatteryNotLow(pw);
+ return getBatteryNotLow(pw);
case "get-storage-seq":
- return runGetStorageSeq(pw);
+ return getStorageSeq(pw);
case "get-storage-not-low":
- return runGetStorageNotLow(pw);
+ return getStorageNotLow(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -154,7 +156,42 @@
}
}
- private int runMonitorBattery(PrintWriter pw) throws Exception {
+ private int timeout(PrintWriter pw) throws Exception {
+ checkPermission("force timeout jobs");
+
+ int userId = UserHandle.USER_ALL;
+
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "-u":
+ case "--user":
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+
+ default:
+ pw.println("Error: unknown option '" + opt + "'");
+ return -1;
+ }
+ }
+
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = ActivityManager.getCurrentUser();
+ }
+
+ final String pkgName = getNextArg();
+ final String jobIdStr = getNextArg();
+ final int jobId = jobIdStr != null ? Integer.parseInt(jobIdStr) : -1;
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return mInternal.executeTimeoutCommand(pw, pkgName, userId, jobIdStr != null, jobId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private int monitorBattery(PrintWriter pw) throws Exception {
checkPermission("change battery monitoring");
String opt = getNextArgRequired();
boolean enabled;
@@ -166,37 +203,42 @@
getErrPrintWriter().println("Error: unknown option " + opt);
return 1;
}
- mInternal.setMonitorBattery(enabled);
- if (enabled) pw.println("Battery monitoring enabled");
- else pw.println("Battery monitoring disabled");
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mInternal.setMonitorBattery(enabled);
+ if (enabled) pw.println("Battery monitoring enabled");
+ else pw.println("Battery monitoring disabled");
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
return 0;
}
- private int runGetBatterySeq(PrintWriter pw) {
+ private int getBatterySeq(PrintWriter pw) {
int seq = mInternal.getBatterySeq();
pw.println(seq);
return 0;
}
- private int runGetBatteryCharging(PrintWriter pw) {
+ private int getBatteryCharging(PrintWriter pw) {
boolean val = mInternal.getBatteryCharging();
pw.println(val);
return 0;
}
- private int runGetBatteryNotLow(PrintWriter pw) {
+ private int getBatteryNotLow(PrintWriter pw) {
boolean val = mInternal.getBatteryNotLow();
pw.println(val);
return 0;
}
- private int runGetStorageSeq(PrintWriter pw) {
+ private int getStorageSeq(PrintWriter pw) {
int seq = mInternal.getStorageSeq();
pw.println(seq);
return 0;
}
- private int runGetStorageNotLow(PrintWriter pw) {
+ private int getStorageNotLow(PrintWriter pw) {
boolean val = mInternal.getStorageNotLow();
pw.println(val);
return 0;
@@ -216,6 +258,12 @@
pw.println(" connectivity are not currently met");
pw.println(" -u or --user: specify which user's job is to be run; the default is");
pw.println(" the primary or system user");
+ pw.println(" timeout [-u | --user USER_ID] [PACKAGE] [JOB_ID]");
+ pw.println(" Trigger immediate timeout of currently executing jobs, as if their.");
+ pw.println(" execution timeout had expired.");
+ pw.println(" Options:");
+ pw.println(" -u or --user: specify which user's job is to be run; the default is");
+ pw.println(" all users");
pw.println(" monitor-battery [on|off]");
pw.println(" Control monitoring of all battery changes. Off by default. Turning");
pw.println(" on makes get-battery-seq useful.");
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 9144966..73beecf 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -184,7 +184,8 @@
scheduleOpTimeOutLocked();
final Intent intent = new Intent().setComponent(job.getServiceComponent());
boolean binding = mContext.bindServiceAsUser(intent, this,
- Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
+ | Context.BIND_IMPORTANT_BACKGROUND,
new UserHandle(job.getUserId()));
if (!binding) {
if (DEBUG) {
@@ -255,6 +256,20 @@
return mTimeoutElapsed;
}
+ boolean timeoutIfExecutingLocked(String pkgName, int userId, boolean matchJobId, int jobId) {
+ final JobStatus executing = getRunningJob();
+ if (executing != null && (userId == UserHandle.USER_ALL || userId == executing.getUserId())
+ && (pkgName == null || pkgName.equals(executing.getSourcePackageName()))
+ && (!matchJobId || jobId == executing.getJobId())) {
+ if (mVerb == VERB_EXECUTING) {
+ mParams.setStopReason(JobParameters.REASON_TIMEOUT);
+ sendStopMessageLocked();
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public void jobFinished(int jobId, boolean reschedule) {
doCallback(reschedule);