summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camera/libcameraservice/CameraService.cpp1
-rw-r--r--core/java/android/app/SearchDialog.java4
-rw-r--r--core/java/android/app/SearchManager.java8
-rw-r--r--core/java/android/content/SyncOperation.java2
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java142
-rw-r--r--core/java/android/os/IPowerManager.aidl1
-rw-r--r--core/tests/coretests/AndroidManifest.xml14
-rw-r--r--core/tests/coretests/src/android/bluetooth/BluetoothRebootStressTest.java94
-rw-r--r--core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java81
-rw-r--r--core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java73
-rw-r--r--core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java441
-rw-r--r--include/media/stagefright/AudioPlayer.h4
-rw-r--r--media/java/android/media/AudioService.java15
-rw-r--r--media/libstagefright/AudioPlayer.cpp66
-rw-r--r--media/libstagefright/codecs/aacdec/AACDecoder.cpp110
-rw-r--r--media/libstagefright/include/AACDecoder.h4
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java19
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java22
-rw-r--r--services/java/com/android/server/MountService.java35
-rw-r--r--services/java/com/android/server/NativeDaemonConnector.java11
-rw-r--r--services/java/com/android/server/NetworkManagementService.java348
-rw-r--r--services/java/com/android/server/PackageManagerService.java53
-rw-r--r--services/java/com/android/server/PowerManagerService.java121
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java4
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java21
-rw-r--r--telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl5
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneSubInfo.java21
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java7
-rwxr-xr-xtelephony/java/com/android/internal/telephony/cdma/CDMAPhone.java9
30 files changed, 1485 insertions, 254 deletions
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 00bd54e..2690182 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -935,6 +935,7 @@ void CameraService::Client::handleShutter(
mHardware->getRawHeap());
mSurface->registerBuffers(buffers);
+ IPCThreadState::self()->flushCommands();
}
}
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 7625c04..cd22fa1 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -588,7 +588,9 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
*/
private void updateVoiceButton(boolean empty) {
int visibility = View.GONE;
- if (mSearchable.getVoiceSearchEnabled() && empty) {
+ if ((mAppSearchData == null || !mAppSearchData.getBoolean(
+ SearchManager.DISABLE_VOICE_SEARCH, false))
+ && mSearchable.getVoiceSearchEnabled() && empty) {
Intent testIntent = null;
if (mSearchable.getVoiceSearchLaunchWebSearch()) {
testIntent = mVoiceWebSearchIntent;
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index a1ca707..2e9cd96 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -395,6 +395,14 @@ public class SearchManager
public final static String CONTEXT_IS_VOICE = "android.search.CONTEXT_IS_VOICE";
/**
+ * This means that the voice icon should not be shown at all, because the
+ * current search engine does not support voice search.
+ * @hide
+ */
+ public final static String DISABLE_VOICE_SEARCH
+ = "android.search.DISABLE_VOICE_SEARCH";
+
+ /**
* Reference to the shared system search service.
*/
private static ISearchManager mService;
diff --git a/core/java/android/content/SyncOperation.java b/core/java/android/content/SyncOperation.java
index a7d036f..b016088 100644
--- a/core/java/android/content/SyncOperation.java
+++ b/core/java/android/content/SyncOperation.java
@@ -90,7 +90,7 @@ public class SyncOperation implements Comparable {
private String toKey() {
StringBuilder sb = new StringBuilder();
sb.append("authority: ").append(authority);
- sb.append(" account: ").append(account);
+ sb.append(" account {name=" + account.name + ", type=" + account.type + "}");
sb.append(" extras: ");
extrasToStringBuilder(extras, sb, true /* asKey */);
return sb.toString();
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index a8c6f9b..31acb5b 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -35,6 +35,11 @@ import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import javax.net.SocketFactory;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
@@ -48,17 +53,33 @@ import org.apache.harmony.xnet.provider.jsse.SSLParameters;
/**
* SSLSocketFactory implementation with several extra features:
+ *
* <ul>
* <li>Timeout specification for SSL handshake operations
+ * <li>Hostname verification in most cases (see WARNINGs below)
* <li>Optional SSL session caching with {@link SSLSessionCache}
* <li>Optionally bypass all SSL certificate checks
* </ul>
- * Note that the handshake timeout does not apply to actual connection.
- * If you want a connection timeout as well, use {@link #createSocket()} and
- * {@link Socket#connect(SocketAddress, int)}.
- * <p>
- * On development devices, "setprop socket.relaxsslcheck yes" bypasses all
- * SSL certificate checks, for testing with development servers.
+ *
+ * The handshake timeout does not apply to actual TCP socket connection.
+ * If you want a connection timeout as well, use {@link #createSocket()}
+ * and {@link Socket#connect(SocketAddress, int)}, after which you
+ * must verify the identity of the server you are connected to.
+ *
+ * <p class="caution"><b>Most {@link SSLSocketFactory} implementations do not
+ * verify the server's identity, allowing man-in-the-middle attacks.</b>
+ * This implementation does check the server's certificate hostname, but only
+ * for createSocket variants that specify a hostname. When using methods that
+ * use {@link InetAddress} or which return an unconnected socket, you MUST
+ * verify the server's identity yourself to ensure a secure connection.</p>
+ *
+ * <p>One way to verify the server's identity is to use
+ * {@link HttpsURLConnection#getDefaultHostnameVerifier()} to get a
+ * {@link HostnameVerifier} to verify the certificate hostname.
+ *
+ * <p>On development devices, "setprop socket.relaxsslcheck yes" bypasses all
+ * SSL certificate and hostname checks for testing purposes. This setting
+ * requires root access.
*/
public class SSLCertificateSocketFactory extends SSLSocketFactory {
private static final String TAG = "SSLCertificateSocketFactory";
@@ -71,6 +92,9 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
};
+ private static final HostnameVerifier HOSTNAME_VERIFIER =
+ HttpsURLConnection.getDefaultHostnameVerifier();
+
private SSLSocketFactory mInsecureFactory = null;
private SSLSocketFactory mSecureFactory = null;
@@ -95,7 +119,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
*
* @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
* for none. The socket timeout is reset to 0 after the handshake.
- * @return a new SocketFactory with the specified parameters
+ * @return a new SSLSocketFactory with the specified parameters
*/
public static SocketFactory getDefault(int handshakeTimeoutMillis) {
return new SSLCertificateSocketFactory(handshakeTimeoutMillis, null, true);
@@ -108,7 +132,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
* @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
* for none. The socket timeout is reset to 0 after the handshake.
* @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
- * @return a new SocketFactory with the specified parameters
+ * @return a new SSLSocketFactory with the specified parameters
*/
public static SSLSocketFactory getDefault(int handshakeTimeoutMillis, SSLSessionCache cache) {
return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true);
@@ -117,13 +141,14 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
/**
* Returns a new instance of a socket factory with all SSL security checks
* disabled, using an optional handshake timeout and SSL session cache.
- * Sockets created using this factory are vulnerable to man-in-the-middle
- * attacks!
+ *
+ * <p class="caution"><b>Warning:</b> Sockets created using this factory
+ * are vulnerable to man-in-the-middle attacks!</p>
*
* @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
* for none. The socket timeout is reset to 0 after the handshake.
* @param cache The {@link SSLClientSessionCache} to use, or null for no cache.
- * @return an insecure SocketFactory with the specified parameters
+ * @return an insecure SSLSocketFactory with the specified parameters
*/
public static SSLSocketFactory getInsecure(int handshakeTimeoutMillis, SSLSessionCache cache) {
return new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, false);
@@ -145,6 +170,44 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
new SSLCertificateSocketFactory(handshakeTimeoutMillis, cache, true));
}
+ /**
+ * Verify the hostname of the certificate used by the other end of a
+ * connected socket. You MUST call this if you did not supply a hostname
+ * to {@link #createSocket()}. It is harmless to call this method
+ * redundantly if the hostname has already been verified.
+ *
+ * <p>Wildcard certificates are allowed to verify any matching hostname,
+ * so "foo.bar.example.com" is verified if the peer has a certificate
+ * for "*.example.com".
+ *
+ * @param socket An SSL socket which has been connected to a server
+ * @param hostname The expected hostname of the remote server
+ * @throws IOException if something goes wrong handshaking with the server
+ * @throws SSLPeerUnverifiedException if the server cannot prove its identity
+ *
+ * @hide
+ */
+ public static void verifyHostname(Socket socket, String hostname) throws IOException {
+ if (!(socket instanceof SSLSocket)) {
+ throw new IllegalArgumentException("Attempt to verify non-SSL socket");
+ }
+
+ if (!isSslCheckRelaxed()) {
+ // The code at the start of OpenSSLSocketImpl.startHandshake()
+ // ensures that the call is idempotent, so we can safely call it.
+ SSLSocket ssl = (SSLSocket) socket;
+ ssl.startHandshake();
+
+ SSLSession session = ssl.getSession();
+ if (session == null) {
+ throw new SSLException("Cannot verify SSL socket without session");
+ }
+ if (!HOSTNAME_VERIFIER.verify(hostname, session)) {
+ throw new SSLPeerUnverifiedException("Cannot verify hostname: " + hostname);
+ }
+ }
+ }
+
private SSLSocketFactory makeSocketFactory(TrustManager[] trustManagers) {
try {
SSLContextImpl sslContext = new SSLContextImpl();
@@ -156,10 +219,14 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
}
+ private static boolean isSslCheckRelaxed() {
+ return "1".equals(SystemProperties.get("ro.debuggable")) &&
+ "yes".equals(SystemProperties.get("socket.relaxsslcheck"));
+ }
+
private synchronized SSLSocketFactory getDelegate() {
// Relax the SSL check if instructed (for this factory, or systemwide)
- if (!mSecure || ("1".equals(SystemProperties.get("ro.debuggable")) &&
- "yes".equals(SystemProperties.get("socket.relaxsslcheck")))) {
+ if (!mSecure || isSslCheckRelaxed()) {
if (mInsecureFactory == null) {
if (mSecure) {
Log.w(TAG, "*** BYPASSING SSL SECURITY CHECKS (socket.relaxsslcheck=yes) ***");
@@ -177,13 +244,30 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
}
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This method verifies the peer's certificate hostname after connecting
+ * (unless created with {@link #getInsecure(int, SSLSessionCache)}).
+ */
@Override
public Socket createSocket(Socket k, String host, int port, boolean close) throws IOException {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+ if (mSecure) {
+ verifyHostname(s, host);
+ }
return s;
}
+ /**
+ * Creates a new socket which is not connected to any remote host.
+ * You must use {@link Socket#connect} to connect the socket.
+ *
+ * <p class="caution"><b>Warning:</b> Hostname verification is not performed
+ * with this method. You MUST verify the server's identity after connecting
+ * the socket to avoid man-in-the-middle attacks.</p>
+ */
@Override
public Socket createSocket() throws IOException {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket();
@@ -191,6 +275,13 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
return s;
}
+ /**
+ * {@inheritDoc}
+ *
+ * <p class="caution"><b>Warning:</b> Hostname verification is not performed
+ * with this method. You MUST verify the server's identity after connecting
+ * the socket to avoid man-in-the-middle attacks.</p>
+ */
@Override
public Socket createSocket(InetAddress addr, int port, InetAddress localAddr, int localPort)
throws IOException {
@@ -200,6 +291,13 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
return s;
}
+ /**
+ * {@inheritDoc}
+ *
+ * <p class="caution"><b>Warning:</b> Hostname verification is not performed
+ * with this method. You MUST verify the server's identity after connecting
+ * the socket to avoid man-in-the-middle attacks.</p>
+ */
@Override
public Socket createSocket(InetAddress addr, int port) throws IOException {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port);
@@ -207,19 +305,37 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
return s;
}
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This method verifies the peer's certificate hostname after connecting
+ * (unless created with {@link #getInsecure(int, SSLSessionCache)}).
+ */
@Override
public Socket createSocket(String host, int port, InetAddress localAddr, int localPort)
throws IOException {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
host, port, localAddr, localPort);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+ if (mSecure) {
+ verifyHostname(s, host);
+ }
return s;
}
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This method verifies the peer's certificate hostname after connecting
+ * (unless created with {@link #getInsecure(int, SSLSessionCache)}).
+ */
@Override
public Socket createSocket(String host, int port) throws IOException {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
+ if (mSecure) {
+ verifyHostname(s, host);
+ }
return s;
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index dedc347..01cc408 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -26,6 +26,7 @@ interface IPowerManager
void releaseWakeLock(IBinder lock, int flags);
void userActivity(long when, boolean noChangeLights);
void userActivityWithForce(long when, boolean noChangeLights, boolean force);
+ void clearUserActivityTimeout(long now, long timeout);
void setPokeLock(int pokey, IBinder lock, String tag);
int getSupportedWakeLockFlags();
void setStayOnSetting(int val);
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index a77717f..ce73ae1 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -36,6 +36,8 @@
android:description="@string/permdesc_testDenied" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
@@ -1203,8 +1205,12 @@
</application>
- <instrumentation
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.frameworks.coretests"
- android:label="Frameworks Core Tests" />
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.frameworks.coretests"
+ android:label="Frameworks Core Tests" />
+
+ <instrumentation android:name="android.bluetooth.BluetoothTestRunner"
+ android:targetPackage="com.android.frameworks.coretests"
+ android:label="Bluetooth Tests" />
+
</manifest>
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothRebootStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothRebootStressTest.java
new file mode 100644
index 0000000..33e9dd7
--- /dev/null
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothRebootStressTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 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.bluetooth;
+
+import android.content.Context;
+import android.test.InstrumentationTestCase;
+
+/**
+ * Instrumentation test case for stress test involving rebooting the device.
+ * <p>
+ * This test case tests that bluetooth is enabled after a device reboot. Because
+ * the device will reboot, the instrumentation must be driven by a script on the
+ * host side.
+ */
+public class BluetoothRebootStressTest extends InstrumentationTestCase {
+ private static final String TAG = "BluetoothRebootStressTest";
+ private static final String OUTPUT_FILE = "BluetoothRebootStressTestOutput.txt";
+
+ private BluetoothTestUtils mTestUtils;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ Context context = getInstrumentation().getTargetContext();
+ mTestUtils = new BluetoothTestUtils(context, TAG, OUTPUT_FILE);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ mTestUtils.close();
+ }
+
+ /**
+ * Test method used to start the test by turning bluetooth on.
+ */
+ public void testStart() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ mTestUtils.enable(adapter);
+ }
+
+ /**
+ * Test method used in the middle iterations of the test to check if
+ * bluetooth is on. Does not toggle bluetooth after the check. Assumes that
+ * bluetooth has been turned on by {@code #testStart()}
+ */
+ public void testMiddleNoToggle() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+
+ assertTrue(adapter.isEnabled());
+ }
+
+ /**
+ * Test method used in the middle iterations of the test to check if
+ * bluetooth is on. Toggles bluetooth after the check. Assumes that
+ * bluetooth has been turned on by {@code #testStart()}
+ */
+ public void testMiddleToggle() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+
+ assertTrue(adapter.isEnabled());
+
+ mTestUtils.disable(adapter);
+ mTestUtils.enable(adapter);
+ }
+
+ /**
+ * Test method used in the stop the test by turning bluetooth off. Assumes
+ * that bluetooth has been turned on by {@code #testStart()}
+ */
+ public void testStop() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+
+ assertTrue(adapter.isEnabled());
+
+ mTestUtils.disable(adapter);
+ }
+}
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
new file mode 100644
index 0000000..d8d9eba
--- /dev/null
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 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.bluetooth;
+
+import android.content.Context;
+import android.test.InstrumentationTestCase;
+
+public class BluetoothStressTest extends InstrumentationTestCase {
+ private static final String TAG = "BluetoothStressTest";
+ private static final String OUTPUT_FILE = "BluetoothStressTestOutput.txt";
+
+ private BluetoothTestUtils mTestUtils;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ Context context = getInstrumentation().getTargetContext();
+ mTestUtils = new BluetoothTestUtils(context, TAG, OUTPUT_FILE);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ mTestUtils.close();
+ }
+
+ public void testEnable() {
+ int iterations = BluetoothTestRunner.sEnableIterations;
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+
+ for (int i = 0; i < iterations; i++) {
+ mTestUtils.writeOutput("enable iteration " + (i + 1) + " of " + iterations);
+ mTestUtils.enable(adapter);
+ mTestUtils.disable(adapter);
+ }
+ }
+
+ public void testDiscoverable() {
+ int iterations = BluetoothTestRunner.sDiscoverableIterations;
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ mTestUtils.enable(adapter);
+
+ for (int i = 0; i < iterations; i++) {
+ mTestUtils.writeOutput("discoverable iteration " + (i + 1) + " of " + iterations);
+ mTestUtils.discoverable(adapter);
+ mTestUtils.undiscoverable(adapter);
+ }
+
+ mTestUtils.disable(adapter);
+ }
+
+ public void testScan() {
+ int iterations = BluetoothTestRunner.sScanIterations;
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ mTestUtils.enable(adapter);
+
+ for (int i = 0; i < iterations; i++) {
+ mTestUtils.writeOutput("scan iteration " + (i + 1) + " of " + iterations);
+ mTestUtils.startScan(adapter);
+ mTestUtils.stopScan(adapter);
+ }
+
+ mTestUtils.disable(adapter);
+ }
+}
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
new file mode 100644
index 0000000..cf0ff99
--- /dev/null
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 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.bluetooth;
+
+import junit.framework.TestSuite;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+
+public class BluetoothTestRunner extends InstrumentationTestRunner {
+ public static int sEnableIterations = 100;
+ public static int sDiscoverableIterations = 1000;
+ public static int sScanIterations = 1000;
+
+ @Override
+ public TestSuite getAllTests() {
+ TestSuite suite = new InstrumentationTestSuite(this);
+ suite.addTestSuite(BluetoothStressTest.class);
+ return suite;
+ }
+
+ @Override
+ public ClassLoader getLoader() {
+ return BluetoothTestRunner.class.getClassLoader();
+ }
+
+ @Override
+ public void onCreate(Bundle arguments) {
+ super.onCreate(arguments);
+
+ String val = arguments.getString("enable_iterations");
+ if (val != null) {
+ try {
+ sEnableIterations = Integer.parseInt(val);
+ } catch (NumberFormatException e) {
+ // Invalid argument, fall back to default value
+ }
+ }
+
+ val = arguments.getString("discoverable_iterations");
+ if (val != null) {
+ try {
+ sDiscoverableIterations = Integer.parseInt(val);
+ } catch (NumberFormatException e) {
+ // Invalid argument, fall back to default value
+ }
+ }
+
+ val = arguments.getString("scan_iterations");
+ if (val != null) {
+ try {
+ sScanIterations = Integer.parseInt(val);
+ } catch (NumberFormatException e) {
+ // Invalid argument, fall back to default value
+ }
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
new file mode 100644
index 0000000..82de509
--- /dev/null
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2010 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.bluetooth;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Environment;
+import android.util.Log;
+
+import junit.framework.Assert;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+public class BluetoothTestUtils extends Assert {
+
+ /**
+ * Timeout for {@link BluetoothAdapter#disable()} in ms.
+ */
+ private static final int DISABLE_TIMEOUT = 5000;
+
+ /**
+ * Timeout for {@link BluetoothAdapter#enable()} in ms.
+ */
+ private static final int ENABLE_TIMEOUT = 20000;
+
+ /**
+ * Timeout for {@link BluetoothAdapter#setScanMode(int)} in ms.
+ */
+ private static final int SET_SCAN_MODE_TIMEOUT = 5000;
+
+ /**
+ * Timeout for {@link BluetoothAdapter#startDiscovery()} in ms.
+ */
+ private static final int START_DISCOVERY_TIMEOUT = 5000;
+
+ /**
+ * Timeout for {@link BluetoothAdapter#cancelDiscovery()} in ms.
+ */
+ private static final int CANCEL_DISCOVERY_TIMEOUT = 5000;
+
+ private static final int DISCOVERY_STARTED_FLAG = 1;
+ private static final int DISCOVERY_FINISHED_FLAG = 1 << 1;
+ private static final int SCAN_MODE_NONE_FLAG = 1 << 2;
+ private static final int SCAN_MODE_CONNECTABLE_FLAG = 1 << 3;
+ private static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG = 1 << 4;
+ private static final int STATE_OFF_FLAG = 1 << 5;
+ private static final int STATE_TURNING_ON_FLAG = 1 << 6;
+ private static final int STATE_ON_FLAG = 1 << 7;
+ private static final int STATE_TURNING_OFF_FLAG = 1 << 8;
+
+ /**
+ * Time between polls in ms.
+ */
+ private static final int POLL_TIME = 100;
+
+ private Context mContext;
+
+ private BufferedWriter mOutputWriter;
+
+ private String mOutputFile;
+ private String mTag;
+
+ private class BluetoothReceiver extends BroadcastReceiver {
+ private int mFiredFlags = 0;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (this) {
+ if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) {
+ mFiredFlags |= DISCOVERY_STARTED_FLAG;
+ } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) {
+ mFiredFlags |= DISCOVERY_FINISHED_FLAG;
+ } else if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(intent.getAction())) {
+ int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
+ BluetoothAdapter.ERROR);
+ assertNotSame(mode, BluetoothAdapter.ERROR);
+ switch (mode) {
+ case BluetoothAdapter.SCAN_MODE_NONE:
+ mFiredFlags |= SCAN_MODE_NONE_FLAG;
+ break;
+ case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
+ mFiredFlags |= SCAN_MODE_CONNECTABLE_FLAG;
+ break;
+ case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+ mFiredFlags |= SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG;
+ break;
+ }
+ } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+ BluetoothAdapter.ERROR);
+ assertNotSame(state, BluetoothAdapter.ERROR);
+ switch (state) {
+ case BluetoothAdapter.STATE_OFF:
+ mFiredFlags |= STATE_OFF_FLAG;
+ break;
+ case BluetoothAdapter.STATE_TURNING_ON:
+ mFiredFlags |= STATE_TURNING_ON_FLAG;
+ break;
+ case BluetoothAdapter.STATE_ON:
+ mFiredFlags |= STATE_ON_FLAG;
+ break;
+ case BluetoothAdapter.STATE_TURNING_OFF:
+ mFiredFlags |= STATE_TURNING_OFF_FLAG;
+ break;
+ }
+ }
+ }
+ }
+
+ public int getFiredFlags() {
+ synchronized (this) {
+ return mFiredFlags;
+ }
+ }
+
+ public void resetFiredFlags() {
+ synchronized (this) {
+ mFiredFlags = 0;
+ }
+ }
+ }
+
+ private BluetoothReceiver mReceiver = new BluetoothReceiver();
+
+ public BluetoothTestUtils(Context context, String tag) {
+ this(context, tag, null);
+ }
+
+ public BluetoothTestUtils(Context context, String tag, String outputFile) {
+ mContext = context;
+ mTag = tag;
+ mOutputFile = outputFile;
+
+ if (mOutputFile == null) {
+ mOutputWriter = null;
+ } else {
+ try {
+ mOutputWriter = new BufferedWriter(new FileWriter(new File(
+ Environment.getExternalStorageDirectory(), mOutputFile), true));
+ } catch (IOException e) {
+ Log.w(mTag, "Test output file could not be opened", e);
+ mOutputWriter = null;
+ }
+ }
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
+ filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
+ filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
+ filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+ mContext.registerReceiver(mReceiver, filter);
+ }
+
+ public void close() {
+ mContext.unregisterReceiver(mReceiver);
+
+ if (mOutputWriter != null) {
+ try {
+ mOutputWriter.close();
+ } catch (IOException e) {
+ Log.w(mTag, "Test output file could not be closed", e);
+ }
+ }
+ }
+
+ public void enable(BluetoothAdapter adapter) {
+ int mask = STATE_TURNING_ON_FLAG | STATE_ON_FLAG | SCAN_MODE_CONNECTABLE_FLAG;
+ mReceiver.resetFiredFlags();
+
+ int state = adapter.getState();
+ switch (state) {
+ case BluetoothAdapter.STATE_ON:
+ assertTrue(adapter.isEnabled());
+ return;
+ case BluetoothAdapter.STATE_OFF:
+ case BluetoothAdapter.STATE_TURNING_OFF:
+ assertFalse(adapter.isEnabled());
+ assertTrue(adapter.enable());
+ break;
+ case BluetoothAdapter.STATE_TURNING_ON:
+ assertFalse(adapter.isEnabled());
+ mask = 0; // Don't check for received intents since we might have missed them.
+ break;
+ default:
+ fail("enable() invalid state: state=" + state);
+ }
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < ENABLE_TIMEOUT) {
+ state = adapter.getState();
+ if (state == BluetoothAdapter.STATE_ON) {
+ assertTrue(adapter.isEnabled());
+ if ((mReceiver.getFiredFlags() & mask) == mask) {
+ mReceiver.resetFiredFlags();
+ writeOutput(String.format("enable() completed in %d ms",
+ (System.currentTimeMillis() - s)));
+ return;
+ }
+ } else {
+ assertFalse(adapter.isEnabled());
+ assertEquals(BluetoothAdapter.STATE_TURNING_ON, state);
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = mReceiver.getFiredFlags();
+ mReceiver.resetFiredFlags();
+ fail(String.format("enable() timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+ state, BluetoothAdapter.STATE_ON, firedFlags, mask));
+ }
+
+ public void disable(BluetoothAdapter adapter) {
+ int mask = STATE_TURNING_OFF_FLAG | STATE_OFF_FLAG | SCAN_MODE_NONE_FLAG;
+ mReceiver.resetFiredFlags();
+
+ int state = adapter.getState();
+ switch (state) {
+ case BluetoothAdapter.STATE_OFF:
+ assertFalse(adapter.isEnabled());
+ return;
+ case BluetoothAdapter.STATE_ON:
+ assertTrue(adapter.isEnabled());
+ assertTrue(adapter.disable());
+ break;
+ case BluetoothAdapter.STATE_TURNING_ON:
+ assertFalse(adapter.isEnabled());
+ assertTrue(adapter.disable());
+ break;
+ case BluetoothAdapter.STATE_TURNING_OFF:
+ assertFalse(adapter.isEnabled());
+ mask = 0; // Don't check for received intents since we might have missed them.
+ break;
+ default:
+ fail("disable() invalid state: state=" + state);
+ }
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < DISABLE_TIMEOUT) {
+ state = adapter.getState();
+ if (state == BluetoothAdapter.STATE_OFF) {
+ assertFalse(adapter.isEnabled());
+ if ((mReceiver.getFiredFlags() & mask) == mask) {
+ mReceiver.resetFiredFlags();
+ writeOutput(String.format("disable() completed in %d ms",
+ (System.currentTimeMillis() - s)));
+ return;
+ }
+ } else {
+ assertFalse(adapter.isEnabled());
+ assertEquals(BluetoothAdapter.STATE_TURNING_OFF, state);
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = mReceiver.getFiredFlags();
+ mReceiver.resetFiredFlags();
+ fail(String.format("disable() timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
+ state, BluetoothAdapter.STATE_OFF, firedFlags, mask));
+ }
+
+ public void discoverable(BluetoothAdapter adapter) {
+ int mask = SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG;
+ mReceiver.resetFiredFlags();
+
+ if (!adapter.isEnabled()) {
+ fail("discoverable() bluetooth not enabled");
+ }
+
+ int scanMode = adapter.getScanMode();
+ if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
+ return;
+ }
+
+ assertEquals(scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE);
+ assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < SET_SCAN_MODE_TIMEOUT) {
+ scanMode = adapter.getScanMode();
+ if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
+ if ((mReceiver.getFiredFlags() & mask) == mask) {
+ mReceiver.resetFiredFlags();
+ writeOutput(String.format("discoverable() completed in %d ms",
+ (System.currentTimeMillis() - s)));
+ return;
+ }
+ } else {
+ assertEquals(scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE);
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = mReceiver.getFiredFlags();
+ mReceiver.resetFiredFlags();
+ fail(String.format("discoverable() timeout: scanMode=%d (expected %d), flags=0x%x "
+ + "(expected 0x%x)", scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE,
+ firedFlags, mask));
+ }
+
+ public void undiscoverable(BluetoothAdapter adapter) {
+ int mask = SCAN_MODE_CONNECTABLE_FLAG;
+ mReceiver.resetFiredFlags();
+
+ if (!adapter.isEnabled()) {
+ fail("undiscoverable() bluetooth not enabled");
+ }
+
+ int scanMode = adapter.getScanMode();
+ if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
+ return;
+ }
+
+ assertEquals(scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+ assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < SET_SCAN_MODE_TIMEOUT) {
+ scanMode = adapter.getScanMode();
+ if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
+ if ((mReceiver.getFiredFlags() & mask) == mask) {
+ mReceiver.resetFiredFlags();
+ writeOutput(String.format("undiscoverable() completed in %d ms",
+ (System.currentTimeMillis() - s)));
+ return;
+ }
+ } else {
+ assertEquals(scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = mReceiver.getFiredFlags();
+ mReceiver.resetFiredFlags();
+ fail(String.format("undiscoverable() timeout: scanMode=%d (expected %d), flags=0x%x "
+ + "(expected 0x%x)", scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE, firedFlags,
+ mask));
+ }
+
+ public void startScan(BluetoothAdapter adapter) {
+ int mask = DISCOVERY_STARTED_FLAG;
+ mReceiver.resetFiredFlags();
+
+ if (!adapter.isEnabled()) {
+ fail("startScan() bluetooth not enabled");
+ }
+
+ if (adapter.isDiscovering()) {
+ return;
+ }
+
+ assertTrue(adapter.startDiscovery());
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < START_DISCOVERY_TIMEOUT) {
+ if (adapter.isDiscovering() && ((mReceiver.getFiredFlags() & mask) == mask)) {
+ mReceiver.resetFiredFlags();
+ writeOutput(String.format("startScan() completed in %d ms",
+ (System.currentTimeMillis() - s)));
+ return;
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = mReceiver.getFiredFlags();
+ mReceiver.resetFiredFlags();
+ fail(String.format("startScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)",
+ adapter.isDiscovering(), firedFlags, mask));
+ }
+
+ public void stopScan(BluetoothAdapter adapter) {
+ int mask = DISCOVERY_FINISHED_FLAG;
+ mReceiver.resetFiredFlags();
+
+ if (!adapter.isEnabled()) {
+ fail("stopScan() bluetooth not enabled");
+ }
+
+ if (!adapter.isDiscovering()) {
+ return;
+ }
+
+ // TODO: put assertTrue() around cancelDiscovery() once it starts returning true.
+ adapter.cancelDiscovery();
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < CANCEL_DISCOVERY_TIMEOUT) {
+ if (!adapter.isDiscovering() && ((mReceiver.getFiredFlags() & mask) == mask)) {
+ mReceiver.resetFiredFlags();
+ writeOutput(String.format("stopScan() completed in %d ms",
+ (System.currentTimeMillis() - s)));
+ return;
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = mReceiver.getFiredFlags();
+ mReceiver.resetFiredFlags();
+ fail(String.format("stopScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)",
+ adapter.isDiscovering(), firedFlags, mask));
+
+ }
+
+ public void writeOutput(String s) {
+ Log.i(mTag, s);
+ if (mOutputWriter == null) {
+ return;
+ }
+ try {
+ mOutputWriter.write(s + "\n");
+ mOutputWriter.flush();
+ } catch (IOException e) {
+ Log.w(mTag, "Could not write to output file", e);
+ }
+ }
+
+ private void sleep(long time) {
+ try {
+ Thread.sleep(time);
+ } catch (InterruptedException e) {
+ }
+ }
+}
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 9af5871..9a09586 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -86,6 +86,10 @@ private:
bool mStarted;
+ bool mIsFirstBuffer;
+ status_t mFirstBufferResult;
+ MediaBuffer *mFirstBuffer;
+
sp<MediaPlayerBase::AudioSink> mAudioSink;
static void AudioCallback(int event, void *user, void *info);
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 5c278d9..08fc782 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -16,6 +16,7 @@
package android.media;
+import java.util.NoSuchElementException;
import android.app.ActivityManagerNative;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -1016,7 +1017,11 @@ public class AudioService extends IAudioService.Stub {
} else {
mStartcount--;
if (mStartcount == 0) {
- mCb.unlinkToDeath(this, 0);
+ try {
+ mCb.unlinkToDeath(this, 0);
+ } catch (NoSuchElementException e) {
+ Log.w(TAG, "decCount() going to 0 but not registered to binder");
+ }
}
requestScoState(BluetoothHeadset.AUDIO_STATE_DISCONNECTED);
}
@@ -1025,8 +1030,14 @@ public class AudioService extends IAudioService.Stub {
public void clearCount(boolean stopSco) {
synchronized(mScoClients) {
+ if (mStartcount != 0) {
+ try {
+ mCb.unlinkToDeath(this, 0);
+ } catch (NoSuchElementException e) {
+ Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
+ }
+ }
mStartcount = 0;
- mCb.unlinkToDeath(this, 0);
if (stopSco) {
requestScoState(BluetoothHeadset.AUDIO_STATE_DISCONNECTED);
}
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index bcf2463..c27cfc8 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -23,6 +23,7 @@
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
@@ -41,6 +42,9 @@ AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink)
mReachedEOS(false),
mFinalStatus(OK),
mStarted(false),
+ mIsFirstBuffer(false),
+ mFirstBufferResult(OK),
+ mFirstBuffer(NULL),
mAudioSink(audioSink) {
}
@@ -68,6 +72,24 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) {
}
}
+ // We allow an optional INFO_FORMAT_CHANGED at the very beginning
+ // of playback, if there is one, getFormat below will retrieve the
+ // updated format, if there isn't, we'll stash away the valid buffer
+ // of data to be used on the first audio callback.
+
+ CHECK(mFirstBuffer == NULL);
+
+ mFirstBufferResult = mSource->read(&mFirstBuffer);
+ if (mFirstBufferResult == INFO_FORMAT_CHANGED) {
+ LOGV("INFO_FORMAT_CHANGED!!!");
+
+ CHECK(mFirstBuffer == NULL);
+ mFirstBufferResult = OK;
+ mIsFirstBuffer = false;
+ } else {
+ mIsFirstBuffer = true;
+ }
+
sp<MetaData> format = mSource->getFormat();
const char *mime;
bool success = format->findCString(kKeyMIMEType, &mime);
@@ -87,7 +109,14 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) {
DEFAULT_AUDIOSINK_BUFFERCOUNT,
&AudioPlayer::AudioSinkCallback, this);
if (err != OK) {
- mSource->stop();
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (!sourceAlreadyStarted) {
+ mSource->stop();
+ }
return err;
}
@@ -108,7 +137,14 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) {
delete mAudioTrack;
mAudioTrack = NULL;
- mSource->stop();
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (!sourceAlreadyStarted) {
+ mSource->stop();
+ }
return err;
}
@@ -159,6 +195,12 @@ void AudioPlayer::stop() {
// Make sure to release any buffer we hold onto so that the
// source is able to stop().
+
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
if (mInputBuffer != NULL) {
LOGV("AudioPlayer releasing input buffer.");
@@ -243,6 +285,14 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) {
Mutex::Autolock autoLock(mLock);
if (mSeeking) {
+ if (mIsFirstBuffer) {
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+ mIsFirstBuffer = false;
+ }
+
options.setSeekTo(mSeekTimeUs);
if (mInputBuffer != NULL) {
@@ -255,7 +305,17 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) {
}
if (mInputBuffer == NULL) {
- status_t err = mSource->read(&mInputBuffer, &options);
+ status_t err;
+
+ if (mIsFirstBuffer) {
+ mInputBuffer = mFirstBuffer;
+ mFirstBuffer = NULL;
+ err = mFirstBufferResult;
+
+ mIsFirstBuffer = false;
+ } else {
+ err = mSource->read(&mInputBuffer, &options);
+ }
CHECK((err == OK && mInputBuffer != NULL)
|| (err != OK && mInputBuffer == NULL));
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index 2bc4448..8ae1135 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -15,6 +15,7 @@
*/
#include "AACDecoder.h"
+#define LOG_TAG "AACDecoder"
#include "../../include/ESDS.h"
@@ -36,26 +37,33 @@ AACDecoder::AACDecoder(const sp<MediaSource> &source)
mAnchorTimeUs(0),
mNumSamplesOutput(0),
mInputBuffer(NULL) {
-}
-AACDecoder::~AACDecoder() {
- if (mStarted) {
- stop();
- }
+ sp<MetaData> srcFormat = mSource->getFormat();
- delete mConfig;
- mConfig = NULL;
-}
+ int32_t sampleRate;
+ CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
-status_t AACDecoder::start(MetaData *params) {
- CHECK(!mStarted);
+ mMeta = new MetaData;
+ mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(new MediaBuffer(2048 * 2));
+ // We'll always output stereo, regardless of how many channels are
+ // present in the input due to decoder limitations.
+ mMeta->setInt32(kKeyChannelCount, 2);
+ mMeta->setInt32(kKeySampleRate, sampleRate);
+ int64_t durationUs;
+ if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
+ mMeta->setInt64(kKeyDuration, durationUs);
+ }
+ mMeta->setCString(kKeyDecoderComponent, "AACDecoder");
+
+ mInitCheck = initCheck();
+}
+
+status_t AACDecoder::initCheck() {
+ memset(mConfig, 0, sizeof(tPVMP4AudioDecoderExternal));
mConfig->outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED;
- mConfig->aacPlusUpsamplingFactor = 0;
- mConfig->aacPlusEnabled = false;
+ mConfig->aacPlusEnabled = 1;
// The software decoder doesn't properly support mono output on
// AACplus files. Always output stereo.
@@ -64,8 +72,11 @@ status_t AACDecoder::start(MetaData *params) {
UInt32 memRequirements = PVMP4AudioDecoderGetMemRequirements();
mDecoderBuf = malloc(memRequirements);
- CHECK_EQ(PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf),
- MP4AUDEC_SUCCESS);
+ status_t err = PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf);
+ if (err != MP4AUDEC_SUCCESS) {
+ LOGE("Failed to initialize MP4 audio decoder");
+ return UNKNOWN_ERROR;
+ }
uint32_t type;
const void *data;
@@ -83,18 +94,29 @@ status_t AACDecoder::start(MetaData *params) {
mConfig->pInputBuffer = (UChar *)codec_specific_data;
mConfig->inputBufferCurrentLength = codec_specific_data_size;
mConfig->inputBufferMaxLength = 0;
- mConfig->inputBufferUsedLength = 0;
- mConfig->remainderBits = 0;
-
- mConfig->pOutputBuffer = NULL;
- mConfig->pOutputBuffer_plus = NULL;
- mConfig->repositionFlag = false;
if (PVMP4AudioDecoderConfig(mConfig, mDecoderBuf)
!= MP4AUDEC_SUCCESS) {
return ERROR_UNSUPPORTED;
}
}
+ return OK;
+}
+
+AACDecoder::~AACDecoder() {
+ if (mStarted) {
+ stop();
+ }
+
+ delete mConfig;
+ mConfig = NULL;
+}
+
+status_t AACDecoder::start(MetaData *params) {
+ CHECK(!mStarted);
+
+ mBufferGroup = new MediaBufferGroup;
+ mBufferGroup->add_buffer(new MediaBuffer(4096 * 2));
mSource->start();
@@ -127,28 +149,7 @@ status_t AACDecoder::stop() {
}
sp<MetaData> AACDecoder::getFormat() {
- sp<MetaData> srcFormat = mSource->getFormat();
-
- int32_t sampleRate;
- CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
-
- sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-
- // We'll always output stereo, regardless of how many channels are
- // present in the input due to decoder limitations.
- meta->setInt32(kKeyChannelCount, 2);
-
- meta->setInt32(kKeySampleRate, sampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- meta->setInt64(kKeyDuration, durationUs);
- }
-
- meta->setCString(kKeyDecoderComponent, "AACDecoder");
-
- return meta;
+ return mMeta;
}
status_t AACDecoder::read(
@@ -200,13 +201,32 @@ status_t AACDecoder::read(
mConfig->remainderBits = 0;
mConfig->pOutputBuffer = static_cast<Int16 *>(buffer->data());
- mConfig->pOutputBuffer_plus = NULL;
+ mConfig->pOutputBuffer_plus = &mConfig->pOutputBuffer[2048];
mConfig->repositionFlag = false;
Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf);
+ // Check on the sampling rate to see whether it is changed.
+ int32_t sampleRate;
+ CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate));
+ if (mConfig->samplingRate != sampleRate) {
+ mMeta->setInt32(kKeySampleRate, mConfig->samplingRate);
+ LOGW("Sample rate was %d, but now is %d",
+ sampleRate, mConfig->samplingRate);
+ buffer->release();
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ return INFO_FORMAT_CHANGED;
+ }
+
size_t numOutBytes =
mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels;
+ if (mConfig->aacPlusUpsamplingFactor == 2) {
+ if (mConfig->desiredChannels == 1) {
+ memcpy(&mConfig->pOutputBuffer[1024], &mConfig->pOutputBuffer[2048], numOutBytes * 2);
+ }
+ numOutBytes *= 2;
+ }
if (decoderErr != MP4AUDEC_SUCCESS) {
LOGW("AAC decoder returned error %d, substituting silence", decoderErr);
diff --git a/media/libstagefright/include/AACDecoder.h b/media/libstagefright/include/AACDecoder.h
index f09addd..200f93c 100644
--- a/media/libstagefright/include/AACDecoder.h
+++ b/media/libstagefright/include/AACDecoder.h
@@ -25,6 +25,7 @@ struct tPVMP4AudioDecoderExternal;
namespace android {
struct MediaBufferGroup;
+struct MetaData;
struct AACDecoder : public MediaSource {
AACDecoder(const sp<MediaSource> &source);
@@ -41,6 +42,7 @@ protected:
virtual ~AACDecoder();
private:
+ sp<MetaData> mMeta;
sp<MediaSource> mSource;
bool mStarted;
@@ -50,9 +52,11 @@ private:
void *mDecoderBuf;
int64_t mAnchorTimeUs;
int64_t mNumSamplesOutput;
+ status_t mInitCheck;
MediaBuffer *mInputBuffer;
+ status_t initCheck();
AACDecoder(const AACDecoder &);
AACDecoder &operator=(const AACDecoder &);
};
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 185d72a..8349fe6 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -47,7 +47,8 @@
<bool name="def_networks_available_notification_on">true</bool>
<bool name="def_backup_enabled">false</bool>
- <string name="def_backup_transport" translatable="false"></string>
+ <string name="def_backup_transport" translatable="false">android/com.android.internal.backup.LocalTransport</string>
+
<!-- Default value for whether or not to pulse the notification LED when there is a
pending notification -->
<bool name="def_notification_pulse">true</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 2b4714d..dab7601 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -49,6 +49,7 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.HashSet;
import java.util.List;
/**
@@ -67,11 +68,29 @@ public class DatabaseHelper extends SQLiteOpenHelper {
private Context mContext;
+ private static final HashSet<String> mValidTables = new HashSet<String>();
+
+ static {
+ mValidTables.add("system");
+ mValidTables.add("secure");
+ mValidTables.add("bluetooth_devices");
+ mValidTables.add("bookmarks");
+
+ // These are old.
+ mValidTables.add("favorites");
+ mValidTables.add("gservices");
+ mValidTables.add("old_favorites");
+ }
+
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mContext = context;
}
+ public static boolean isValidTable(String name) {
+ return mValidTables.contains(name);
+ }
+
private void createSecureTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE secure (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index c4b4c31..b8c4961 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -84,6 +84,9 @@ public class SettingsProvider extends ContentProvider {
SqlArguments(Uri url, String where, String[] args) {
if (url.getPathSegments().size() == 1) {
this.table = url.getPathSegments().get(0);
+ if (!DatabaseHelper.isValidTable(this.table)) {
+ throw new IllegalArgumentException("Bad root path: " + this.table);
+ }
this.where = where;
this.args = args;
} else if (url.getPathSegments().size() != 2) {
@@ -92,6 +95,9 @@ public class SettingsProvider extends ContentProvider {
throw new UnsupportedOperationException("WHERE clause not supported: " + url);
} else {
this.table = url.getPathSegments().get(0);
+ if (!DatabaseHelper.isValidTable(this.table)) {
+ throw new IllegalArgumentException("Bad root path: " + this.table);
+ }
if ("system".equals(this.table) || "secure".equals(this.table)) {
this.where = Settings.NameValueTable.NAME + "=?";
this.args = new String[] { url.getPathSegments().get(1) };
@@ -106,6 +112,9 @@ public class SettingsProvider extends ContentProvider {
SqlArguments(Uri url) {
if (url.getPathSegments().size() == 1) {
this.table = url.getPathSegments().get(0);
+ if (!DatabaseHelper.isValidTable(this.table)) {
+ throw new IllegalArgumentException("Bad root path: " + this.table);
+ }
this.where = null;
this.args = null;
} else {
@@ -214,16 +223,11 @@ public class SettingsProvider extends ContentProvider {
final String value = c.moveToNext() ? c.getString(0) : null;
if (value == null) {
final SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
- String serial = SystemProperties.get("ro.serialno");
- if (serial != null) {
- try {
- random.setSeed(serial.getBytes("UTF-8"));
- } catch (UnsupportedEncodingException ignore) {
- // stick with default seed
- }
- }
+ String serial = SystemProperties.get("ro.serialno", "");
+ random.setSeed(
+ (serial + System.nanoTime() + new SecureRandom().nextLong()).getBytes());
final String newAndroidIdValue = Long.toHexString(random.nextLong());
- Log.d(TAG, "Generated and saved new ANDROID_ID");
+ Log.d(TAG, "Generated and saved new ANDROID_ID [" + newAndroidIdValue + "]");
final ContentValues values = new ContentValues();
values.put(Settings.NameValueTable.NAME, Settings.Secure.ANDROID_ID);
values.put(Settings.NameValueTable.VALUE, newAndroidIdValue);
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 6ceeb95..6c2f1b2 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -642,10 +642,21 @@ class MountService extends IMountService.Stub
}
private boolean doGetShareMethodAvailable(String method) {
- ArrayList<String> rsp = mConnector.doCommand("share status " + method);
+ ArrayList<String> rsp;
+ try {
+ rsp = mConnector.doCommand("share status " + method);
+ } catch (NativeDaemonConnectorException ex) {
+ Slog.e(TAG, "Failed to determine whether share method " + method + " is available.");
+ return false;
+ }
for (String line : rsp) {
- String []tok = line.split(" ");
+ String[] tok = line.split(" ");
+ if (tok.length < 3) {
+ Slog.e(TAG, "Malformed response to share status " + method);
+ return false;
+ }
+
int code;
try {
code = Integer.parseInt(tok[0]);
@@ -770,10 +781,22 @@ class MountService extends IMountService.Stub
private boolean doGetVolumeShared(String path, String method) {
String cmd = String.format("volume shared %s %s", path, method);
- ArrayList<String> rsp = mConnector.doCommand(cmd);
+ ArrayList<String> rsp;
+
+ try {
+ rsp = mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException ex) {
+ Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method);
+ return false;
+ }
for (String line : rsp) {
- String []tok = line.split(" ");
+ String[] tok = line.split(" ");
+ if (tok.length < 3) {
+ Slog.e(TAG, "Malformed response to volume shared " + path + " " + method + " command");
+ return false;
+ }
+
int code;
try {
code = Integer.parseInt(tok[0]);
@@ -782,9 +805,7 @@ class MountService extends IMountService.Stub
return false;
}
if (code == VoldResponseCode.ShareEnabledResult) {
- if (tok[2].equals("enabled"))
- return true;
- return false;
+ return "enabled".equals(tok[2]);
} else {
Slog.e(TAG, String.format("Unexpected response code %d", code));
return false;
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 08d7ce6..c452590 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -128,12 +128,11 @@ final class NativeDaemonConnector implements Runnable {
Slog.e(TAG, String.format(
"Error handling '%s'", event), ex);
}
- } else {
- try {
- mResponseQueue.put(event);
- } catch (InterruptedException ex) {
- Slog.e(TAG, "Failed to put response onto queue", ex);
- }
+ }
+ try {
+ mResponseQueue.put(event);
+ } catch (InterruptedException ex) {
+ Slog.e(TAG, "Failed to put response onto queue", ex);
}
} catch (NumberFormatException nfe) {
Slog.w(TAG, String.format("Bad msg (%s)", event));
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index cbbc7be..c156150 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -35,6 +35,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import java.util.ArrayList;
+import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import android.provider.Settings;
import android.content.ContentResolver;
@@ -226,44 +227,61 @@ class NetworkManagementService extends INetworkManagementService.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
- return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
+ try {
+ return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Cannot communicate with native daemon to list interfaces");
+ }
}
public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
- String rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
+ String rsp;
+ try {
+ rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Cannot communicate with native daemon to get interface config");
+ }
Slog.d(TAG, String.format("rsp <%s>", rsp));
// Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz.zzz.zzz.zzz [flag1 flag2 flag3]
StringTokenizer st = new StringTokenizer(rsp);
+ InterfaceConfiguration cfg;
try {
- int code = Integer.parseInt(st.nextToken(" "));
- if (code != NetdResponseCode.InterfaceGetCfgResult) {
+ try {
+ int code = Integer.parseInt(st.nextToken(" "));
+ if (code != NetdResponseCode.InterfaceGetCfgResult) {
+ throw new IllegalStateException(
+ String.format("Expected code %d, but got %d",
+ NetdResponseCode.InterfaceGetCfgResult, code));
+ }
+ } catch (NumberFormatException nfe) {
throw new IllegalStateException(
- String.format("Expected code %d, but got %d",
- NetdResponseCode.InterfaceGetCfgResult, code));
+ String.format("Invalid response from daemon (%s)", rsp));
}
- } catch (NumberFormatException nfe) {
- throw new IllegalStateException(
- String.format("Invalid response from daemon (%s)", rsp));
- }
- InterfaceConfiguration cfg = new InterfaceConfiguration();
- cfg.hwAddr = st.nextToken(" ");
- try {
- cfg.ipAddr = stringToIpAddr(st.nextToken(" "));
- } catch (UnknownHostException uhe) {
- Slog.e(TAG, "Failed to parse ipaddr", uhe);
- cfg.ipAddr = 0;
- }
+ cfg = new InterfaceConfiguration();
+ cfg.hwAddr = st.nextToken(" ");
+ try {
+ cfg.ipAddr = stringToIpAddr(st.nextToken(" "));
+ } catch (UnknownHostException uhe) {
+ Slog.e(TAG, "Failed to parse ipaddr", uhe);
+ cfg.ipAddr = 0;
+ }
- try {
- cfg.netmask = stringToIpAddr(st.nextToken(" "));
- } catch (UnknownHostException uhe) {
- Slog.e(TAG, "Failed to parse netmask", uhe);
- cfg.netmask = 0;
+ try {
+ cfg.netmask = stringToIpAddr(st.nextToken(" "));
+ } catch (UnknownHostException uhe) {
+ Slog.e(TAG, "Failed to parse netmask", uhe);
+ cfg.netmask = 0;
+ }
+ cfg.interfaceFlags = st.nextToken("]").trim() +"]";
+ } catch (NoSuchElementException nsee) {
+ throw new IllegalStateException(
+ String.format("Invalid response from daemon (%s)", rsp));
}
- cfg.interfaceFlags = st.nextToken("]").trim() +"]";
Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
return cfg;
}
@@ -272,7 +290,12 @@ class NetworkManagementService extends INetworkManagementService.Stub {
String iface, InterfaceConfiguration cfg) throws IllegalStateException {
String cmd = String.format("interface setcfg %s %s %s %s", iface,
intToIpString(cfg.ipAddr), intToIpString(cfg.netmask), cfg.interfaceFlags);
- mConnector.doCommand(cmd);
+ try {
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Unable to communicate with native daemon to interface setcfg");
+ }
}
public void shutdown() {
@@ -289,20 +312,25 @@ class NetworkManagementService extends INetworkManagementService.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
- ArrayList<String> rsp = mConnector.doCommand("ipfwd status");
+ ArrayList<String> rsp;
+ try {
+ rsp = mConnector.doCommand("ipfwd status");
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Unable to communicate with native daemon to ipfwd status");
+ }
for (String line : rsp) {
- String []tok = line.split(" ");
+ String[] tok = line.split(" ");
+ if (tok.length < 3) {
+ Slog.e(TAG, "Malformed response from native daemon: " + line);
+ return false;
+ }
+
int code = Integer.parseInt(tok[0]);
if (code == NetdResponseCode.IpFwdStatusResult) {
// 211 Forwarding <enabled/disabled>
- if (tok.length !=2) {
- throw new IllegalStateException(
- String.format("Malformatted list entry '%s'", line));
- }
- if (tok[2].equals("enabled"))
- return true;
- return false;
+ return "enabled".equals(tok[2]);
} else {
throw new IllegalStateException(String.format("Unexpected response code %d", code));
}
@@ -326,29 +354,45 @@ class NetworkManagementService extends INetworkManagementService.Stub {
for (String d : dhcpRange) {
cmd += " " + d;
}
- mConnector.doCommand(cmd);
+
+ try {
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Unable to communicate to native daemon");
+ }
}
public void stopTethering() throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
- mConnector.doCommand("tether stop");
+ try {
+ mConnector.doCommand("tether stop");
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
+ }
}
public boolean isTetheringStarted() throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
- ArrayList<String> rsp = mConnector.doCommand("tether status");
+ ArrayList<String> rsp;
+ try {
+ rsp = mConnector.doCommand("tether status");
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Unable to communicate to native daemon to get tether status");
+ }
for (String line : rsp) {
- String []tok = line.split(" ");
+ String[] tok = line.split(" ");
+ if (tok.length < 3) {
+ throw new IllegalStateException("Malformed response for tether status: " + line);
+ }
int code = Integer.parseInt(tok[0]);
if (code == NetdResponseCode.TetherStatusResult) {
// XXX: Tethering services <started/stopped> <TBD>...
- if (tok[2].equals("started"))
- return true;
- return false;
+ return "started".equals(tok[2]);
} else {
throw new IllegalStateException(String.format("Unexpected response code %d", code));
}
@@ -359,20 +403,35 @@ class NetworkManagementService extends INetworkManagementService.Stub {
public void tetherInterface(String iface) throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
- mConnector.doCommand("tether interface add " + iface);
+ try {
+ mConnector.doCommand("tether interface add " + iface);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Unable to communicate to native daemon for adding tether interface");
+ }
}
public void untetherInterface(String iface) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
- mConnector.doCommand("tether interface remove " + iface);
+ try {
+ mConnector.doCommand("tether interface remove " + iface);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Unable to communicate to native daemon for removing tether interface");
+ }
}
public String[] listTetheredInterfaces() throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
- return mConnector.doListCommand(
- "tether interface list", NetdResponseCode.TetherInterfaceListResult);
+ try {
+ return mConnector.doListCommand(
+ "tether interface list", NetdResponseCode.TetherInterfaceListResult);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Unable to communicate to native daemon for listing tether interfaces");
+ }
}
public void setDnsForwarders(String[] dns) throws IllegalStateException {
@@ -383,7 +442,12 @@ class NetworkManagementService extends INetworkManagementService.Stub {
for (String s : dns) {
cmd += " " + InetAddress.getByName(s).getHostAddress();
}
- mConnector.doCommand(cmd);
+ try {
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Unable to communicate to native daemon for setting tether dns");
+ }
} catch (UnknownHostException e) {
throw new IllegalStateException("Error resolving dns name", e);
}
@@ -392,30 +456,50 @@ class NetworkManagementService extends INetworkManagementService.Stub {
public String[] getDnsForwarders() throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
- return mConnector.doListCommand(
- "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
+ try {
+ return mConnector.doListCommand(
+ "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Unable to communicate to native daemon for listing tether dns");
+ }
}
public void enableNat(String internalInterface, String externalInterface)
throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
- mConnector.doCommand(
- String.format("nat enable %s %s", internalInterface, externalInterface));
+ try {
+ mConnector.doCommand(
+ String.format("nat enable %s %s", internalInterface, externalInterface));
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Unable to communicate to native daemon for enabling NAT interface");
+ }
}
public void disableNat(String internalInterface, String externalInterface)
throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
- mConnector.doCommand(
- String.format("nat disable %s %s", internalInterface, externalInterface));
+ try {
+ mConnector.doCommand(
+ String.format("nat disable %s %s", internalInterface, externalInterface));
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Unable to communicate to native daemon for disabling NAT interface");
+ }
}
public String[] listTtys() throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
- return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
+ try {
+ return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Unable to communicate to native daemon for listing TTYs");
+ }
}
public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
@@ -430,31 +514,52 @@ class NetworkManagementService extends INetworkManagementService.Stub {
InetAddress.getByName(dns2Addr).getHostAddress()));
} catch (UnknownHostException e) {
throw new IllegalStateException("Error resolving addr", e);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
}
}
public void detachPppd(String tty) throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
- mConnector.doCommand(String.format("pppd detach %s", tty));
+ try {
+ mConnector.doCommand(String.format("pppd detach %s", tty));
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
+ }
}
public void startUsbRNDIS() throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
- mConnector.doCommand("usb startrndis");
+ try {
+ mConnector.doCommand("usb startrndis");
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Error communicating to native daemon for starting RNDIS", e);
+ }
}
public void stopUsbRNDIS() throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
- mConnector.doCommand("usb stoprndis");
+ try {
+ mConnector.doCommand("usb stoprndis");
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
}
public boolean isUsbRNDISStarted() throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
- ArrayList<String> rsp = mConnector.doCommand("usb rndisstatus");
+ ArrayList<String> rsp;
+ try {
+ rsp = mConnector.doCommand("usb rndisstatus");
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Error communicating to native daemon to check RNDIS status", e);
+ }
for (String line : rsp) {
String []tok = line.split(" ");
@@ -476,31 +581,35 @@ class NetworkManagementService extends INetworkManagementService.Stub {
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
- mConnector.doCommand(String.format("softap stop " + wlanIface));
- mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
- mConnector.doCommand(String.format("softap start " + wlanIface));
- if (wifiConfig == null) {
- mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
- } else {
- /**
- * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
- * argv1 - wlan interface
- * argv2 - softap interface
- * argv3 - SSID
- * argv4 - Security
- * argv5 - Key
- * argv6 - Channel
- * argv7 - Preamble
- * argv8 - Max SCB
- */
- String str = String.format("softap set " + wlanIface + " " + softapIface +
- " %s %s %s", convertQuotedString(wifiConfig.SSID),
- wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
- "wpa2-psk" : "open",
- convertQuotedString(wifiConfig.preSharedKey));
- mConnector.doCommand(str);
- }
- mConnector.doCommand(String.format("softap startap"));
+ try {
+ mConnector.doCommand(String.format("softap stop " + wlanIface));
+ mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
+ mConnector.doCommand(String.format("softap start " + wlanIface));
+ if (wifiConfig == null) {
+ mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
+ } else {
+ /**
+ * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
+ * argv1 - wlan interface
+ * argv2 - softap interface
+ * argv3 - SSID
+ * argv4 - Security
+ * argv5 - Key
+ * argv6 - Channel
+ * argv7 - Preamble
+ * argv8 - Max SCB
+ */
+ String str = String.format("softap set " + wlanIface + " " + softapIface +
+ " %s %s %s", convertQuotedString(wifiConfig.SSID),
+ wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
+ "wpa2-psk" : "open",
+ convertQuotedString(wifiConfig.preSharedKey));
+ mConnector.doCommand(str);
+ }
+ mConnector.doCommand(String.format("softap startap"));
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon to start softap", e);
+ }
}
private String convertQuotedString(String s) {
@@ -516,7 +625,12 @@ class NetworkManagementService extends INetworkManagementService.Stub {
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
- mConnector.doCommand("softap stopap");
+ try {
+ mConnector.doCommand("softap stopap");
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
+ e);
+ }
}
public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
@@ -525,15 +639,19 @@ class NetworkManagementService extends INetworkManagementService.Stub {
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
- if (wifiConfig == null) {
- mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
- } else {
- String str = String.format("softap set " + wlanIface + " " + softapIface +
- " %s %s %s", convertQuotedString(wifiConfig.SSID),
- wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?
- "wpa2-psk" : "open",
- convertQuotedString(wifiConfig.preSharedKey));
- mConnector.doCommand(str);
+ try {
+ if (wifiConfig == null) {
+ mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
+ } else {
+ String str = String.format("softap set " + wlanIface + " " + softapIface
+ + " %s %s %s", convertQuotedString(wifiConfig.SSID),
+ wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ? "wpa2-psk" : "open",
+ convertQuotedString(wifiConfig.preSharedKey));
+ mConnector.doCommand(str);
+ }
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon to set soft AP",
+ e);
}
}
@@ -541,9 +659,22 @@ class NetworkManagementService extends INetworkManagementService.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
try {
- String rsp = mConnector.doCommand(
- String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
- String []tok = rsp.split(" ");
+ String rsp;
+ try {
+ rsp = mConnector.doCommand(
+ String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
+ } catch (NativeDaemonConnectorException e1) {
+ Slog.e(TAG, "Error communicating with native daemon", e1);
+ return -1;
+ }
+
+ String[] tok = rsp.split(" ");
+ if (tok.length < 2) {
+ Slog.e(TAG, String.format("Malformed response for reading %s interface",
+ (rx ? "rx" : "tx")));
+ return -1;
+ }
+
int code;
try {
code = Integer.parseInt(tok[0]);
@@ -575,17 +706,34 @@ class NetworkManagementService extends INetworkManagementService.Stub {
public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
- mConnector.doCommand(String.format(
- "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
+ try {
+ mConnector.doCommand(String.format(
+ "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
+ } catch (NativeDaemonConnectorException e) {
+ Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
+ }
}
private int getInterfaceThrottle(String iface, boolean rx) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
try {
- String rsp = mConnector.doCommand(
- String.format("interface getthrottle %s %s", iface,(rx ? "rx" : "tx"))).get(0);
- String []tok = rsp.split(" ");
+ String rsp;
+ try {
+ rsp = mConnector.doCommand(
+ String.format("interface getthrottle %s %s", iface,
+ (rx ? "rx" : "tx"))).get(0);
+ } catch (NativeDaemonConnectorException e) {
+ Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
+ return -1;
+ }
+
+ String[] tok = rsp.split(" ");
+ if (tok.length < 2) {
+ Slog.e(TAG, "Malformed response to getthrottle command");
+ return -1;
+ }
+
int code;
try {
code = Integer.parseInt(tok[0]);
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 0931cc0..c2ec774 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -3654,21 +3654,19 @@ class PackageManagerService extends IPackageManager.Stub {
installedNativeLibraries = true;
+ // Always extract the shared library
String sharedLibraryFilePath = sharedLibraryDir.getPath() +
File.separator + libFileName;
File sharedLibraryFile = new File(sharedLibraryFilePath);
- if (! sharedLibraryFile.exists() ||
- sharedLibraryFile.length() != entry.getSize() ||
- sharedLibraryFile.lastModified() != entry.getTime()) {
- if (Config.LOGD) {
- Log.d(TAG, "Caching shared lib " + entry.getName());
- }
- if (mInstaller == null) {
- sharedLibraryDir.mkdir();
- }
- cacheNativeBinaryLI(pkg, zipFile, entry, sharedLibraryDir,
- sharedLibraryFile);
+
+ if (Config.LOGD) {
+ Log.d(TAG, "Caching shared lib " + entry.getName());
}
+ if (mInstaller == null) {
+ sharedLibraryDir.mkdir();
+ }
+ cacheNativeBinaryLI(pkg, zipFile, entry, sharedLibraryDir,
+ sharedLibraryFile);
}
if (!hasNativeLibraries)
return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
@@ -3710,18 +3708,16 @@ class PackageManagerService extends IPackageManager.Stub {
String installGdbServerPath = installGdbServerDir.getPath() +
"/" + GDBSERVER;
File installGdbServerFile = new File(installGdbServerPath);
- if (! installGdbServerFile.exists() ||
- installGdbServerFile.length() != entry.getSize() ||
- installGdbServerFile.lastModified() != entry.getTime()) {
- if (Config.LOGD) {
- Log.d(TAG, "Caching gdbserver " + entry.getName());
- }
- if (mInstaller == null) {
- installGdbServerDir.mkdir();
- }
- cacheNativeBinaryLI(pkg, zipFile, entry, installGdbServerDir,
- installGdbServerFile);
+
+ if (Config.LOGD) {
+ Log.d(TAG, "Caching gdbserver " + entry.getName());
+ }
+ if (mInstaller == null) {
+ installGdbServerDir.mkdir();
}
+ cacheNativeBinaryLI(pkg, zipFile, entry, installGdbServerDir,
+ installGdbServerFile);
+
return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
}
return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
@@ -3735,6 +3731,16 @@ class PackageManagerService extends IPackageManager.Stub {
// one if ro.product.cpu.abi2 is defined.
//
private int cachePackageSharedLibsLI(PackageParser.Package pkg, File scanFile) {
+ // Remove all native binaries from a directory. This is used when upgrading
+ // a package: in case the new .apk doesn't contain a native binary that was
+ // in the old one (and thus installed), we need to remove it from
+ // /data/data/<appname>/lib
+ //
+ // The simplest way to do that is to remove all files in this directory,
+ // since it is owned by "system", applications are not supposed to write
+ // anything there.
+ removeNativeBinariesLI(pkg);
+
String cpuAbi = Build.CPU_ABI;
try {
int result = cachePackageSharedLibsForAbiLI(pkg, scanFile, cpuAbi);
@@ -6439,11 +6445,10 @@ class PackageManagerService extends IPackageManager.Stub {
File dataDir = new File(pkg.applicationInfo.dataDir);
dataDir.delete();
}
+ schedulePackageCleaning(packageName);
}
synchronized (mPackages) {
if (deletedPs != null) {
- schedulePackageCleaning(packageName);
-
if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
if (outInfo != null) {
outInfo.removedUid = mSettings.removePackageLP(packageName);
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 493a348..55f9d60 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -1022,36 +1022,76 @@ class PowerManagerService extends IPowerManager.Stub
}
}
- private void setTimeoutLocked(long now, int nextState)
- {
+ private void setTimeoutLocked(long now, int nextState) {
+ setTimeoutLocked(now, -1, nextState);
+ }
+
+ // If they gave a timeoutOverride it is the number of seconds
+ // to screen-off. Figure out where in the countdown cycle we
+ // should jump to.
+ private void setTimeoutLocked(long now, final long originalTimeoutOverride, int nextState) {
+ long timeoutOverride = originalTimeoutOverride;
if (mBootCompleted) {
- mHandler.removeCallbacks(mTimeoutTask);
- mTimeoutTask.nextState = nextState;
- long when = now;
- switch (nextState)
- {
- case SCREEN_BRIGHT:
- when += mKeylightDelay;
- break;
- case SCREEN_DIM:
- if (mDimDelay >= 0) {
- when += mDimDelay;
- break;
- } else {
- Slog.w(TAG, "mDimDelay=" + mDimDelay + " while trying to dim");
+ synchronized (mLocks) {
+ long when = 0;
+ if (timeoutOverride <= 0) {
+ switch (nextState)
+ {
+ case SCREEN_BRIGHT:
+ when = now + mKeylightDelay;
+ break;
+ case SCREEN_DIM:
+ if (mDimDelay >= 0) {
+ when = now + mDimDelay;
+ break;
+ } else {
+ Slog.w(TAG, "mDimDelay=" + mDimDelay + " while trying to dim");
+ }
+ case SCREEN_OFF:
+ synchronized (mLocks) {
+ when = now + mScreenOffDelay;
+ }
+ break;
+ default:
+ when = now;
+ break;
}
- case SCREEN_OFF:
- synchronized (mLocks) {
- when += mScreenOffDelay;
+ } else {
+ override: {
+ if (timeoutOverride <= mScreenOffDelay) {
+ when = now + timeoutOverride;
+ nextState = SCREEN_OFF;
+ break override;
+ }
+ timeoutOverride -= mScreenOffDelay;
+
+ if (mDimDelay >= 0) {
+ if (timeoutOverride <= mDimDelay) {
+ when = now + timeoutOverride;
+ nextState = SCREEN_DIM;
+ break override;
+ }
+ timeoutOverride -= mDimDelay;
+ }
+
+ when = now + timeoutOverride;
+ nextState = SCREEN_BRIGHT;
}
- break;
- }
- if (mSpew) {
- Slog.d(TAG, "setTimeoutLocked now=" + now + " nextState=" + nextState
- + " when=" + when);
+ }
+ if (mSpew) {
+ Slog.d(TAG, "setTimeoutLocked now=" + now
+ + " timeoutOverride=" + timeoutOverride
+ + " nextState=" + nextState + " when=" + when);
+ }
+
+ mHandler.removeCallbacks(mTimeoutTask);
+ mTimeoutTask.nextState = nextState;
+ mTimeoutTask.remainingTimeoutOverride = timeoutOverride > 0
+ ? (originalTimeoutOverride - timeoutOverride)
+ : -1;
+ mHandler.postAtTime(mTimeoutTask, when);
+ mNextTimeout = when; // for debugging
}
- mHandler.postAtTime(mTimeoutTask, when);
- mNextTimeout = when; // for debugging
}
}
@@ -1064,6 +1104,7 @@ class PowerManagerService extends IPowerManager.Stub
private class TimeoutTask implements Runnable
{
int nextState; // access should be synchronized on mLocks
+ long remainingTimeoutOverride;
public void run()
{
synchronized (mLocks) {
@@ -1084,11 +1125,11 @@ class PowerManagerService extends IPowerManager.Stub
{
case SCREEN_BRIGHT:
if (mDimDelay >= 0) {
- setTimeoutLocked(now, SCREEN_DIM);
+ setTimeoutLocked(now, remainingTimeoutOverride, SCREEN_DIM);
break;
}
case SCREEN_DIM:
- setTimeoutLocked(now, SCREEN_OFF);
+ setTimeoutLocked(now, remainingTimeoutOverride, SCREEN_OFF);
break;
}
}
@@ -1958,18 +1999,33 @@ class PowerManagerService extends IPowerManager.Stub
public void userActivityWithForce(long time, boolean noChangeLights, boolean force) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
- userActivity(time, noChangeLights, OTHER_EVENT, force);
+ userActivity(time, -1, noChangeLights, OTHER_EVENT, force);
}
public void userActivity(long time, boolean noChangeLights) {
- userActivity(time, noChangeLights, OTHER_EVENT, false);
+ userActivity(time, -1, noChangeLights, OTHER_EVENT, false);
}
public void userActivity(long time, boolean noChangeLights, int eventType) {
- userActivity(time, noChangeLights, eventType, false);
+ userActivity(time, -1, noChangeLights, eventType, false);
}
public void userActivity(long time, boolean noChangeLights, int eventType, boolean force) {
+ userActivity(time, -1, noChangeLights, eventType, force);
+ }
+
+ /*
+ * Reset the user activity timeout to now + timeout. This overrides whatever else is going
+ * on with user activity. Don't use this function.
+ */
+ public void clearUserActivityTimeout(long now, long timeout) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+ Slog.i(TAG, "clearUserActivity for " + timeout + "ms from now");
+ userActivity(now, timeout, false, OTHER_EVENT, false);
+ }
+
+ private void userActivity(long time, long timeoutOverride, boolean noChangeLights,
+ int eventType, boolean force) {
//mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)
@@ -2004,6 +2060,7 @@ class PowerManagerService extends IPowerManager.Stub
+ " mUserState=0x" + Integer.toHexString(mUserState)
+ " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)
+ " mProximitySensorActive=" + mProximitySensorActive
+ + " timeoutOverride=" + timeoutOverride
+ " force=" + force);
}
// ignore user activity if we are in the process of turning off the screen
@@ -2041,7 +2098,7 @@ class PowerManagerService extends IPowerManager.Stub
mWakeLockState = mLocks.reactivateScreenLocksLocked();
setPowerState(mUserState | mWakeLockState, noChangeLights,
WindowManagerPolicy.OFF_BECAUSE_OF_USER);
- setTimeoutLocked(time, SCREEN_BRIGHT);
+ setTimeoutLocked(time, timeoutOverride, SCREEN_BRIGHT);
}
}
}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 32e7176..55d25a5 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -135,9 +135,9 @@ public class PhoneNumberUtils
}
// TODO: We don't check for SecurityException here (requires
- // READ_PHONE_STATE permission).
+ // CALL_PRIVILEGED permission).
if (scheme.equals("voicemail")) {
- return TelephonyManager.getDefault().getVoiceMailNumber();
+ return TelephonyManager.getDefault().getCompleteVoiceMailNumber();
}
if (context == null) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f018d10..278e8ca 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -177,7 +177,7 @@ public class TelephonyManager {
/**
* Returns the unique device ID, for example, the IMEI for GSM and the MEID
- * for CDMA phones. Return null if device ID is not available.
+ * or ESN for CDMA phones. Return null if device ID is not available.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -659,6 +659,25 @@ public class TelephonyManager {
}
/**
+ * Returns the complete voice mail number. Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#CALL_PRIVILEGED CALL_PRIVILEGED}
+ *
+ * @hide
+ */
+ public String getCompleteVoiceMailNumber() {
+ try {
+ return getSubscriberInfo().getCompleteVoiceMailNumber();
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return null;
+ }
+ }
+
+ /**
* Returns the voice mail count. Return 0 if unavailable.
* <p>
* Requires Permission:
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index e74b9e4..5cba2e1 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -59,6 +59,11 @@ interface IPhoneSubInfo {
String getVoiceMailNumber();
/**
+ * Retrieves the complete voice mail number.
+ */
+ String getCompleteVoiceMailNumber();
+
+ /**
* Retrieves the alpha identifier associated with the voice mail number.
*/
String getVoiceMailAlphaTag();
diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
index 1ac2da3..0b55736 100644
--- a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
+++ b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
@@ -21,6 +21,7 @@ import java.io.PrintWriter;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
+import android.telephony.PhoneNumberUtils;
import android.util.Log;
public class PhoneSubInfo extends IPhoneSubInfo.Stub {
@@ -29,6 +30,9 @@ public class PhoneSubInfo extends IPhoneSubInfo.Stub {
private Context mContext;
private static final String READ_PHONE_STATE =
android.Manifest.permission.READ_PHONE_STATE;
+ private static final String CALL_PRIVILEGED =
+ // TODO Add core/res/AndriodManifest.xml#READ_PRIVILEGED_PHONE_STATE
+ android.Manifest.permission.CALL_PRIVILEGED;
public PhoneSubInfo(Phone phone) {
mPhone = phone;
@@ -101,7 +105,22 @@ public class PhoneSubInfo extends IPhoneSubInfo.Stub {
*/
public String getVoiceMailNumber() {
mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
- return (String) mPhone.getVoiceMailNumber();
+ String number = PhoneNumberUtils.extractNetworkPortion(mPhone.getVoiceMailNumber());
+ Log.d(LOG_TAG, "VM: PhoneSubInfo.getVoiceMailNUmber: "); // + number);
+ return number;
+ }
+
+ /**
+ * Retrieves the compelete voice mail number.
+ *
+ * @hide
+ */
+ public String getCompleteVoiceMailNumber() {
+ mContext.enforceCallingOrSelfPermission(CALL_PRIVILEGED,
+ "Requires CALL_PRIVILEGED");
+ String number = mPhone.getVoiceMailNumber();
+ Log.d(LOG_TAG, "VM: PhoneSubInfo.getCompleteVoiceMailNUmber: "); // + number);
+ return number;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
index adfbe20..a036046 100644
--- a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
@@ -82,6 +82,13 @@ public class PhoneSubInfoProxy extends IPhoneSubInfo.Stub {
}
/**
+ * Retrieves the complete voice mail number.
+ */
+ public String getCompleteVoiceMailNumber() {
+ return mPhoneSubInfo.getCompleteVoiceMailNumber();
+ }
+
+ /**
* Retrieves the alpha identifier associated with the voice mail number.
*/
public String getVoiceMailAlphaTag() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 1f5accf..58dfeb9 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -430,9 +430,14 @@ public class CDMAPhone extends PhoneBase {
return mMeid;
}
- //returns MEID in CDMA
+ //returns MEID or ESN in CDMA
public String getDeviceId() {
- return getMeid();
+ String id = getMeid();
+ if ((id == null) || id.matches("^0*$")) {
+ Log.d(LOG_TAG, "getDeviceId(): MEID is not initialized use ESN");
+ id = getEsn();
+ }
+ return id;
}
public String getDeviceSvn() {