summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2013-04-30 17:24:15 -0700
committerDianne Hackborn <hackbod@google.com>2013-05-02 17:42:40 -0700
commit8d044e8bc287c1a567d82aedbe30085b011544c3 (patch)
tree89966111423d4519c15874aa871d35d3cc92b206 /services/java/com/android/server
parent34761434a0957dde28d6156afb48372934581c16 (diff)
downloadframeworks_base-8d044e8bc287c1a567d82aedbe30085b011544c3.zip
frameworks_base-8d044e8bc287c1a567d82aedbe30085b011544c3.tar.gz
frameworks_base-8d044e8bc287c1a567d82aedbe30085b011544c3.tar.bz2
Start combining threads in system process.
This introduces four generic thread that services can use in the system process: - Background: part of the framework for all processes, for work that is purely background (no timing constraint). - UI: for time-critical display of UI. - Foreground: normal foreground work. - IO: performing IO operations. I went through and moved services into these threads in the places I felt relatively comfortable about understanding what they are doing. There are still a bunch more we need to look at -- lots of networking stuff left, 3 or so different native daemon connectors which I didn't know how much would block, audio stuff, etc. Also updated Watchdog to be aware of and check these new threads, with a new API for other threads to also participate in this checking. Change-Id: Ie2f11061cebde5f018d7383b3a910fbbd11d5e11
Diffstat (limited to 'services/java/com/android/server')
-rw-r--r--services/java/com/android/server/AppWidgetService.java6
-rw-r--r--services/java/com/android/server/BluetoothManagerService.java6
-rw-r--r--services/java/com/android/server/CountryDetectorService.java9
-rw-r--r--services/java/com/android/server/FgThread.java65
-rw-r--r--services/java/com/android/server/IoThread.java62
-rw-r--r--services/java/com/android/server/LocationManagerService.java7
-rw-r--r--services/java/com/android/server/MountService.java12
-rw-r--r--services/java/com/android/server/NativeDaemonConnector.java5
-rw-r--r--services/java/com/android/server/NetworkTimeUpdateService.java7
-rw-r--r--services/java/com/android/server/SystemServer.java30
-rw-r--r--services/java/com/android/server/UiThread.java71
-rw-r--r--services/java/com/android/server/Watchdog.java159
-rw-r--r--services/java/com/android/server/accounts/AccountManagerService.java7
-rw-r--r--services/java/com/android/server/connectivity/Tethering.java9
-rw-r--r--services/java/com/android/server/content/SyncManager.java9
-rw-r--r--services/java/com/android/server/display/DisplayManagerService.java5
-rw-r--r--services/java/com/android/server/net/NetworkPolicyManagerService.java7
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java7
-rw-r--r--services/java/com/android/server/usb/UsbDebuggingManager.java10
-rw-r--r--services/java/com/android/server/usb/UsbDeviceManager.java9
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java9
21 files changed, 354 insertions, 157 deletions
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index d5715a5..5b76f39 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -27,7 +27,6 @@ import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -37,6 +36,7 @@ import android.widget.RemoteViews;
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
@@ -63,9 +63,7 @@ class AppWidgetService extends IAppWidgetService.Stub
AppWidgetService(Context context) {
mContext = context;
- HandlerThread handlerThread = new HandlerThread("AppWidgetService -- Save state");
- handlerThread.start();
- mSaveStateHandler = new Handler(handlerThread.getLooper());
+ mSaveStateHandler = BackgroundThread.getHandler();
mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler);
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index ea7b696..8684e5b 100644
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -33,7 +33,6 @@ import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -115,7 +114,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// used inside handler thread
private boolean mEnable;
private int mState;
- private HandlerThread mThread;
private final BluetoothHandler mHandler;
private void registerForAirplaneMode(IntentFilter filter) {
@@ -188,9 +186,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
};
BluetoothManagerService(Context context) {
- mThread = new HandlerThread("BluetoothManager");
- mThread.start();
- mHandler = new BluetoothHandler(mThread.getLooper());
+ mHandler = new BluetoothHandler(IoThread.get().getLooper());
mContext = context;
mBluetooth = null;
diff --git a/services/java/com/android/server/CountryDetectorService.java b/services/java/com/android/server/CountryDetectorService.java
index fc76277..8407fa4 100644
--- a/services/java/com/android/server/CountryDetectorService.java
+++ b/services/java/com/android/server/CountryDetectorService.java
@@ -20,6 +20,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
+import com.android.internal.os.BackgroundThread;
import com.android.server.location.ComprehensiveCountryDetector;
import android.content.Context;
@@ -29,8 +30,6 @@ import android.location.ICountryDetector;
import android.location.ICountryListener;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
-import android.os.Process;
import android.os.RemoteException;
import android.util.PrintWriterPrinter;
import android.util.Printer;
@@ -169,8 +168,7 @@ public class CountryDetectorService extends ICountryDetector.Stub implements Run
void systemReady() {
// Shall we wait for the initialization finish.
- Thread thread = new Thread(this, "CountryDetectorService");
- thread.start();
+ BackgroundThread.getHandler().post(this);
}
private void initialize() {
@@ -187,12 +185,9 @@ public class CountryDetectorService extends ICountryDetector.Stub implements Run
}
public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- Looper.prepare();
mHandler = new Handler();
initialize();
mSystemReady = true;
- Looper.loop();
}
protected void setCountryListener(final CountryListener listener) {
diff --git a/services/java/com/android/server/FgThread.java b/services/java/com/android/server/FgThread.java
new file mode 100644
index 0000000..3b655f2
--- /dev/null
+++ b/services/java/com/android/server/FgThread.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+
+/**
+ * Shared singleton foreground thread for the system. This is a thread for regular
+ * foreground service operations, which shouldn't be blocked by anything running in
+ * the background. In particular, the shared background thread could be doing
+ * relatively long-running operations like saving state to disk (in addition to
+ * simply being a background priority), which can cause operations scheduled on it
+ * to be delayed for a user-noticeable amount of time.
+ */
+public final class FgThread extends HandlerThread {
+ private static FgThread sInstance;
+ private static Handler sHandler;
+
+ private FgThread() {
+ super("android.fg", android.os.Process.THREAD_PRIORITY_DEFAULT);
+ }
+
+ private static void ensureThreadLocked() {
+ if (sInstance == null) {
+ sInstance = new FgThread();
+ sInstance.start();
+ sHandler = new Handler(sInstance.getLooper());
+ sHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ android.os.Process.setCanSelfBackground(false);
+ }
+ });
+ }
+ }
+
+ public static FgThread get() {
+ synchronized (UiThread.class) {
+ ensureThreadLocked();
+ return sInstance;
+ }
+ }
+
+ public static Handler getHandler() {
+ synchronized (UiThread.class) {
+ ensureThreadLocked();
+ return sHandler;
+ }
+ }
+}
diff --git a/services/java/com/android/server/IoThread.java b/services/java/com/android/server/IoThread.java
new file mode 100644
index 0000000..b443578
--- /dev/null
+++ b/services/java/com/android/server/IoThread.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+
+/**
+ * Shared singleton I/O thread for the system. This is a thread for non-background
+ * service operations that can potential block briefly on network IO operations
+ * (not waiting for data itself, but communicating with network daemons).
+ */
+public final class IoThread extends HandlerThread {
+ private static IoThread sInstance;
+ private static Handler sHandler;
+
+ private IoThread() {
+ super("android.io", android.os.Process.THREAD_PRIORITY_DEFAULT);
+ }
+
+ private static void ensureThreadLocked() {
+ if (sInstance == null) {
+ sInstance = new IoThread();
+ sInstance.start();
+ sHandler = new Handler(sInstance.getLooper());
+ sHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ android.os.Process.setCanSelfBackground(false);
+ }
+ });
+ }
+ }
+
+ public static IoThread get() {
+ synchronized (UiThread.class) {
+ ensureThreadLocked();
+ return sInstance;
+ }
+ }
+
+ public static Handler getHandler() {
+ synchronized (UiThread.class) {
+ ensureThreadLocked();
+ return sHandler;
+ }
+ }
+}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 2675309..b162c6b 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -63,6 +63,7 @@ import android.util.Slog;
import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
+import com.android.internal.os.BackgroundThread;
import com.android.server.location.GeocoderProxy;
import com.android.server.location.GeofenceProxy;
import com.android.server.location.GeofenceManager;
@@ -93,7 +94,6 @@ public class LocationManagerService extends ILocationManager.Stub {
public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
private static final String WAKELOCK_KEY = TAG;
- private static final String THREAD_NAME = TAG;
// Location resolution level: no location data whatsoever
private static final int RESOLUTION_LEVEL_NONE = 0;
@@ -143,7 +143,6 @@ public class LocationManagerService extends ILocationManager.Stub {
private LocationWorkerHandler mLocationHandler;
private PassiveProvider mPassiveProvider; // track passive provider for special cases
private LocationBlacklist mBlacklist;
- private HandlerThread mHandlerThread;
// --- fields below are protected by mWakeLock ---
private int mPendingBroadcasts;
@@ -216,9 +215,7 @@ public class LocationManagerService extends ILocationManager.Stub {
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
// prepare worker thread
- mHandlerThread = new HandlerThread(THREAD_NAME, Process.THREAD_PRIORITY_BACKGROUND);
- mHandlerThread.start();
- mLocationHandler = new LocationWorkerHandler(mHandlerThread.getLooper());
+ mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
// prepare mLocationHandler's dependents
mLocationFudger = new LocationFudger(mContext, mLocationHandler);
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index e8d7882..9f40000 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -37,7 +37,6 @@ import android.os.Binder;
import android.os.Environment;
import android.os.Environment.UserEnvironment;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -485,7 +484,6 @@ class MountService extends IMountService.Stub
}
};
- private final HandlerThread mHandlerThread;
private final Handler mHandler;
void waitForAsecScan() {
@@ -820,7 +818,7 @@ class MountService extends IMountService.Stub
}
if (code == VoldResponseCode.VolumeDiskInserted) {
- new Thread() {
+ new Thread("MountService#VolumeDiskInserted") {
@Override
public void run() {
try {
@@ -1105,7 +1103,7 @@ class MountService extends IMountService.Stub
/*
* USB mass storage disconnected while enabled
*/
- new Thread() {
+ new Thread("MountService#AvailabilityChange") {
@Override
public void run() {
try {
@@ -1304,9 +1302,7 @@ class MountService extends IMountService.Stub
// XXX: This will go away soon in favor of IMountServiceObserver
mPms = (PackageManagerService) ServiceManager.getService("package");
- mHandlerThread = new HandlerThread("MountService");
- mHandlerThread.start();
- mHandler = new MountServiceHandler(mHandlerThread.getLooper());
+ mHandler = new MountServiceHandler(IoThread.get().getLooper());
// Watch for user changes
final IntentFilter userFilter = new IntentFilter();
@@ -1328,7 +1324,7 @@ class MountService extends IMountService.Stub
idleMaintenanceFilter, null, mHandler);
// Add OBB Action Handler to MountService thread.
- mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
+ mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
/*
* Create the connection to vold with a maximum queue of twice the
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index c3f2afa..abcd8ee 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -19,7 +19,6 @@ package com.android.server;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.Message;
import android.os.SystemClock;
import android.util.LocalLog;
@@ -81,9 +80,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
@Override
public void run() {
- HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
- thread.start();
- mCallbackHandler = new Handler(thread.getLooper(), this);
+ mCallbackHandler = new Handler(FgThread.get().getLooper(), this);
while (true) {
try {
diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/java/com/android/server/NetworkTimeUpdateService.java
index 3bfd190..02b42b8 100644
--- a/services/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/java/com/android/server/NetworkTimeUpdateService.java
@@ -27,7 +27,6 @@ import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
@@ -36,6 +35,7 @@ import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.TrustedTime;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.telephony.TelephonyIntents;
/**
@@ -71,7 +71,6 @@ public class NetworkTimeUpdateService {
// NTP lookup is done on this thread and handler
private Handler mHandler;
- private HandlerThread mThread;
private AlarmManager mAlarmManager;
private PendingIntent mPendingPollIntent;
private SettingsObserver mSettingsObserver;
@@ -114,9 +113,7 @@ public class NetworkTimeUpdateService {
registerForAlarms();
registerForConnectivityIntents();
- mThread = new HandlerThread(TAG);
- mThread.start();
- mHandler = new MyHandler(mThread.getLooper());
+ mHandler = new MyHandler(BackgroundThread.get().getLooper());
// Check the network time on the new thread
mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b263680..3f9d666 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -154,30 +154,6 @@ class ServerThread extends Thread {
InputManagerService inputManager = null;
TelephonyRegistry telephonyRegistry = null;
- // Create a shared handler thread for UI within the system server.
- // This thread is used by at least the following components:
- // - WindowManagerPolicy
- // - KeyguardViewManager
- // - DisplayManagerService
- HandlerThread uiHandlerThread = new HandlerThread("UI");
- uiHandlerThread.start();
- Handler uiHandler = new Handler(uiHandlerThread.getLooper());
- uiHandler.post(new Runnable() {
- @Override
- public void run() {
- //Looper.myLooper().setMessageLogging(new LogPrinter(
- // Log.VERBOSE, "WindowManagerPolicy", Log.LOG_ID_SYSTEM));
- android.os.Process.setThreadPriority(
- android.os.Process.THREAD_PRIORITY_FOREGROUND);
- android.os.Process.setCanSelfBackground(false);
-
- // For debug builds, log event loop stalls to dropbox for analysis.
- if (StrictMode.conditionallyEnableDebugLogging()) {
- Slog.i(TAG, "Enabled StrictMode logging for UI Looper");
- }
- }
- });
-
// Create a handler thread just for the window manager to enjoy.
HandlerThread wmHandlerThread = new HandlerThread("WindowManager");
wmHandlerThread.start();
@@ -231,7 +207,7 @@ class ServerThread extends Thread {
try {
Slog.i(TAG, "Display Manager");
- display = new DisplayManagerService(context, wmHandler, uiHandler);
+ display = new DisplayManagerService(context, wmHandler);
ServiceManager.addService(Context.DISPLAY_SERVICE, display, true);
Slog.i(TAG, "Telephony Registry");
@@ -319,14 +295,14 @@ class ServerThread extends Thread {
Slog.i(TAG, "Init Watchdog");
Watchdog.getInstance().init(context, battery, power, alarm,
ActivityManagerService.self());
+ Watchdog.getInstance().addThread(wmHandler, "WindowManager thread");
Slog.i(TAG, "Input Manager");
inputManager = new InputManagerService(context, wmHandler);
Slog.i(TAG, "Window Manager");
wm = WindowManagerService.main(context, power, display, inputManager,
- uiHandler, wmHandler,
- factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
+ wmHandler, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot, onlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
diff --git a/services/java/com/android/server/UiThread.java b/services/java/com/android/server/UiThread.java
new file mode 100644
index 0000000..60d73aa
--- /dev/null
+++ b/services/java/com/android/server/UiThread.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.StrictMode;
+import android.util.Slog;
+
+/**
+ * Shared singleton thread for showing UI. This is a foreground thread, and in
+ * additional should not have operations that can take more than a few ms scheduled
+ * on it to avoid UI jank.
+ */
+public final class UiThread extends HandlerThread {
+ private static UiThread sInstance;
+ private static Handler sHandler;
+
+ private UiThread() {
+ super("android.ui", android.os.Process.THREAD_PRIORITY_FOREGROUND);
+ }
+
+ private static void ensureThreadLocked() {
+ if (sInstance == null) {
+ sInstance = new UiThread();
+ sInstance.start();
+ sHandler = new Handler(sInstance.getLooper());
+ sHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ //Looper.myLooper().setMessageLogging(new LogPrinter(
+ // Log.VERBOSE, "WindowManagerPolicy", Log.LOG_ID_SYSTEM));
+ android.os.Process.setCanSelfBackground(false);
+
+ // For debug builds, log event loop stalls to dropbox for analysis.
+ if (StrictMode.conditionallyEnableDebugLogging()) {
+ Slog.i("UiThread", "Enabled StrictMode logging for UI thread");
+ }
+ }
+ });
+ }
+ }
+
+ public static UiThread get() {
+ synchronized (UiThread.class) {
+ ensureThreadLocked();
+ return sInstance;
+ }
+ }
+
+ public static Handler getHandler() {
+ synchronized (UiThread.class) {
+ ensureThreadLocked();
+ return sHandler;
+ }
+ }
+}
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index d4d3850..fc95790 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -80,15 +80,13 @@ public class Watchdog extends Thread {
static Watchdog sWatchdog;
/* This handler will be used to post message back onto the main thread */
- final Handler mHandler;
- final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
+ final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<HandlerChecker>();
+ final HandlerChecker mMonitorChecker;
ContentResolver mResolver;
BatteryService mBattery;
PowerManagerService mPower;
AlarmManagerService mAlarm;
ActivityManagerService mActivity;
- boolean mCompleted;
- Monitor mCurrentMonitor;
int mPhonePid;
@@ -111,40 +109,65 @@ public class Watchdog extends Thread {
int mReqRecheckInterval= -1; // >= 0 if a specific recheck interval has been requested
/**
- * Used for scheduling monitor callbacks and checking memory usage.
+ * Used for checking status of handle threads and scheduling monitor callbacks.
*/
- final class HeartbeatHandler extends Handler {
- HeartbeatHandler(Looper looper) {
- super(looper);
+ public final class HandlerChecker implements Runnable {
+ private final Handler mHandler;
+ private final String mName;
+ private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
+ private final boolean mCheckReboot;
+ private boolean mCompleted;
+ private Monitor mCurrentMonitor;
+
+ HandlerChecker(Handler handler, String name, boolean checkReboot) {
+ mHandler = handler;
+ mName = name;
+ mCheckReboot = checkReboot;
+ }
+
+ public void addMonitor(Monitor monitor) {
+ mMonitors.add(monitor);
+ }
+
+ public void scheduleCheckLocked() {
+ mCompleted = false;
+ mCurrentMonitor = null;
+ mHandler.postAtFrontOfQueue(this);
+ }
+
+ public boolean isCompletedLocked() {
+ return mCompleted;
+ }
+
+ public String describeBlockedStateLocked() {
+ return mCurrentMonitor == null ? mName : mCurrentMonitor.getClass().getName();
}
@Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MONITOR: {
- // See if we should force a reboot.
- int rebootInterval = mReqRebootInterval >= 0
- ? mReqRebootInterval : REBOOT_DEFAULT_INTERVAL;
- if (mRebootInterval != rebootInterval) {
- mRebootInterval = rebootInterval;
- // We have been running long enough that a reboot can
- // be considered...
- checkReboot(false);
- }
+ public void run() {
+ // See if we should force a reboot.
+ if (mCheckReboot) {
+ int rebootInterval = mReqRebootInterval >= 0
+ ? mReqRebootInterval : REBOOT_DEFAULT_INTERVAL;
+ if (mRebootInterval != rebootInterval) {
+ mRebootInterval = rebootInterval;
+ // We have been running long enough that a reboot can
+ // be considered...
+ checkReboot(false);
+ }
+ }
- final int size = mMonitors.size();
- for (int i = 0 ; i < size ; i++) {
- synchronized (Watchdog.this) {
- mCurrentMonitor = mMonitors.get(i);
- }
- mCurrentMonitor.monitor();
- }
+ final int size = mMonitors.size();
+ for (int i = 0 ; i < size ; i++) {
+ synchronized (Watchdog.this) {
+ mCurrentMonitor = mMonitors.get(i);
+ }
+ mCurrentMonitor.monitor();
+ }
- synchronized (Watchdog.this) {
- mCompleted = true;
- mCurrentMonitor = null;
- }
- } break;
+ synchronized (Watchdog.this) {
+ mCompleted = true;
+ mCurrentMonitor = null;
}
}
}
@@ -189,9 +212,23 @@ public class Watchdog extends Thread {
private Watchdog() {
super("watchdog");
- // Explicitly bind the HeartbeatHandler to run on the ServerThread, so
- // that it can't get accidentally bound to another thread.
- mHandler = new HeartbeatHandler(Looper.getMainLooper());
+ // Initialize handler checkers for each common thread we want to check. Note
+ // that we are not currently checking the background thread, since it can
+ // potentially hold longer running operations with no guarantees about the timeliness
+ // of operations there.
+
+ // The shared foreground thread is the main checker. It is where we
+ // will also dispatch monitor checks and do other work.
+ mMonitorChecker = new HandlerChecker(FgThread.getHandler(), "foreground thread", true);
+ mHandlerCheckers.add(mMonitorChecker);
+ // Add checker for main thread. We only do a quick check since there
+ // can be UI running on the thread.
+ mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
+ "main thread", false));
+ // Add checker for shared UI thread.
+ mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(), "ui thread", false));
+ // And also check IO thread.
+ mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(), "i/o thread", false));
}
public void init(Context context, BatteryService battery,
@@ -226,9 +263,18 @@ public class Watchdog extends Thread {
public void addMonitor(Monitor monitor) {
synchronized (this) {
if (isAlive()) {
- throw new RuntimeException("Monitors can't be added while the Watchdog is running");
+ throw new RuntimeException("Monitors can't be added once the Watchdog is running");
}
- mMonitors.add(monitor);
+ mMonitorChecker.addMonitor(monitor);
+ }
+ }
+
+ public void addThread(Handler thread, String name) {
+ synchronized (this) {
+ if (isAlive()) {
+ throw new RuntimeException("Threads can't be added once the Watchdog is running");
+ }
+ mHandlerCheckers.add(new HandlerChecker(thread, name, false));
}
}
@@ -382,6 +428,30 @@ public class Watchdog extends Thread {
return newTime;
}
+ private boolean haveAllCheckersCompletedLocked() {
+ for (int i=0; i<mHandlerCheckers.size(); i++) {
+ HandlerChecker hc = mHandlerCheckers.get(i);
+ if (!hc.isCompletedLocked()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private String describeBlockedCheckersLocked() {
+ StringBuilder builder = new StringBuilder(128);
+ for (int i=0; i<mHandlerCheckers.size(); i++) {
+ HandlerChecker hc = mHandlerCheckers.get(i);
+ if (!hc.isCompletedLocked()) {
+ if (builder.length() > 0) {
+ builder.append(", ");
+ }
+ builder.append(hc.describeBlockedStateLocked());
+ }
+ }
+ return builder.toString();
+ }
+
@Override
public void run() {
boolean waitedHalf = false;
@@ -389,8 +459,14 @@ public class Watchdog extends Thread {
final String name;
synchronized (this) {
long timeout = TIME_TO_WAIT;
- mCompleted = false;
- mHandler.sendEmptyMessage(MONITOR);
+ if (!waitedHalf) {
+ // If we are not at the half-point of waiting, perform a
+ // new set of checks. Otherwise we are still waiting for a previous set.
+ for (int i=0; i<mHandlerCheckers.size(); i++) {
+ HandlerChecker hc = mHandlerCheckers.get(i);
+ hc.scheduleCheckLocked();
+ }
+ }
// NOTE: We use uptimeMillis() here because we do not want to increment the time we
// wait while asleep. If the device is asleep then the thing that we are waiting
@@ -406,7 +482,7 @@ public class Watchdog extends Thread {
timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start);
}
- if (mCompleted) {
+ if (haveAllCheckersCompletedLocked()) {
// The monitors have returned.
waitedHalf = false;
continue;
@@ -423,8 +499,7 @@ public class Watchdog extends Thread {
continue;
}
- name = (mCurrentMonitor != null) ?
- mCurrentMonitor.getClass().getName() : "main thread blocked";
+ name = describeBlockedCheckersLocked();
}
// If we got here, that means that the system is most likely hung.
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
index 2e8d6df..d1236c1 100644
--- a/services/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -56,7 +56,6 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -74,6 +73,7 @@ import android.util.SparseArray;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.FgThread;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
@@ -113,7 +113,6 @@ public class AccountManagerService
private final PackageManager mPackageManager;
private UserManager mUserManager;
- private HandlerThread mMessageThread;
private final MessageHandler mMessageHandler;
// Messages that can be sent on mHandler
@@ -234,9 +233,7 @@ public class AccountManagerService
mContext = context;
mPackageManager = packageManager;
- mMessageThread = new HandlerThread("AccountManagerService");
- mMessageThread.start();
- mMessageHandler = new MessageHandler(mMessageThread.getLooper());
+ mMessageHandler = new MessageHandler(FgThread.get().getLooper());
mAuthenticatorCache = authenticatorCache;
mAuthenticatorCache.setListener(this, null /* Handler */);
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 32f39b7..87263b3 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -37,13 +37,10 @@ import android.net.NetworkInfo;
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.os.Binder;
-import android.os.HandlerThread;
-import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
@@ -53,6 +50,7 @@ import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.IState;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import com.android.server.IoThread;
import com.google.android.collect.Lists;
import java.io.FileDescriptor;
@@ -100,7 +98,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
private final INetworkStatsService mStatsService;
private final IConnectivityManager mConnService;
private Looper mLooper;
- private HandlerThread mThread;
private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces
@@ -147,9 +144,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
mIfaces = new HashMap<String, TetherInterfaceSM>();
// make our own thread so we don't anr the system
- mThread = new HandlerThread("Tethering");
- mThread.start();
- mLooper = mThread.getLooper();
+ mLooper = IoThread.get().getLooper();
mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
mTetherMasterSM.start();
diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java
index 1c883ec..cf593ce 100644
--- a/services/java/com/android/server/content/SyncManager.java
+++ b/services/java/com/android/server/content/SyncManager.java
@@ -53,12 +53,10 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
-import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -74,6 +72,7 @@ import android.util.Pair;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.accounts.AccountManagerService;
import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
@@ -82,7 +81,6 @@ import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
import java.io.FileDescriptor;
-import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -381,10 +379,7 @@ public class SyncManager {
mSyncAdapters = new SyncAdaptersCache(mContext);
mSyncQueue = new SyncQueue(mContext.getPackageManager(), mSyncStorageEngine, mSyncAdapters);
- HandlerThread syncThread = new HandlerThread("SyncHandlerThread",
- Process.THREAD_PRIORITY_BACKGROUND);
- syncThread.start();
- mSyncHandler = new SyncHandler(syncThread.getLooper());
+ mSyncHandler = new SyncHandler(BackgroundThread.get().getLooper());
mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() {
@Override
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 17b0662..ca85e42 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -37,6 +37,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
+import com.android.server.UiThread;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -190,12 +191,12 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
- public DisplayManagerService(Context context, Handler mainHandler, Handler uiHandler) {
+ public DisplayManagerService(Context context, Handler mainHandler) {
mContext = context;
mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
mHandler = new DisplayManagerHandler(mainHandler.getLooper());
- mUiHandler = uiHandler;
+ mUiHandler = UiThread.getHandler();
mDisplayAdapterListener = new DisplayAdapterListener();
mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index a82f421..5ca7242 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -106,7 +106,6 @@ import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.INetworkManagementService;
import android.os.IPowerManager;
import android.os.Message;
@@ -134,6 +133,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Objects;
+import com.android.server.IoThread;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
@@ -274,7 +274,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
INetworkPolicyListener>();
- private final HandlerThread mHandlerThread;
private final Handler mHandler;
private final AtomicFile mPolicyFile;
@@ -306,9 +305,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
mTime = checkNotNull(time, "missing TrustedTime");
- mHandlerThread = new HandlerThread(TAG);
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
+ mHandler = new Handler(IoThread.get().getLooper(), mHandlerCallback);
mSuppressDefaultPolicy = suppressDefaultPolicy;
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 74be472..5074409 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -96,7 +96,6 @@ import android.os.Binder;
import android.os.DropBoxManager;
import android.os.Environment;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.PowerManager;
@@ -120,6 +119,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
+import com.android.server.IoThread;
import com.android.server.connectivity.Tethering;
import com.google.android.collect.Maps;
@@ -240,7 +240,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
/** Data layer operation counters for splicing into other structures. */
private NetworkStats mUidOperations = new NetworkStats(0L, 10);
- private final HandlerThread mHandlerThread;
private final Handler mHandler;
private boolean mSystemReady;
@@ -271,9 +270,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mHandlerThread = new HandlerThread(TAG);
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
+ mHandler = new Handler(IoThread.get().getLooper(), mHandlerCallback);
mSystemDir = checkNotNull(systemDir);
mBaseDir = new File(systemDir, "netstats");
diff --git a/services/java/com/android/server/usb/UsbDebuggingManager.java b/services/java/com/android/server/usb/UsbDebuggingManager.java
index 93d3114..ba3f1d1 100644
--- a/services/java/com/android/server/usb/UsbDebuggingManager.java
+++ b/services/java/com/android/server/usb/UsbDebuggingManager.java
@@ -22,15 +22,14 @@ import android.content.Intent;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Looper;
import android.os.Message;
-import android.os.Process;
import android.os.SystemClock;
import android.util.Slog;
import android.util.Base64;
+import com.android.server.FgThread;
import java.lang.Thread;
import java.io.File;
@@ -54,7 +53,6 @@ public class UsbDebuggingManager implements Runnable {
private final Context mContext;
private final Handler mHandler;
- private final HandlerThread mHandlerThread;
private Thread mThread;
private boolean mAdbEnabled = false;
private String mFingerprints;
@@ -62,9 +60,7 @@ public class UsbDebuggingManager implements Runnable {
private OutputStream mOutputStream = null;
public UsbDebuggingManager(Context context) {
- mHandlerThread = new HandlerThread("UsbDebuggingHandler");
- mHandlerThread.start();
- mHandler = new UsbDebuggingHandler(mHandlerThread.getLooper());
+ mHandler = new UsbDebuggingHandler(FgThread.get().getLooper());
mContext = context;
}
@@ -165,7 +161,7 @@ public class UsbDebuggingManager implements Runnable {
mAdbEnabled = true;
- mThread = new Thread(UsbDebuggingManager.this);
+ mThread = new Thread(UsbDebuggingManager.this, "UsbDebuggingManager");
mThread.start();
break;
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 87aa8cce..3a5357a 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -32,11 +32,9 @@ import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.FileUtils;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
-import android.os.Process;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UEventObserver;
@@ -48,6 +46,7 @@ import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.FgThread;
import java.io.File;
import java.io.FileDescriptor;
@@ -158,11 +157,7 @@ public class UsbDeviceManager {
readOemUsbOverrideConfig();
- // create a thread for our Handler
- HandlerThread thread = new HandlerThread("UsbDeviceManager",
- Process.THREAD_PRIORITY_BACKGROUND);
- thread.start();
- mHandler = new UsbHandler(thread.getLooper());
+ mHandler = new UsbHandler(FgThread.get().getLooper());
if (nativeIsStartRequested()) {
if (DEBUG) Slog.d(TAG, "accessory attached at boot");
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 6a2d3e2..24f8cf1 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -34,6 +34,7 @@ import com.android.internal.view.IInputMethodManager;
import com.android.internal.view.WindowManagerPolicyThread;
import com.android.server.AttributeCache;
import com.android.server.EventLogTags;
+import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.am.BatteryStatsService;
import com.android.server.display.DisplayManagerService;
@@ -701,8 +702,7 @@ public class WindowManagerService extends IWindowManager.Stub
public static WindowManagerService main(final Context context,
final PowerManagerService pm, final DisplayManagerService dm,
- final InputManagerService im,
- final Handler uiHandler, final Handler wmHandler,
+ final InputManagerService im, final Handler wmHandler,
final boolean haveInputMethods, final boolean showBootMsgs,
final boolean onlyCore) {
final WindowManagerService[] holder = new WindowManagerService[1];
@@ -710,7 +710,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void run() {
holder[0] = new WindowManagerService(context, pm, dm, im,
- uiHandler, haveInputMethods, showBootMsgs, onlyCore);
+ haveInputMethods, showBootMsgs, onlyCore);
}
}, 0);
return holder[0];
@@ -732,7 +732,6 @@ public class WindowManagerService extends IWindowManager.Stub
private WindowManagerService(Context context, PowerManagerService pm,
DisplayManagerService displayManager, InputManagerService inputManager,
- Handler uiHandler,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
mContext = context;
mHaveInputMethods = haveInputMethods;
@@ -795,7 +794,7 @@ public class WindowManagerService extends IWindowManager.Stub
mFxSession = new SurfaceSession();
mAnimator = new WindowAnimator(this);
- initPolicy(uiHandler);
+ initPolicy(UiThread.getHandler());
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);