diff options
| author | 2017-04-26 13:59:47 -0700 | |
|---|---|---|
| committer | 2017-04-29 19:41:12 -0700 | |
| commit | 83b40f69bef4ba17bb63ac30d52f661a12d5b4f4 (patch) | |
| tree | 886ed06a37a347d91230c9cc325ec7d5a4f6e71b | |
| parent | 34c226d6024cb324f2acf8800d29abb3a69c1c53 (diff) | |
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
24 files changed, 1065 insertions, 141 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 223047241480..6bc59fc0334f 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -458,42 +458,45 @@ public class ActivityManager { /** @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 @@ public class ActivityManager { /** @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 @@ public class ActivityManager { 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 @@ public class ActivityManager { } 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 2e2d444d3f14..bf7af2027b99 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -323,6 +323,12 @@ public abstract class Context { 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 95be39bdbd93..f215ae7ce405 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -724,6 +724,19 @@ public final class Settings { "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 @@ public final class Settings { * 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 8c2c2362f994..94706687f6de 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 @@ public final class ProcessState { 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 ef20750cdb19..fef85da27f17 100644 --- a/core/java/com/android/internal/notification/SystemNotificationChannels.java +++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java @@ -45,6 +45,7 @@ public class SystemNotificationChannels { 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 @@ public class SystemNotificationChannels { 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 35b12ffb5d68..e633d66514cc 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 1e529da7b14a..5c17788835cb 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 bf39bc4b96ea..490bee48aac6 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 000000000000..0a1dea05413f --- /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 000000000000..b5434b2402aa --- /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 9097c5375e13..bf70c5a2fc49 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 000000000000..086e5e52e037 --- /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 cc6e43550710..ff99b190fbc6 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -3952,6 +3952,11 @@ message MetricsEvent { // 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 65cc17eec6bd..53b3fe9c1a0d 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -176,6 +176,10 @@ message SystemMessage { // 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 9d3d5313eb4a..e1756d1bf198 100644 --- a/services/core/java/com/android/server/DropBoxManagerService.java +++ b/services/core/java/com/android/server/DropBoxManagerService.java @@ -371,6 +371,14 @@ public final class DropBoxManagerService extends SystemService { 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 8ad3d23648bf..20a6d14e5ca4 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -212,6 +212,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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 d008c5e0ccb6..5edf19a9d012 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 java.util.Set; 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.Looper; 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 @@ public final class ActiveServices { // 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 @@ public final class ActiveServices { /** 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 @@ public final class ActiveServices { }; /** + * 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { rescheduleDelayedStartsLocked(); } } break; + case MSG_UPDATE_FOREGROUND_APPS: { + updateForegroundApps(this); + } break; } } @@ -528,7 +534,7 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { } } + 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 @@ public final class ActiveServices { } 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { } cancelForegroundNotificationLocked(r); + if (r.isForeground) { + decActiveForegroundAppLocked(smap, r); + } r.isForeground = false; r.foregroundId = 0; r.foregroundNoti = null; @@ -2612,6 +2805,22 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { } } + 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 55ee18335410..5749f31ddb2e 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.content.ContentResolver; 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 @@ final class ActivityManagerConstants extends ContentObserver { } 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 @@ final class ActivityManagerConstants extends ContentObserver { 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 71ef23028651..d46a24bec6cb 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 @@ public class ActivityManagerService extends IActivityManager.Stub // 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 @@ public class ActivityManagerService extends IActivityManager.Stub // 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub "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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub } 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub } } } + } 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 @@ public class ActivityManagerService extends IActivityManager.Stub } } - 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub */ 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub && 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 @@ public class ActivityManagerService extends IActivityManager.Stub // 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 cd370412554e..9b7a0c43b191 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 @@ final class ConnectionRecord { 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 0dc678813338..80e7c757931c 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 @@ final class ProcessList { 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 @@ final class ProcessList { 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 @@ final class ProcessList { 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 @@ final class ProcessList { 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 @@ final class ProcessList { 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 @@ final class ProcessList { 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 abb2b555be57..e2c1274a4be6 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 @@ public final class JobSchedulerService extends com.android.server.SystemService } 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 @@ public final class JobSchedulerService extends com.android.server.SystemService 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 1c31c3e6af96..fdfb345b3fb2 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 @@ public class JobSchedulerShellCommand extends ShellCommand { 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 @@ public class JobSchedulerShellCommand extends ShellCommand { } } - 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 @@ public class JobSchedulerShellCommand extends ShellCommand { 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 @@ public class JobSchedulerShellCommand extends ShellCommand { 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 9144966da409..73beecfdd711 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 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne 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 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne 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); |