From 34c0b2ee11c237be5244eecc34814862b3003822 Mon Sep 17 00:00:00 2001 From: Dan Egnor Date: Tue, 29 Jun 2010 17:51:28 -0700 Subject: [PATCH 01/14] Verify hostname where possible, and clarify where not. Bug: 2807409 Change-Id: I6f6a6b22a48149d9f1f45ff8f53103b25706ecc0 --- .../net/SSLCertificateSocketFactory.java | 133 ++++++++++++++++-- 1 file changed, 120 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index a8c6f9b59990f..9ad125b312e14 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: + * * - * 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)}. - *

- * 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. + * + *

Most {@link SSLSocketFactory} implementations do not + * verify the server's identity, allowing man-in-the-middle attacks. + * 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.

+ * + *

One way to verify the server's identity is to use + * {@link HttpsURLConnection#getDefaultHostnameVerifier()} to get a + * {@link HostnameVerifier} to verify the certificate hostname. + * + *

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! + * + *

Warning: Sockets created using this factory + * are vulnerable to man-in-the-middle attacks!

* * @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. + * + *

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,27 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { } } + /** + * {@inheritDoc} + * + *

This method verifies the peer's certificate hostname after connecting. + */ @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); + 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. + * + *

Warning: 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.

+ */ @Override public Socket createSocket() throws IOException { OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(); @@ -191,6 +272,13 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { return s; } + /** + * {@inheritDoc} + * + *

Warning: 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.

+ */ @Override public Socket createSocket(InetAddress addr, int port, InetAddress localAddr, int localPort) throws IOException { @@ -200,6 +288,13 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { return s; } + /** + * {@inheritDoc} + * + *

Warning: 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.

+ */ @Override public Socket createSocket(InetAddress addr, int port) throws IOException { OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port); @@ -207,19 +302,31 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { return s; } + /** + * {@inheritDoc} + * + *

This method verifies the peer's certificate hostname after connecting. + */ @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); + verifyHostname(s, host); return s; } + /** + * {@inheritDoc} + * + *

This method verifies the peer's certificate hostname after connecting. + */ @Override public Socket createSocket(String host, int port) throws IOException { OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port); s.setHandshakeTimeout(mHandshakeTimeoutMillis); + verifyHostname(s, host); return s; } From 00ccd5d026fcd0e4b9d27dc5a9ffa13ca0408449 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 30 Jun 2010 19:41:56 -0700 Subject: [PATCH 02/14] Fix issue 2811538: System server crash when disconnecting BT headset after using SCO off call. Problem: When the bluetooth device is removed, the AudioService clears all active SCO connections and unlinks from the client application's binder interface death. The problem is that the unlinking is done even if no more connections are active for a given client, which throws a runtime exception that is not catched causing the system server to crash. The fix consists in calling unlinkToDeath() in ScoClient.clearCount() only if the number of active SCO connections for this client is not 0. The NoSuchElementException exception is also catched when calling unlinkToDeath() Change-Id: I7086424301fc63a5666da61c38169349d3e078f4 --- media/java/android/media/AudioService.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 5c278d908ff84..08fc782c2cbcf 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); } From f47b7085b62895d49d3559bd2e8cca5e79c9a1ed Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 12 Jul 2010 15:54:38 -0700 Subject: [PATCH 03/14] Fix issue #2834005: Android Settings.Secure bypass Change-Id: Ic4f14e2ff5c2b4f623405d30389863a9e3e82572 --- .../providers/settings/DatabaseHelper.java | 19 +++++++++++++++++++ .../providers/settings/SettingsProvider.java | 9 +++++++++ 2 files changed, 28 insertions(+) diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 2b4714def1f8c..dab7601e68e8d 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 mValidTables = new HashSet(); + + 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 1b4ba817adecf..4372cd89e0868 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -83,6 +83,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) { @@ -91,6 +94,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) }; @@ -105,6 +111,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 { From 9ffe79c7ebd448de4a0defe7807efec332fdefb4 Mon Sep 17 00:00:00 2001 From: Chih-Chung Chang Date: Thu, 1 Jul 2010 21:06:45 +0800 Subject: [PATCH 04/14] Flush binder buffer after setting raw heap to avoid leaking a reference. The problem was: 1. In handleShutter(), thread A in CameraService calls registerBuffers(IMemoryHeap) and it's received by thread B in system_server. [transaction 1] 2. While thread A is waiting for the reply, thread B calls back to thread A to get the id of the heap (IMemoryHeap.getHeapID). [transaction 2] 3. Thread A replies transaction 2 and is preemptied in kernel. Thread B gets the reply and finishes registerBuffers and send reply for transaction 1. 4. When thread A runs again, it gets the reply for transaction 1 and returns to handleShutter(). 5. At this point the transaction buffer for transaction 2 (which holds a reference to IMemoryHeap) is not freed because the BC_FREE_BUFFER command is kept in thread A's local command queue and not sent to the kernel. 6. Normally when thread A makes next transaction, the BC_FREE_BUFFER command will be sent together (piggyback) with the commands for that transaction. But in this case thread A is a callback thread from camera driver, so it does not make any binder calls afterwards, and the IMemoryHeap is never freed (until the next time handleShutter is called). Change-Id: I435a258187509bdbbaf353339eb9ea577610cbd2 --- camera/libcameraservice/CameraService.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp index 00bd54eb59758..26901829e932a 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(); } } From f1f07993792dbf2d49613d474a696ec0927828d2 Mon Sep 17 00:00:00 2001 From: Andrew Stadler Date: Mon, 12 Jul 2010 15:31:40 -0700 Subject: [PATCH 05/14] Skip hostname verification when using insecure factory If the factory was obtained by calling getInsecure(), calls to createSocket() should skip hostname verification (along with all of the other skipped safety checks.) This change slightly relaxes the too-strict checking that was introduced in change 7fc93c36ae235115727296780dbc35101622bbd4. Bug: 2834174 Change-Id: Iab7ef861ad0ca727f82ee8cdb78b89b9e835740d --- .../net/SSLCertificateSocketFactory.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index 9ad125b312e14..31acb5b177e8f 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -247,13 +247,16 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { /** * {@inheritDoc} * - *

