Merge "Add projection info to RenderNode dumps" into mnc-dev
diff --git a/Android.mk b/Android.mk
index 6bfed8e..68f471a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -343,6 +343,7 @@
media/java/android/media/IVolumeController.aidl \
media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl \
media/java/android/media/midi/IMidiDeviceListener.aidl \
+ media/java/android/media/midi/IMidiDeviceOpenCallback.aidl \
media/java/android/media/midi/IMidiDeviceServer.aidl \
media/java/android/media/midi/IMidiManager.aidl \
media/java/android/media/projection/IMediaProjection.aidl \
diff --git a/api/current.txt b/api/current.txt
index 8fbd593..989a732 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28,6 +28,7 @@
field public static final java.lang.String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
field public static final java.lang.String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
+ field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
@@ -3761,8 +3762,8 @@
method public void requestUsageTimeReport(android.app.PendingIntent);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);
- field public static final java.lang.String EXTRA_USAGE_REPORT_PACKAGES = "android.package";
- field public static final java.lang.String EXTRA_USAGE_REPORT_TIME = "android.time";
+ field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.usage_time";
+ field public static final java.lang.String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
}
public class AlarmManager {
@@ -17360,6 +17361,7 @@
method public final android.media.midi.MidiDeviceInfo getDeviceInfo();
method public final android.media.midi.MidiReceiver[] getOutputPortReceivers();
method public android.os.IBinder onBind(android.content.Intent);
+ method public void onClose();
method public void onDeviceStatusChanged(android.media.midi.MidiDeviceStatus);
method public abstract android.media.midi.MidiReceiver[] onGetInputPortReceivers();
field public static final java.lang.String SERVICE_INTERFACE = "android.media.midi.MidiDeviceService";
diff --git a/api/system-current.txt b/api/system-current.txt
index f7f335d..424da48 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -40,6 +40,7 @@
field public static final java.lang.String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
+ field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
@@ -3854,8 +3855,8 @@
method public void requestUsageTimeReport(android.app.PendingIntent);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);
- field public static final java.lang.String EXTRA_USAGE_REPORT_PACKAGES = "android.package";
- field public static final java.lang.String EXTRA_USAGE_REPORT_TIME = "android.time";
+ field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.usage_time";
+ field public static final java.lang.String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
}
public class AlarmManager {
@@ -18672,6 +18673,7 @@
method public final android.media.midi.MidiDeviceInfo getDeviceInfo();
method public final android.media.midi.MidiReceiver[] getOutputPortReceivers();
method public android.os.IBinder onBind(android.content.Intent);
+ method public void onClose();
method public void onDeviceStatusChanged(android.media.midi.MidiDeviceStatus);
method public abstract android.media.midi.MidiReceiver[] onGetInputPortReceivers();
field public static final java.lang.String SERVICE_INTERFACE = "android.media.midi.MidiDeviceService";
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 9f23b43..6fb997e 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -41,16 +41,16 @@
/**
* A long in the extras delivered by {@link #requestUsageTimeReport} that contains
- * the total time (in ms) the user spent in the app.
+ * the total time (in ms) the user spent in the app flow.
*/
- public static final String EXTRA_USAGE_REPORT_TIME = "android.time";
+ public static final String EXTRA_USAGE_TIME_REPORT = "android.usage_time";
/**
* A Bundle in the extras delivered by {@link #requestUsageTimeReport} that contains
* detailed information about the time spent in each package associated with the app;
* each key is a package name, whose value is a long containing the time (in ms).
*/
- public static final String EXTRA_USAGE_REPORT_PACKAGES = "android.package";
+ public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
/**
* The package name that created the options.
@@ -915,7 +915,7 @@
/**
* Ask the the system track that time the user spends in the app being launched, and
* report it back once done. The report will be sent to the given receiver, with
- * the extras {@link #EXTRA_USAGE_REPORT_TIME} and {@link #EXTRA_USAGE_REPORT_PACKAGES}
+ * the extras {@link #EXTRA_USAGE_TIME_REPORT} and {@link #EXTRA_USAGE_TIME_REPORT_PACKAGES}
* filled in.
*
* <p>The time interval tracked is from launching this activity until the user leaves
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 0d00908..10e8a53 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -691,7 +691,7 @@
@Override
public MidiManager createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(Context.MIDI_SERVICE);
- return new MidiManager(ctx, IMidiManager.Stub.asInterface(b));
+ return new MidiManager(IMidiManager.Stub.asInterface(b));
}});
registerService(Context.RADIO_SERVICE, RadioManager.class,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f32918d..709de9e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1827,6 +1827,11 @@
<permission android:name="android.permission.BIND_INPUT_METHOD"
android:protectionLevel="signature" />
+ <!-- Must be required by an {@link android.media.midi.MidiDeviceService},
+ to ensure that only the system can bind to it. -->
+ <permission android:name="android.permission.BIND_MIDI_DEVICE_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- Must be required by an {@link android.accessibilityservice.AccessibilityService},
to ensure that only the system can bind to it. -->
<permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 1a05104..367257a 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -231,14 +231,6 @@
return list(prefix, UID_SELF);
}
- public String[] saw(String prefix, int uid) {
- return list(prefix, uid);
- }
-
- public String[] saw(String prefix) {
- return saw(prefix, UID_SELF);
- }
-
public boolean reset() {
try {
return mBinder.reset() == NO_ERROR;
@@ -328,23 +320,6 @@
}
}
- public byte[] getPubkey(String key) {
- try {
- return mBinder.get_pubkey(key);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- }
- }
-
- public boolean delKey(String key, int uid) {
- return delete(key, uid);
- }
-
- public boolean delKey(String key) {
- return delKey(key, UID_SELF);
- }
-
public byte[] sign(String key, byte[] data) {
try {
return mBinder.sign(key, data);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
index fd9bdb8..0e8d03e 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
@@ -56,6 +56,7 @@
// Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after
// doFinal finishes.
private boolean mEncrypting;
+ private int mKeymasterPurposeOverride = -1;
private AndroidKeyStoreKey mKey;
private SecureRandom mRng;
@@ -165,6 +166,7 @@
mKeyStore.abort(operationToken);
}
mEncrypting = false;
+ mKeymasterPurposeOverride = -1;
mKey = null;
mRng = null;
mOperationToken = null;
@@ -210,9 +212,16 @@
byte[] additionalEntropy = KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
mRng, getAdditionalEntropyAmountForBegin());
+ int purpose;
+ if (mKeymasterPurposeOverride != -1) {
+ purpose = mKeymasterPurposeOverride;
+ } else {
+ purpose = mEncrypting
+ ? KeymasterDefs.KM_PURPOSE_ENCRYPT : KeymasterDefs.KM_PURPOSE_DECRYPT;
+ }
OperationResult opResult = mKeyStore.begin(
mKey.getAlias(),
- mEncrypting ? KeymasterDefs.KM_PURPOSE_ENCRYPT : KeymasterDefs.KM_PURPOSE_DECRYPT,
+ purpose,
true, // permit aborting this operation if keystore runs out of resources
keymasterInputArgs,
additionalEntropy);
@@ -346,11 +355,11 @@
} catch (KeyStoreException e) {
switch (e.getErrorCode()) {
case KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH:
- throw new IllegalBlockSizeException();
+ throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
case KeymasterDefs.KM_ERROR_INVALID_ARGUMENT:
- throw new BadPaddingException();
+ throw (BadPaddingException) new BadPaddingException().initCause(e);
case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
- throw new AEADBadTagException();
+ throw (AEADBadTagException) new AEADBadTagException().initCause(e);
default:
throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
}
@@ -437,6 +446,17 @@
}
/**
+ * Overrides the default purpose/type of the crypto operation.
+ */
+ protected final void setKeymasterPurposeOverride(int keymasterPurpose) {
+ mKeymasterPurposeOverride = keymasterPurpose;
+ }
+
+ protected final int getKeymasterPurposeOverride() {
+ return mKeymasterPurposeOverride;
+ }
+
+ /**
* Returns {@code true} if this cipher is initialized for encryption, {@code false} if this
* cipher is initialized for decryption.
*/
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 7b5ca3a..c5ea0f7 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -20,6 +20,8 @@
import android.security.Credentials;
import android.security.KeyPairGeneratorSpec;
import android.security.KeyStore;
+import android.security.keymaster.ExportResult;
+import android.security.keymaster.KeymasterDefs;
import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
import com.android.org.conscrypt.NativeConstants;
@@ -33,6 +35,7 @@
import java.security.KeyPairGeneratorSpi;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
+import java.security.ProviderException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.CertificateEncodingException;
@@ -153,7 +156,18 @@
throw new RuntimeException("Can't get key", e);
}
- final byte[] pubKeyBytes = mKeyStore.getPubkey(privateKeyAlias);
+ ExportResult exportResult =
+ mKeyStore.exportKey(
+ privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
+ if (exportResult == null) {
+ throw new KeyStoreConnectException();
+ } else if (exportResult.resultCode != KeyStore.NO_ERROR) {
+ throw new ProviderException(
+ "Failed to obtain public key in X.509 format",
+ KeyStore.getKeyStoreException(exportResult.resultCode));
+ }
+ final byte[] pubKeyBytes = exportResult.exportData;
+
final PublicKey pubKey;
try {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
index f70c323..5643caf 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
@@ -60,6 +60,13 @@
}
@Override
+ protected boolean isEncryptingUsingPrivateKeyPermitted() {
+ // RSA encryption with no padding using private key is is a way to implement raw RSA
+ // signatures. We have to support this.
+ return true;
+ }
+
+ @Override
protected void initAlgorithmSpecificParameters() throws InvalidKeyException {}
@Override
@@ -152,8 +159,11 @@
paddedInput.length - bufferedInput.length,
bufferedInput.length);
} else {
- // No need to pad input
- paddedInput = bufferedInput;
+ // RI throws BadPaddingException in this scenario. INVALID_ARGUMENT below will
+ // be translated into BadPaddingException.
+ throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_ARGUMENT,
+ "Message size (" + bufferedInput.length + " bytes) must be smaller than"
+ + " modulus (" + mModulusSizeBytes + " bytes)");
}
return mDelegate.doFinal(paddedInput, 0, paddedInput.length);
}
@@ -412,14 +422,46 @@
}
if (keystoreKey instanceof PrivateKey) {
- if ((opmode != Cipher.DECRYPT_MODE) && (opmode != Cipher.UNWRAP_MODE)) {
- throw new InvalidKeyException("Private key cannot be used with opmode: " + opmode
- + ". Only DECRYPT_MODE and UNWRAP_MODE supported");
+ // Private key
+ switch (opmode) {
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ // Permitted
+ break;
+ case Cipher.ENCRYPT_MODE:
+ if (!isEncryptingUsingPrivateKeyPermitted()) {
+ throw new InvalidKeyException(
+ "RSA private keys cannot be used with Cipher.ENCRYPT_MODE"
+ + ". Only RSA public keys supported for this mode");
+ }
+ // JCA doesn't provide a way to generate raw RSA signatures (with arbitrary
+ // padding). Thus, encrypting with private key is used instead.
+ setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
+ break;
+ case Cipher.WRAP_MODE:
+ throw new InvalidKeyException(
+ "RSA private keys cannot be used with Cipher.WRAP_MODE"
+ + ". Only RSA public keys supported for this mode");
+ // break;
+ default:
+ throw new InvalidKeyException(
+ "RSA private keys cannot be used with opmode: " + opmode);
}
} else {
- if ((opmode != Cipher.ENCRYPT_MODE) && (opmode != Cipher.WRAP_MODE)) {
- throw new InvalidKeyException("Public key cannot be used with opmode: " + opmode
- + ". Only ENCRYPT_MODE and WRAP_MODE supported");
+ // Public key
+ switch (opmode) {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ // Permitted
+ return;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ throw new InvalidKeyException("RSA public keys cannot be used with opmode: "
+ + opmode + ". Only RSA private keys supported for this opmode.");
+ // break;
+ default:
+ throw new InvalidKeyException(
+ "RSA public keys cannot be used with opmode: " + opmode);
}
}
@@ -438,6 +480,10 @@
setKey(keystoreKey);
}
+ protected boolean isEncryptingUsingPrivateKeyPermitted() {
+ return false;
+ }
+
@Override
protected final void resetAll() {
mModulusSizeBytes = -1;
@@ -454,6 +500,13 @@
@NonNull KeymasterArguments keymasterArgs) {
keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
keymasterArgs.addInt(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
+ int purposeOverride = getKeymasterPurposeOverride();
+ if ((purposeOverride != -1)
+ && ((purposeOverride == KeymasterDefs.KM_PURPOSE_SIGN)
+ || (purposeOverride == KeymasterDefs.KM_PURPOSE_VERIFY))) {
+ // Keymaster sign/verify requires digest to be specified. For raw sign/verify it's NONE.
+ keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
+ }
}
@Override
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 05ddef6..7c9c0cf 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -685,7 +685,7 @@
}
private Set<String> getUniqueAliases() {
- final String[] rawAliases = mKeyStore.saw("");
+ final String[] rawAliases = mKeyStore.list("");
if (rawAliases == null) {
return new HashSet<String>();
}
@@ -778,7 +778,7 @@
* equivalent to the USER_CERTIFICATE prefix for the Android keystore
* convention.
*/
- final String[] certAliases = mKeyStore.saw(Credentials.USER_CERTIFICATE);
+ final String[] certAliases = mKeyStore.list(Credentials.USER_CERTIFICATE);
if (certAliases != null) {
for (String alias : certAliases) {
final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
@@ -799,7 +799,7 @@
* Look at all the TrustedCertificateEntry types. Skip all the
* PrivateKeyEntry we looked at above.
*/
- final String[] caAliases = mKeyStore.saw(Credentials.CA_CERTIFICATE);
+ final String[] caAliases = mKeyStore.list(Credentials.CA_CERTIFICATE);
if (certAliases != null) {
for (String alias : caAliases) {
if (nonCaEntries.contains(alias)) {
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index e048ec9..44fb826 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -276,8 +276,8 @@
assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
}
- public void testSaw() throws Exception {
- String[] emptyResult = mKeyStore.saw(TEST_KEYNAME);
+ public void testList() throws Exception {
+ String[] emptyResult = mKeyStore.list(TEST_KEYNAME);
assertNotNull(emptyResult);
assertEquals(0, emptyResult.length);
@@ -285,26 +285,26 @@
mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
- String[] results = mKeyStore.saw(TEST_KEYNAME);
+ String[] results = mKeyStore.list(TEST_KEYNAME);
assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
TEST_KEYNAME2.substring(TEST_KEYNAME.length()))),
new HashSet(Arrays.asList(results)));
}
- public void testSaw_ungrantedUid_Bluetooth() throws Exception {
- String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
+ public void testList_ungrantedUid_Bluetooth() throws Exception {
+ String[] results1 = mKeyStore.list(TEST_KEYNAME, Process.BLUETOOTH_UID);
assertEquals(0, results1.length);
mKeyStore.onUserPasswordChanged(TEST_PASSWD);
mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
- String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
+ String[] results2 = mKeyStore.list(TEST_KEYNAME, Process.BLUETOOTH_UID);
assertEquals(0, results2.length);
}
- public void testSaw_grantedUid_Wifi() throws Exception {
- String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.WIFI_UID);
+ public void testList_grantedUid_Wifi() throws Exception {
+ String[] results1 = mKeyStore.list(TEST_KEYNAME, Process.WIFI_UID);
assertNotNull(results1);
assertEquals(0, results1.length);
@@ -312,14 +312,14 @@
mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED);
mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED);
- String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.WIFI_UID);
+ String[] results2 = mKeyStore.list(TEST_KEYNAME, Process.WIFI_UID);
assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
TEST_KEYNAME2.substring(TEST_KEYNAME.length()))),
new HashSet(Arrays.asList(results2)));
}
- public void testSaw_grantedUid_Vpn() throws Exception {
- String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.VPN_UID);
+ public void testList_grantedUid_Vpn() throws Exception {
+ String[] results1 = mKeyStore.list(TEST_KEYNAME, Process.VPN_UID);
assertNotNull(results1);
assertEquals(0, results1.length);
@@ -327,7 +327,7 @@
mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.VPN_UID, KeyStore.FLAG_ENCRYPTED);
mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.VPN_UID, KeyStore.FLAG_ENCRYPTED);
- String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.VPN_UID);
+ String[] results2 = mKeyStore.list(TEST_KEYNAME, Process.VPN_UID);
assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
TEST_KEYNAME2.substring(TEST_KEYNAME.length()))),
new HashSet(Arrays.asList(results2)));
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
index cad4e54..8488acd 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
@@ -18,6 +18,9 @@
import android.security.Credentials;
import android.security.KeyPairGeneratorSpec;
+import android.security.KeyStore;
+import android.security.keymaster.ExportResult;
+import android.security.keymaster.KeymasterDefs;
import android.test.AndroidTestCase;
import java.io.ByteArrayInputStream;
@@ -78,7 +81,7 @@
assertTrue(mAndroidKeyStore.onUserPasswordChanged("1111"));
assertTrue(mAndroidKeyStore.isUnlocked());
- String[] aliases = mAndroidKeyStore.saw("");
+ String[] aliases = mAndroidKeyStore.list("");
assertNotNull(aliases);
assertEquals(0, aliases.length);
}
@@ -359,7 +362,10 @@
final byte[] caCerts = mAndroidKeyStore.get(Credentials.CA_CERTIFICATE + alias);
assertNull("A list of CA certificates should not exist for the generated entry", caCerts);
- final byte[] pubKeyBytes = mAndroidKeyStore.getPubkey(Credentials.USER_PRIVATE_KEY + alias);
+ ExportResult exportResult = mAndroidKeyStore.exportKey(
+ Credentials.USER_PRIVATE_KEY + alias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
+ assertEquals(KeyStore.NO_ERROR, exportResult.resultCode);
+ final byte[] pubKeyBytes = exportResult.exportData;
assertNotNull("The keystore should return the public key for the generated key",
pubKeyBytes);
}
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
index 2d4e4a0..336fa40 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
@@ -24,6 +24,8 @@
import android.security.Credentials;
import android.security.KeyStore;
import android.security.KeyStoreParameter;
+import android.security.keymaster.ExportResult;
+import android.security.keymaster.KeymasterDefs;
import android.test.AndroidTestCase;
import java.io.ByteArrayInputStream;
@@ -742,7 +744,7 @@
assertTrue(mAndroidKeyStore.onUserPasswordChanged("1111"));
assertTrue(mAndroidKeyStore.isUnlocked());
- assertEquals(0, mAndroidKeyStore.saw("").length);
+ assertEquals(0, mAndroidKeyStore.list("").length);
}
private void assertAliases(final String[] expectedAliases) throws KeyStoreException {
@@ -1932,7 +1934,10 @@
throw new RuntimeException("Can't get key", e);
}
- final byte[] pubKeyBytes = keyStore.getPubkey(privateKeyAlias);
+ ExportResult exportResult =
+ keyStore.exportKey(privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
+ assertEquals(KeyStore.NO_ERROR, exportResult.resultCode);
+ final byte[] pubKeyBytes = exportResult.exportData;
final PublicKey pubKey;
try {
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
index a5bfde7..9590595 100644
--- a/libs/hwui/Android.common.mk
+++ b/libs/hwui/Android.common.mk
@@ -118,5 +118,9 @@
# Defaults for ATRACE_TAG and LOG_TAG for libhwui
LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\"
+LOCAL_CFLAGS += -Wall -Wno-unused-parameter -Wunreachable-code
-LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter -Wunreachable-code
+# b/21698669
+ifneq ($(USE_CLANG_PLATFORM_BUILD),true)
+ LOCAL_CFLAGS += -Werror
+endif
diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp
index 5b81ac9..7f9d9b9 100644
--- a/libs/hwui/FrameInfoVisualizer.cpp
+++ b/libs/hwui/FrameInfoVisualizer.cpp
@@ -28,7 +28,6 @@
#define PROFILE_DRAW_DP_PER_MS 7
// Must be NUM_ELEMENTS in size
-static const SkColor CURRENT_FRAME_COLOR = 0xcf5faa4d;
static const SkColor THRESHOLD_COLOR = 0xff5faa4d;
static const SkColor BAR_FAST_ALPHA = 0x8F000000;
static const SkColor BAR_JANKY_ALPHA = 0xDF000000;
diff --git a/media/java/android/media/midi/IMidiDeviceOpenCallback.aidl b/media/java/android/media/midi/IMidiDeviceOpenCallback.aidl
new file mode 100644
index 0000000..6e3dbbf
--- /dev/null
+++ b/media/java/android/media/midi/IMidiDeviceOpenCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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 android.media.midi;
+
+import android.media.midi.IMidiDeviceServer;
+
+/** @hide */
+oneway interface IMidiDeviceOpenCallback
+{
+ void onDeviceOpened(in IMidiDeviceServer server, IBinder token);
+}
diff --git a/media/java/android/media/midi/IMidiDeviceServer.aidl b/media/java/android/media/midi/IMidiDeviceServer.aidl
index 96d12fd..e30796d 100644
--- a/media/java/android/media/midi/IMidiDeviceServer.aidl
+++ b/media/java/android/media/midi/IMidiDeviceServer.aidl
@@ -25,6 +25,7 @@
ParcelFileDescriptor openInputPort(IBinder token, int portNumber);
ParcelFileDescriptor openOutputPort(IBinder token, int portNumber);
void closePort(IBinder token);
+ void closeDevice();
// connects the input port pfd to the specified output port
void connectPorts(IBinder token, in ParcelFileDescriptor pfd, int outputPortNumber);
diff --git a/media/java/android/media/midi/IMidiManager.aidl b/media/java/android/media/midi/IMidiManager.aidl
index fcd4aff..d3c8e0a 100644
--- a/media/java/android/media/midi/IMidiManager.aidl
+++ b/media/java/android/media/midi/IMidiManager.aidl
@@ -16,7 +16,10 @@
package android.media.midi;
+import android.bluetooth.BluetoothDevice;
import android.media.midi.IMidiDeviceListener;
+import android.media.midi.IMidiDeviceOpenCallback;
+import android.media.midi.IMidiDeviceServer;
import android.media.midi.IMidiDeviceServer;
import android.media.midi.MidiDeviceInfo;
import android.media.midi.MidiDeviceStatus;
@@ -29,11 +32,13 @@
MidiDeviceInfo[] getDevices();
// for device creation & removal notifications
- void registerListener(IBinder token, in IMidiDeviceListener listener);
- void unregisterListener(IBinder token, in IMidiDeviceListener listener);
+ void registerListener(IBinder clientToken, in IMidiDeviceListener listener);
+ void unregisterListener(IBinder clientToken, in IMidiDeviceListener listener);
- // for opening built-in MIDI devices
- IMidiDeviceServer openDevice(IBinder token, in MidiDeviceInfo device);
+ void openDevice(IBinder clientToken, in MidiDeviceInfo device, in IMidiDeviceOpenCallback callback);
+ void openBluetoothDevice(IBinder clientToken, in BluetoothDevice bluetoothDevice,
+ in IMidiDeviceOpenCallback callback);
+ void closeDevice(IBinder clientToken, IBinder deviceToken);
// for registering built-in MIDI devices
MidiDeviceInfo registerDeviceServer(in IMidiDeviceServer server, int numInputPorts,
@@ -52,5 +57,5 @@
// used by MIDI devices to report their status
// the token is used by MidiService for death notification
- void setDeviceStatus(IBinder token, in MidiDeviceStatus status);
+ void setDeviceStatus(in IMidiDeviceServer server, in MidiDeviceStatus status);
}
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
index 6526adc..7998a92 100644
--- a/media/java/android/media/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -16,8 +16,6 @@
package android.media.midi;
-import android.content.Context;
-import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -40,9 +38,9 @@
private final MidiDeviceInfo mDeviceInfo;
private final IMidiDeviceServer mDeviceServer;
- private Context mContext;
- private ServiceConnection mServiceConnection;
-
+ private final IMidiManager mMidiManager;
+ private final IBinder mClientToken;
+ private final IBinder mDeviceToken;
private final CloseGuard mGuard = CloseGuard.get();
@@ -71,16 +69,13 @@
}
}
- /* package */ MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server) {
- this(deviceInfo, server, null, null);
- }
-
/* package */ MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server,
- Context context, ServiceConnection serviceConnection) {
+ IMidiManager midiManager, IBinder clientToken, IBinder deviceToken) {
mDeviceInfo = deviceInfo;
mDeviceServer = server;
- mContext = context;
- mServiceConnection = serviceConnection;
+ mMidiManager = midiManager;
+ mClientToken = clientToken;
+ mDeviceToken = deviceToken;
mGuard.open("close");
}
@@ -170,10 +165,10 @@
public void close() throws IOException {
synchronized (mGuard) {
mGuard.close();
- if (mContext != null && mServiceConnection != null) {
- mContext.unbindService(mServiceConnection);
- mContext = null;
- mServiceConnection = null;
+ try {
+ mMidiManager.closeDevice(mClientToken, mDeviceToken);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in closeDevice");
}
}
}
diff --git a/media/java/android/media/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java
index a316a44..1b56e1c 100644
--- a/media/java/android/media/midi/MidiDeviceServer.java
+++ b/media/java/android/media/midi/MidiDeviceServer.java
@@ -65,7 +65,6 @@
// for reporting device status
- private final IBinder mDeviceStatusToken = new Binder();
private final boolean[] mInputPortOpen;
private final int[] mOutputPortOpenCount;
@@ -81,6 +80,11 @@
* @param status the {@link MidiDeviceStatus} for the device
*/
public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status);
+
+ /**
+ * Called to notify when the device is closed
+ */
+ public void onClose();
}
abstract private class PortClient implements IBinder.DeathRecipient {
@@ -242,6 +246,14 @@
}
@Override
+ public void closeDevice() {
+ if (mCallback != null) {
+ mCallback.onClose();
+ }
+ IoUtils.closeQuietly(MidiDeviceServer.this);
+ }
+
+ @Override
public void connectPorts(IBinder token, ParcelFileDescriptor pfd,
int outputPortNumber) {
MidiInputPort inputPort = new MidiInputPort(pfd, outputPortNumber);
@@ -305,7 +317,7 @@
mCallback.onDeviceStatusChanged(this, status);
}
try {
- mMidiManager.setDeviceStatus(mDeviceStatusToken, status);
+ mMidiManager.setDeviceStatus(mServer, status);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in updateDeviceStatus");
} finally {
diff --git a/media/java/android/media/midi/MidiDeviceService.java b/media/java/android/media/midi/MidiDeviceService.java
index ce12a4f..d897ad2 100644
--- a/media/java/android/media/midi/MidiDeviceService.java
+++ b/media/java/android/media/midi/MidiDeviceService.java
@@ -59,6 +59,11 @@
public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status) {
MidiDeviceService.this.onDeviceStatusChanged(status);
}
+
+ @Override
+ public void onClose() {
+ MidiDeviceService.this.onClose();
+ }
};
@Override
@@ -125,6 +130,12 @@
public void onDeviceStatusChanged(MidiDeviceStatus status) {
}
+ /**
+ * Called to notify when our device has been closed by all its clients
+ */
+ public void onClose() {
+ }
+
@Override
public IBinder onBind(Intent intent) {
if (SERVICE_INTERFACE.equals(intent.getAction()) && mServer != null) {
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index d19cf36..0beb9a4 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -17,11 +17,6 @@
package android.media.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.ServiceInfo;
import android.os.Binder;
import android.os.IBinder;
import android.os.Bundle;
@@ -52,16 +47,17 @@
/**
* BluetoothMidiService package name
+ * @hide
*/
- private static final String BLUETOOTH_MIDI_SERVICE_PACKAGE = "com.android.bluetoothmidiservice";
+ public static final String BLUETOOTH_MIDI_SERVICE_PACKAGE = "com.android.bluetoothmidiservice";
/**
* BluetoothMidiService class name
+ * @hide
*/
- private static final String BLUETOOTH_MIDI_SERVICE_CLASS =
+ public static final String BLUETOOTH_MIDI_SERVICE_CLASS =
"com.android.bluetoothmidiservice.BluetoothMidiService";
- private final Context mContext;
private final IMidiManager mService;
private final IBinder mToken = new Binder();
@@ -166,8 +162,7 @@
/**
* @hide
*/
- public MidiManager(Context context, IMidiManager service) {
- mContext = context;
+ public MidiManager(IMidiManager service) {
mService = service;
}
@@ -237,7 +232,7 @@
* Opens a MIDI device for reading and writing.
*
* @param deviceInfo a {@link android.media.midi.MidiDeviceInfo} to open
- * @param listener a {@link MidiManager.OnDeviceOpenedListener} to be called
+ * @param listener a {@link MidiManager.OnDeviceOpenedListener} to be called
* to receive the result
* @param handler the {@link android.os.Handler Handler} that will be used for delivering
* the result. If handler is null, then the thread used for the
@@ -245,52 +240,28 @@
*/
public void openDevice(MidiDeviceInfo deviceInfo, OnDeviceOpenedListener listener,
Handler handler) {
- MidiDevice device = null;
- try {
- IMidiDeviceServer server = mService.openDevice(mToken, deviceInfo);
- if (server == null) {
- ServiceInfo serviceInfo = (ServiceInfo)deviceInfo.getProperties().getParcelable(
- MidiDeviceInfo.PROPERTY_SERVICE_INFO);
- if (serviceInfo == null) {
- Log.e(TAG, "no ServiceInfo for " + deviceInfo);
- } else {
- Intent intent = new Intent(MidiDeviceService.SERVICE_INTERFACE);
- intent.setComponent(new ComponentName(serviceInfo.packageName,
- serviceInfo.name));
- final MidiDeviceInfo deviceInfoF = deviceInfo;
- final OnDeviceOpenedListener listenerF = listener;
- final Handler handlerF = handler;
- if (mContext.bindService(intent,
- new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
- IMidiDeviceServer server =
- IMidiDeviceServer.Stub.asInterface(binder);
- MidiDevice device = new MidiDevice(deviceInfoF, server, mContext,
- this);
- sendOpenDeviceResponse(device, listenerF, handlerF);
- }
+ final MidiDeviceInfo deviceInfoF = deviceInfo;
+ final OnDeviceOpenedListener listenerF = listener;
+ final Handler handlerF = handler;
- @Override
- public void onServiceDisconnected(ComponentName name) {
- // FIXME - anything to do here?
- }
- },
- Context.BIND_AUTO_CREATE))
- {
- // return immediately to avoid calling sendOpenDeviceResponse below
- return;
- } else {
- Log.e(TAG, "Unable to bind service: " + intent);
- }
+ IMidiDeviceOpenCallback callback = new IMidiDeviceOpenCallback.Stub() {
+ @Override
+ public void onDeviceOpened(IMidiDeviceServer server, IBinder deviceToken) {
+ MidiDevice device;
+ if (server != null) {
+ device = new MidiDevice(deviceInfoF, server, mService, mToken, deviceToken);
+ } else {
+ device = null;
}
- } else {
- device = new MidiDevice(deviceInfo, server);
+ sendOpenDeviceResponse(device, listenerF, handlerF);
}
+ };
+
+ try {
+ mService.openDevice(mToken, deviceInfo, callback);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in openDevice");
}
- sendOpenDeviceResponse(device, listener, handler);
}
/**
@@ -303,38 +274,33 @@
* the result. If handler is null, then the thread used for the
* listener is unspecified.
*/
- public void openBluetoothDevice(final BluetoothDevice bluetoothDevice,
- final OnDeviceOpenedListener listener, final Handler handler) {
- Intent intent = new Intent(BLUETOOTH_MIDI_SERVICE_INTENT);
- intent.setComponent(new ComponentName(BLUETOOTH_MIDI_SERVICE_PACKAGE,
- BLUETOOTH_MIDI_SERVICE_CLASS));
- intent.putExtra("device", bluetoothDevice);
- if (!mContext.bindService(intent,
- new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
- IMidiDeviceServer server =
- IMidiDeviceServer.Stub.asInterface(binder);
+ public void openBluetoothDevice(BluetoothDevice bluetoothDevice,
+ OnDeviceOpenedListener listener, Handler handler) {
+ final OnDeviceOpenedListener listenerF = listener;
+ final Handler handlerF = handler;
+
+ IMidiDeviceOpenCallback callback = new IMidiDeviceOpenCallback.Stub() {
+ @Override
+ public void onDeviceOpened(IMidiDeviceServer server, IBinder deviceToken) {
+ MidiDevice device = null;
+ if (server != null) {
try {
// fetch MidiDeviceInfo from the server
MidiDeviceInfo deviceInfo = server.getDeviceInfo();
- MidiDevice device = new MidiDevice(deviceInfo, server, mContext, this);
- sendOpenDeviceResponse(device, listener, handler);
+ device = new MidiDevice(deviceInfo, server, mService, mToken, deviceToken);
+ sendOpenDeviceResponse(device, listenerF, handlerF);
} catch (RemoteException e) {
- Log.e(TAG, "remote exception in onServiceConnected");
- sendOpenDeviceResponse(null, listener, handler);
+ Log.e(TAG, "remote exception in getDeviceInfo()");
}
}
+ sendOpenDeviceResponse(device, listenerF, handlerF);
+ }
+ };
- @Override
- public void onServiceDisconnected(ComponentName name) {
- // FIXME - anything to do here?
- }
- },
- Context.BIND_AUTO_CREATE))
- {
- Log.e(TAG, "Unable to bind service: " + intent);
- sendOpenDeviceResponse(null, listener, handler);
+ try {
+ mService.openBluetoothDevice(mToken, bluetoothDevice, callback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in openDevice");
}
}
diff --git a/media/java/android/media/midi/package.html b/media/java/android/media/midi/package.html
index bd589a9..8b2bd16 100644
--- a/media/java/android/media/midi/package.html
+++ b/media/java/android/media/midi/package.html
@@ -241,7 +241,8 @@
<p>An app can provide a MIDI Service that can be used by other apps. For example,
-an app can provide a custom synthesizer that other apps can send messages to. </p>
+an app can provide a custom synthesizer that other apps can send messages to.
+The service must be guarded with permission "android.permission.BIND_MIDI_DEVICE_SERVICE".</p>
<h2 id=manifest_files>Manifest Files</h2>
@@ -250,7 +251,8 @@
AndroidManifest.xml file.</p>
<pre class=prettyprint>
-<service android:name="<strong>MySynthDeviceService</strong>">
+<service android:name="<strong>MySynthDeviceService</strong>"
+ android:permission="android.permission.BIND_MIDI_DEVICE_SERVICE">
<intent-filter>
<action android:name="android.media.midi.MidiDeviceService" />
</intent-filter>
diff --git a/media/packages/BluetoothMidiService/AndroidManifest.xml b/media/packages/BluetoothMidiService/AndroidManifest.xml
index 15aa581..b0b389a 100644
--- a/media/packages/BluetoothMidiService/AndroidManifest.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifest.xml
@@ -8,7 +8,8 @@
<application
android:label="@string/app_name">
- <service android:name="BluetoothMidiService">
+ <service android:name="BluetoothMidiService"
+ android:permission="android.permission.BIND_MIDI_DEVICE_SERVICE">
<intent-filter>
<action android:name="android.media.midi.BluetoothMidiService" />
</intent-filter>
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
index 60c6570..e6d59e4 100644
--- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
@@ -24,10 +24,11 @@
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
-import android.media.midi.MidiReceiver;
-import android.media.midi.MidiManager;
-import android.media.midi.MidiDeviceServer;
import android.media.midi.MidiDeviceInfo;
+import android.media.midi.MidiDeviceServer;
+import android.media.midi.MidiDeviceStatus;
+import android.media.midi.MidiManager;
+import android.media.midi.MidiReceiver;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
@@ -81,6 +82,18 @@
private final BluetoothPacketDecoder mPacketDecoder
= new BluetoothPacketDecoder(MAX_PACKET_SIZE);
+ private final MidiDeviceServer.Callback mDeviceServerCallback
+ = new MidiDeviceServer.Callback() {
+ @Override
+ public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status) {
+ }
+
+ @Override
+ public void onClose() {
+ close();
+ }
+ };
+
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
@@ -213,7 +226,7 @@
inputPortReceivers[0] = mEventScheduler.getReceiver();
mDeviceServer = mMidiManager.createDeviceServer(inputPortReceivers, 1,
- null, null, properties, MidiDeviceInfo.TYPE_BLUETOOTH, null);
+ null, null, properties, MidiDeviceInfo.TYPE_BLUETOOTH, mDeviceServerCallback);
mOutputReceiver = mDeviceServer.getOutputPortReceivers()[0];
@@ -248,11 +261,12 @@
private void close() {
synchronized (mBluetoothDevice) {
- mEventScheduler.close();
+ mEventScheduler.close();
+ mService.deviceClosed(mBluetoothDevice);
+
if (mDeviceServer != null) {
IoUtils.closeQuietly(mDeviceServer);
mDeviceServer = null;
- mService.deviceClosed(mBluetoothDevice);
}
if (mBluetoothGatt != null) {
mBluetoothGatt.close();
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index a8451f5..e92f74c 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -40,7 +40,7 @@
<!-- Label of the color mode widget. [CHAR LIMIT=20] -->
<string name="label_color">Color</string>
- <!-- Label of the duplex mode widget. [CHAR LIMIT=20] -->
+ <!-- Label of the printer mode to print on both sides of paper. [CHAR LIMIT=20] -->
<string name="label_duplex">Two-sided</string>
<!-- Label of the orientation widget. [CHAR LIMIT=20] -->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 4bc317a..39dc480 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -998,6 +998,9 @@
mAfforanceHelper.updatePreviews();
}
}
+ if (keyguardShowing) {
+ updateDozingVisibilities(false /* animate */);
+ }
resetVerticalPanelPosition();
updateQsState();
}
@@ -2109,6 +2112,10 @@
public void setDozing(boolean dozing, boolean animate) {
if (dozing == mDozing) return;
mDozing = dozing;
+ updateDozingVisibilities(animate);
+ }
+
+ private void updateDozingVisibilities(boolean animate) {
if (mDozing) {
mKeyguardStatusBar.setVisibility(View.INVISIBLE);
mKeyguardBottomArea.setVisibility(View.INVISIBLE);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b6cc1c7..1046b29 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10216,6 +10216,7 @@
void finishRunningVoiceLocked() {
if (mRunningVoice != null) {
mRunningVoice = null;
+ mVoiceWakeLock.release();
updateSleepIfNeededLocked();
}
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 3765a3c..d16eab6 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -982,7 +982,7 @@
final long totalTime = stack.mLaunchStartTime != 0
? (curTime - stack.mLaunchStartTime) : thisTime;
if (SHOW_ACTIVITY_START_TIME) {
- Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching", 0);
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching: " + packageName, 0);
EventLog.writeEvent(EventLogTags.AM_ACTIVITY_LAUNCH_TIME,
userId, System.identityHashCode(this), shortComponentName,
thisTime, totalTime);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 30ee214..eb5af9e5 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -679,11 +679,11 @@
"Launch completed; removing icicle of " + r.icicle);
}
- private void startLaunchTraces() {
+ private void startLaunchTraces(String packageName) {
if (mFullyDrawnStartTime != 0) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
}
- Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching", 0);
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching: " + packageName, 0);
Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
}
@@ -698,11 +698,11 @@
if (r.displayStartTime == 0) {
r.fullyDrawnStartTime = r.displayStartTime = SystemClock.uptimeMillis();
if (mLaunchStartTime == 0) {
- startLaunchTraces();
+ startLaunchTraces(r.packageName);
mLaunchStartTime = mFullyDrawnStartTime = r.displayStartTime;
}
} else if (mLaunchStartTime == 0) {
- startLaunchTraces();
+ startLaunchTraces(r.packageName);
mLaunchStartTime = mFullyDrawnStartTime = SystemClock.uptimeMillis();
}
}
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 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 e370afc..604ac97 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5031,7 +5031,7 @@
scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
scanFlags, currentTime, null);
} catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage(), e);
+ Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
// Delete invalid userdata apps
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
@@ -6166,9 +6166,16 @@
}
} 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/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index da4cc48..3b9cc9d 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -62,8 +62,6 @@
static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jintArray outIrqs,
jobjectArray outReasons)
{
- bool first_time = false;
-
if (outIrqs == NULL || outReasons == NULL) {
jniThrowException(env, "java/lang/NullPointerException", "null argument");
return -1;
@@ -83,19 +81,17 @@
}
ALOGV("Registering callback...");
set_wakeup_callback(&wakeup_callback);
- // First time through, we will just drain the current wakeup reasons.
- first_time = true;
- } else {
- // On following calls, we need to wait for wakeup.
- ALOGV("Waiting for wakeup...");
- int ret = sem_wait(&wakeup_sem);
- if (ret < 0) {
- char buf[80];
- strerror_r(errno, buf, sizeof(buf));
- ALOGE("Error waiting on semaphore: %s\n", buf);
- // Return 0 here to let it continue looping but not return results.
- return 0;
- }
+ }
+
+ // Wait for wakeup.
+ ALOGV("Waiting for wakeup...");
+ int ret = sem_wait(&wakeup_sem);
+ if (ret < 0) {
+ char buf[80];
+ strerror_r(errno, buf, sizeof(buf));
+ ALOGE("Error waiting on semaphore: %s\n", buf);
+ // Return 0 here to let it continue looping but not return results.
+ return 0;
}
FILE *fp = fopen(LAST_RESUME_REASON, "r");
@@ -169,9 +165,6 @@
}
ALOGV("Got %d reasons", i);
- if (first_time) {
- i = 0;
- }
if (i > 0) {
irqs[0] = firstirq;
*mergedreasonpos = 0;
@@ -185,7 +178,7 @@
return -1;
}
- return first_time ? 0 : i;
+ return i;
}
static JNINativeMethod method_table[] = {
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.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 @@
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 @@
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 @@
// 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 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 @@
}
}
+ 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 @@
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 @@
}
}
- 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,14 +382,105 @@
return (!mDeviceInfo.isPrivate() || mUid == uid);
}
- public void binderDied() {
- synchronized (mDevicesByInfo) {
- if (mDevicesByInfo.remove(mDeviceInfo) != null) {
- removeDeviceLocked(this);
+ 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) {
+ closeLocked();
+ }
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder("Device Info: ");
@@ -300,10 +489,56 @@
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 @@
}
}
}
+
+ 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 @@
}
@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");
+ }
}
- 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);
+ }
}
- return device.getDeviceServer();
+ // clear calling identity so bindService does not fail
+ long identity = Binder.clearCallingIdentity();
+ try {
+ client.addDeviceConnection(device, callback);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void closeDevice(IBinder clientToken, IBinder deviceToken) {
+ Client client = getClient(clientToken);
+ if (client == null) return;
+ client.removeDeviceConnection(deviceToken);
}
@Override
@@ -376,6 +666,8 @@
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 @@
synchronized (mDevicesByInfo) {
Device device = mDevicesByServer.get(server.asBinder());
if (device != null) {
- mDevicesByInfo.remove(device.getDeviceInfo());
- removeDeviceLocked(device);
+ device.closeLocked();
}
}
}
@@ -420,19 +711,16 @@
}
@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;
+ 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);
}
- if (Binder.getCallingUid() != device.getUid()) {
- throw new SecurityException("setDeviceStatus() caller UID " + Binder.getCallingUid()
- + " does not match device's UID " + device.getUid());
- }
- device.setDeviceStatus(token, status);
- notifyDeviceStatusChanged(device, status);
}
private void notifyDeviceStatusChanged(Device device, MidiDeviceStatus status) {
@@ -452,18 +740,24 @@
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 @@
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 @@
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;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 193285f..e085d89 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1107,9 +1107,9 @@
}
/**
- * Returns a constant indicating the state of sim for the subscription.
+ * Returns a constant indicating the state of sim for the slot idx.
*
- * @param subId
+ * @param slotIdx
*
* {@See TelephonyManager#SIM_STATE_UNKNOWN}
* {@See TelephonyManager#SIM_STATE_ABSENT}
@@ -1123,16 +1123,16 @@
*
* {@hide}
*/
- public static int getSimStateForSubscriber(int subId) {
+ public static int getSimStateForSlotIdx(int slotIdx) {
int simState;
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
- simState = iSub.getSimStateForSubscriber(subId);
+ simState = iSub.getSimStateForSlotIdx(slotIdx);
} catch (RemoteException ex) {
simState = TelephonyManager.SIM_STATE_UNKNOWN;
}
- logd("getSimStateForSubscriber: simState=" + simState + " subId=" + subId);
+ logd("getSimStateForSubscriber: simState=" + simState + " slotIdx=" + slotIdx);
return simState;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2445bf6e..f5a7c0f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -803,17 +803,26 @@
public CellLocation getCellLocation() {
try {
ITelephony telephony = getITelephony();
- if (telephony == null)
+ if (telephony == null) {
+ Rlog.d(TAG, "getCellLocation returning null because telephony is null");
return null;
+ }
Bundle bundle = telephony.getCellLocation(mContext.getOpPackageName());
- if (bundle.isEmpty()) return null;
- CellLocation cl = CellLocation.newFromBundle(bundle);
- if (cl.isEmpty())
+ if (bundle.isEmpty()) {
+ Rlog.d(TAG, "getCellLocation returning null because bundle is empty");
return null;
+ }
+ CellLocation cl = CellLocation.newFromBundle(bundle);
+ if (cl.isEmpty()) {
+ Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty");
+ return null;
+ }
return cl;
} catch (RemoteException ex) {
+ Rlog.d(TAG, "getCellLocation returning null due to RemoteException " + ex);
return null;
} catch (NullPointerException ex) {
+ Rlog.d(TAG, "getCellLocation returning null due to NullPointerException " + ex);
return null;
}
}
@@ -1625,7 +1634,25 @@
* @see #SIM_STATE_CARD_IO_ERROR
*/
public int getSimState() {
- return getSimState(getDefaultSim());
+ int slotIdx = getDefaultSim();
+ // slotIdx may be invalid due to sim being absent. In that case query all slots to get
+ // sim state
+ if (slotIdx < 0) {
+ // query for all slots and return absent if all sim states are absent, otherwise
+ // return unknown
+ for (int i = 0; i < getPhoneCount(); i++) {
+ int simState = getSimState(i);
+ if (simState != SIM_STATE_ABSENT) {
+ Rlog.d(TAG, "getSimState: default sim:" + slotIdx + ", sim state for " +
+ "slotIdx=" + i + " is " + simState + ", return state as unknown");
+ return SIM_STATE_UNKNOWN;
+ }
+ }
+ Rlog.d(TAG, "getSimState: default sim:" + slotIdx + ", all SIMs absent, return " +
+ "state as absent");
+ return SIM_STATE_ABSENT;
+ }
+ return getSimState(slotIdx);
}
/**
@@ -1645,12 +1672,7 @@
*/
/** {@hide} */
public int getSimState(int slotIdx) {
- int[] subId = SubscriptionManager.getSubId(slotIdx);
- if (subId == null || subId.length == 0) {
- Rlog.d(TAG, "getSimState:- empty subId return SIM_STATE_ABSENT");
- return SIM_STATE_UNKNOWN;
- }
- int simState = SubscriptionManager.getSimStateForSubscriber(subId[0]);
+ int simState = SubscriptionManager.getSimStateForSlotIdx(slotIdx);
return simState;
}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 1037f2d..918a2eb 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -180,10 +180,10 @@
int[] getActiveSubIdList();
/**
- * Get the SIM state for the subscriber
+ * Get the SIM state for the slot idx
* @return SIM state as the ordinal of IccCardConstants.State
*/
- int getSimStateForSubscriber(int subId);
+ int getSimStateForSlotIdx(int slotIdx);
boolean isActiveSubId(int subId);
}
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/TrackTimeReceiver.java b/tests/ActivityTests/src/com/google/android/test/activity/TrackTimeReceiver.java
index c30d33a..0cc0090 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/TrackTimeReceiver.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/TrackTimeReceiver.java
@@ -27,7 +27,7 @@
@Override
public void onReceive(Context context, Intent intent) {
Bundle data = intent.getExtras();
- data.getLong(ActivityOptions.EXTRA_USAGE_REPORT_TIME);
+ data.getLong(ActivityOptions.EXTRA_USAGE_TIME_REPORT);
Log.i("ActivityTest", "Received time: " + data);
}
}