summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java47
-rw-r--r--services/core/java/com/android/server/AssetAtlasService.java2
-rw-r--r--services/core/java/com/android/server/MidiService.java309
-rwxr-xr-xservices/core/java/com/android/server/am/ActiveServices.java145
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerDebugConfig.java84
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java248
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java43
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java110
-rw-r--r--services/core/java/com/android/server/am/DumpHeapProvider.java89
-rw-r--r--services/core/java/com/android/server/am/LockTaskNotify.java22
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java6
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java245
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java1
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java12
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java18
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java4
-rw-r--r--services/core/java/com/android/server/pm/KeySetManagerService.java24
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java2
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java55
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java13
-rw-r--r--services/core/java/com/android/server/trust/TrustAgentWrapper.java1
-rw-r--r--services/core/java/com/android/server/tv/TvInputHardwareManager.java15
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java67
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java47
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java199
-rw-r--r--services/java/com/android/server/SystemServer.java3
-rw-r--r--services/usb/java/com/android/server/usb/UsbMidiDevice.java76
27 files changed, 1324 insertions, 563 deletions
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 94d400a..26510328 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -601,7 +601,7 @@ public class BackupManagerService {
return token;
}
- // High level policy: apps are ineligible for backup if certain conditions apply
+ // High level policy: apps are generally ineligible for backup if certain conditions apply
public static boolean appIsEligibleForBackup(ApplicationInfo app) {
// 1. their manifest states android:allowBackup="false"
if ((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
@@ -628,7 +628,7 @@ public class BackupManagerService {
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0;
}
- // No agent means we do full backups for it
+ // No agent or fullBackupOnly="true" means we do indeed perform full-data backups for it
return true;
}
@@ -1266,7 +1266,23 @@ public class BackupManagerService {
for (int i = 0; i < N; i++) {
String pkgName = in.readUTF();
long lastBackup = in.readLong();
- schedule.add(new FullBackupEntry(pkgName, lastBackup));
+ try {
+ PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0);
+ if (appGetsFullBackup(pkg)
+ && appIsEligibleForBackup(pkg.applicationInfo)) {
+ schedule.add(new FullBackupEntry(pkgName, lastBackup));
+ } else {
+ if (DEBUG) {
+ Slog.i(TAG, "Package " + pkgName
+ + " no longer eligible for full backup");
+ }
+ }
+ } catch (NameNotFoundException e) {
+ if (DEBUG) {
+ Slog.i(TAG, "Package " + pkgName
+ + " not installed; dropping from full backup");
+ }
+ }
}
Collections.sort(schedule);
} catch (Exception e) {
@@ -1289,7 +1305,7 @@ public class BackupManagerService {
schedule = new ArrayList<FullBackupEntry>(N);
for (int i = 0; i < N; i++) {
PackageInfo info = apps.get(i);
- if (appGetsFullBackup(info)) {
+ if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) {
schedule.add(new FullBackupEntry(info.packageName, 0));
}
}
@@ -1761,11 +1777,11 @@ public class BackupManagerService {
addPackageParticipantsLocked(pkgList);
}
// If they're full-backup candidates, add them there instead
+ final long now = System.currentTimeMillis();
for (String packageName : pkgList) {
try {
PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
- long now = System.currentTimeMillis();
- if (appGetsFullBackup(app)) {
+ if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
enqueueFullBackup(packageName, now);
scheduleNextFullBackupJob();
}
@@ -2462,7 +2478,7 @@ public class BackupManagerService {
BackupRequest request = mQueue.get(0);
mQueue.remove(0);
- Slog.d(TAG, "starting agent for backup of " + request);
+ Slog.d(TAG, "starting key/value backup of " + request);
addBackupTrace("launch agent for " + request.packageName);
// Verify that the requested app exists; it might be something that
@@ -2473,13 +2489,24 @@ public class BackupManagerService {
try {
mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
PackageManager.GET_SIGNATURES);
- if (mCurrentPackage.applicationInfo.backupAgentName == null) {
+ if (!appIsEligibleForBackup(mCurrentPackage.applicationInfo)) {
// The manifest has changed but we had a stale backup request pending.
// This won't happen again because the app won't be requesting further
// backups.
Slog.i(TAG, "Package " + request.packageName
+ " no longer supports backup; skipping");
- addBackupTrace("skipping - no agent, completion is noop");
+ addBackupTrace("skipping - not eligible, completion is noop");
+ executeNextState(BackupState.RUNNING_QUEUE);
+ return;
+ }
+
+ if (appGetsFullBackup(mCurrentPackage)) {
+ // It's possible that this app *formerly* was enqueued for key/value backup,
+ // but has since been updated and now only supports the full-data path.
+ // Don't proceed with a key/value backup for it in this case.
+ Slog.i(TAG, "Package " + request.packageName
+ + " requests full-data rather than key/value; skipping");
+ addBackupTrace("skipping - fullBackupOnly, completion is noop");
executeNextState(BackupState.RUNNING_QUEUE);
return;
}
@@ -9161,6 +9188,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
// check whether there is data for it in the current dataset, falling back
// to the ancestral dataset if not.
long token = getAvailableRestoreToken(packageName);
+ if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName
+ + " token=" + Long.toHexString(token));
// If we didn't come up with a place to look -- no ancestral dataset and
// the app has never been backed up from this device -- there's nothing
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index a2c87b9..e6dc1c7 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -291,7 +291,7 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
}
canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
canvas.restore();
- atlasMap[mapIndex++] = bitmap.mNativeBitmap;
+ atlasMap[mapIndex++] = bitmap.getSkBitmap();
atlasMap[mapIndex++] = entry.x;
atlasMap[mapIndex++] = entry.y;
atlasMap[mapIndex++] = entry.rotated ? 1 : 0;
diff --git a/services/core/java/com/android/server/MidiService.java b/services/core/java/com/android/server/MidiService.java
index 59b82da..7f98b30 100644
--- a/services/core/java/com/android/server/MidiService.java
+++ b/services/core/java/com/android/server/MidiService.java
@@ -17,10 +17,18 @@
package com.android.server;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.XmlResourceParser;
+import android.media.midi.IMidiDeviceListener;
import android.media.midi.IMidiDeviceServer;
-import android.media.midi.IMidiListener;
import android.media.midi.IMidiManager;
import android.media.midi.MidiDeviceInfo;
+import android.media.midi.MidiDeviceService;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -28,12 +36,17 @@ import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.content.PackageMonitor;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
public class MidiService extends IMidiManager.Stub {
private static final String TAG = "MidiService";
@@ -53,6 +66,27 @@ public class MidiService extends IMidiManager.Stub {
// used for assigning IDs to MIDI devices
private int mNextDeviceId = 1;
+ private final PackageManager mPackageManager;
+
+ // PackageMonitor for listening to package changes
+ private final PackageMonitor mPackageMonitor = new PackageMonitor() {
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ addPackageDeviceServers(packageName);
+ }
+
+ @Override
+ public void onPackageModified(String packageName) {
+ removePackageDeviceServers(packageName);
+ addPackageDeviceServers(packageName);
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ removePackageDeviceServers(packageName);
+ }
+ };
+
private final class Client implements IBinder.DeathRecipient {
// Binder token for this client
private final IBinder mToken;
@@ -61,7 +95,8 @@ public class MidiService extends IMidiManager.Stub {
// This client's PID
private final int mPid;
// List of all receivers for this client
- private final ArrayList<IMidiListener> mListeners = new ArrayList<IMidiListener>();
+ private final ArrayList<IMidiDeviceListener> mListeners
+ = new ArrayList<IMidiDeviceListener>();
public Client(IBinder token) {
mToken = token;
@@ -73,11 +108,11 @@ public class MidiService extends IMidiManager.Stub {
return mUid;
}
- public void addListener(IMidiListener listener) {
+ public void addListener(IMidiDeviceListener listener) {
mListeners.add(listener);
}
- public void removeListener(IMidiListener listener) {
+ public void removeListener(IMidiDeviceListener listener) {
mListeners.remove(listener);
if (mListeners.size() == 0) {
removeClient(mToken);
@@ -90,7 +125,7 @@ public class MidiService extends IMidiManager.Stub {
MidiDeviceInfo deviceInfo = device.getDeviceInfo();
try {
- for (IMidiListener listener : mListeners) {
+ for (IMidiDeviceListener listener : mListeners) {
listener.onDeviceAdded(deviceInfo);
}
} catch (RemoteException e) {
@@ -104,7 +139,7 @@ public class MidiService extends IMidiManager.Stub {
MidiDeviceInfo deviceInfo = device.getDeviceInfo();
try {
- for (IMidiListener listener : mListeners) {
+ for (IMidiDeviceListener listener : mListeners) {
listener.onDeviceRemoved(deviceInfo);
}
} catch (RemoteException e) {
@@ -152,16 +187,17 @@ public class MidiService extends IMidiManager.Stub {
private final class Device implements IBinder.DeathRecipient {
private final IMidiDeviceServer mServer;
private final MidiDeviceInfo mDeviceInfo;
- // UID of device creator
+ // ServiceInfo for the device's MidiDeviceServer implementation (virtual devices only)
+ private final ServiceInfo mServiceInfo;
+ // UID of device implementation
private final int mUid;
- // PID of device creator
- private final int mPid;
- public Device(IMidiDeviceServer server, MidiDeviceInfo deviceInfo) {
+ public Device(IMidiDeviceServer server, MidiDeviceInfo deviceInfo,
+ ServiceInfo serviceInfo, int uid) {
mServer = server;
mDeviceInfo = deviceInfo;
- mUid = Binder.getCallingUid();
- mPid = Binder.getCallingPid();
+ mServiceInfo = serviceInfo;
+ mUid = uid;
}
public MidiDeviceInfo getDeviceInfo() {
@@ -172,13 +208,20 @@ public class MidiService extends IMidiManager.Stub {
return mServer;
}
+ public ServiceInfo getServiceInfo() {
+ return mServiceInfo;
+ }
+
+ public String getPackageName() {
+ return (mServiceInfo == null ? null : mServiceInfo.packageName);
+ }
+
public boolean isUidAllowed(int uid) {
- // FIXME
- return true;
+ return (!mDeviceInfo.isPrivate() || mUid == uid);
}
public void binderDied() {
- synchronized (mDevicesByServer) {
+ synchronized (mDevicesByInfo) {
removeDeviceLocked(this);
}
}
@@ -189,32 +232,59 @@ public class MidiService extends IMidiManager.Stub {
sb.append(mDeviceInfo);
sb.append(" UID: ");
sb.append(mUid);
- sb.append(" PID: ");
- sb.append(mPid);
return sb.toString();
}
}
public MidiService(Context context) {
mContext = context;
- }
+ mPackageManager = context.getPackageManager();
+ mPackageMonitor.register(context, null, true);
+
+ Intent intent = new Intent(MidiDeviceService.SERVICE_INTERFACE);
+ List<ResolveInfo> resolveInfos = mPackageManager.queryIntentServices(intent,
+ PackageManager.GET_META_DATA);
+ if (resolveInfos != null) {
+ int count = resolveInfos.size();
+ for (int i = 0; i < count; i++) {
+ ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
+ if (serviceInfo != null) {
+ addPackageDeviceServer(serviceInfo);
+ }
+ }
+ }
+ }
- public void registerListener(IBinder token, IMidiListener listener) {
+ @Override
+ public void registerListener(IBinder token, IMidiDeviceListener listener) {
Client client = getClient(token);
if (client == null) return;
client.addListener(listener);
}
- public void unregisterListener(IBinder token, IMidiListener listener) {
+ @Override
+ public void unregisterListener(IBinder token, IMidiDeviceListener listener) {
Client client = getClient(token);
if (client == null) return;
client.removeListener(listener);
}
public MidiDeviceInfo[] getDeviceList() {
- return mDevicesByInfo.keySet().toArray(new MidiDeviceInfo[0]);
+ ArrayList<MidiDeviceInfo> deviceInfos = new ArrayList<MidiDeviceInfo>();
+ int uid = Binder.getCallingUid();
+
+ synchronized (mDevicesByInfo) {
+ for (Device device : mDevicesByInfo.values()) {
+ if (device.isUidAllowed(uid)) {
+ deviceInfos.add(device.getDeviceInfo());
+ }
+ }
+ }
+
+ return deviceInfos.toArray(new MidiDeviceInfo[0]);
}
+ @Override
public IMidiDeviceServer openDevice(IBinder token, MidiDeviceInfo deviceInfo) {
Device device = mDevicesByInfo.get(deviceInfo);
if (device == null) {
@@ -229,28 +299,64 @@ public class MidiService extends IMidiManager.Stub {
return device.getDeviceServer();
}
+ @Override
public MidiDeviceInfo registerDeviceServer(IMidiDeviceServer server, int numInputPorts,
- int numOutputPorts, Bundle properties, boolean isPrivate, int type) {
+ int numOutputPorts, Bundle properties, int type) {
if (type != MidiDeviceInfo.TYPE_VIRTUAL && Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("only system can create non-virtual devices");
}
- MidiDeviceInfo deviceInfo;
- Device device;
+ synchronized (mDevicesByInfo) {
+ return addDeviceLocked(type, numInputPorts, numOutputPorts, properties,
+ server, null, false, -1);
+ }
+ }
- synchronized (mDevicesByServer) {
- int id = mNextDeviceId++;
- deviceInfo = new MidiDeviceInfo(type, id, numInputPorts, numOutputPorts, properties);
+ @Override
+ public void unregisterDeviceServer(IMidiDeviceServer server) {
+ synchronized (mDevicesByInfo) {
+ Device device = mDevicesByServer.get(server.asBinder());
+ if (device != null) {
+ removeDeviceLocked(device);
+ }
+ }
+ }
+
+ @Override
+ public MidiDeviceInfo getServiceDeviceInfo(String packageName, String className) {
+ synchronized (mDevicesByInfo) {
+ for (Device device : mDevicesByInfo.values()) {
+ ServiceInfo serviceInfo = device.getServiceInfo();
+ if (serviceInfo != null &&
+ packageName.equals(serviceInfo.packageName) &&
+ className.equals(serviceInfo.name)) {
+ return device.getDeviceInfo();
+ }
+ }
+ return null;
+ }
+ }
+
+ // synchronize on mDevicesByInfo
+ private MidiDeviceInfo addDeviceLocked(int type, int numInputPorts, int numOutputPorts,
+ Bundle properties, IMidiDeviceServer server, ServiceInfo serviceInfo,
+ boolean isPrivate, int uid) {
+
+ int id = mNextDeviceId++;
+ MidiDeviceInfo deviceInfo = new MidiDeviceInfo(type, id, numInputPorts, numOutputPorts,
+ properties, isPrivate);
+ Device device = new Device(server, deviceInfo, serviceInfo, uid);
+
+ if (server != null) {
IBinder binder = server.asBinder();
- device = new Device(server, deviceInfo);
try {
binder.linkToDeath(device, 0);
} catch (RemoteException e) {
return null;
}
- mDevicesByInfo.put(deviceInfo, device);
- mDevicesByServer.put(server.asBinder(), device);
+ mDevicesByServer.put(binder, device);
}
+ mDevicesByInfo.put(deviceInfo, device);
synchronized (mClients) {
for (Client c : mClients.values()) {
@@ -261,16 +367,13 @@ public class MidiService extends IMidiManager.Stub {
return deviceInfo;
}
- public void unregisterDeviceServer(IMidiDeviceServer server) {
- synchronized (mDevicesByServer) {
- removeDeviceLocked(mDevicesByServer.get(server.asBinder()));
- }
- }
-
- // synchronize on mDevicesByServer
+ // synchronize on mDevicesByInfo
private void removeDeviceLocked(Device device) {
- if (mDevicesByServer.remove(device.getDeviceServer().asBinder()) != null) {
- mDevicesByInfo.remove(device.getDeviceInfo());
+ if (mDevicesByInfo.remove(device.getDeviceInfo()) != null) {
+ IMidiDeviceServer server = device.getDeviceServer();
+ if (server != null) {
+ mDevicesByServer.remove(server);
+ }
synchronized (mClients) {
for (Client c : mClients.values()) {
@@ -280,6 +383,134 @@ public class MidiService extends IMidiManager.Stub {
}
}
+ private void addPackageDeviceServers(String packageName) {
+ PackageInfo info;
+
+ try {
+ info = mPackageManager.getPackageInfo(packageName,
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
+ return;
+ }
+
+ ServiceInfo[] services = info.services;
+ if (services == null) return;
+ for (int i = 0; i < services.length; i++) {
+ addPackageDeviceServer(services[i]);
+ }
+ }
+
+ private void addPackageDeviceServer(ServiceInfo serviceInfo) {
+ XmlResourceParser parser = null;
+
+ try {
+ parser = serviceInfo.loadXmlMetaData(mPackageManager,
+ MidiDeviceService.SERVICE_INTERFACE);
+ if (parser == null) return;
+
+ Bundle properties = null;
+ int numInputPorts = 0;
+ int numOutputPorts = 0;
+ boolean isPrivate = false;
+
+ while (true) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.END_DOCUMENT) {
+ break;
+ } else if (eventType == XmlPullParser.START_TAG) {
+ String tagName = parser.getName();
+ if ("device".equals(tagName)) {
+ if (properties != null) {
+ Log.w(TAG, "nested <device> elements in metadata for "
+ + serviceInfo.packageName);
+ continue;
+ }
+ properties = new Bundle();
+ properties.putParcelable(MidiDeviceInfo.PROPERTY_SERVICE_INFO, serviceInfo);
+ numInputPorts = 0;
+ numOutputPorts = 0;
+ isPrivate = false;
+
+ int count = parser.getAttributeCount();
+ for (int i = 0; i < count; i++) {
+ String name = parser.getAttributeName(i);
+ String value = parser.getAttributeValue(i);
+ if ("private".equals(name)) {
+ isPrivate = "true".equals(value);
+ } else {
+ properties.putString(name, value);
+ }
+ }
+ } else if ("input-port".equals(tagName)) {
+ if (properties == null) {
+ Log.w(TAG, "<input-port> outside of <device> in metadata for "
+ + serviceInfo.packageName);
+ continue;
+ }
+ numInputPorts++;
+ // TODO - add support for port properties
+ } else if ("output-port".equals(tagName)) {
+ if (properties == null) {
+ Log.w(TAG, "<output-port> outside of <device> in metadata for "
+ + serviceInfo.packageName);
+ continue;
+ }
+ numOutputPorts++;
+ // TODO - add support for port properties
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ String tagName = parser.getName();
+ if ("device".equals(tagName)) {
+ if (properties != null) {
+ if (numInputPorts == 0 && numOutputPorts == 0) {
+ Log.w(TAG, "<device> with no ports in metadata for "
+ + serviceInfo.packageName);
+ continue;
+ }
+
+ int uid = -1;
+ if (isPrivate) {
+ try {
+ ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
+ serviceInfo.packageName, 0);
+ uid = appInfo.uid;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "could not fetch ApplicationInfo for "
+ + serviceInfo.packageName);
+ continue;
+ }
+ }
+
+ synchronized (mDevicesByInfo) {
+ addDeviceLocked(MidiDeviceInfo.TYPE_VIRTUAL,
+ numInputPorts, numOutputPorts, properties,
+ null, serviceInfo, isPrivate, uid);
+ }
+ // setting properties to null signals that we are no longer
+ // processing a <device>
+ properties = null;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Unable to load component info " + serviceInfo.toString(), e);
+ } finally {
+ if (parser != null) parser.close();
+ }
+ }
+
+ private void removePackageDeviceServers(String packageName) {
+ synchronized (mDevicesByInfo) {
+ for (Device device : mDevicesByInfo.values()) {
+ if (packageName.equals(device.getPackageName())) {
+ removeDeviceLocked(device);
+ }
+ }
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 059dde1..fc95b00 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
@@ -33,6 +35,7 @@ import android.os.Looper;
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.ArraySet;
+
import com.android.internal.app.ProcessStats;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.TransferPipe;
@@ -67,14 +70,15 @@ import android.util.SparseArray;
import android.util.TimeUtils;
public final class ActiveServices {
- static final boolean DEBUG_SERVICE = ActivityManagerService.DEBUG_SERVICE;
- static final boolean DEBUG_SERVICE_EXECUTING = ActivityManagerService.DEBUG_SERVICE_EXECUTING;
- static final boolean DEBUG_DELAYED_SERVICE = ActivityManagerService.DEBUG_SERVICE;
- static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE;
- static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
- static final boolean LOG_SERVICE_START_STOP = false;
- static final String TAG = ActivityManagerService.TAG;
- static final String TAG_MU = ActivityManagerService.TAG_MU;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ActiveServices" : TAG_AM;
+ private static final String TAG_MU = TAG + POSTFIX_MU;
+ private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
+ private static final String TAG_SERVICE_EXECUTING = TAG + POSTFIX_SERVICE_EXECUTING;
+
+ private static final boolean DEBUG_DELAYED_SERVICE = DEBUG_SERVICE;
+ private static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE;
+
+ private static final boolean LOG_SERVICE_START_STOP = false;
// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;
@@ -206,11 +210,12 @@ public final class ActiveServices {
void ensureNotStartingBackground(ServiceRecord r) {
if (mStartingBackground.remove(r)) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer background starting: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+ "No longer background starting: " + r);
rescheduleDelayedStarts();
}
if (mDelayedStartList.remove(r)) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer delaying start: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "No longer delaying start: " + r);
}
}
@@ -229,16 +234,17 @@ public final class ActiveServices {
while (mDelayedStartList.size() > 0
&& mStartingBackground.size() < mMaxStartingBackground) {
ServiceRecord r = mDelayedStartList.remove(0);
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (exec next): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+ "REM FR DELAY LIST (exec next): " + r);
if (r.pendingStarts.size() <= 0) {
Slog.w(TAG, "**** NO PENDING STARTS! " + r + " startReq=" + r.startRequested
+ " delayedStop=" + r.delayedStop);
}
if (DEBUG_DELAYED_SERVICE) {
if (mDelayedStartList.size() > 0) {
- Slog.v(TAG, "Remaining delayed list:");
+ Slog.v(TAG_SERVICE, "Remaining delayed list:");
for (int i=0; i<mDelayedStartList.size(); i++) {
- Slog.v(TAG, " #" + i + ": " + mDelayedStartList.get(i));
+ Slog.v(TAG_SERVICE, " #" + i + ": " + mDelayedStartList.get(i));
}
}
}
@@ -248,7 +254,7 @@ public final class ActiveServices {
if (mStartingBackground.size() > 0) {
ServiceRecord next = mStartingBackground.get(0);
long when = next.startingBgTimeout > now ? next.startingBgTimeout : now;
- if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Top bg start is " + next
+ if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Top bg start is " + next
+ ", can delay others up to " + when);
Message msg = obtainMessage(MSG_BG_START_TIMEOUT);
sendMessageAtTime(msg, when);
@@ -298,7 +304,7 @@ public final class ActiveServices {
ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType,
int callingPid, int callingUid, int userId) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "startService: " + service
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
final boolean callerFg;
@@ -337,7 +343,7 @@ public final class ActiveServices {
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
if (unscheduleServiceRestartLocked(r, callingUid, false)) {
- if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
}
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
@@ -360,29 +366,30 @@ public final class ActiveServices {
// service is started. This is especially the case for receivers, which
// may start a service in onReceive() to do some additional work and have
// initialized some global state as part of that.
- if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Potential start delay of " + r + " in "
- + proc);
+ if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Potential start delay of "
+ + r + " in " + proc);
if (r.delayed) {
// This service is already scheduled for a delayed start; just leave
// it still waiting.
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Continuing to delay: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
return r.name;
}
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
// Something else is starting, delay!
- Slog.i(TAG, "Delaying start of: " + r);
+ Slog.i(TAG_SERVICE, "Delaying start of: " + r);
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r);
addToStarting = true;
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
// We slightly loosen when we will enqueue this new service as a background
// starting service we are waiting for, to also include processes that are
// currently running other services or receivers.
addToStarting = true;
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+ "Not delaying, but counting as bg: " + r);
} else if (DEBUG_DELAYED_STARTS) {
StringBuilder sb = new StringBuilder(128);
sb.append("Not potential delay (state=").append(proc.curProcState)
@@ -394,16 +401,17 @@ public final class ActiveServices {
}
sb.append("): ");
sb.append(r.toString());
- Slog.v(TAG, sb.toString());
+ Slog.v(TAG_SERVICE, sb.toString());
}
} else if (DEBUG_DELAYED_STARTS) {
if (callerFg) {
- Slog.v(TAG, "Not potential delay (callerFg=" + callerFg + " uid="
+ Slog.v(TAG_SERVICE, "Not potential delay (callerFg=" + callerFg + " uid="
+ callingUid + " pid=" + callingPid + "): " + r);
} else if (r.app != null) {
- Slog.v(TAG, "Not potential delay (cur app=" + r.app + "): " + r);
+ Slog.v(TAG_SERVICE, "Not potential delay (cur app=" + r.app + "): " + r);
} else {
- Slog.v(TAG, "Not potential delay (user " + r.userId + " not started): " + r);
+ Slog.v(TAG_SERVICE,
+ "Not potential delay (user " + r.userId + " not started): " + r);
}
}
@@ -432,9 +440,9 @@ public final class ActiveServices {
if (DEBUG_DELAYED_SERVICE) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
- Slog.v(TAG, "Starting background (first=" + first + "): " + r, here);
+ Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r, here);
} else if (DEBUG_DELAYED_STARTS) {
- Slog.v(TAG, "Starting background (first=" + first + "): " + r);
+ Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r);
}
if (first) {
smap.rescheduleDelayedStarts();
@@ -451,7 +459,7 @@ public final class ActiveServices {
// If service isn't actually running, but is is being held in the
// delayed list, then we need to keep it started but note that it
// should be stopped once no longer delayed.
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Delaying stop of pending: " + service);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Delaying stop of pending: " + service);
service.delayedStop = true;
return;
}
@@ -469,7 +477,7 @@ public final class ActiveServices {
int stopServiceLocked(IApplicationThread caller, Intent service,
String resolvedType, int userId) {
- if (DEBUG_SERVICE) Slog.v(TAG, "stopService: " + service
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopService: " + service
+ " type=" + resolvedType);
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
@@ -525,7 +533,7 @@ public final class ActiveServices {
boolean stopServiceTokenLocked(ComponentName className, IBinder token,
int startId) {
- if (DEBUG_SERVICE) Slog.v(TAG, "stopServiceToken: " + className
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopServiceToken: " + className
+ " " + token + " startId=" + startId);
ServiceRecord r = findServiceLocked(className, token, UserHandle.getCallingUserId());
if (r != null) {
@@ -687,7 +695,7 @@ public final class ActiveServices {
int bindServiceLocked(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags, int userId) {
- if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
+ " flags=0x" + Integer.toHexString(flags));
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
@@ -751,7 +759,7 @@ public final class ActiveServices {
try {
if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
- if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "BIND SERVICE WHILE RESTART PENDING: "
+ s);
}
@@ -819,7 +827,7 @@ public final class ActiveServices {
mAm.updateOomAdjLocked(s.app);
}
- if (DEBUG_SERVICE) Slog.v(TAG, "Bind " + s + " with " + b
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b
+ ": received=" + b.intent.received
+ " apps=" + b.intent.apps.size()
+ " doRebind=" + b.intent.doRebind);
@@ -857,7 +865,7 @@ public final class ActiveServices {
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
- if (DEBUG_SERVICE) Slog.v(TAG, "PUBLISHING " + r
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
+ " " + intent + ": " + service);
if (r != null) {
Intent.FilterComparison filter
@@ -873,14 +881,14 @@ public final class ActiveServices {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
if (DEBUG_SERVICE) Slog.v(
- TAG, "Not publishing to: " + c);
+ TAG_SERVICE, "Not publishing to: " + c);
if (DEBUG_SERVICE) Slog.v(
- TAG, "Bound intent: " + c.binding.intent.intent);
+ TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
if (DEBUG_SERVICE) Slog.v(
- TAG, "Published intent: " + intent);
+ TAG_SERVICE, "Published intent: " + intent);
continue;
}
- if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
try {
c.conn.connected(r.name, service);
} catch (Exception e) {
@@ -901,7 +909,7 @@ public final class ActiveServices {
boolean unbindServiceLocked(IServiceConnection connection) {
IBinder binder = connection.asBinder();
- if (DEBUG_SERVICE) Slog.v(TAG, "unbindService: conn=" + binder);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindService: conn=" + binder);
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null) {
Slog.w(TAG, "Unbind failed: could not find connection for "
@@ -945,7 +953,7 @@ public final class ActiveServices {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
- if (DEBUG_SERVICE) Slog.v(TAG, "unbindFinished in " + r
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindFinished in " + r
+ " at " + b + ": apps="
+ (b != null ? b.apps.size() : 0));
@@ -1012,7 +1020,7 @@ public final class ActiveServices {
String resolvedType, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg) {
ServiceRecord r = null;
- if (DEBUG_SERVICE) Slog.v(TAG, "retrieveServiceLocked: " + service
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
+ " type=" + resolvedType + " callingUid=" + callingUid);
userId = mAm.handleIncomingUser(callingPid, callingUid, userId,
@@ -1036,7 +1044,7 @@ public final class ActiveServices {
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
if (sInfo == null) {
- Slog.w(TAG, "Unable to start service " + service + " U=" + userId +
+ Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
": not found");
return null;
}
@@ -1110,9 +1118,9 @@ public final class ActiveServices {
}
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
- if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING "
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING "
+ why + " of " + r + " in app " + r.app);
- else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, ">>> EXECUTING "
+ else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING "
+ why + " of " + r.shortName);
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) {
@@ -1155,7 +1163,7 @@ public final class ActiveServices {
i.hasBound = true;
i.doRebind = false;
} catch (RemoteException e) {
- if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
return false;
}
}
@@ -1336,7 +1344,7 @@ public final class ActiveServices {
return null;
}
- if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent);
// We are now bringing the service up, so no longer in the
// restarting state.
@@ -1347,7 +1355,7 @@ public final class ActiveServices {
// Make sure this service is no longer considered delayed, we are starting it now.
if (r.delayed) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (bring up): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
@@ -1430,7 +1438,8 @@ public final class ActiveServices {
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+ "Applying delayed stop (in bring up): " + r);
stopServiceLocked(r);
}
}
@@ -1509,7 +1518,7 @@ public final class ActiveServices {
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
@@ -1518,7 +1527,8 @@ public final class ActiveServices {
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (from start): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+ "Applying delayed stop (from start): " + r);
stopServiceLocked(r);
}
}
@@ -1534,7 +1544,7 @@ public final class ActiveServices {
while (r.pendingStarts.size() > 0) {
try {
ServiceRecord.StartItem si = r.pendingStarts.remove(0);
- if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to: "
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Sending arguments to: "
+ r + " " + r.intent + " args=" + si.intent);
if (si.intent == null && N > 1) {
// If somehow we got a dummy null intent in the middle,
@@ -1566,7 +1576,7 @@ public final class ActiveServices {
} catch (RemoteException e) {
// Remote process gone... we'll let the normal cleanup take
// care of this.
- if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while scheduling start: " + r);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while scheduling start: " + r);
break;
} catch (Exception e) {
Slog.w(TAG, "Unexpected exception", e);
@@ -1636,7 +1646,7 @@ public final class ActiveServices {
if (r.app != null && r.app.thread != null) {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
- if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down binding " + ibr
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down binding " + ibr
+ ": hasBound=" + ibr.hasBound);
if (ibr.hasBound) {
try {
@@ -1654,7 +1664,7 @@ public final class ActiveServices {
}
}
- if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down " + r + " " + r.intent);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down " + r + " " + r.intent);
r.destroyTime = SystemClock.uptimeMillis();
if (LOG_SERVICE_START_STOP) {
EventLogTags.writeAmDestroyService(
@@ -1671,7 +1681,7 @@ public final class ActiveServices {
for (int i=mPendingServices.size()-1; i>=0; i--) {
if (mPendingServices.get(i) == r) {
mPendingServices.remove(i);
- if (DEBUG_SERVICE) Slog.v(TAG, "Removed pending: " + r);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Removed pending: " + r);
}
}
@@ -1704,11 +1714,11 @@ public final class ActiveServices {
}
} else {
if (DEBUG_SERVICE) Slog.v(
- TAG, "Removed service that has no process: " + r);
+ TAG_SERVICE, "Removed service that has no process: " + r);
}
} else {
if (DEBUG_SERVICE) Slog.v(
- TAG, "Removed service that is not running: " + r);
+ TAG_SERVICE, "Removed service that is not running: " + r);
}
if (r.bindings.size() > 0) {
@@ -1775,7 +1785,7 @@ public final class ActiveServices {
}
if (!c.serviceDead) {
- if (DEBUG_SERVICE) Slog.v(TAG, "Disconnecting binding " + b.intent
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Disconnecting binding " + b.intent
+ ": shouldUnbind=" + b.intent.hasBound);
if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
&& b.intent.hasBound) {
@@ -1902,19 +1912,20 @@ public final class ActiveServices {
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
- if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "<<< DONE EXECUTING " + r
+ ": nesting=" + r.executeNesting
+ ", inDestroying=" + inDestroying + ", app=" + r.app);
- else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, "<<< DONE EXECUTING " + r.shortName);
+ else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
+ "<<< DONE EXECUTING " + r.shortName);
r.executeNesting--;
if (r.executeNesting <= 0) {
if (r.app != null) {
- if (DEBUG_SERVICE) Slog.v(TAG,
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"Nesting at 0 of " + r.shortName);
r.app.execServicesFg = false;
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
- if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG,
+ if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
"No more executingServices of " + r.shortName);
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
} else if (r.executeFg) {
@@ -1927,7 +1938,7 @@ public final class ActiveServices {
}
}
if (inDestroying) {
- if (DEBUG_SERVICE) Slog.v(TAG,
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"doneExecuting remove destroying " + r);
mDestroyingServices.remove(r);
r.bindings.clear();
@@ -2141,13 +2152,13 @@ public final class ActiveServices {
sr.executeNesting = 0;
sr.forceClearTracker();
if (mDestroyingServices.remove(sr)) {
- if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
}
final int numClients = sr.bindings.size();
for (int bindingi=numClients-1; bindingi>=0; bindingi--) {
IntentBindRecord b = sr.bindings.valueAt(bindingi);
- if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Killing binding " + b
+ ": shouldUnbind=" + b.hasBound);
b.binder = null;
b.requested = b.received = b.hasBound = false;
@@ -2281,7 +2292,7 @@ public final class ActiveServices {
if (sr.app == app) {
sr.forceClearTracker();
mDestroyingServices.remove(i);
- if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
new file mode 100644
index 0000000..03f253b
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014 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.am;
+
+/**
+ * Common class for the various debug {@link android.util.Log} output configuration in the activity
+ * manager package.
+ */
+class ActivityManagerDebugConfig {
+
+ // All output logs in the activity manager package use the {@link #TAG_AM} string for tagging
+ // their log output. This makes it easy to identify the origin of the log message when sifting
+ // through a large amount of log output from multiple sources. However, it also makes trying
+ // to figure-out the origin of a log message while debugging the activity manager a little
+ // painful. By setting this constant to true, log messages from the activity manager package
+ // will be tagged with their class names instead fot the generic tag.
+ static final boolean TAG_WITH_CLASS_NAME = false;
+
+ // While debugging it is sometimes useful to have the category name of the log prepended to the
+ // base log tag to make sifting through logs with the same base tag easier. By setting this
+ // constant to true, the category name of the log point will be prepended to the log tag.
+ static final boolean PREPEND_CATEGORY_NAME = false;
+
+ // Default log tag for the activity manager package.
+ static final String TAG_AM = "ActivityManager";
+
+ // Enable all debug log categories.
+ static final boolean DEBUG_ALL = false;
+
+ // Available log categories in the activity manager package.
+ static final boolean DEBUG_BACKUP = DEBUG_ALL || false;
+ static final boolean DEBUG_BROADCAST = DEBUG_ALL || false;
+ static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || false;
+ static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
+ static final boolean DEBUG_CLEANUP = DEBUG_ALL || false;
+ static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false;
+ static final boolean DEBUG_FOCUS = false;
+ static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
+ static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false;
+ static final boolean DEBUG_LRU = DEBUG_ALL || false;
+ static final boolean DEBUG_MU = DEBUG_ALL || false;
+ static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
+ static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
+ static final boolean DEBUG_POWER = DEBUG_ALL || false;
+ static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
+ static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
+ static final boolean DEBUG_PROCESSES = DEBUG_ALL || false;
+ static final boolean DEBUG_PROVIDER = DEBUG_ALL || false;
+ static final boolean DEBUG_PSS = DEBUG_ALL || false;
+ static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
+ static final boolean DEBUG_RESULTS = DEBUG_ALL || false;
+ static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
+ static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
+ static final boolean DEBUG_STACK = DEBUG_ALL || false;
+ static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
+ static final boolean DEBUG_TASKS = DEBUG_ALL || false;
+ static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false;
+ static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
+ static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
+ static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
+ static final boolean DEBUG_VISBILITY = DEBUG_ALL || false;
+
+ static final String POSTFIX_BACKUP = (PREPEND_CATEGORY_NAME) ? "_Backup" : "";
+ static final String POSTFIX_BROADCAST = (PREPEND_CATEGORY_NAME) ? "_Broadcast" : "";
+ static final String POSTFIX_MU = "_MU";
+ static final String POSTFIX_SERVICE = (PREPEND_CATEGORY_NAME) ? "_Service" : "";
+ static final String POSTFIX_SERVICE_EXECUTING =
+ (PREPEND_CATEGORY_NAME) ? "_ServiceExecuting" : "";
+
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 008d718..46f07cc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -30,6 +30,7 @@ import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import android.Manifest;
@@ -55,11 +56,13 @@ import android.os.storage.StorageManager;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.DebugUtils;
import android.util.SparseIntArray;
import android.view.Display;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.DumpHeapActivity;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ProcessMap;
@@ -245,10 +248,11 @@ public final class ActivityManagerService extends ActivityManagerNative
// File that stores last updated system version and called preboot receivers
static final String CALLED_PRE_BOOTS_FILENAME = "called_pre_boots.dat";
- static final String TAG = "ActivityManager";
- static final String TAG_MU = "ActivityManagerServiceMU";
- static final boolean DEBUG = false;
- static final boolean localLOGV = DEBUG;
+ static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
+ private static final String TAG_MU = TAG + POSTFIX_MU;
+
+ // TODO(ogunwale): Migrate all the constants below to use ActivityManagerDebugConfig class.
+ static final boolean localLOGV = DEBUG_ALL || false;
static final boolean DEBUG_BACKUP = localLOGV || false;
static final boolean DEBUG_BROADCAST = localLOGV || false;
static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
@@ -1124,6 +1128,11 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean mAutoStopProfiler = false;
int mProfileType = 0;
String mOpenGlTraceApp = null;
+ final ArrayMap<String, Long> mMemWatchProcesses = new ArrayMap<>();
+ String mMemWatchDumpProcName;
+ String mMemWatchDumpFile;
+ int mMemWatchDumpPid;
+ int mMemWatchDumpUid;
final long[] mTmpLong = new long[1];
@@ -1266,6 +1275,8 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int DISMISS_DIALOG_MSG = 48;
static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 49;
static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 50;
+ static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 51;
+ static final int DELETE_DUMPHEAP_MSG = 52;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1820,6 +1831,78 @@ public final class ActivityManagerService extends ActivityManagerNative
}
break;
}
+ case POST_DUMP_HEAP_NOTIFICATION_MSG: {
+ final String procName;
+ final int uid;
+ final long memLimit;
+ synchronized (ActivityManagerService.this) {
+ procName = mMemWatchDumpProcName;
+ uid = mMemWatchDumpUid;
+ Long limit = mMemWatchProcesses.get(procName);
+ memLimit = limit != null ? limit : 0;
+ }
+ if (procName == null) {
+ return;
+ }
+
+ if (DEBUG_PSS) Slog.d(TAG, "Showing dump heap notification from "
+ + procName + "/" + uid);
+
+ INotificationManager inm = NotificationManager.getService();
+ if (inm == null) {
+ return;
+ }
+
+ String text = mContext.getString(R.string.dump_heap_notification, procName);
+ Notification notification = new Notification();
+ notification.icon = com.android.internal.R.drawable.stat_sys_adb;
+ notification.when = 0;
+ notification.flags = Notification.FLAG_ONGOING_EVENT|Notification.FLAG_AUTO_CANCEL;
+ notification.tickerText = text;
+ notification.defaults = 0; // please be quiet
+ notification.sound = null;
+ notification.vibrate = null;
+ notification.color = mContext.getResources().getColor(
+ com.android.internal.R.color.system_notification_accent_color);
+ Intent deleteIntent = new Intent();
+ deleteIntent.setAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP);
+ notification.deleteIntent = PendingIntent.getBroadcastAsUser(mContext, 0,
+ deleteIntent, 0, UserHandle.OWNER);
+ Intent intent = new Intent();
+ intent.setClassName("android", DumpHeapActivity.class.getName());
+ intent.putExtra(DumpHeapActivity.KEY_PROCESS, procName);
+ intent.putExtra(DumpHeapActivity.KEY_SIZE, memLimit);
+ int userId = UserHandle.getUserId(uid);
+ notification.setLatestEventInfo(mContext, text,
+ mContext.getText(R.string.dump_heap_notification_detail),
+ PendingIntent.getActivityAsUser(mContext, 0, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT, null,
+ new UserHandle(userId)));
+
+ try {
+ int[] outId = new int[1];
+ inm.enqueueNotificationWithTag("android", "android", null,
+ R.string.dump_heap_notification,
+ notification, outId, userId);
+ } catch (RuntimeException e) {
+ Slog.w(ActivityManagerService.TAG,
+ "Error showing notification for dump heap", e);
+ } catch (RemoteException e) {
+ }
+ } break;
+ case DELETE_DUMPHEAP_MSG: {
+ revokeUriPermission(ActivityThread.currentActivityThread().getApplicationThread(),
+ DumpHeapActivity.JAVA_URI,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+ UserHandle.myUserId());
+ synchronized (ActivityManagerService.this) {
+ mMemWatchDumpFile = null;
+ mMemWatchDumpProcName = null;
+ mMemWatchDumpPid = -1;
+ mMemWatchDumpUid = -1;
+ }
+ } break;
}
}
};
@@ -1906,7 +1989,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (pss != 0 && proc.thread != null && proc.setProcState == procState
&& proc.pid == pid && proc.lastPssTime == lastPssTime) {
num++;
- recordPssSample(proc, procState, pss, tmp[0],
+ recordPssSampleLocked(proc, procState, pss, tmp[0],
SystemClock.uptimeMillis());
}
}
@@ -2318,7 +2401,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
ps.addCpuTimeLocked(st.rel_utime - otherUTime,
st.rel_stime - otherSTime, cpuSpeedTimes);
- pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10;
+ pr.curCpuTime += st.rel_utime + st.rel_stime;
} else {
BatteryStatsImpl.Uid.Proc ps = st.batteryStats;
if (ps == null || !ps.isActive()) {
@@ -5704,7 +5787,7 @@ public final class ActivityManagerService extends ActivityManagerNative
for (String pkg : pkgs) {
synchronized (ActivityManagerService.this) {
if (forceStopPackageLocked(pkg, -1, false, false, false, false, false,
- 0, "finished booting")) {
+ 0, "query restart")) {
setResultCode(Activity.RESULT_OK);
return;
}
@@ -5714,6 +5797,19 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}, pkgFilter);
+ IntentFilter dumpheapFilter = new IntentFilter();
+ dumpheapFilter.addAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getBooleanExtra(DumpHeapActivity.EXTRA_DELAY_DELETE, false)) {
+ mHandler.sendEmptyMessageDelayed(POST_DUMP_HEAP_NOTIFICATION_MSG, 5*60*1000);
+ } else {
+ mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+ }
+ }
+ }, dumpheapFilter);
+
// Let system services know.
mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);
@@ -8347,6 +8443,9 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized (this) {
pkg = task.intent.getComponent().getPackageName();
}
+ // isSystemInitiated is used to distinguish between locked and pinned mode, as pinned mode
+ // is initiated by system after the pinning request was shown and locked mode is initiated
+ // by an authorized app directly
boolean isSystemInitiated = Binder.getCallingUid() == Process.SYSTEM_UID;
if (!isSystemInitiated && !isLockTaskAuthorized(pkg)) {
StatusBarManagerInternal statusBarManager = LocalServices.getService(
@@ -8367,7 +8466,9 @@ public final class ActivityManagerService extends ActivityManagerNative
|| (task != mStackSupervisor.getFocusedStack().topTask()))) {
throw new IllegalArgumentException("Invalid task, not in foreground");
}
- mStackSupervisor.setLockTaskModeLocked(task, !isSystemInitiated,
+ mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated ?
+ ActivityManager.LOCK_TASK_MODE_PINNED :
+ ActivityManager.LOCK_TASK_MODE_LOCKED,
"startLockTask");
}
}
@@ -8453,7 +8554,8 @@ public final class ActivityManagerService extends ActivityManagerNative
Log.d(TAG, "stopLockTaskMode");
// Stop lock task
synchronized (this) {
- mStackSupervisor.setLockTaskModeLocked(null, false, "stopLockTask");
+ mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
+ "stopLockTask");
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -8474,8 +8576,13 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public boolean isInLockTaskMode() {
+ return getLockTaskModeState() != ActivityManager.LOCK_TASK_MODE_NONE;
+ }
+
+ @Override
+ public int getLockTaskModeState() {
synchronized (this) {
- return mStackSupervisor.isInLockTaskMode();
+ return mStackSupervisor.getLockTaskModeState();
}
}
@@ -12728,6 +12835,22 @@ public final class ActivityManagerService extends ActivityManagerNative
+ " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
}
}
+ if (mMemWatchProcesses.size() > 0) {
+ pw.println(" Mem watch processes:");
+ for (int i=0; i<mMemWatchProcesses.size(); i++) {
+ if (needSep) {
+ pw.println();
+ needSep = false;
+ }
+ pw.print(" "); pw.print(mMemWatchProcesses.keyAt(i));
+ pw.print(": "); DebugUtils.printSizeValue(pw, mMemWatchProcesses.valueAt(i));
+ pw.println();
+ }
+ pw.print(" mMemWatchDumpProcName="); pw.println(mMemWatchDumpProcName);
+ pw.print(" mMemWatchDumpFile="); pw.println(mMemWatchDumpFile);
+ pw.print(" mMemWatchDumpPid="); pw.print(mMemWatchDumpPid);
+ pw.print(" mMemWatchDumpUid="); pw.println(mMemWatchDumpUid);
+ }
if (mOpenGlTraceApp != null) {
if (dumpPackage == null || dumpPackage.equals(mOpenGlTraceApp)) {
if (needSep) {
@@ -13410,8 +13533,9 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.print(" ");
pw.print("state: cur="); pw.print(ProcessList.makeProcStateString(r.curProcState));
pw.print(" set="); pw.print(ProcessList.makeProcStateString(r.setProcState));
- pw.print(" lastPss="); pw.print(r.lastPss);
- pw.print(" lastCachedPss="); pw.println(r.lastCachedPss);
+ pw.print(" lastPss="); DebugUtils.printSizeValue(pw, r.lastPss*1024);
+ pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, r.lastCachedPss*1024);
+ pw.println();
pw.print(prefix);
pw.print(" ");
pw.print("cached="); pw.print(r.cached);
@@ -17219,7 +17343,7 @@ public final class ActivityManagerService extends ActivityManagerNative
/**
* Record new PSS sample for a process.
*/
- void recordPssSample(ProcessRecord proc, int procState, long pss, long uss, long now) {
+ void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss, long now) {
EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss*1024, uss*1024);
proc.lastPssTime = now;
proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList);
@@ -17233,6 +17357,67 @@ public final class ActivityManagerService extends ActivityManagerNative
if (procState >= ActivityManager.PROCESS_STATE_HOME) {
proc.lastCachedPss = pss;
}
+
+ Long check = mMemWatchProcesses.get(proc.processName);
+ if (check != null) {
+ if ((pss*1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) {
+ boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+ if (!isDebuggable) {
+ if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ isDebuggable = true;
+ }
+ }
+ if (isDebuggable) {
+ Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check + "; reporting");
+ final ProcessRecord myProc = proc;
+ final File heapdumpFile = DumpHeapProvider.getJavaFile();
+ mMemWatchDumpProcName = proc.processName;
+ mMemWatchDumpFile = heapdumpFile.toString();
+ mMemWatchDumpPid = proc.pid;
+ mMemWatchDumpUid = proc.uid;
+ BackgroundThread.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ revokeUriPermission(ActivityThread.currentActivityThread()
+ .getApplicationThread(),
+ DumpHeapActivity.JAVA_URI,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+ UserHandle.myUserId());
+ ParcelFileDescriptor fd = null;
+ try {
+ heapdumpFile.delete();
+ fd = ParcelFileDescriptor.open(heapdumpFile,
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE |
+ ParcelFileDescriptor.MODE_READ_WRITE);
+ IApplicationThread thread = myProc.thread;
+ if (thread != null) {
+ try {
+ if (DEBUG_PSS) Slog.d(TAG, "Requesting dump heap from "
+ + myProc + " to " + heapdumpFile);
+ thread.dumpHeap(true, heapdumpFile.toString(), fd);
+ } catch (RemoteException e) {
+ }
+ }
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } finally {
+ if (fd != null) {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+ });
+ } else {
+ Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check
+ + ", but debugging not enabled");
+ }
+ }
+ }
}
/**
@@ -17591,7 +17776,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// states, which well tend to give noisy data.
long start = SystemClock.uptimeMillis();
long pss = Debug.getPss(app.pid, mTmpLong, null);
- recordPssSample(app, app.curProcState, pss, mTmpLong[0], now);
+ recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], now);
mPendingPssProcesses.remove(app);
Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
+ " to " + app.curProcState + ": "
@@ -18411,6 +18596,38 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ @Override
+ public void setDumpHeapDebugLimit(String processName, long maxMemSize) {
+ enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
+ "setDumpHeapDebugLimit()");
+ synchronized (this) {
+ if (maxMemSize > 0) {
+ mMemWatchProcesses.put(processName, maxMemSize);
+ mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+ } else {
+ mMemWatchProcesses.remove(processName);
+ }
+ }
+ }
+
+ @Override
+ public void dumpHeapFinished(String path) {
+ synchronized (this) {
+ if (Binder.getCallingPid() != mMemWatchDumpPid) {
+ Slog.w(TAG, "dumpHeapFinished: Calling pid " + Binder.getCallingPid()
+ + " does not match last pid " + mMemWatchDumpPid);
+ return;
+ }
+ if (mMemWatchDumpFile == null || !mMemWatchDumpFile.equals(path)) {
+ Slog.w(TAG, "dumpHeapFinished: Calling path " + path
+ + " does not match last path " + mMemWatchDumpFile);
+ return;
+ }
+ if (DEBUG_PSS) Slog.d(TAG, "Dump heap finished for " + path);
+ mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+ }
+ }
+
/** In this method we try to acquire our lock to make sure that we have not deadlocked */
public void monitor() {
synchronized (this) { }
@@ -18534,7 +18751,8 @@ public final class ActivityManagerService extends ActivityManagerNative
return true;
}
- mStackSupervisor.setLockTaskModeLocked(null, false, "startUser");
+ mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
+ "startUser");
final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
if (userInfo == null) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index a260330..8b95ae8 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -20,6 +20,7 @@ import static android.Manifest.permission.START_ANY_ACTIVITY;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.ActivityManagerService.localLOGV;
import static com.android.server.am.ActivityManagerService.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerService.DEBUG_FOCUS;
@@ -116,7 +117,7 @@ import java.util.ArrayList;
import java.util.List;
public final class ActivityStackSupervisor implements DisplayListener {
- static final boolean DEBUG = ActivityManagerService.DEBUG || false;
+ static final boolean DEBUG = DEBUG_ALL || false;
static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
static final boolean DEBUG_APP = DEBUG || false;
static final boolean DEBUG_CONTAINERS = DEBUG || false;
@@ -267,9 +268,11 @@ public final class ActivityStackSupervisor implements DisplayListener {
/** If non-null then the task specified remains in front and no other tasks may be started
* until the task exits or #stopLockTaskMode() is called. */
TaskRecord mLockTaskModeTask;
- /** Whether lock task has been entered by an authorized app and cannot
- * be exited. */
- private boolean mLockTaskIsLocked;
+ /** Store the current lock task mode. Possible values:
+ * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActicityManager#LOCK_TASK_MODE_LOCKED},
+ * {@link ActicityManager#LOCK_TASK_MODE_PINNED}
+ */
+ private int mLockTaskModeState;
/**
* Notifies the user when entering/exiting lock-task.
*/
@@ -3546,10 +3549,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
void showLockTaskToast() {
- mLockTaskNotify.showToast(mLockTaskIsLocked);
+ mLockTaskNotify.showToast(mLockTaskModeState);
}
- void setLockTaskModeLocked(TaskRecord task, boolean isLocked, String reason) {
+ void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason) {
if (task == null) {
// Take out of lock task mode if necessary
if (mLockTaskModeTask != null) {
@@ -3573,7 +3576,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
lockTaskMsg.obj = mLockTaskModeTask.intent.getComponent().getPackageName();
lockTaskMsg.arg1 = mLockTaskModeTask.userId;
lockTaskMsg.what = LOCK_TASK_START_MSG;
- lockTaskMsg.arg2 = !isLocked ? 1 : 0;
+ lockTaskMsg.arg2 = lockTaskModeState;
mHandler.sendMessage(lockTaskMsg);
}
@@ -3591,8 +3594,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
- boolean isInLockTaskMode() {
- return mLockTaskModeTask != null;
+ int getLockTaskModeState() {
+ return mLockTaskModeState;
}
private final class ActivityStackSupervisorHandler extends Handler {
@@ -3684,13 +3687,18 @@ public final class ActivityStackSupervisor implements DisplayListener {
mLockTaskNotify = new LockTaskNotify(mService.mContext);
}
mLockTaskNotify.show(true);
- mLockTaskIsLocked = msg.arg2 == 0;
+ mLockTaskModeState = msg.arg2;
if (getStatusBarService() != null) {
- int flags =
- StatusBarManager.DISABLE_MASK ^ StatusBarManager.DISABLE_BACK;
- if (!mLockTaskIsLocked) {
- flags ^= StatusBarManager.DISABLE_HOME
- | StatusBarManager.DISABLE_RECENT;
+ int flags = 0;
+ if (mLockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) {
+ flags = StatusBarManager.DISABLE_MASK
+ & (~StatusBarManager.DISABLE_BACK);
+ } else if (mLockTaskModeState ==
+ ActivityManager.LOCK_TASK_MODE_PINNED) {
+ flags = StatusBarManager.DISABLE_MASK
+ & (~StatusBarManager.DISABLE_BACK)
+ & (~StatusBarManager.DISABLE_HOME)
+ & (~StatusBarManager.DISABLE_RECENT);
}
getStatusBarService().disable(flags, mToken,
mService.mContext.getPackageName());
@@ -3724,7 +3732,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
boolean shouldLockKeyguard = Settings.Secure.getInt(
mService.mContext.getContentResolver(),
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED) != 0;
- if (!mLockTaskIsLocked && shouldLockKeyguard) {
+ if (mLockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED &&
+ shouldLockKeyguard) {
mWindowManager.lockNow(null);
mWindowManager.dismissKeyguard();
new LockPatternUtils(mService.mContext)
@@ -3735,6 +3744,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
} catch (RemoteException ex) {
throw new RuntimeException(ex);
+ } finally {
+ mLockTaskModeState = ActivityManager.LOCK_TASK_MODE_NONE;
}
} break;
case CONTAINER_CALLBACK_TASK_LIST_EMPTY: {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 5083b1d..8fe1238 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -41,6 +41,8 @@ import android.os.UserHandle;
import android.util.EventLog;
import android.util.Slog;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+
/**
* BROADCASTS
*
@@ -48,11 +50,9 @@ import android.util.Slog;
* foreground priority, and one for normal (background-priority) broadcasts.
*/
public final class BroadcastQueue {
- static final String TAG = "BroadcastQueue";
- static final String TAG_MU = ActivityManagerService.TAG_MU;
- static final boolean DEBUG_BROADCAST = ActivityManagerService.DEBUG_BROADCAST;
- static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT;
- static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "BroadcastQueue" : TAG_AM;
+ private static final String TAG_MU = TAG + POSTFIX_MU;
+ private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 50;
static final int MAX_BROADCAST_SUMMARY_HISTORY
@@ -143,7 +143,7 @@ public final class BroadcastQueue {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
- TAG, "Received BROADCAST_INTENT_MSG");
+ TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
@@ -196,7 +196,7 @@ public final class BroadcastQueue {
public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"***** DROPPING PARALLEL ["
+ mQueueName + "]: " + r.intent);
mParallelBroadcasts.set(i, r);
@@ -209,7 +209,7 @@ public final class BroadcastQueue {
public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) {
for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"***** DROPPING ORDERED ["
+ mQueueName + "]: " + r.intent);
mOrderedBroadcasts.set(i, r);
@@ -221,7 +221,7 @@ public final class BroadcastQueue {
private final void processCurBroadcastLocked(BroadcastRecord r,
ProcessRecord app) throws RemoteException {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " for app " + app);
if (app.thread == null) {
throw new RemoteException();
@@ -238,7 +238,7 @@ public final class BroadcastQueue {
boolean started = false;
try {
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG,
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
"Delivering to component " + r.curComponent
+ ": " + r);
mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
@@ -246,12 +246,12 @@ public final class BroadcastQueue {
mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
app.repProcState);
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " DELIVERED for app " + app);
started = true;
} finally {
if (!started) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + ": NOT STARTED!");
r.receiver = null;
r.curApp = null;
@@ -305,23 +305,22 @@ public final class BroadcastQueue {
r.resultExtras, r.resultAbort, false);
reschedule = true;
}
-
- r = mPendingBroadcast;
- if (r != null && r.curApp == app) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (r == null && mPendingBroadcast != null && mPendingBroadcast.curApp == app) {
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"[" + mQueueName + "] skip & discard pending app " + r);
+ r = mPendingBroadcast;
+ }
+
+ if (r != null) {
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
- reschedule = true;
- }
- if (reschedule) {
scheduleBroadcastsLocked();
}
}
public void scheduleBroadcastsLocked() {
- if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
@@ -391,8 +390,7 @@ public final class BroadcastQueue {
// on. If there are background services currently starting, then we will go into a
// special state where we hold off on continuing this broadcast until they are done.
if (mService.mServices.hasBackgroundServices(r.userId)) {
- Slog.i(ActivityManagerService.TAG, "Delay finish: "
- + r.curComponent.flattenToShortString());
+ Slog.i(TAG, "Delay finish: " + r.curComponent.flattenToShortString());
r.state = BroadcastRecord.WAITING_SERVICES;
return false;
}
@@ -412,7 +410,7 @@ public final class BroadcastQueue {
if (mOrderedBroadcasts.size() > 0) {
BroadcastRecord br = mOrderedBroadcasts.get(0);
if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) {
- Slog.i(ActivityManagerService.TAG, "Resuming delayed broadcast");
+ Slog.i(TAG, "Resuming delayed broadcast");
br.curComponent = null;
br.state = BroadcastRecord.IDLE;
processNextBroadcast(false);
@@ -475,7 +473,7 @@ public final class BroadcastQueue {
int mode = mService.mAppOpsService.noteOperation(r.appOp,
filter.receiverList.uid, filter.packageName);
if (mode != AppOpsManager.MODE_ALLOWED) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"App op " + r.appOp + " not allowed for broadcast to uid "
+ filter.receiverList.uid + " pkg " + filter.packageName);
skip = true;
@@ -513,10 +511,11 @@ public final class BroadcastQueue {
}
}
try {
- if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG, "Delivering to " + filter + " : " + r);
+ if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
+ "Delivering to " + filter + " : " + r);
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
- new Intent(r.intent), r.resultCode, r.resultData,
- r.resultExtras, r.ordered, r.initialSticky, r.userId);
+ new Intent(r.intent), r.resultCode, r.resultData,
+ r.resultExtras, r.ordered, r.initialSticky, r.userId);
if (ordered) {
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}
@@ -538,7 +537,7 @@ public final class BroadcastQueue {
synchronized(mService) {
BroadcastRecord r;
- if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast ["
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
+ mQueueName + "]: "
+ mParallelBroadcasts.size() + " broadcasts, "
+ mOrderedBroadcasts.size() + " ordered broadcasts");
@@ -555,17 +554,17 @@ public final class BroadcastQueue {
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
final int N = r.receivers.size();
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
+ mQueueName + "] " + r);
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering non-ordered on [" + mQueueName + "] to registered "
+ target + ": " + r);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
}
addBroadcastToHistoryLocked(r);
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
+ mQueueName + "] " + r);
}
@@ -575,11 +574,9 @@ public final class BroadcastQueue {
// broadcast, then do nothing at this point. Just in case, we
// check that the process we're waiting for still exists.
if (mPendingBroadcast != null) {
- if (DEBUG_BROADCAST_LIGHT) {
- Slog.v(TAG, "processNextBroadcast ["
- + mQueueName + "]: waiting for "
- + mPendingBroadcast.curApp);
- }
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
+ "processNextBroadcast [" + mQueueName + "]: waiting for "
+ + mPendingBroadcast.curApp);
boolean isDead;
synchronized (mService.mPidsSelfLocked) {
@@ -645,7 +642,7 @@ public final class BroadcastQueue {
}
if (r.state != BroadcastRecord.IDLE) {
- if (DEBUG_BROADCAST) Slog.d(TAG,
+ if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
"processNextBroadcast("
+ mQueueName + ") called when not idle (state="
+ r.state + ")");
@@ -658,7 +655,7 @@ public final class BroadcastQueue {
// result if requested...
if (r.resultTo != null) {
try {
- if (DEBUG_BROADCAST) Slog.i(TAG,
+ if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
"Finishing broadcast [" + mQueueName + "] "
+ r.intent.getAction() + " app=" + r.callerApp);
performReceiveLocked(r.callerApp, r.resultTo,
@@ -675,11 +672,11 @@ public final class BroadcastQueue {
}
}
- if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
cancelBroadcastTimeoutLocked();
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
- + r);
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
+ "Finished with ordered broadcast " + r);
// ... and on to the next...
addBroadcastToHistoryLocked(r);
@@ -699,12 +696,12 @@ public final class BroadcastQueue {
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;
r.dispatchClockTime = System.currentTimeMillis();
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast ["
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["
+ mQueueName + "] " + r);
}
if (! mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mTimeoutPeriod;
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Submitting BROADCAST_TIMEOUT_MSG ["
+ mQueueName + "] for " + r + " at " + timeoutTime);
setBroadcastTimeoutLocked(timeoutTime);
@@ -715,7 +712,7 @@ public final class BroadcastQueue {
// Simple case: this is a registered receiver who gets
// a direct call.
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering ordered ["
+ mQueueName + "] to registered "
+ filter + ": " + r);
@@ -723,7 +720,7 @@ public final class BroadcastQueue {
if (r.receiver == null || !r.ordered) {
// The receiver has already finished, so schedule to
// process the next one.
- if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing ["
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
+ mQueueName + "]: ordered="
+ r.ordered + " receiver=" + r.receiver);
r.state = BroadcastRecord.IDLE;
@@ -786,7 +783,7 @@ public final class BroadcastQueue {
int mode = mService.mAppOpsService.noteOperation(r.appOp,
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName);
if (mode != AppOpsManager.MODE_ALLOWED) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"App op " + r.appOp + " not allowed for broadcast to uid "
+ info.activityInfo.applicationInfo.uid + " pkg "
+ info.activityInfo.packageName);
@@ -835,19 +832,18 @@ public final class BroadcastQueue {
+ info.activityInfo.packageName, e);
}
if (!isAvailable) {
- if (DEBUG_BROADCAST) {
- Slog.v(TAG, "Skipping delivery to " + info.activityInfo.packageName
- + " / " + info.activityInfo.applicationInfo.uid
- + " : package no longer available");
- }
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
+ "Skipping delivery to " + info.activityInfo.packageName + " / "
+ + info.activityInfo.applicationInfo.uid
+ + " : package no longer available");
skip = true;
}
}
if (skip) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Skipping delivery of ordered ["
- + mQueueName + "] " + r + " for whatever reason");
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
+ "Skipping delivery of ordered [" + mQueueName + "] "
+ + r + " for whatever reason");
r.receiver = null;
r.curFilter = null;
r.state = BroadcastRecord.IDLE;
@@ -915,7 +911,7 @@ public final class BroadcastQueue {
}
// Not running -- get it started, to be executed when the app comes up.
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Need to start app ["
+ mQueueName + "] " + targetProcess + " for broadcast " + r);
if ((r.curApp=mService.startProcessLocked(targetProcess,
@@ -990,7 +986,7 @@ public final class BroadcastQueue {
// broadcast timeout message after each receiver finishes. Instead, we set up
// an initial timeout then kick it down the road a little further as needed
// when it expires.
- if (DEBUG_BROADCAST) Slog.v(TAG,
+ if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Premature timeout ["
+ mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
+ timeoutTime);
@@ -1005,7 +1001,7 @@ public final class BroadcastQueue {
// for started services to finish as well before going on. So if we have actually
// waited long enough time timeout the broadcast, let's give up on the whole thing
// and just move on to the next.
- Slog.i(ActivityManagerService.TAG, "Waited long enough for: " + (br.curComponent != null
+ Slog.i(TAG, "Waited long enough for: " + (br.curComponent != null
? br.curComponent.flattenToShortString() : "(null)"));
br.curComponent = null;
br.state = BroadcastRecord.IDLE;
diff --git a/services/core/java/com/android/server/am/DumpHeapProvider.java b/services/core/java/com/android/server/am/DumpHeapProvider.java
new file mode 100644
index 0000000..a8b639e
--- /dev/null
+++ b/services/core/java/com/android/server/am/DumpHeapProvider.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+public class DumpHeapProvider extends ContentProvider {
+ static final Object sLock = new Object();
+ static File sHeapDumpJavaFile;
+
+ static public File getJavaFile() {
+ synchronized (sLock) {
+ return sHeapDumpJavaFile;
+ }
+ }
+
+ @Override
+ public boolean onCreate() {
+ synchronized (sLock) {
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ File heapdumpDir = new File(systemDir, "heapdump");
+ heapdumpDir.mkdir();
+ sHeapDumpJavaFile = new File(heapdumpDir, "javaheap.bin");
+ }
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return "application/octet-stream";
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+ synchronized (sLock) {
+ String path = uri.getEncodedPath();
+ final String tag = Uri.decode(path);
+ if (tag.equals("/java")) {
+ return ParcelFileDescriptor.open(sHeapDumpJavaFile,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ } else {
+ throw new FileNotFoundException("Invalid path for " + uri);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java
index b3777ed..afde322 100644
--- a/services/core/java/com/android/server/am/LockTaskNotify.java
+++ b/services/core/java/com/android/server/am/LockTaskNotify.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.app.ActivityManager;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
@@ -44,15 +45,20 @@ public class LockTaskNotify {
mHandler = new H();
}
- public void showToast(boolean isLocked) {
- mHandler.obtainMessage(H.SHOW_TOAST, isLocked ? 1 : 0, 0 /* Not used */).sendToTarget();
+ public void showToast(int lockTaskModeState) {
+ mHandler.obtainMessage(H.SHOW_TOAST, lockTaskModeState, 0 /* Not used */).sendToTarget();
}
- public void handleShowToast(boolean isLocked) {
- String text = mContext.getString(isLocked
- ? R.string.lock_to_app_toast_locked : R.string.lock_to_app_toast);
- if (!isLocked && mAccessibilityManager.isEnabled()) {
- text = mContext.getString(R.string.lock_to_app_toast_accessible);
+ public void handleShowToast(int lockTaskModeState) {
+ String text = null;
+ if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) {
+ text = mContext.getString(R.string.lock_to_app_toast_locked);
+ } else if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED) {
+ text = mContext.getString(mAccessibilityManager.isEnabled()
+ ? R.string.lock_to_app_toast_accessible : R.string.lock_to_app_toast);
+ }
+ if (text == null) {
+ return;
}
if (mLastToast != null) {
mLastToast.cancel();
@@ -83,7 +89,7 @@ public class LockTaskNotify {
public void handleMessage(Message msg) {
switch(msg.what) {
case SHOW_TOAST:
- handleShowToast(msg.arg1 != 0);
+ handleShowToast(msg.arg1);
break;
}
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index a6c616a..f374c86 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import android.util.ArraySet;
+import android.util.DebugUtils;
import android.util.EventLog;
import android.util.Slog;
import com.android.internal.app.ProcessStats;
@@ -248,8 +249,9 @@ final class ProcessRecord {
pw.println();
pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
pw.print(" lruSeq="); pw.print(lruSeq);
- pw.print(" lastPss="); pw.print(lastPss);
- pw.print(" lastCachedPss="); pw.println(lastCachedPss);
+ pw.print(" lastPss="); DebugUtils.printSizeValue(pw, lastPss*1024);
+ pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, lastCachedPss*1024);
+ pw.println();
pw.print(prefix); pw.print("cached="); pw.print(cached);
pw.print(" empty="); pw.println(empty);
if (serviceb) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 018d77a..61a7263 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -188,7 +188,6 @@ public class AudioService extends IAudioService.Stub {
// AudioHandler messages
private static final int MSG_SET_DEVICE_VOLUME = 0;
private static final int MSG_PERSIST_VOLUME = 1;
- private static final int MSG_PERSIST_MASTER_VOLUME = 2;
private static final int MSG_PERSIST_RINGER_MODE = 3;
private static final int MSG_MEDIA_SERVER_DIED = 4;
private static final int MSG_PLAY_SOUND_EFFECT = 5;
@@ -239,10 +238,6 @@ public class AudioService extends IAudioService.Stub {
private final Object mSoundEffectsLock = new Object();
private static final int NUM_SOUNDPOOL_CHANNELS = 4;
- // Internally master volume is a float in the 0.0 - 1.0 range,
- // but to support integer based AudioManager API we translate it to 0 - 100
- private static final int MAX_MASTER_VOLUME = 100;
-
// Maximum volume adjust steps allowed in a single batch call.
private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
@@ -386,11 +381,6 @@ public class AudioService extends IAudioService.Stub {
// Forced device usage for communications
private int mForcedUseForComm;
- // True if we have master volume support
- private final boolean mUseMasterVolume;
-
- private final int[] mMasterVolumeRamp;
-
// List of binder death handlers for setMode() client processes.
// The last process to have called setMode() is at the top of the list.
private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
@@ -595,10 +585,6 @@ public class AudioService extends IAudioService.Stub {
mUseFixedVolume = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_useFixedVolume);
- mUseMasterVolume = context.getResources().getBoolean(
- com.android.internal.R.bool.config_useMasterVolume);
- mMasterVolumeRamp = context.getResources().getIntArray(
- com.android.internal.R.array.config_masterVolumeRamp);
// must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
// array initialized by updateStreamVolumeAlias()
@@ -647,8 +633,6 @@ public class AudioService extends IAudioService.Stub {
context.registerReceiver(mReceiver, intentFilter);
- restoreMasterVolume();
-
LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
}
@@ -882,7 +866,7 @@ public class AudioService extends IAudioService.Stub {
UserHandle.USER_CURRENT);
boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
- 0, UserHandle.USER_CURRENT) == 1;
+ 0, UserHandle.USER_CURRENT) == 1;
if (mUseFixedVolume) {
masterMute = false;
AudioSystem.setMasterVolume(1.0f);
@@ -1050,7 +1034,7 @@ public class AudioService extends IAudioService.Stub {
// If either the client forces allowing ringer modes for this adjustment,
// or the stream type is one that is affected by ringer modes
if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
- (streamTypeAlias == getMasterStreamType())) {
+ (streamTypeAlias == getUiSoundsStreamType())) {
int ringerMode = getRingerModeInternal();
// do not vibrate if already in vibrate mode
if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
@@ -1183,33 +1167,6 @@ public class AudioService extends IAudioService.Stub {
}
}
- /** @see AudioManager#adjustMasterVolume(int, int) */
- public void adjustMasterVolume(int steps, int flags, String callingPackage) {
- adjustMasterVolume(steps, flags, callingPackage, Binder.getCallingUid());
- }
-
- public void adjustMasterVolume(int steps, int flags, String callingPackage, int uid) {
- if (mUseFixedVolume) {
- return;
- }
- if (isMuteAdjust(steps)) {
- setMasterMuteInternal(steps, flags, callingPackage, uid);
- return;
- }
- ensureValidSteps(steps);
- int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
- int delta = 0;
- int numSteps = Math.abs(steps);
- int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
- for (int i = 0; i < numSteps; ++i) {
- delta = findVolumeDelta(direction, volume);
- volume += delta;
- }
-
- //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
- setMasterVolume(volume, flags, callingPackage, uid);
- }
-
// StreamVolumeCommand contains the information needed to defer the process of
// setStreamVolume() in case the user has to acknowledge the safe volume warning message.
class StreamVolumeCommand {
@@ -1235,9 +1192,9 @@ public class AudioService extends IAudioService.Stub {
private void onSetStreamVolume(int streamType, int index, int flags, int device) {
setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
- // setting volume on master stream type also controls silent mode
+ // setting volume on ui sounds stream type also controls silent mode
if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
- (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
+ (mStreamVolumeAlias[streamType] == getUiSoundsStreamType())) {
int newRingerMode;
if (index == 0) {
newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
@@ -1381,41 +1338,6 @@ public class AudioService extends IAudioService.Stub {
}
}
- private int findVolumeDelta(int direction, int volume) {
- int delta = 0;
- if (direction == AudioManager.ADJUST_RAISE) {
- if (volume == MAX_MASTER_VOLUME) {
- return 0;
- }
- // This is the default value if we make it to the end
- delta = mMasterVolumeRamp[1];
- // If we're raising the volume move down the ramp array until we
- // find the volume we're above and use that groups delta.
- for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
- if (volume >= mMasterVolumeRamp[i - 1]) {
- delta = mMasterVolumeRamp[i];
- break;
- }
- }
- } else if (direction == AudioManager.ADJUST_LOWER){
- if (volume == 0) {
- return 0;
- }
- int length = mMasterVolumeRamp.length;
- // This is the default value if we make it to the end
- delta = -mMasterVolumeRamp[length - 1];
- // If we're lowering the volume move up the ramp array until we
- // find the volume we're below and use the group below it's delta
- for (int i = 2; i < length; i += 2) {
- if (volume <= mMasterVolumeRamp[i]) {
- delta = -mMasterVolumeRamp[i - 1];
- break;
- }
- }
- }
- return delta;
- }
-
private void sendBroadcastToAll(Intent intent) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -1464,16 +1386,6 @@ public class AudioService extends IAudioService.Stub {
}
// UI update and Broadcast Intent
- private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
- mVolumeController.postMasterVolumeChanged(updateFlagsForSystemAudio(flags));
-
- Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
- intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
- intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
- sendBroadcastToAll(intent);
- }
-
- // UI update and Broadcast Intent
private void sendMasterMuteUpdate(boolean muted, int flags) {
mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
broadcastMasterMuteStatus(muted);
@@ -1641,27 +1553,21 @@ public class AudioService extends IAudioService.Stub {
}
}
- private void setMasterMuteInternal(int adjust, int flags, String callingPackage, int uid) {
+ private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid) {
if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
!= AppOpsManager.MODE_ALLOWED) {
return;
}
- boolean state;
- if (adjust == AudioManager.ADJUST_TOGGLE_MUTE) {
- state = !AudioSystem.getMasterMute();
- } else {
- state = adjust == AudioManager.ADJUST_MUTE;
- }
- if (state != AudioSystem.getMasterMute()) {
- setSystemAudioMute(state);
- AudioSystem.setMasterMute(state);
+ if (mute != AudioSystem.getMasterMute()) {
+ setSystemAudioMute(mute);
+ AudioSystem.setMasterMute(mute);
// Post a persist master volume msg
- sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
+ sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
: 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
- sendMasterMuteUpdate(state, flags);
+ sendMasterMuteUpdate(mute, flags);
Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
- intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, state);
+ intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
sendBroadcastToAll(intent);
}
}
@@ -1671,6 +1577,10 @@ public class AudioService extends IAudioService.Stub {
return AudioSystem.getMasterMute();
}
+ public void setMasterMute(boolean mute, int flags, String callingPackage) {
+ setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid());
+ }
+
protected static int getMaxStreamVolume(int streamType) {
return MAX_STREAM_VOLUME[streamType];
}
@@ -1694,63 +1604,12 @@ public class AudioService extends IAudioService.Stub {
}
}
- @Override
- public int getMasterVolume() {
- if (isMasterMute()) return 0;
- return getLastAudibleMasterVolume();
- }
-
- @Override
- public void setMasterVolume(int volume, int flags, String callingPackage) {
- setMasterVolume(volume, flags, callingPackage, Binder.getCallingUid());
- }
-
- public void setMasterVolume(int volume, int flags, String callingPackage, int uid) {
- if (mUseFixedVolume) {
- return;
- }
-
- if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
- != AppOpsManager.MODE_ALLOWED) {
- return;
- }
-
- if (volume < 0) {
- volume = 0;
- } else if (volume > MAX_MASTER_VOLUME) {
- volume = MAX_MASTER_VOLUME;
- }
- doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
- }
-
- private void doSetMasterVolume(float volume, int flags) {
- // don't allow changing master volume when muted
- if (!AudioSystem.getMasterMute()) {
- int oldVolume = getMasterVolume();
- AudioSystem.setMasterVolume(volume);
-
- int newVolume = getMasterVolume();
- if (newVolume != oldVolume) {
- // Post a persist master volume msg
- sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
- Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
- setSystemAudioVolume(oldVolume, newVolume, getMasterMaxVolume(), flags);
- }
- // Send the volume update regardless whether there was a change.
- sendMasterVolumeUpdate(flags, oldVolume, newVolume);
- }
- }
-
/** @see AudioManager#getStreamMaxVolume(int) */
public int getStreamMaxVolume(int streamType) {
ensureValidStreamType(streamType);
return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
}
- public int getMasterMaxVolume() {
- return MAX_MASTER_VOLUME;
- }
-
/** Get last audible volume before stream was muted. */
public int getLastAudibleStreamVolume(int streamType) {
ensureValidStreamType(streamType);
@@ -1758,13 +1617,8 @@ public class AudioService extends IAudioService.Stub {
return (mStreamStates[streamType].getIndex(device) + 5) / 10;
}
- /** Get last audible master volume before it was muted. */
- public int getLastAudibleMasterVolume() {
- return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
- }
-
- /** @see AudioManager#getMasterStreamType() */
- public int getMasterStreamType() {
+ /** @see AudioManager#getUiSoundsStreamType() */
+ public int getUiSoundsStreamType() {
return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
}
@@ -1932,20 +1786,6 @@ public class AudioService extends IAudioService.Stub {
}
}
- private void restoreMasterVolume() {
- if (mUseFixedVolume) {
- AudioSystem.setMasterVolume(1.0f);
- return;
- }
- if (mUseMasterVolume) {
- float volume = Settings.System.getFloatForUser(mContentResolver,
- Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
- if (volume >= 0.0f) {
- AudioSystem.setMasterVolume(volume);
- }
- }
- }
-
/** @see AudioManager#shouldVibrate(int) */
public boolean shouldVibrate(int vibrateType) {
if (!mHasVibrator) return false;
@@ -3510,9 +3350,8 @@ public class AudioService extends IAudioService.Stub {
public void readSettings() {
synchronized (VolumeStreamState.class) {
- // force maximum volume on all streams if fixed volume property
- // or master volume property is set
- if (mUseFixedVolume || mUseMasterVolume) {
+ // force maximum volume on all streams if fixed volume property is set
+ if (mUseFixedVolume) {
mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
return;
}
@@ -3747,7 +3586,7 @@ public class AudioService extends IAudioService.Stub {
private int getValidIndex(int index) {
if (index < 0) {
return 0;
- } else if (mUseFixedVolume || mUseMasterVolume || index > mIndexMax) {
+ } else if (mUseFixedVolume || index > mIndexMax) {
return mIndexMax;
}
@@ -3777,6 +3616,21 @@ public class AudioService extends IAudioService.Stub {
final int index = (mIndexMap.valueAt(i) + 5) / 10;
pw.print(index);
}
+ pw.println();
+ pw.print(" Devices: ");
+ final int devices = AudioSystem.getDevicesForStream(mStreamType);
+ int device, i = 0, n = 0;
+ // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
+ // (the default device is not returned by getDevicesForStream)
+ while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
+ if ((devices & device) != 0) {
+ if (n++ > 0) {
+ pw.print(", ");
+ }
+ pw.print(AudioSystem.getOutputDeviceName(device));
+ }
+ i++;
+ }
}
}
@@ -4119,16 +3973,6 @@ public class AudioService extends IAudioService.Stub {
persistVolume((VolumeStreamState) msg.obj, msg.arg1);
break;
- case MSG_PERSIST_MASTER_VOLUME:
- if (mUseFixedVolume) {
- return;
- }
- Settings.System.putFloatForUser(mContentResolver,
- Settings.System.VOLUME_MASTER,
- msg.arg1 / (float)1000.0,
- UserHandle.USER_CURRENT);
- break;
-
case MSG_PERSIST_MASTER_VOLUME_MUTE:
if (mUseFixedVolume) {
return;
@@ -4197,9 +4041,6 @@ public class AudioService extends IAudioService.Stub {
// Restore ringer mode
setRingerModeInt(getRingerModeInternal(), false);
- // Restore master volume
- restoreMasterVolume();
-
// Reset device orientation (if monitored for this device)
if (mMonitorOrientation) {
setOrientationForAudioSystem();
@@ -5666,16 +5507,6 @@ public class AudioService extends IAudioService.Stub {
}
}
- public void postMasterVolumeChanged(int flags) {
- if (mController == null)
- return;
- try {
- mController.masterVolumeChanged(flags);
- } catch (RemoteException e) {
- Log.w(TAG, "Error calling masterVolumeChanged", e);
- }
- }
-
public void postMasterMuteChanged(int flags) {
if (mController == null)
return;
@@ -5741,12 +5572,6 @@ public class AudioService extends IAudioService.Stub {
}
@Override
- public void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
- int uid) {
- adjustMasterVolume(steps, flags, callingPackage, uid);
- }
-
- @Override
public int getRingerModeInternal() {
return AudioService.this.getRingerModeInternal();
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 82c99f7..7c93e56 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -202,7 +202,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
reason != HdmiControlService.INITIATED_BY_BOOT_UP);
mLocalDeviceAddresses = initLocalDeviceAddresses();
launchDeviceDiscovery();
- startQueuedActions();
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 3345e46..5363968 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -90,14 +90,12 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
private final SessionStub mSession;
private final SessionCb mSessionCb;
private final MediaSessionService mService;
- private final boolean mUseMasterVolume;
private final Object mLock = new Object();
private final ArrayList<ISessionControllerCallback> mControllerCallbacks =
new ArrayList<ISessionControllerCallback>();
private long mFlags;
- private IMediaRouter mMediaRouter;
private PendingIntent mMediaButtonReceiver;
private PendingIntent mLaunchIntent;
@@ -141,8 +139,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
mAudioManager = (AudioManager) service.getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
mAudioAttrs = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build();
- mUseMasterVolume = service.getContext().getResources().getBoolean(
- com.android.internal.R.bool.config_useMasterVolume);
}
/**
@@ -247,13 +243,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
flags &= ~AudioManager.FLAG_PLAY_SOUND;
}
if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
- if (mUseMasterVolume) {
- // If this device only uses master volume and playback is local
- // just adjust the master volume and return.
- mAudioManagerInternal.adjustMasterVolumeForUid(direction, flags, packageName,
- uid);
- return;
- }
int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
if (useSuggested) {
if (AudioSystem.isStreamActive(stream, 0)) {
@@ -729,7 +718,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
@Override
public void setMediaRouter(IMediaRouter router) {
- mMediaRouter = router;
mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 4383bb1..72205d6 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -89,11 +89,9 @@ public class MediaSessionService extends SystemService implements Monitor {
private final Object mLock = new Object();
private final MessageHandler mHandler = new MessageHandler();
private final PowerManager.WakeLock mMediaEventWakeLock;
- private final boolean mUseMasterVolume;
private KeyguardManager mKeyguardManager;
private IAudioService mAudioService;
- private AudioManager mAudioManager;
private AudioManagerInternal mAudioManagerInternal;
private ContentResolver mContentResolver;
private SettingsObserver mSettingsObserver;
@@ -110,8 +108,6 @@ public class MediaSessionService extends SystemService implements Monitor {
mPriorityStack = new MediaSessionStack();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
- mUseMasterVolume = context.getResources().getBoolean(
- com.android.internal.R.bool.config_useMasterVolume);
}
@Override
@@ -121,7 +117,6 @@ public class MediaSessionService extends SystemService implements Monitor {
mKeyguardManager =
(KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
mAudioService = getAudioService();
- mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
mContentResolver = getContext().getContentResolver();
mSettingsObserver = new SettingsObserver();
@@ -468,11 +463,6 @@ public class MediaSessionService extends SystemService implements Monitor {
return -1;
}
- private boolean isSessionDiscoverable(MediaSessionRecord record) {
- // TODO probably want to check more than if it's active.
- return record.isActive();
- }
-
private void pushSessionsChanged(int userId) {
synchronized (mLock) {
List<MediaSessionRecord> records = mPriorityStack.getActiveSessions(userId);
@@ -889,12 +879,8 @@ public class MediaSessionService extends SystemService implements Monitor {
}
try {
String packageName = getContext().getOpPackageName();
- if (mUseMasterVolume) {
- mAudioService.adjustMasterVolume(direction, flags, packageName);
- } else {
- mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
- flags, packageName);
- }
+ mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
+ flags, packageName);
} catch (RemoteException e) {
Log.e(TAG, "Error adjusting default volume.", e);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 9b6b5fb..bedcabe 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2584,8 +2584,8 @@ public class NotificationManagerService extends SystemService {
@Override
public void run() {
String listenerName = listener == null ? null : listener.component.toShortString();
- EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, userId,
- mustHaveFlags, mustNotHaveFlags, reason, listenerName);
+ if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
+ userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
synchronized (mNotificationList) {
int index = indexOfNotificationLocked(pkg, tag, id, userId);
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 773b164..aa63932 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -414,9 +414,9 @@ public class KeySetManagerService {
// Get the package's known keys and KeySets
ArraySet<Long> deletableKeySets = getOriginalKeySetsByPackageNameLPr(packageName);
ArraySet<Long> deletableKeys = new ArraySet<Long>();
- ArraySet<Long> knownKeys = null;
- for (Long ks : deletableKeySets) {
- knownKeys = mKeySetMapping.get(ks);
+ final int origDksSize = deletableKeySets.size();
+ for (int i = 0; i < origDksSize; i++) {
+ ArraySet<Long> knownKeys = mKeySetMapping.get(deletableKeySets.valueAt(i));
if (knownKeys != null) {
deletableKeys.addAll(knownKeys);
}
@@ -429,9 +429,9 @@ public class KeySetManagerService {
}
ArraySet<Long> knownKeySets = getOriginalKeySetsByPackageNameLPr(pkgName);
deletableKeySets.removeAll(knownKeySets);
- knownKeys = new ArraySet<Long>();
- for (Long ks : knownKeySets) {
- knownKeys = mKeySetMapping.get(ks);
+ final int kksSize = knownKeySets.size();
+ for (int i = 0; i < kksSize; i++) {
+ ArraySet<Long> knownKeys = mKeySetMapping.get(knownKeySets.valueAt(i));
if (knownKeys != null) {
deletableKeys.removeAll(knownKeys);
}
@@ -440,18 +440,22 @@ public class KeySetManagerService {
// The remaining keys and KeySets are not relied on by any other
// application and so can be safely deleted.
- for (Long ks : deletableKeySets) {
+ final int dksSize = deletableKeySets.size();
+ for (int i = 0; i < dksSize; i++) {
+ Long ks = deletableKeySets.valueAt(i);
mKeySets.delete(ks);
mKeySetMapping.delete(ks);
}
- for (Long keyId : deletableKeys) {
- mPublicKeys.delete(keyId);
+ final int dkSize = deletableKeys.size();
+ for (int i = 0; i < dkSize; i++) {
+ mPublicKeys.delete(deletableKeys.valueAt(i));
}
// Now remove the deleted KeySets from each package's signingKeySets
for (String pkgName : mPackages.keySet()) {
PackageSetting p = mPackages.get(pkgName);
- for (Long ks : deletableKeySets) {
+ for (int i = 0; i < dksSize; i++) {
+ Long ks = deletableKeySets.valueAt(i);
p.keySetData.removeSigningKeySet(ks);
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 2729392..e4f5e7d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -917,6 +917,7 @@ public class UserManagerService extends IUserManager.Stub {
writeBoolean(serializer, restrictions, UserManager.DISALLOW_CREATE_WINDOWS);
writeBoolean(serializer, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
writeBoolean(serializer, restrictions, UserManager.DISALLOW_OUTGOING_BEAM);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_WALLPAPER);
serializer.endTag(null, TAG_RESTRICTIONS);
}
@@ -1063,6 +1064,7 @@ public class UserManagerService extends IUserManager.Stub {
readBoolean(parser, restrictions, UserManager.DISALLOW_CREATE_WINDOWS);
readBoolean(parser, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
readBoolean(parser, restrictions, UserManager.DISALLOW_OUTGOING_BEAM);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_WALLPAPER);
}
private void readBoolean(XmlPullParser parser, Bundle restrictions,
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 9746142..62e7af4 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -380,7 +380,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean mHasSoftInput = false;
boolean mTranslucentDecorEnabled = true;
boolean mUseTvRouting;
- boolean mUseMasterVolume;
int mPointerLocationMode = 0; // guarded by mLock
@@ -540,6 +539,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private boolean mAllowTheaterModeWakeFromLidSwitch;
private boolean mAllowTheaterModeWakeFromWakeGesture;
+ // Whether to support long press from power button in non-interactive mode
+ private boolean mSupportLongPressPowerWhenNonInteractive;
+
// Whether to go to sleep entering theater mode from power button
private boolean mGoToSleepOnButtonPressTheaterMode;
@@ -886,12 +888,21 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
} else {
wakeUpFromPowerKey(event.getDownTime());
- final int maxCount = getMaxMultiPressPowerCount();
- if (maxCount <= 1) {
- mPowerKeyHandled = true;
- } else {
+ if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
+ Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg,
+ ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
mBeganFromNonInteractive = true;
+ } else {
+ final int maxCount = getMaxMultiPressPowerCount();
+
+ if (maxCount <= 1) {
+ mPowerKeyHandled = true;
+ } else {
+ mBeganFromNonInteractive = true;
+ }
}
}
}
@@ -1260,6 +1271,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mGoToSleepOnButtonPressTheaterMode = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_goToSleepOnButtonPressTheaterMode);
+ mSupportLongPressPowerWhenNonInteractive = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_supportLongPressPowerWhenNonInteractive);
+
mShortPressOnPowerBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shortPressOnPowerBehavior);
mLongPressOnPowerBehavior = mContext.getResources().getInteger(
@@ -1270,8 +1284,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
com.android.internal.R.integer.config_triplePressOnPowerBehavior);
mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
- mUseMasterVolume = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_useMasterVolume);
readConfigurationDependentBehaviors();
@@ -4859,26 +4871,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
try {
- if (mUseMasterVolume) {
- getAudioService().adjustMasterVolume(AudioManager.ADJUST_RAISE, flags,
- pkgName);
- } else {
- getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
- AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
- }
+ getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
+ AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
} catch (RemoteException e) {
Log.e(TAG, "Error dispatching volume up in dispatchTvAudioEvent.", e);
}
break;
case KeyEvent.KEYCODE_VOLUME_DOWN:
try {
- if (mUseMasterVolume) {
- getAudioService().adjustMasterVolume(AudioManager.ADJUST_LOWER, flags,
- pkgName);
- } else {
- getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
- AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
- }
+ getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
+ AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
} catch (RemoteException e) {
Log.e(TAG, "Error dispatching volume down in dispatchTvAudioEvent.", e);
}
@@ -4886,14 +4888,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_VOLUME_MUTE:
try {
if (event.getRepeatCount() == 0) {
- if (mUseMasterVolume) {
- getAudioService().adjustMasterVolume(AudioManager.ADJUST_TOGGLE_MUTE,
- flags, pkgName);
- } else {
- getAudioService().adjustSuggestedStreamVolume(
- AudioManager.ADJUST_TOGGLE_MUTE,
- AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
- }
+ getAudioService().adjustSuggestedStreamVolume(
+ AudioManager.ADJUST_TOGGLE_MUTE,
+ AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName);
}
} catch (RemoteException e) {
Log.e(TAG, "Error dispatching mute in dispatchTvAudioEvent.", e);
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index c3fc195..75c33af 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -5,6 +5,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.os.IBinder;
@@ -27,9 +28,6 @@ import com.android.internal.policy.IKeyguardShowCallback;
* local or remote instances of keyguard.
*/
public class KeyguardServiceDelegate {
- public static final String KEYGUARD_PACKAGE = "com.android.systemui";
- public static final String KEYGUARD_CLASS = "com.android.systemui.keyguard.KeyguardService";
-
private static final String TAG = "KeyguardServiceDelegate";
private static final boolean DEBUG = true;
@@ -111,10 +109,15 @@ public class KeyguardServiceDelegate {
public void bindService(Context context) {
Intent intent = new Intent();
- intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
+ final Resources resources = context.getApplicationContext().getResources();
+
+ final ComponentName keyguardComponent = ComponentName.unflattenFromString(
+ resources.getString(com.android.internal.R.string.config_keyguardComponent));
+ intent.setComponent(keyguardComponent);
+
if (!context.bindServiceAsUser(intent, mKeyguardConnection,
Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
- Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
+ Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
mKeyguardState.showing = false;
mKeyguardState.showingAndNotOccluded = false;
mKeyguardState.secure = false;
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 57b204d..583cc6b 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -395,6 +395,7 @@ public class TrustAgentWrapper {
}
public void destroy() {
+ mContext.unregisterReceiver(mBroadcastReceiver);
mHandler.removeMessages(MSG_RESTART_TIMEOUT);
if (!mBound) {
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index e57396f..ac8ad30 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -102,7 +102,6 @@ class TvInputHardwareManager implements TvInputHal.Callback {
};
private int mCurrentIndex = 0;
private int mCurrentMaxIndex = 0;
- private final boolean mUseMasterVolume;
// TODO: Should handle STANDBY case.
private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
@@ -117,8 +116,6 @@ class TvInputHardwareManager implements TvInputHal.Callback {
mContext = context;
mListener = listener;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- mUseMasterVolume = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_useMasterVolume);
mHal.init();
}
@@ -139,12 +136,10 @@ class TvInputHardwareManager implements TvInputHal.Callback {
} else {
Slog.w(TAG, "HdmiControlService is not available");
}
- if (!mUseMasterVolume) {
- final IntentFilter filter = new IntentFilter();
- filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
- filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
- mContext.registerReceiver(mVolumeReceiver, filter);
- }
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
+ filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
+ mContext.registerReceiver(mVolumeReceiver, filter);
updateVolume();
}
}
@@ -545,7 +540,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
private float getMediaStreamVolume() {
- return mUseMasterVolume ? 1.0f : ((float) mCurrentIndex / (float) mCurrentMaxIndex);
+ return (float) mCurrentIndex / (float) mCurrentMaxIndex;
}
private class Connection implements IBinder.DeathRecipient {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index b48fadb..99cf8df 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -20,6 +20,7 @@ import static android.os.ParcelFileDescriptor.*;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
+import android.app.AppOpsManager;
import android.app.IUserSwitchObserver;
import android.app.IWallpaperManager;
import android.app.IWallpaperManagerCallback;
@@ -164,6 +165,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
final IWindowManager mIWindowManager;
final IPackageManager mIPackageManager;
final MyPackageMonitor mMonitor;
+ final AppOpsManager mAppOpsManager;
WallpaperData mLastWallpaper;
/**
@@ -478,6 +480,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
mIWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
mIPackageManager = AppGlobals.getPackageManager();
+ mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mMonitor = new MyPackageMonitor();
mMonitor.register(context, null, UserHandle.ALL, true);
getWallpaperDir(UserHandle.USER_OWNER).mkdirs();
@@ -613,8 +616,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
- public void clearWallpaper() {
+ public void clearWallpaper(String callingPackage) {
if (DEBUG) Slog.v(TAG, "clearWallpaper");
+ checkPermission(android.Manifest.permission.SET_WALLPAPER);
+ if (!isWallpaperSupported(callingPackage)) {
+ return;
+ }
synchronized (mLock) {
clearWallpaperLocked(false, UserHandle.getCallingUserId(), null);
}
@@ -622,6 +629,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
void clearWallpaperLocked(boolean defaultFailed, int userId, IRemoteCallback reply) {
WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ return;
+ }
File f = new File(getWallpaperDir(userId), WALLPAPER);
if (f.exists()) {
f.delete();
@@ -668,6 +678,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
Binder.restoreCallingIdentity(ident);
}
for (UserInfo user: users) {
+ // ignore managed profiles
+ if (user.isManagedProfile()) {
+ continue;
+ }
WallpaperData wd = mWallpaperMap.get(user.id);
if (wd == null) {
// User hasn't started yet, so load her settings to peek at the wallpaper
@@ -690,8 +704,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
return p;
}
- public void setDimensionHints(int width, int height) throws RemoteException {
+ public void setDimensionHints(int width, int height, String callingPackage)
+ throws RemoteException {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
+ if (!isWallpaperSupported(callingPackage)) {
+ return;
+ }
synchronized (mLock) {
int userId = UserHandle.getCallingUserId();
WallpaperData wallpaper = mWallpaperMap.get(userId);
@@ -733,19 +751,30 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
public int getWidthHint() throws RemoteException {
synchronized (mLock) {
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
- return wallpaper.width;
+ if (wallpaper != null) {
+ return wallpaper.width;
+ } else {
+ return 0;
+ }
}
}
public int getHeightHint() throws RemoteException {
synchronized (mLock) {
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
- return wallpaper.height;
+ if (wallpaper != null) {
+ return wallpaper.height;
+ } else {
+ return 0;
+ }
}
}
- public void setDisplayPadding(Rect padding) {
+ public void setDisplayPadding(Rect padding, String callingPackage) {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
+ if (!isWallpaperSupported(callingPackage)) {
+ return;
+ }
synchronized (mLock) {
int userId = UserHandle.getCallingUserId();
WallpaperData wallpaper = mWallpaperMap.get(userId);
@@ -791,6 +820,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
wallpaperUserId = UserHandle.getUserId(callingUid);
}
WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId);
+ if (wallpaper == null) {
+ return null;
+ }
try {
if (outParams != null) {
outParams.putInt("width", wallpaper.width);
@@ -814,15 +846,18 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
int userId = UserHandle.getCallingUserId();
synchronized (mLock) {
WallpaperData wallpaper = mWallpaperMap.get(userId);
- if (wallpaper.connection != null) {
+ if (wallpaper != null && wallpaper.connection != null) {
return wallpaper.connection.mInfo;
}
return null;
}
}
- public ParcelFileDescriptor setWallpaper(String name) {
+ public ParcelFileDescriptor setWallpaper(String name, String callingPackage) {
checkPermission(android.Manifest.permission.SET_WALLPAPER);
+ if (!isWallpaperSupported(callingPackage)) {
+ return null;
+ }
synchronized (mLock) {
if (DEBUG) Slog.v(TAG, "setWallpaper");
int userId = UserHandle.getCallingUserId();
@@ -868,6 +903,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
return null;
}
+ public void setWallpaperComponentChecked(ComponentName name, String callingPackage) {
+ if (isWallpaperSupported(callingPackage)) {
+ setWallpaperComponent(name);
+ }
+ }
+
+ // ToDo: Remove this version of the function
public void setWallpaperComponent(ComponentName name) {
checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
synchronized (mLock) {
@@ -1097,6 +1139,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ /**
+ * Certain user types do not support wallpapers (e.g. managed profiles). The check is
+ * implemented through through the OP_WRITE_WALLPAPER AppOp.
+ */
+ public boolean isWallpaperSupported(String callingPackage) {
+ return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_WRITE_WALLPAPER, Binder.getCallingUid(),
+ callingPackage) == AppOpsManager.MODE_ALLOWED;
+ }
+
private static JournaledFile makeJournaledFile(int userId) {
final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
return new JournaledFile(new File(base), new File(base + ".tmp"));
@@ -1174,7 +1225,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
private void loadSettingsLocked(int userId) {
if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
-
+
JournaledFile journal = makeJournaledFile(userId);
FileInputStream stream = null;
File file = journal.chooseForRead();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 57ed876..ea59d4b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -53,6 +53,7 @@ class DeviceOwner {
private static final String DEVICE_OWNER_XML = "device_owner.xml";
private static final String TAG_DEVICE_OWNER = "device-owner";
+ private static final String TAG_DEVICE_INITIALIZER = "device-initializer";
private static final String TAG_PROFILE_OWNER = "profile-owner";
private static final String ATTR_NAME = "name";
private static final String ATTR_PACKAGE = "package";
@@ -68,6 +69,9 @@ class DeviceOwner {
// Internal state for the device owner package.
private OwnerInfo mDeviceOwner;
+ // Internal state for the device initializer package.
+ private OwnerInfo mDeviceInitializer;
+
// Internal state for the profile owner packages.
private final HashMap<Integer, OwnerInfo> mProfileOwners = new HashMap<Integer, OwnerInfo>();
@@ -104,6 +108,15 @@ class DeviceOwner {
}
/**
+ * Creates an instance of the device owner object with the device initializer set.
+ */
+ static DeviceOwner createWithDeviceInitializer(String packageName, String ownerName) {
+ DeviceOwner owner = new DeviceOwner();
+ owner.mDeviceInitializer = new OwnerInfo(ownerName, packageName);
+ return owner;
+ }
+
+ /**
* Creates an instance of the device owner object with the profile owner set.
*/
static DeviceOwner createWithProfileOwner(ComponentName admin, String ownerName, int userId) {
@@ -128,6 +141,26 @@ class DeviceOwner {
mDeviceOwner = null;
}
+ String getDeviceInitializerPackageName() {
+ return mDeviceInitializer != null ? mDeviceInitializer.packageName : null;
+ }
+
+ String getDeviceInitializerName() {
+ return mDeviceInitializer != null ? mDeviceInitializer.name : null;
+ }
+
+ void setDeviceInitializer(String packageName, String ownerName) {
+ mDeviceInitializer = new OwnerInfo(ownerName, packageName);
+ }
+
+ void clearDeviceInitializer() {
+ mDeviceInitializer = null;
+ }
+
+ boolean hasDeviceInitializer() {
+ return mDeviceInitializer != null;
+ }
+
void setProfileOwner(ComponentName admin, String ownerName, int userId) {
mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
}
@@ -199,6 +232,10 @@ class DeviceOwner {
String name = parser.getAttributeValue(null, ATTR_NAME);
String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
mDeviceOwner = new OwnerInfo(name, packageName);
+ } else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+ mDeviceInitializer = new OwnerInfo(name, packageName);
} else if (tag.equals(TAG_PROFILE_OWNER)) {
String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
@@ -259,6 +296,16 @@ class DeviceOwner {
out.endTag(null, TAG_DEVICE_OWNER);
}
+ // Write device initializer tag
+ if (mDeviceInitializer != null) {
+ out.startTag(null, TAG_DEVICE_INITIALIZER);
+ out.attribute(null, ATTR_PACKAGE, mDeviceInitializer.packageName);
+ if (mDeviceInitializer.name != null) {
+ out.attribute(null, ATTR_NAME, mDeviceInitializer.name);
+ }
+ out.endTag(null, TAG_DEVICE_INITIALIZER);
+ }
+
// Write profile owner tags
if (mProfileOwners.size() > 0) {
for (HashMap.Entry<Integer, OwnerInfo> owner : mProfileOwners.entrySet()) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a19cd9f..00d7971 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -51,6 +51,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
+import android.graphics.Bitmap;
import android.hardware.usb.UsbManager;
import android.media.AudioManager;
import android.media.IAudioService;
@@ -179,6 +180,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_SMS);
}
+ // The following user restrictions cannot be changed by any active admin, including device
+ // owner and profile owner.
+ private static final Set<String> IMMUTABLE_USER_RESTRICTIONS;
+ static {
+ IMMUTABLE_USER_RESTRICTIONS = new HashSet();
+ IMMUTABLE_USER_RESTRICTIONS.add(UserManager.DISALLOW_WALLPAPER);
+ }
+
private static final Set<String> SECURE_SETTINGS_WHITELIST;
private static final Set<String> SECURE_SETTINGS_DEVICEOWNER_WHITELIST;
private static final Set<String> GLOBAL_SETTINGS_WHITELIST;
@@ -1139,13 +1148,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
boolean ownsProfile = (getProfileOwner(userHandle) != null
&& getProfileOwner(userHandle).getPackageName()
.equals(admin.info.getPackageName()));
+ boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName())
+ && !hasUserSetupCompleted(userHandle);
if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
- if (ownsDevice) {
+ if (ownsDevice || (userHandle == UserHandle.USER_OWNER && ownsInitialization)) {
return admin;
}
} else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
- if (ownsDevice || ownsProfile) {
+ if (ownsDevice || ownsProfile || ownsInitialization) {
return admin;
}
} else {
@@ -1899,7 +1910,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return;
}
if (admin.getUid() != Binder.getCallingUid()) {
- // If trying to remove device owner, refuse when the caller is not the owner.
+ // Active device owners must remain active admins.
if (isDeviceOwner(adminReceiver.getPackageName())) {
return;
}
@@ -3866,6 +3877,110 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
+ public boolean setDeviceInitializer(ComponentName who, ComponentName initializer,
+ String ownerName) {
+ if (!mHasFeature) {
+ return false;
+ }
+ if (initializer == null || !DeviceOwner.isInstalled(
+ initializer.getPackageName(), mContext.getPackageManager())) {
+ throw new IllegalArgumentException("Invalid component name " + initializer
+ + " for device initializer");
+ }
+ synchronized (this) {
+ enforceCanSetDeviceInitializer(who);
+
+ if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
+ throw new IllegalStateException(
+ "Trying to set device initializer but device initializer is already set.");
+ }
+
+ if (mDeviceOwner == null) {
+ // Device owner state does not exist, create it.
+ mDeviceOwner = DeviceOwner.createWithDeviceInitializer(
+ initializer.getPackageName(), ownerName);
+ mDeviceOwner.writeOwnerFile();
+ return true;
+ } else {
+ // Device owner already exists, update it.
+ mDeviceOwner.setDeviceInitializer(initializer.getPackageName(), ownerName);
+ mDeviceOwner.writeOwnerFile();
+ return true;
+ }
+ }
+ }
+
+ private void enforceCanSetDeviceInitializer(ComponentName who) {
+ if (who == null) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
+ if (hasUserSetupCompleted(UserHandle.USER_OWNER)) {
+ throw new IllegalStateException(
+ "Trying to set device initializer but device is already provisioned.");
+ }
+ } else {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ }
+ }
+
+ @Override
+ public boolean isDeviceInitializer(String packageName) {
+ if (!mHasFeature) {
+ return false;
+ }
+ synchronized (this) {
+ return mDeviceOwner != null
+ && mDeviceOwner.hasDeviceInitializer()
+ && mDeviceOwner.getDeviceInitializerPackageName().equals(packageName);
+ }
+ }
+
+ @Override
+ public String getDeviceInitializer() {
+ if (!mHasFeature) {
+ return null;
+ }
+ synchronized (this) {
+ if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
+ return mDeviceOwner.getDeviceInitializerPackageName();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void clearDeviceInitializer(ComponentName who) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, UserHandle.getCallingUserId());
+
+ if (admin.getUid() != Binder.getCallingUid()) {
+ throw new SecurityException("Admin " + who + " is not owned by uid "
+ + Binder.getCallingUid());
+ }
+
+ if (!isDeviceInitializer(admin.info.getPackageName())
+ && !isDeviceOwner(admin.info.getPackageName())) {
+ throw new SecurityException(
+ "clearDeviceInitializer can only be called by the device initializer/owner");
+ }
+ synchronized (this) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ if (mDeviceOwner != null) {
+ mDeviceOwner.clearDeviceInitializer();
+ mDeviceOwner.writeOwnerFile();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @Override
public boolean setProfileOwner(ComponentName who, String ownerName, int userHandle) {
if (!mHasFeature) {
return false;
@@ -3938,7 +4053,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Bundle userRestrictions = mUserManager.getUserRestrictions();
mUserManager.setUserRestrictions(new Bundle(), userHandle);
if (userRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)) {
- audioManager.adjustMasterVolume(AudioManager.ADJUST_UNMUTE, 0);
+ audioManager.setMasterMute(false, 0);
}
if (userRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE)) {
audioManager.setMicrophoneMute(false);
@@ -3960,6 +4075,51 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
+ public boolean setUserEnabled(ComponentName who) {
+ if (!mHasFeature) {
+ return false;
+ }
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ int userId = UserHandle.getCallingUserId();
+
+ ActiveAdmin activeAdmin =
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!isDeviceInitializer(activeAdmin.info.getPackageName())) {
+ throw new SecurityException(
+ "This method can only be called by device initializers");
+ }
+
+ long id = Binder.clearCallingIdentity();
+ try {
+ if (!isDeviceOwner(activeAdmin.info.getPackageName())) {
+ IPackageManager ipm = AppGlobals.getPackageManager();
+ ipm.setComponentEnabledSetting(who,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP, userId);
+
+ removeActiveAdmin(who, userId);
+ }
+
+ if (userId == UserHandle.USER_OWNER) {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 1);
+ }
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 1, userId);
+ } catch (RemoteException e) {
+ Log.i(LOG_TAG, "Can't talk to package manager", e);
+ return false;
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ return true;
+ }
+ }
+
+ @Override
public void setProfileEnabled(ComponentName who) {
if (!mHasFeature) {
return;
@@ -4801,6 +4961,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
&& DEVICE_OWNER_USER_RESTRICTIONS.contains(key)) {
throw new SecurityException("Profile owners cannot set user restriction " + key);
}
+ if (IMMUTABLE_USER_RESTRICTIONS.contains(key)) {
+ throw new SecurityException("User restriction " + key + " cannot be changed");
+ }
boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user);
IAudioService iAudioService = null;
@@ -4815,8 +4978,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
iAudioService.setMicrophoneMute(true, who.getPackageName());
} else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
- iAudioService.adjustMasterVolume(AudioManager.ADJUST_MUTE, 0,
- who.getPackageName());
+ iAudioService.setMasterMute(true, 0, who.getPackageName());
}
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
@@ -4881,8 +5043,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
iAudioService.setMicrophoneMute(false, who.getPackageName());
} else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
- iAudioService.adjustMasterVolume(AudioManager.ADJUST_UNMUTE, 0,
- who.getPackageName());
+ iAudioService.setMasterMute(false, 0, who.getPackageName());
}
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
@@ -5322,10 +5483,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
IAudioService iAudioService = IAudioService.Stub.asInterface(
ServiceManager.getService(Context.AUDIO_SERVICE));
- try{
- iAudioService.adjustMasterVolume(
- on ? AudioManager.ADJUST_MUTE : AudioManager.ADJUST_UNMUTE, 0,
- who.getPackageName());
+ try {
+ iAudioService.setMasterMute(on, 0, who.getPackageName());
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Failed to setMasterMute", re);
}
@@ -5344,6 +5503,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ @Override
+ public void setUserIcon(ComponentName who, Bitmap icon) {
+ synchronized (this) {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ int userId = UserHandle.getCallingUserId();
+ long id = Binder.clearCallingIdentity();
+ try {
+ mUserManager.setUserIcon(userId, icon);
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+ }
+
/**
* We need to update the internal state of whether a user has completed setup once. After
* that, we ignore any changes that reset the Settings.Secure.USER_SETUP_COMPLETE changes
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cd6e786..a0c7f86 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -669,7 +669,8 @@ public final class SystemServer {
mSystemServiceManager.startService("com.android.server.wifi.RttService");
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET)) {
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
+ mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
}
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index e17abc0..51d61bb 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -19,8 +19,8 @@ package com.android.server.usb;
import android.content.Context;
import android.media.midi.MidiDeviceInfo;
import android.media.midi.MidiDeviceServer;
+import android.media.midi.MidiDispatcher;
import android.media.midi.MidiManager;
-import android.media.midi.MidiPort;
import android.media.midi.MidiReceiver;
import android.media.midi.MidiSender;
import android.os.Bundle;
@@ -30,6 +30,8 @@ import android.system.OsConstants;
import android.system.StructPollfd;
import android.util.Log;
+import libcore.io.IoUtils;
+
import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -39,8 +41,11 @@ import java.io.IOException;
public final class UsbMidiDevice implements Closeable {
private static final String TAG = "UsbMidiDevice";
- private final MidiDeviceServer mServer;
- private final MidiReceiver[] mOutputPortReceivers;
+ private MidiDeviceServer mServer;
+
+ private final MidiReceiver[] mInputPortReceivers;
+
+ private static final int BUFFER_SIZE = 512;
// for polling multiple FileDescriptors for MIDI events
private final StructPollfd[] mPollFDs;
@@ -50,12 +55,6 @@ public final class UsbMidiDevice implements Closeable {
private final FileOutputStream[] mOutputStreams;
public static UsbMidiDevice create(Context context, Bundle properties, int card, int device) {
- MidiManager midiManager = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
- if (midiManager == null) {
- Log.e(TAG, "No MidiManager in UsbMidiDevice.create()");
- return null;
- }
-
// FIXME - support devices with different number of input and output ports
int subDevices = nativeGetSubdeviceCount(card, device);
if (subDevices <= 0) {
@@ -70,19 +69,16 @@ public final class UsbMidiDevice implements Closeable {
return null;
}
- MidiDeviceServer server = midiManager.createDeviceServer(subDevices, subDevices, properties,
- false, MidiDeviceInfo.TYPE_USB);
- if (server == null) {
+ UsbMidiDevice midiDevice = new UsbMidiDevice(fileDescriptors, fileDescriptors);
+ if (!midiDevice.register(context, properties)) {
+ IoUtils.closeQuietly(midiDevice);
Log.e(TAG, "createDeviceServer failed");
return null;
}
-
- return new UsbMidiDevice(server, fileDescriptors, fileDescriptors);
+ return midiDevice;
}
- private UsbMidiDevice(MidiDeviceServer server, FileDescriptor[] inputFiles,
- FileDescriptor[] outputFiles) {
- mServer = server;
+ private UsbMidiDevice(FileDescriptor[] inputFiles, FileDescriptor[] outputFiles) {
int inputCount = inputFiles.length;
int outputCount = outputFiles.length;
@@ -102,30 +98,40 @@ public final class UsbMidiDevice implements Closeable {
mOutputStreams[i] = new FileOutputStream(outputFiles[i]);
}
- mOutputPortReceivers = new MidiReceiver[outputCount];
- for (int port = 0; port < outputCount; port++) {
- mOutputPortReceivers[port] = server.openOutputPortReceiver(port);
- }
-
+ mInputPortReceivers = new MidiReceiver[inputCount];
for (int port = 0; port < inputCount; port++) {
- final int portNumberF = port;
- MidiReceiver receiver = new MidiReceiver() {
-
+ final int portF = port;
+ mInputPortReceivers[port] = new MidiReceiver() {
@Override
- public void post(byte[] data, int offset, int count, long timestamp)
+ public void receive(byte[] data, int offset, int count, long timestamp)
throws IOException {
// FIXME - timestamps are ignored, future posting not supported yet.
- mOutputStreams[portNumberF].write(data, offset, count);
+ mOutputStreams[portF].write(data, offset, count);
}
};
- MidiSender sender = server.openInputPortSender(port);
- sender.connect(receiver);
}
+ }
+ private boolean register(Context context, Bundle properties) {
+ MidiManager midiManager = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
+ if (midiManager == null) {
+ Log.e(TAG, "No MidiManager in UsbMidiDevice.create()");
+ return false;
+ }
+
+ int outputCount = mOutputStreams.length;
+ mServer = midiManager.createDeviceServer(mInputPortReceivers, outputCount,
+ properties, MidiDeviceInfo.TYPE_USB);
+ if (mServer == null) {
+ return false;
+ }
+ final MidiReceiver[] outputReceivers = mServer.getOutputPortReceivers();
+
+ // FIXME can we only run this when we have a dispatcher that has listeners?
new Thread() {
@Override
public void run() {
- byte[] buffer = new byte[MidiPort.MAX_PACKET_DATA_SIZE];
+ byte[] buffer = new byte[BUFFER_SIZE];
try {
boolean done = false;
while (!done) {
@@ -137,8 +143,8 @@ public final class UsbMidiDevice implements Closeable {
pfd.revents = 0;
int count = mInputStreams[index].read(buffer);
- mOutputPortReceivers[index].post(buffer, 0, count,
- System.nanoTime());
+ long timestamp = System.nanoTime();
+ outputReceivers[index].receive(buffer, 0, count, timestamp);
} else if ((pfd.revents & (OsConstants.POLLERR
| OsConstants.POLLHUP)) != 0) {
done = true;
@@ -155,11 +161,15 @@ public final class UsbMidiDevice implements Closeable {
}
}
}.start();
+
+ return true;
}
@Override
public void close() throws IOException {
- mServer.close();
+ if (mServer != null) {
+ mServer.close();
+ }
for (int i = 0; i < mInputStreams.length; i++) {
mInputStreams[i].close();