This method verifies the peer's certificate hostname after connecting. + *

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); - verifyHostname(s, host); + if (mSecure) { + verifyHostname(s, host); + } return s; } @@ -305,7 +308,8 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { /** * {@inheritDoc} * - *

This method verifies the peer's certificate hostname after connecting. + *

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) @@ -313,20 +317,25 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket( host, port, localAddr, localPort); s.setHandshakeTimeout(mHandshakeTimeoutMillis); - verifyHostname(s, host); + if (mSecure) { + verifyHostname(s, host); + } return s; } /** * {@inheritDoc} * - *

This method verifies the peer's certificate hostname after connecting. + *

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); - verifyHostname(s, host); + if (mSecure) { + verifyHostname(s, host); + } return s; } From 803bb14cd22f56ea2ba7d1f950ea736c27ddd83e Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 29 Jul 2010 13:57:56 -0700 Subject: [PATCH 06/14] Fix a bug where we cleaned an apps external data when upgrading it. :( Change-Id: I0eee1e7062d334c66d6daa3c43e11a292263aada --- services/java/com/android/server/PackageManagerService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 49d2a76f0d74f..0b84c8d43fc16 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -6222,11 +6222,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); From c58e918f94455c2ee9ed7fe17f4d0f468f3f5ac3 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Mon, 2 Aug 2010 11:05:28 -0700 Subject: [PATCH 07/14] Add PhoneSubInfo.getCompleteVoiceMailNumber. PhoneSubInfo.getVoiceMailNumber now returns only the network portion of the voicemail number. Use the new method PhoneSubInfo.getCompleteVoiceMailNumber to get the netowrk portion and the post dial portion. Bug: 2881483 Change-Id: I7637d4fa0ffa046b4eebc4d599719bb668c940b5 --- .../android/telephony/PhoneNumberUtils.java | 4 ++-- .../android/telephony/TelephonyManager.java | 19 +++++++++++++++++ .../internal/telephony/IPhoneSubInfo.aidl | 5 +++++ .../internal/telephony/PhoneSubInfo.java | 21 ++++++++++++++++++- .../internal/telephony/PhoneSubInfoProxy.java | 7 +++++++ 5 files changed, 53 insertions(+), 3 deletions(-) diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index 32e717685fe5b..55d25a5950a87 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 f018d1074a745..4ee95609c3e1b 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -658,6 +658,25 @@ public class TelephonyManager { } } + /** + * Returns the complete voice mail number. Return null if it is unavailable. + *

+ * 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. *

diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl index e74b9e4a10999..5cba2e165fd48 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl @@ -58,6 +58,11 @@ interface IPhoneSubInfo { */ String getVoiceMailNumber(); + /** + * Retrieves the complete voice mail number. + */ + String getCompleteVoiceMailNumber(); + /** * Retrieves the alpha identifier associated with the voice mail number. */ diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java index 1ac2da36338ef..0b557368b48ef 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 adfbe20b067fb..a0360462f2bf2 100644 --- a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java +++ b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java @@ -81,6 +81,13 @@ public class PhoneSubInfoProxy extends IPhoneSubInfo.Stub { return mPhoneSubInfo.getVoiceMailNumber(); } + /** + * Retrieves the complete voice mail number. + */ + public String getCompleteVoiceMailNumber() { + return mPhoneSubInfo.getCompleteVoiceMailNumber(); + } + /** * Retrieves the alpha identifier associated with the voice mail number. */ From e2fd45af93178b30e6da97b46fcd31b7d30f5426 Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Thu, 3 Jun 2010 14:37:42 -0700 Subject: [PATCH 08/14] PackageManagerService: always install native binaries from .apk The previous implementation fails to work properly when the .apk and installed versions of the binaries have the same size and date. Change-Id: I063817a935da9ad459858d7eec8bb3d940607850 --- .../android/server/PackageManagerService.java | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 0b84c8d43fc16..b70d69bab7d81 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -3623,21 +3623,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; @@ -3679,18 +3677,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; @@ -3704,6 +3700,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//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); From eb2e09546986652259364daedba24b7f914c32c6 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Tue, 1 Jun 2010 13:23:53 -0700 Subject: [PATCH 09/14] Add more error checking for ndc In NativeDaemonConnector.doCommand() calls, there was inconsistent error checking. This change adds error checking for every call and makes it so that any call to .doCommand() that gets an error code won't cause the code to hang forever. Change-Id: If714282b6642f278fb8137f652af1a012670253b --- .../java/com/android/server/MountService.java | 34 +- .../android/server/NativeDaemonConnector.java | 11 +- .../server/NetworkManagementService.java | 346 +++++++++++++----- 3 files changed, 279 insertions(+), 112 deletions(-) diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 6ceeb95852ec6..413d66f3ddf9c 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -642,10 +642,20 @@ class MountService extends IMountService.Stub } private boolean doGetShareMethodAvailable(String method) { - ArrayList rsp = mConnector.doCommand("share status " + method); + try { + ArrayList 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 +780,22 @@ class MountService extends IMountService.Stub private boolean doGetVolumeShared(String path, String method) { String cmd = String.format("volume shared %s %s", path, method); - ArrayList rsp = mConnector.doCommand(cmd); + ArrayList 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 +804,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 08d7ce6b30afd..c45259064c452 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 cbbc7bedcd249..c15615064fccb 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) { + + 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; + } + cfg.interfaceFlags = st.nextToken("]").trim() +"]"; + } catch (NoSuchElementException nsee) { 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; - } - - 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() +"]"; 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 rsp = mConnector.doCommand("ipfwd status"); + ArrayList 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 - 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 rsp = mConnector.doCommand("tether status"); + ArrayList 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 ... - 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 rsp = mConnector.doCommand("usb rndisstatus"); + ArrayList 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); + 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); } - mConnector.doCommand(String.format("softap startap")); } 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]); From 4b34662bacbf542a68708a9ddc25b7f22649ab99 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Tue, 20 Jul 2010 09:44:34 -0700 Subject: [PATCH 10/14] Squashed commit of the following: commit 4abf16bb04dc9695fedf4007a84f903074312ccd Author: Andreas Huber Date: Tue Jul 20 09:21:17 2010 -0700 Support a single format change at the beginning of audio playback. This way the AAC+ decoder may change its output format from what is originally encoded in the audio stream and we'll still play it back correctly. Change-Id: Icc790122744745e9a88099788d4818ca1e265a82 related-to-bug: 2826841 commit 09c74da63e6ad5cb5dafb70f62696d75d2978967 Author: James Dong Date: Sun Jul 18 17:57:01 2010 -0700 Fix MPEG4Extractor to extract sampling frequency correctly when SBR is enabled. Change-Id: I883c81dad3ea465e71cb5590e89d763671a90ff8 commit f672bf2a782dc7d5fb6325d611a7fe17045dfe9a Author: James Dong Date: Thu Jul 8 20:56:13 2010 -0700 Enable the support for decoding audio with AAC+ and eAAC+ features bug - 282684 Change-Id: I73c8377af3cc4edd3ee7cea86dc3b1c369fbd78b Change-Id: I012f1179e933b6d1345d2368f357576c722485f7 --- include/media/stagefright/AudioPlayer.h | 4 + media/libstagefright/AudioPlayer.cpp | 66 ++++++++++- .../codecs/aacdec/AACDecoder.cpp | 110 +++++++++++------- media/libstagefright/include/AACDecoder.h | 4 + 4 files changed, 136 insertions(+), 48 deletions(-) diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h index 9af587121b947..9a09586be68e2 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 mAudioSink; static void AudioCallback(int event, void *user, void *info); diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index bcf2463972663..c27cfc81739dc 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,9 @@ AudioPlayer::AudioPlayer(const sp &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 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 2bc44483fd3f9..8ae1135b704a8 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 &source) mAnchorTimeUs(0), mNumSamplesOutput(0), mInputBuffer(NULL) { -} -AACDecoder::~AACDecoder() { - if (mStarted) { - stop(); + sp srcFormat = mSource->getFormat(); + + int32_t sampleRate; + CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate)); + + mMeta = new MetaData; + mMeta->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. + mMeta->setInt32(kKeyChannelCount, 2); + mMeta->setInt32(kKeySampleRate, sampleRate); + + int64_t durationUs; + if (srcFormat->findInt64(kKeyDuration, &durationUs)) { + mMeta->setInt64(kKeyDuration, durationUs); } + mMeta->setCString(kKeyDecoderComponent, "AACDecoder"); - delete mConfig; - mConfig = NULL; + mInitCheck = initCheck(); } -status_t AACDecoder::start(MetaData *params) { - CHECK(!mStarted); - - mBufferGroup = new MediaBufferGroup; - mBufferGroup->add_buffer(new MediaBuffer(2048 * 2)); - +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 AACDecoder::getFormat() { - sp srcFormat = mSource->getFormat(); - - int32_t sampleRate; - CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate)); - - sp 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(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 f09addd2d6114..200f93c646b82 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 &source); @@ -41,6 +42,7 @@ protected: virtual ~AACDecoder(); private: + sp mMeta; sp 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 &); }; From 5cbaba857a48b1de1fad93cd943a508fdb1e2850 Mon Sep 17 00:00:00 2001 From: Fred Quintana Date: Thu, 5 Aug 2010 14:14:49 -0700 Subject: [PATCH 11/14] Changed SyncOperation.toKey() to not rely on the implementation of Account.toString() bug: 2898033 Change-Id: I6bfac976127190d2d667312df7aa9c7d57b21555 --- core/java/android/content/SyncOperation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/content/SyncOperation.java b/core/java/android/content/SyncOperation.java index a7d036f875f59..b01608856cc6f 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(); From 1fdb1fb43a39c8c29e3265592e0d6a2da419e08e Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Sat, 24 Jul 2010 11:50:05 -0400 Subject: [PATCH 12/14] Add a method to let a properly permissioned app directly manipulate the user activity timeout. We should come up with a better API for this, but this is for a last minute power manager hack to turn off the screen sooner after a phone call ends. Change-Id: I76422f952e3e894c90b3311e7d889899c79cbbaa --- core/java/android/os/IPowerManager.aidl | 1 + .../android/server/PowerManagerService.java | 106 +++++++++++++----- 2 files changed, 77 insertions(+), 30 deletions(-) diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index dedc34773c91c..01cc408074d09 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/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 493a34826bd70..ffdc8b2a170ad 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -1022,36 +1022,67 @@ 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, long timeoutOverride, int nextState) { 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) { + mHandler.removeCallbacks(mTimeoutTask); + mTimeoutTask.nextState = nextState; + long when = 0; + if (timeoutOverride <= 0) { + switch (nextState) + { + case SCREEN_BRIGHT: + when = now + mKeylightDelay; + break; + case SCREEN_DIM: + if (mDimDelay >= 0) { + when = now + mDimDelay; + } else { + Slog.w(TAG, "mDimDelay=" + mDimDelay + " while trying to dim"); + } + case SCREEN_OFF: + synchronized (mLocks) { + when = now + mScreenOffDelay; + } + 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 + + " timeoutOverride=" + timeoutOverride + + " nextState=" + nextState + " when=" + when); + } + mHandler.postAtTime(mTimeoutTask, when); + mNextTimeout = when; // for debugging } - if (mSpew) { - Slog.d(TAG, "setTimeoutLocked now=" + now + " nextState=" + nextState - + " when=" + when); - } - mHandler.postAtTime(mTimeoutTask, when); - mNextTimeout = when; // for debugging } } @@ -1958,18 +1989,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) @@ -2041,7 +2087,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); } } } From b9f1c70a88046c97453d79c7a41c4b493d4d5ed5 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Tue, 1 Jun 2010 20:50:21 -0700 Subject: [PATCH 13/14] Amend previous ndc commit Submitted wrong patchset. This includes the delta for the latest patchset. Change-Id: I63bb9a37dd9100550ae07a3a1c9fdd9fd71724e1 --- services/java/com/android/server/MountService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 413d66f3ddf9c..6c2f1b2d77b8d 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -642,8 +642,9 @@ class MountService extends IMountService.Stub } private boolean doGetShareMethodAvailable(String method) { + ArrayList rsp; try { - ArrayList rsp = mConnector.doCommand("share status " + method); + rsp = mConnector.doCommand("share status " + method); } catch (NativeDaemonConnectorException ex) { Slog.e(TAG, "Failed to determine whether share method " + method + " is available."); return false; From 8812535137ca657f6830dd01189c429bdb13c237 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Tue, 27 Jul 2010 16:49:10 -0700 Subject: [PATCH 14/14] Add a missing break; to restore old functionality and not turn off the screen after 30secs regardless of system preference. Change-Id: Ib71113a3bc5aa5fdc088ab4ac3627352499ad3fa --- services/java/com/android/server/PowerManagerService.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index ffdc8b2a170ad..7bbc32ffec286 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -1044,6 +1044,7 @@ class PowerManagerService extends IPowerManager.Stub case SCREEN_DIM: if (mDimDelay >= 0) { when = now + mDimDelay; + break; } else { Slog.w(TAG, "mDimDelay=" + mDimDelay + " while trying to dim"); } @@ -1052,6 +1053,9 @@ class PowerManagerService extends IPowerManager.Stub when = now + mScreenOffDelay; } break; + default: + when = now; + break; } } else { override: {