diff options
Diffstat (limited to 'services')
4 files changed, 382 insertions, 71 deletions
diff --git a/services/core/java/com/android/server/am/AppTimeTracker.java b/services/core/java/com/android/server/am/AppTimeTracker.java index bddd66f..910f33d 100644 --- a/services/core/java/com/android/server/am/AppTimeTracker.java +++ b/services/core/java/com/android/server/am/AppTimeTracker.java @@ -80,12 +80,12 @@ public class AppTimeTracker { public void deliverResult(Context context) { stop(); Bundle extras = new Bundle(); - extras.putLong(ActivityOptions.EXTRA_USAGE_REPORT_TIME, mTotalTime); + extras.putLong(ActivityOptions.EXTRA_USAGE_TIME_REPORT, mTotalTime); Bundle pkgs = new Bundle(); for (int i=mPackageTimes.size()-1; i>=0; i--) { pkgs.putLong(mPackageTimes.keyAt(i), mPackageTimes.valueAt(i).value); } - extras.putBundle(ActivityOptions.EXTRA_USAGE_REPORT_PACKAGES, pkgs); + extras.putBundle(ActivityOptions.EXTRA_USAGE_TIME_REPORT_PACKAGES, pkgs); Intent fillinIntent = new Intent(); fillinIntent.putExtras(extras); try { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 939bb1a..604ac97 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -6166,9 +6166,16 @@ public class PackageManagerService extends IPackageManager.Stub { } } else { if (!checkUpgradeKeySetLP(pkgSetting, pkg)) { - throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " - + pkg.packageName + " upgrade keys do not match the " - + "previously installed version"); + if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { + throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, + "Package " + pkg.packageName + " upgrade keys do not match the " + + "previously installed version"); + } else { + pkgSetting.signatures.mSignatures = pkg.mSignatures; + String msg = "System package " + pkg.packageName + + " signature changed; retaining data."; + reportSettingsProblem(Log.WARN, msg); + } } else { // We just determined the app is signed correctly, so bring // over the latest parsed certs. diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 3305e1e..6dc1183 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -208,7 +208,7 @@ public class WindowAnimator { // Only hide windows if the keyguard is active and not animating away. boolean keyguardOn = mPolicy.isKeyguardShowingOrOccluded() && mForceHiding != KEYGUARD_ANIMATING_OUT; - return keyguardOn && hideWhenLocked; + return keyguardOn && hideWhenLocked && (win.getDisplayId() == Display.DEFAULT_DISPLAY); } private void updateWindowsLocked(final int displayId) { diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java index 370f125..d1bbbfc 100644 --- a/services/midi/java/com/android/server/midi/MidiService.java +++ b/services/midi/java/com/android/server/midi/MidiService.java @@ -16,8 +16,11 @@ package com.android.server.midi; +import android.bluetooth.BluetoothDevice; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -25,11 +28,13 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.XmlResourceParser; import android.media.midi.IMidiDeviceListener; +import android.media.midi.IMidiDeviceOpenCallback; import android.media.midi.IMidiDeviceServer; import android.media.midi.IMidiManager; import android.media.midi.MidiDeviceInfo; import android.media.midi.MidiDeviceService; import android.media.midi.MidiDeviceStatus; +import android.media.midi.MidiManager; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -78,6 +83,10 @@ public class MidiService extends IMidiManager.Stub { private final HashMap<MidiDeviceInfo, Device> mDevicesByInfo = new HashMap<MidiDeviceInfo, Device>(); + // list of all Bluetooth devices, keyed by BluetoothDevice + private final HashMap<BluetoothDevice, Device> mBluetoothDevices + = new HashMap<BluetoothDevice, Device>(); + // list of all devices, keyed by IMidiDeviceServer private final HashMap<IBinder, Device> mDevicesByServer = new HashMap<IBinder, Device>(); @@ -86,6 +95,9 @@ public class MidiService extends IMidiManager.Stub { private final PackageManager mPackageManager; + // UID of BluetoothMidiService + private final int mBluetoothServiceUid; + // PackageMonitor for listening to package changes private final PackageMonitor mPackageMonitor = new PackageMonitor() { @Override @@ -115,6 +127,9 @@ public class MidiService extends IMidiManager.Stub { // List of all receivers for this client private final ArrayList<IMidiDeviceListener> mListeners = new ArrayList<IMidiDeviceListener>(); + // List of all device connections for this client + private final HashMap<IBinder, DeviceConnection> mDeviceConnections + = new HashMap<IBinder, DeviceConnection>(); public Client(IBinder token) { mToken = token; @@ -132,8 +147,33 @@ public class MidiService extends IMidiManager.Stub { public void removeListener(IMidiDeviceListener listener) { mListeners.remove(listener); - if (mListeners.size() == 0) { - removeClient(mToken); + if (mListeners.size() == 0 && mDeviceConnections.size() == 0) { + close(); + } + } + + public void addDeviceConnection(Device device, IMidiDeviceOpenCallback callback) { + DeviceConnection connection = new DeviceConnection(device, this, callback); + mDeviceConnections.put(connection.getToken(), connection); + device.addDeviceConnection(connection); + } + + // called from MidiService.closeDevice() + public void removeDeviceConnection(IBinder token) { + DeviceConnection connection = mDeviceConnections.remove(token); + if (connection != null) { + connection.getDevice().removeDeviceConnection(connection); + } + if (mListeners.size() == 0 && mDeviceConnections.size() == 0) { + close(); + } + } + + // called from Device.close() + public void removeDeviceConnection(DeviceConnection connection) { + mDeviceConnections.remove(connection.getToken()); + if (mListeners.size() == 0 && mDeviceConnections.size() == 0) { + close(); } } @@ -178,8 +218,21 @@ public class MidiService extends IMidiManager.Stub { } } + private void close() { + synchronized (mClients) { + mClients.remove(mToken); + mToken.unlinkToDeath(this, 0); + } + + for (DeviceConnection connection : mDeviceConnections.values()) { + connection.getDevice().removeDeviceConnection(connection); + } + } + + @Override public void binderDied() { - removeClient(mToken); + Log.d(TAG, "Client died: " + this); + close(); } @Override @@ -190,6 +243,12 @@ public class MidiService extends IMidiManager.Stub { sb.append(mPid); sb.append(" listener count: "); sb.append(mListeners.size()); + sb.append(" Device Connections:"); + for (DeviceConnection connection : mDeviceConnections.values()) { + sb.append(" <device "); + sb.append(connection.getDevice().getDeviceInfo().getId()); + sb.append(">"); + } return sb.toString(); } } @@ -211,57 +270,96 @@ public class MidiService extends IMidiManager.Stub { } } - private void removeClient(IBinder token) { - mClients.remove(token); - } - private final class Device implements IBinder.DeathRecipient { - private final IMidiDeviceServer mServer; - private final MidiDeviceInfo mDeviceInfo; + private IMidiDeviceServer mServer; + private MidiDeviceInfo mDeviceInfo; + private final BluetoothDevice mBluetoothDevice; private MidiDeviceStatus mDeviceStatus; - private IBinder mDeviceStatusToken; + // ServiceInfo for the device's MidiDeviceServer implementation (virtual devices only) private final ServiceInfo mServiceInfo; // UID of device implementation private final int mUid; + // ServiceConnection for implementing Service (virtual devices only) + // mServiceConnection is non-null when connected or attempting to connect to the service + private ServiceConnection mServiceConnection; + + // List of all device connections for this device + private final ArrayList<DeviceConnection> mDeviceConnections + = new ArrayList<DeviceConnection>(); + public Device(IMidiDeviceServer server, MidiDeviceInfo deviceInfo, ServiceInfo serviceInfo, int uid) { - mServer = server; mDeviceInfo = deviceInfo; mServiceInfo = serviceInfo; mUid = uid; + mBluetoothDevice = (BluetoothDevice)deviceInfo.getProperties().getParcelable( + MidiDeviceInfo.PROPERTY_BLUETOOTH_DEVICE);; + setDeviceServer(server); + } + + public Device(BluetoothDevice bluetoothDevice) { + mBluetoothDevice = bluetoothDevice; + mServiceInfo = null; + mUid = mBluetoothServiceUid; + } + + private void setDeviceServer(IMidiDeviceServer server) { + if (server != null) { + if (mServer != null) { + Log.e(TAG, "mServer already set in setDeviceServer"); + return; + } + IBinder binder = server.asBinder(); + try { + if (mDeviceInfo == null) { + mDeviceInfo = server.getDeviceInfo(); + } + binder.linkToDeath(this, 0); + mServer = server; + } catch (RemoteException e) { + mServer = null; + return; + } + mDevicesByServer.put(binder, this); + } else if (mServer != null) { + server = mServer; + mServer = null; + + IBinder binder = server.asBinder(); + mDevicesByServer.remove(binder); + + try { + server.closeDevice(); + binder.unlinkToDeath(this, 0); + } catch (RemoteException e) { + // nothing to do here + } + } + + if (mDeviceConnections != null) { + for (DeviceConnection connection : mDeviceConnections) { + connection.notifyClient(server); + } + } } public MidiDeviceInfo getDeviceInfo() { return mDeviceInfo; } + // only used for bluetooth devices, which are created before we have a MidiDeviceInfo + public void setDeviceInfo(MidiDeviceInfo deviceInfo) { + mDeviceInfo = deviceInfo; + } + public MidiDeviceStatus getDeviceStatus() { return mDeviceStatus; } - public void setDeviceStatus(IBinder token, MidiDeviceStatus status) { + public void setDeviceStatus(MidiDeviceStatus status) { mDeviceStatus = status; - - if (mDeviceStatusToken == null && token != null) { - // register a death recipient so we can clear the status when the device dies - try { - token.linkToDeath(new IBinder.DeathRecipient() { - @Override - public void binderDied() { - // reset to default status and clear the token - mDeviceStatus = new MidiDeviceStatus(mDeviceInfo); - mDeviceStatusToken = null; - notifyDeviceStatusChanged(Device.this, mDeviceStatus); - } - }, 0); - mDeviceStatusToken = token; - } catch (RemoteException e) { - // reset to default status - mDeviceStatus = new MidiDeviceStatus(mDeviceInfo); - } - } } public IMidiDeviceServer getDeviceServer() { @@ -284,11 +382,102 @@ public class MidiService extends IMidiManager.Stub { return (!mDeviceInfo.isPrivate() || mUid == uid); } + public void addDeviceConnection(DeviceConnection connection) { + synchronized (mDeviceConnections) { + if (mServer != null) { + mDeviceConnections.add(connection); + connection.notifyClient(mServer); + } else if (mServiceConnection == null && + (mServiceInfo != null || mBluetoothDevice != null)) { + mDeviceConnections.add(connection); + + mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + IMidiDeviceServer server = IMidiDeviceServer.Stub.asInterface(service); + setDeviceServer(server); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + setDeviceServer(null); + mServiceConnection = null; + } + }; + + Intent intent; + if (mBluetoothDevice != null) { + intent = new Intent(MidiManager.BLUETOOTH_MIDI_SERVICE_INTENT); + intent.setComponent(new ComponentName( + MidiManager.BLUETOOTH_MIDI_SERVICE_PACKAGE, + MidiManager.BLUETOOTH_MIDI_SERVICE_CLASS)); + intent.putExtra("device", mBluetoothDevice); + } else { + intent = new Intent(MidiDeviceService.SERVICE_INTERFACE); + intent.setComponent( + new ComponentName(mServiceInfo.packageName, mServiceInfo.name)); + } + + if (!mContext.bindService(intent, mServiceConnection, + Context.BIND_AUTO_CREATE)) { + Log.e(TAG, "Unable to bind service: " + intent); + setDeviceServer(null); + mServiceConnection = null; + } + } else { + Log.e(TAG, "No way to connect to device in addDeviceConnection"); + connection.notifyClient(null); + } + } + } + + public void removeDeviceConnection(DeviceConnection connection) { + synchronized (mDeviceConnections) { + mDeviceConnections.remove(connection); + + if (mDeviceConnections.size() == 0 && mServiceConnection != null) { + mContext.unbindService(mServiceConnection); + mServiceConnection = null; + if (mBluetoothDevice != null) { + // Bluetooth devices are ephemeral - remove when no clients exist + synchronized (mDevicesByInfo) { + closeLocked(); + } + } else { + setDeviceServer(null); + } + } + } + } + + // synchronize on mDevicesByInfo + public void closeLocked() { + synchronized (mDeviceConnections) { + for (DeviceConnection connection : mDeviceConnections) { + connection.getClient().removeDeviceConnection(connection); + } + mDeviceConnections.clear(); + } + setDeviceServer(null); + + // closed virtual devices should not be removed from mDevicesByInfo + // since they can be restarted on demand + if (mServiceInfo == null) { + removeDeviceLocked(this); + } else { + mDeviceStatus = new MidiDeviceStatus(mDeviceInfo); + } + + if (mBluetoothDevice != null) { + mBluetoothDevices.remove(mBluetoothDevice); + } + } + + @Override public void binderDied() { + Log.d(TAG, "Device died: " + this); synchronized (mDevicesByInfo) { - if (mDevicesByInfo.remove(mDeviceInfo) != null) { - removeDeviceLocked(this); - } + closeLocked(); } } @@ -300,10 +489,56 @@ public class MidiService extends IMidiManager.Stub { sb.append(mDeviceStatus); sb.append(" UID: "); sb.append(mUid); + sb.append(" DeviceConnection count: "); + sb.append(mDeviceConnections.size()); + sb.append(" mServiceConnection: "); + sb.append(mServiceConnection); return sb.toString(); } } + // Represents a connection between a client and a device + private final class DeviceConnection { + private final IBinder mToken = new Binder(); + private final Device mDevice; + private final Client mClient; + private IMidiDeviceOpenCallback mCallback; + + public DeviceConnection(Device device, Client client, IMidiDeviceOpenCallback callback) { + mDevice = device; + mClient = client; + mCallback = callback; + } + + public Device getDevice() { + return mDevice; + } + + public Client getClient() { + return mClient; + } + + public IBinder getToken() { + return mToken; + } + + public void notifyClient(IMidiDeviceServer deviceServer) { + if (mCallback != null) { + try { + mCallback.onDeviceOpened(deviceServer, (deviceServer == null ? null : mToken)); + } catch (RemoteException e) { + // Client binderDied() method will do necessary cleanup, so nothing to do here + } + mCallback = null; + } + } + + @Override + public String toString() { + return "DeviceConnection Device ID: " + mDevice.getDeviceInfo().getId(); + } + } + public MidiService(Context context) { mContext = context; mPackageManager = context.getPackageManager(); @@ -321,6 +556,18 @@ public class MidiService extends IMidiManager.Stub { } } } + + PackageInfo info; + try { + info = mPackageManager.getPackageInfo(MidiManager.BLUETOOTH_MIDI_SERVICE_PACKAGE, 0); + } catch (PackageManager.NameNotFoundException e) { + info = null; + } + if (info != null && info.applicationInfo != null) { + mBluetoothServiceUid = info.applicationInfo.uid; + } else { + mBluetoothServiceUid = -1; + } } @Override @@ -355,18 +602,61 @@ public class MidiService extends IMidiManager.Stub { } @Override - public IMidiDeviceServer openDevice(IBinder token, MidiDeviceInfo deviceInfo) { - Device device = mDevicesByInfo.get(deviceInfo); - if (device == null) { - Log.e(TAG, "device not found in openDevice: " + deviceInfo); - return null; + public void openDevice(IBinder token, MidiDeviceInfo deviceInfo, + IMidiDeviceOpenCallback callback) { + Client client = getClient(token); + if (client == null) return; + + Device device; + synchronized (mDevicesByInfo) { + device = mDevicesByInfo.get(deviceInfo); + if (device == null) { + throw new IllegalArgumentException("device does not exist: " + deviceInfo); + } + if (!device.isUidAllowed(Binder.getCallingUid())) { + throw new SecurityException("Attempt to open private device with wrong UID"); + } + } + + // clear calling identity so bindService does not fail + long identity = Binder.clearCallingIdentity(); + try { + client.addDeviceConnection(device, callback); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void openBluetoothDevice(IBinder token, BluetoothDevice bluetoothDevice, + IMidiDeviceOpenCallback callback) { + Client client = getClient(token); + if (client == null) return; + + // Bluetooth devices are created on demand + Device device; + synchronized (mDevicesByInfo) { + device = mBluetoothDevices.get(bluetoothDevice); + if (device == null) { + device = new Device(bluetoothDevice); + mBluetoothDevices.put(bluetoothDevice, device); + } } - if (!device.isUidAllowed(Binder.getCallingUid())) { - throw new SecurityException("Attempt to open private device with wrong UID"); + // clear calling identity so bindService does not fail + long identity = Binder.clearCallingIdentity(); + try { + client.addDeviceConnection(device, callback); + } finally { + Binder.restoreCallingIdentity(identity); } + } - return device.getDeviceServer(); + @Override + public void closeDevice(IBinder clientToken, IBinder deviceToken) { + Client client = getClient(clientToken); + if (client == null) return; + client.removeDeviceConnection(deviceToken); } @Override @@ -376,6 +666,8 @@ public class MidiService extends IMidiManager.Stub { int uid = Binder.getCallingUid(); if (type == MidiDeviceInfo.TYPE_USB && uid != Process.SYSTEM_UID) { throw new SecurityException("only system can create USB devices"); + } else if (type == MidiDeviceInfo.TYPE_BLUETOOTH && uid != mBluetoothServiceUid) { + throw new SecurityException("only MidiBluetoothService can create Bluetooth devices"); } synchronized (mDevicesByInfo) { @@ -389,8 +681,7 @@ public class MidiService extends IMidiManager.Stub { synchronized (mDevicesByInfo) { Device device = mDevicesByServer.get(server.asBinder()); if (device != null) { - mDevicesByInfo.remove(device.getDeviceInfo()); - removeDeviceLocked(device); + device.closeLocked(); } } } @@ -420,19 +711,16 @@ public class MidiService extends IMidiManager.Stub { } @Override - public void setDeviceStatus(IBinder token, MidiDeviceStatus status) { - MidiDeviceInfo deviceInfo = status.getDeviceInfo(); - Device device = mDevicesByInfo.get(deviceInfo); - if (device == null) { - // Just return quietly here if device no longer exists - return; - } - if (Binder.getCallingUid() != device.getUid()) { - throw new SecurityException("setDeviceStatus() caller UID " + Binder.getCallingUid() - + " does not match device's UID " + device.getUid()); + public void setDeviceStatus(IMidiDeviceServer server, MidiDeviceStatus status) { + Device device = mDevicesByServer.get(server.asBinder()); + if (device != null) { + if (Binder.getCallingUid() != device.getUid()) { + throw new SecurityException("setDeviceStatus() caller UID " + Binder.getCallingUid() + + " does not match device's UID " + device.getUid()); + } + device.setDeviceStatus(status); + notifyDeviceStatusChanged(device, status); } - device.setDeviceStatus(token, status); - notifyDeviceStatusChanged(device, status); } private void notifyDeviceStatusChanged(Device device, MidiDeviceStatus status) { @@ -452,18 +740,24 @@ public class MidiService extends IMidiManager.Stub { int id = mNextDeviceId++; MidiDeviceInfo deviceInfo = new MidiDeviceInfo(type, id, numInputPorts, numOutputPorts, inputPortNames, outputPortNames, properties, isPrivate); - Device device = new Device(server, deviceInfo, serviceInfo, uid); - if (server != null) { - IBinder binder = server.asBinder(); - try { - binder.linkToDeath(device, 0); - } catch (RemoteException e) { - return null; + Device device = null; + BluetoothDevice bluetoothDevice = null; + if (type == MidiDeviceInfo.TYPE_BLUETOOTH) { + bluetoothDevice = (BluetoothDevice)properties.getParcelable( + MidiDeviceInfo.PROPERTY_BLUETOOTH_DEVICE); + device = mBluetoothDevices.get(bluetoothDevice); + if (device != null) { + device.setDeviceInfo(deviceInfo); } - mDevicesByServer.put(binder, device); + } + if (device == null) { + device = new Device(server, deviceInfo, serviceInfo, uid); } mDevicesByInfo.put(deviceInfo, device); + if (bluetoothDevice != null) { + mBluetoothDevices.put(bluetoothDevice, device); + } synchronized (mClients) { for (Client c : mClients.values()) { @@ -478,8 +772,9 @@ public class MidiService extends IMidiManager.Stub { private void removeDeviceLocked(Device device) { IMidiDeviceServer server = device.getDeviceServer(); if (server != null) { - mDevicesByServer.remove(server); + mDevicesByServer.remove(server.asBinder()); } + mDevicesByInfo.remove(device.getDeviceInfo()); synchronized (mClients) { for (Client c : mClients.values()) { @@ -516,6 +811,15 @@ public class MidiService extends IMidiManager.Stub { MidiDeviceService.SERVICE_INTERFACE); if (parser == null) return; + // ignore virtual device servers that do not require the correct permission + if (!android.Manifest.permission.BIND_MIDI_DEVICE_SERVICE.equals( + serviceInfo.permission)) { + Log.w(TAG, "Skipping MIDI device service " + serviceInfo.packageName + + ": it does not require the permission " + + android.Manifest.permission.BIND_MIDI_DEVICE_SERVICE); + return; + } + Bundle properties = null; int numInputPorts = 0; int numOutputPorts = 0; |