Merge "Work on issue #36891897: Need to ensure foreground services can't..." into oc-dev
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);