diff options
53 files changed, 815 insertions, 347 deletions
diff --git a/api/current.txt b/api/current.txt index 309e747a20f3..5053859bc69c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3453,6 +3453,7 @@ package android.app { field public static final java.lang.String SUGGEST_COLUMN_INTENT_DATA = "suggest_intent_data"; field public static final java.lang.String SUGGEST_COLUMN_INTENT_DATA_ID = "suggest_intent_data_id"; field public static final java.lang.String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data"; + field public static final java.lang.String SUGGEST_COLUMN_LAST_ACCESS_HINT = "suggest_last_access_hint"; field public static final java.lang.String SUGGEST_COLUMN_QUERY = "suggest_intent_query"; field public static final java.lang.String SUGGEST_COLUMN_SHORTCUT_ID = "suggest_shortcut_id"; field public static final java.lang.String SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING = "suggest_spinner_while_refreshing"; @@ -22263,6 +22264,7 @@ package android.view { method public static deprecated int getTouchSlop(); method public static deprecated int getWindowTouchSlop(); method public static long getZoomControlsTimeout(); + method public boolean hasPermanentMenuKey(); } public class ViewDebug { diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index 85a2fa831f65..7274362e77b5 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -329,6 +329,15 @@ public class SearchManager public final static String SUGGEST_COLUMN_FLAGS = "suggest_flags"; /** + * Column name for suggestions cursor. <i>Optional.</i> This column may be + * used to specify the time in (@link System#currentTimeMillis + * System.currentTImeMillis()} (wall time in UTC) when an item was last + * accessed within the results-providing application. If set, this may be + * used to show more-recently-used items first. + */ + public final static String SUGGEST_COLUMN_LAST_ACCESS_HINT = "suggest_last_access_hint"; + + /** * Column value for suggestion column {@link #SUGGEST_COLUMN_SHORTCUT_ID} when a suggestion * should not be stored as a shortcut in global search. */ diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index ae9aa05e0bce..054825024b9a 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -33,4 +33,7 @@ interface INetworkStatsService { /** Return usage summary per UID for traffic that matches template. */ NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); + /** Force update of statistics. */ + void forceUpdate(); + } diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index ff6e220cac41..dd2945ca18af 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -279,10 +279,17 @@ public class NetworkStatsHistory implements Parcelable { return (long) (start + (r.nextFloat() * (end - start))); } - public void dump(String prefix, PrintWriter pw) { + public void dump(String prefix, PrintWriter pw, boolean fullHistory) { pw.print(prefix); pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration); - for (int i = 0; i < bucketCount; i++) { + + final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32); + if (start > 0) { + pw.print(prefix); + pw.print(" (omitting "); pw.print(start); pw.println(" buckets)"); + } + + for (int i = start; i < bucketCount; i++) { pw.print(prefix); pw.print(" bucketStart="); pw.print(bucketStart[i]); pw.print(" rx="); pw.print(rx[i]); @@ -293,7 +300,7 @@ public class NetworkStatsHistory implements Parcelable { @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); - dump("", new PrintWriter(writer)); + dump("", new PrintWriter(writer), false); return writer.toString(); } diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java index 54583d61f4f9..a73067a5f709 100644 --- a/core/java/android/nfc/Tag.java +++ b/core/java/android/nfc/Tag.java @@ -313,14 +313,16 @@ public final class Tag implements Parcelable { */ @Override public String toString() { - StringBuilder sb = new StringBuilder("TAG ") - .append("uid = ") - .append(mId) - .append(" Tech ["); - for (int i : mTechList) { - sb.append(i) - .append(", "); + StringBuilder sb = new StringBuilder("TAG: Tech ["); + String[] techList = getTechList(); + int length = techList.length; + for (int i = 0; i < length; i++) { + sb.append(techList[i]); + if (i < length - 1) { + sb.append(", "); + } } + sb.append("]"); return sb.toString(); } diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index c9b6121adcf9..fcf479631b03 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -241,6 +241,4 @@ interface INetworkManagementService */ int getInterfaceTxThrottle(String iface); - void setBandwidthControlEnabled(boolean enabled); - } diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java index ab0cb505eb2d..41d3e7173eaf 100644 --- a/core/java/android/provider/VoicemailContract.java +++ b/core/java/android/provider/VoicemailContract.java @@ -52,18 +52,24 @@ public class VoicemailContract { /** The authority used by the voicemail provider. */ public static final String AUTHORITY = "com.android.voicemail"; - /** URI to insert/retrieve all voicemails. */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/voicemail"); /** URI to insert/retrieve voicemails by a given voicemail source. */ public static final Uri CONTENT_URI_SOURCE = Uri.parse("content://" + AUTHORITY + "/voicemail/source/"); + /** URI to insert/retrieve status of voicemail source. */ + public static final Uri STATUS_CONTENT_URI = + Uri.parse("content://" + AUTHORITY + "/status"); + /** + * Parameter key used in the URI to specify the voicemail source package name. + * <p> This field must be set in all requests that originate from a voicemail source. + */ + public static final String PARAM_KEY_SOURCE_PACKAGE = "source_package"; // TODO: Move ACTION_NEW_VOICEMAIL to the Intent class. /** Broadcast intent when a new voicemail record is inserted. */ public static final String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL"; - /** * Extra included in {@value Intent#ACTION_PROVIDER_CHANGED} and * {@value #ACTION_NEW_VOICEMAIL} broadcast intents to indicate if the receiving @@ -72,9 +78,27 @@ public class VoicemailContract { public static final String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE"; /** The mime type for a collection of voicemails. */ - public static final String DIR_TYPE = - "vnd.android.cursor.dir/voicemails"; + public static final String DIR_TYPE = "vnd.android.cursor.dir/voicemails"; + + /** + * A convenience method to build voicemail URI specific to a source package. Appends URI param + * {@link #PARAM_KEY_SOURCE_PACKAGE} to the base voicemail content URI. + */ + public static Uri buildSourceVoicemailUri(String packageName) { + return CONTENT_URI.buildUpon() + .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build(); + } + + /** + * A convenience method to build status URI specific to a source package. Appends URI param + * {@link #PARAM_KEY_SOURCE_PACKAGE} to the base status content URI. + */ + public static Uri buildSourceStatusUri(String packageName) { + return STATUS_CONTENT_URI.buildUpon() + .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build(); + } + /** Defines fields exposed through the /voicemail path of this content provider. */ public static final class Voicemails implements BaseColumns { /** Not instantiable. */ private Voicemails() { @@ -144,4 +168,76 @@ public class VoicemailContract { */ public static final String _DATA = "_data"; } + + /** Defines fields exposed through the /status path of this content provider. */ + public static final class Status implements BaseColumns { + /** Not instantiable. */ + private Status() { + } + /** + * The package name of the voicemail source. There can only be a one entry per source. + * <P>Type: TEXT</P> + */ + public static final String SOURCE_PACKAGE = "source_package"; + /** + * The URI to call to invoke source specific voicemail settings screen. On a user request + * to setup voicemail an intent with action VIEW with this URI will be fired by the system. + * <P>Type: TEXT</P> + */ + public static final String SETTINGS_URI = "settings_uri"; + /** + * The URI to call when the user requests to directly access the voicemail from the remote + * server. In case of an IVR voicemail system this is typically set to the the voicemail + * number specified using a tel:/ URI. + * <P>Type: TEXT</P> + */ + public static final String VOICEMAIL_ACCESS_URI = "voicemail_access_uri"; + /** + * The configuration state of the voicemail source. + * <P> Possible values: + * {@link #CONFIGURATION_STATE_OK}, + * {@link #CONFIGURATION_STATE_NOT_CONFIGURED}, + * {@link #CONFIGURATION_STATE_CAN_BE_CONFIGURED} + * <P>Type: INTEGER</P> + */ + public static final String CONFIGURATION_STATE = "configuration_state"; + public static final int CONFIGURATION_STATE_OK = 0; + public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; + /** + * This state must be used when the source has verified that the current user can be + * upgraded to visual voicemail and would like to show a set up invitation message. + */ + public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; + /** + * The data channel state of the voicemail source. This the channel through which the source + * pulls voicemail data from a remote server. + * <P> Possible values: + * {@link #DATA_CHANNEL_STATE_OK}, + * {@link #DATA_CHANNEL_STATE_NO_CONNECTION} + * </P> + * <P>Type: INTEGER</P> + */ + public static final String DATA_CHANNEL_STATE = "data_channel_state"; + public static final int DATA_CHANNEL_STATE_OK = 0; + public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1; + /** + * The notification channel state of the voicemail source. This is the channel through which + * the source gets notified of new voicemails on the remote server. + * <P> Possible values: + * {@link #NOTIFICATION_CHANNEL_STATE_OK}, + * {@link #NOTIFICATION_CHANNEL_STATE_NO_CONNECTION}, + * {@link #NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING} + * </P> + * <P>Type: INTEGER</P> + */ + public static final String NOTIFICATION_CHANNEL_STATE = "notification_channel_state"; + public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; + public static final int NOTIFICATION_CHANNEL_STATE_NO_CONNECTION = 1; + /** + * Use this state when the notification can only tell that there are pending messages on + * the server but no details of the sender/time etc are known. + */ + public static final int NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING = 2; + + } } diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java index 2b692f3e93f1..d70c79850a18 100644 --- a/core/java/android/view/ViewAncestor.java +++ b/core/java/android/view/ViewAncestor.java @@ -4637,13 +4637,18 @@ public final class ViewAncestor extends Handler implements ViewParent, public void run() { if (mView != null) { - // Send the event directly since we do not want to append the - // source text because this is the text for the entire window - // and we just want to notify that the content has changed. - AccessibilityEvent event = AccessibilityEvent.obtain( - AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); - mView.onInitializeAccessibilityEvent(event); - AccessibilityManager.getInstance(mView.mContext).sendAccessibilityEvent(event); + // Check again for accessibility state since this is executed delayed. + AccessibilityManager accessibilityManager = + AccessibilityManager.getInstance(mView.mContext); + if (accessibilityManager.isEnabled()) { + // Send the event directly since we do not want to append the + // source text because this is the text for the entire window + // and we just want to notify that the content has changed. + AccessibilityEvent event = AccessibilityEvent.obtain( + AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); + mView.onInitializeAccessibilityEvent(event); + accessibilityManager.sendAccessibilityEvent(event); + } mIsPending = false; } } diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index f3a5050001ea..dbcbd6e5ae1f 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -19,6 +19,8 @@ package android.view; import android.app.AppGlobals; import android.content.Context; import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.RemoteException; import android.provider.Settings; import android.util.DisplayMetrics; import android.util.SparseArray; @@ -219,6 +221,9 @@ public class ViewConfiguration { private final int mOverscrollDistance; private final int mOverflingDistance; + private boolean sHasPermanentMenuKey; + private boolean sHasPermanentMenuKeySet; + private static final SparseArray<ViewConfiguration> sConfigurations = new SparseArray<ViewConfiguration>(2); @@ -254,11 +259,12 @@ public class ViewConfiguration { * @see android.util.DisplayMetrics */ private ViewConfiguration(Context context) { - final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + final Resources res = context.getResources(); + final DisplayMetrics metrics = res.getDisplayMetrics(); + final Configuration config = res.getConfiguration(); final float density = metrics.density; final float sizeAndDensity; - if (context.getResources().getConfiguration().isLayoutSizeAtLeast( - Configuration.SCREENLAYOUT_SIZE_XLARGE)) { + if (config.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_XLARGE)) { sizeAndDensity = density * 1.5f; } else { sizeAndDensity = density; @@ -280,6 +286,17 @@ public class ViewConfiguration { mOverscrollDistance = (int) (sizeAndDensity * OVERSCROLL_DISTANCE + 0.5f); mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f); + + if (!sHasPermanentMenuKeySet) { + IWindowManager wm = Display.getWindowManager(); + try { + sHasPermanentMenuKey = wm.canStatusBarHide() && !res.getBoolean( + com.android.internal.R.bool.config_showNavigationBar); + sHasPermanentMenuKeySet = true; + } catch (RemoteException ex) { + sHasPermanentMenuKey = false; + } + } } /** @@ -640,4 +657,20 @@ public class ViewConfiguration { public static float getScrollFriction() { return SCROLL_FRICTION; } + + /** + * Report if the device has a permanent menu key available to the user. + * + * <p>As of Android 3.0, devices may not have a permanent menu key available. + * Apps should use the action bar to present menu options to users. + * However, there are some apps where the action bar is inappropriate + * or undesirable. This method may be used to detect if a menu key is present. + * If not, applications should provide another on-screen affordance to access + * functionality. + * + * @return true if a permanent menu key is present, false otherwise. + */ + public boolean hasPermanentMenuKey() { + return sHasPermanentMenuKey; + } } diff --git a/core/java/android/webkit/L10nUtils.java b/core/java/android/webkit/L10nUtils.java index 5b4fb1df72de..4c42cde5b693 100644 --- a/core/java/android/webkit/L10nUtils.java +++ b/core/java/android/webkit/L10nUtils.java @@ -70,7 +70,11 @@ public class L10nUtils { com.android.internal.R.string.autofill_expiration_month_re, // IDS_AUTOFILL_EXPIRATION_MONTH_RE com.android.internal.R.string.autofill_expiration_date_re, // IDS_AUTOFILL_EXPIRATION_DATE_RE com.android.internal.R.string.autofill_card_ignored_re, // IDS_AUTOFILL_CARD_IGNORED_RE - com.android.internal.R.string.autofill_fax_re // IDS_AUTOFILL_FAX_RE + com.android.internal.R.string.autofill_fax_re, // IDS_AUTOFILL_FAX_RE + com.android.internal.R.string.autofill_country_code_re, // IDS_AUTOFILL_COUNTRY_CODE_RE + com.android.internal.R.string.autofill_area_code_notext_re, // IDS_AUTOFILL_AREA_CODE_NOTEXT_RE + com.android.internal.R.string.autofill_phone_prefix_separator_re, // IDS_AUTOFILL_PHONE_PREFIX_SEPARATOR_RE + com.android.internal.R.string.autofill_phone_suffix_separator_re // IDS_AUTOFILL_PHONE_SUFFIX_SEPARATOR_RE }; private static Context mApplicationContext; diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java index 773be5bc2b21..572a1d761d65 100644 --- a/core/java/com/android/internal/net/VpnConfig.java +++ b/core/java/com/android/internal/net/VpnConfig.java @@ -23,6 +23,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; +import java.util.List; + /** * A simple container used to carry information in VpnBuilder, VpnDialogs, * and com.android.server.connectivity.Vpn. Internal use only. @@ -33,12 +35,6 @@ public class VpnConfig implements Parcelable { public static final String ACTION_VPN_REVOKED = "android.net.vpn.action.REVOKED"; - public static void enforceCallingPackage(String packageName) { - if (!"com.android.vpndialogs".equals(packageName)) { - throw new SecurityException("Unauthorized Caller"); - } - } - public static Intent getIntentForConfirmation() { Intent intent = new Intent(); intent.setClassName("com.android.vpndialogs", "com.android.vpndialogs.ConfirmDialog"); @@ -58,11 +54,12 @@ public class VpnConfig implements Parcelable { public String packageName; public String sessionName; public String interfaceName; - public String configureActivity; + public PendingIntent configureIntent; public int mtu = -1; public String addresses; public String routes; - public String dnsServers; + public List<String> dnsServers; + public List<String> searchDomains; public long startTime = -1; @Override @@ -75,11 +72,12 @@ public class VpnConfig implements Parcelable { out.writeString(packageName); out.writeString(sessionName); out.writeString(interfaceName); - out.writeString(configureActivity); + out.writeParcelable(configureIntent, flags); out.writeInt(mtu); out.writeString(addresses); out.writeString(routes); - out.writeString(dnsServers); + out.writeStringList(dnsServers); + out.writeStringList(searchDomains); out.writeLong(startTime); } @@ -91,11 +89,12 @@ public class VpnConfig implements Parcelable { config.packageName = in.readString(); config.sessionName = in.readString(); config.interfaceName = in.readString(); - config.configureActivity = in.readString(); + config.configureIntent = in.readParcelable(null); config.mtu = in.readInt(); config.addresses = in.readString(); config.routes = in.readString(); - config.dnsServers = in.readString(); + config.dnsServers = in.createStringArrayList(); + config.searchDomains = in.createStringArrayList(); config.startTime = in.readLong(); return config; } diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java index 322a8545d559..2fec9cd09f5b 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java @@ -26,6 +26,7 @@ import android.view.MenuItem; import android.view.SoundEffectConstants; import android.view.View; import android.view.View.MeasureSpec; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.ImageButton; @@ -69,9 +70,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter { final Resources res = context.getResources(); if (!mReserveOverflowSet) { - // TODO Use the no-buttons specifier instead here - mReserveOverflow = res.getConfiguration() - .isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE); + mReserveOverflow = !ViewConfiguration.get(context).hasPermanentMenuKey(); } if (!mWidthLimitSet) { diff --git a/core/res/res/layout-land/ssl_certificate.xml b/core/res/res/layout-land/ssl_certificate.xml index 56e4e70ca033..c3e6deb832e3 100644 --- a/core/res/res/layout-land/ssl_certificate.xml +++ b/core/res/res/layout-land/ssl_certificate.xml @@ -20,6 +20,7 @@ android:layout_height="wrap_content" > <LinearLayout + android:id="@+id/body" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > diff --git a/core/res/res/layout/ssl_certificate.xml b/core/res/res/layout/ssl_certificate.xml index 7206077ce6f5..ae661ce8ef67 100644 --- a/core/res/res/layout/ssl_certificate.xml +++ b/core/res/res/layout/ssl_certificate.xml @@ -20,6 +20,7 @@ android:layout_height="wrap_content" > <LinearLayout + android:id="@+id/body" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 827153e7243e..2c10b3dabe8f 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -658,4 +658,8 @@ This is intended to allow packaging drivers or tools for installation on a PC. --> <string translatable="false" name="config_isoImagePath"></string> + <!-- Whether a software navigation bar should be shown. NOTE: in the future this may be + autodetected from the Configuration. --> + <bool name="config_showNavigationBar">false</bool> + </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 88ed9c6bc586..29fca74c4e14 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2073,6 +2073,18 @@ <!-- Do not translate. Regex used by AutoFill. --> <string name="autofill_fax_re">fax<!-- fr-FR -->|télécopie|telecopie<!-- ja-JP -->|ファックス<!-- ru -->|факс<!-- zh-CN -->|传真<!-- zh-TW -->|傳真</string> + <!-- Do not translate. Regex used by AutoFill. --> + <string name="autofill_country_code_re">country.*code|ccode|_cc</string> + + <!-- Do not translate. Regex used by AutoFill. --> + <string name="autofill_area_code_notext_re">^\($</string> + + <!-- Do not translate. Regex used by AutoFill. --> + <string name="autofill_phone_prefix_separator_re">^-$|^\)$</string> + + <!-- Do not translate. Regex used by AutoFill. --> + <string name="autofill_phone_suffix_separator_re">^-$</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_readHistoryBookmarks">read Browser\'s history and bookmarks</string> @@ -2788,10 +2800,10 @@ <string name="l2tp_ipsec_psk_vpn_description">Pre-shared key based L2TP/IPSec VPN</string> <string name="l2tp_ipsec_crt_vpn_description">Certificate based L2TP/IPSec VPN</string> - <!-- Ticker text to show when VPN is active. --> - <string name="vpn_ticker"><xliff:g id="app" example="FooVPN client">%s</xliff:g> is activating VPN...</string> <!-- The title of the notification when VPN is active. --> - <string name="vpn_title">VPN is activated by <xliff:g id="app" example="FooVPN client">%s</xliff:g></string> + <string name="vpn_title">VPN is activated.</string> + <!-- The title of the notification when VPN is active with an application name. --> + <string name="vpn_title_long">VPN is activated by <xliff:g id="app" example="FooVPN client">%s</xliff:g></string> <!-- The text of the notification when VPN is active. --> <string name="vpn_text">Tap to manage the network.</string> <!-- The text of the notification when VPN is active with a session name. --> diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index c82fb9b77ed4..e36360c167a8 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -139,7 +139,7 @@ public: // setFrameAvailableListener sets the listener object that will be notified // when a new frame becomes available. - void setFrameAvailableListener(const sp<FrameAvailableListener>& l); + void setFrameAvailableListener(const sp<FrameAvailableListener>& listener); // getAllocator retrieves the binder object that must be referenced as long // as the GraphicBuffers dequeued from this SurfaceTexture are referenced. @@ -343,7 +343,7 @@ private: uint32_t mNextTransform; // mTexName is the name of the OpenGL texture to which streamed images will - // be bound when updateTexImage is called. It is set at construction time + // be bound when updateTexImage is called. It is set at construction time // changed with a call to setTexName. const GLuint mTexName; diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h index a31395ed9509..37dbcd8eae84 100644 --- a/include/media/stagefright/MediaSource.h +++ b/include/media/stagefright/MediaSource.h @@ -22,6 +22,7 @@ #include <media/stagefright/MediaErrors.h> #include <utils/RefBase.h> +#include <utils/Vector.h> namespace android { @@ -99,6 +100,15 @@ struct MediaSource : public RefBase { return ERROR_UNSUPPORTED; } + // The consumer of this media source requests that the given buffers + // are to be returned exclusively in response to read calls. + // This will be called after a successful start() and before the + // first read() call. + // Callee assumes ownership of the buffers if no error is returned. + virtual status_t setBuffers(const Vector<MediaBuffer *> &buffers) { + return ERROR_UNSUPPORTED; + } + protected: virtual ~MediaSource(); diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index 99b72ad86415..57f678c75512 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -121,6 +121,8 @@ enum { // To store the timed text format data kKeyTextFormatData = 'text', // raw data + + kKeyRequiresSecureBuffers = 'secu', // bool (int32_t) }; enum { diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index 92331a16f96a..7f3c497ecb32 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -53,6 +53,9 @@ struct OMXCodec : public MediaSource, // Enable GRALLOC_USAGE_PROTECTED for output buffers from native window kEnableGrallocUsageProtected = 128, + + // Secure decoding mode + kUseSecureInputBuffers = 256, }; static sp<MediaSource> Create( const sp<IOMX> &omx, @@ -164,6 +167,10 @@ private: bool mOMXLivesLocally; IOMX::node_id mNode; uint32_t mQuirks; + + // Flags specified in the creation of the codec. + uint32_t mFlags; + bool mIsEncoder; char *mMIME; char *mComponentName; @@ -205,15 +212,12 @@ private: List<size_t> mFilledBuffers; Condition mBufferFilled; - bool mIsMetaDataStoredInVideoBuffers; - bool mOnlySubmitOneBufferAtOneTime; - bool mEnableGrallocUsageProtected; - // Used to record the decoding time for an output picture from // a video encoder. List<int64_t> mDecodingTimeList; - OMXCodec(const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks, + OMXCodec(const sp<IOMX> &omx, IOMX::node_id node, + uint32_t quirks, uint32_t flags, bool isEncoder, const char *mime, const char *componentName, const sp<MediaSource> &source, const sp<ANativeWindow> &nativeWindow); @@ -287,6 +291,10 @@ private: void drainInputBuffers(); void fillOutputBuffers(); + bool drainAnyInputBuffer(); + BufferInfo *findInputBufferByDataPointer(void *ptr); + BufferInfo *findEmptyInputBuffer(); + // Returns true iff a flush was initiated and a completion event is // upcoming, false otherwise (A flush was not necessary as we own all // the buffers on that port). @@ -313,7 +321,7 @@ private: void dumpPortStatus(OMX_U32 portIndex); - status_t configureCodec(const sp<MetaData> &meta, uint32_t flags); + status_t configureCodec(const sp<MetaData> &meta); static uint32_t getComponentQuirks( const char *componentName, bool isEncoder); diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 0925001965dd..3bf6477cf208 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -148,6 +148,11 @@ status_t SurfaceTexture::setBufferCount(int bufferCount) { LOGV("SurfaceTexture::setBufferCount"); Mutex::Autolock lock(mMutex); + if (bufferCount > NUM_BUFFER_SLOTS) { + LOGE("setBufferCount: bufferCount larger than slots available"); + return BAD_VALUE; + } + // Error out if the user has dequeued buffers for (int i=0 ; i<mBufferCount ; i++) { if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { @@ -208,7 +213,7 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { LOGV("SurfaceTexture::dequeueBuffer"); - if ((w && !h) || (!w & h)) { + if ((w && !h) || (!w && h)) { LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); return BAD_VALUE; } @@ -699,10 +704,10 @@ nsecs_t SurfaceTexture::getTimestamp() { } void SurfaceTexture::setFrameAvailableListener( - const sp<FrameAvailableListener>& l) { + const sp<FrameAvailableListener>& listener) { LOGV("SurfaceTexture::setFrameAvailableListener"); Mutex::Autolock lock(mMutex); - mFrameAvailableListener = l; + mFrameAvailableListener = listener; } sp<IBinder> SurfaceTexture::getAllocator() { diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index ffc3346da993..29dec6373b19 100755 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -205,7 +205,7 @@ public class GpsNetInitiatedHandler { mNiNotification.defaults &= ~Notification.DEFAULT_SOUND; } - mNiNotification.flags = Notification.FLAG_ONGOING_EVENT; + mNiNotification.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_AUTO_CANCEL; mNiNotification.tickerText = getNotifTicker(notif, mContext); // if not to popup dialog immediately, pending intent will open the dialog diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index e36b01fbd7a8..1ac2c1fbbfb4 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -477,6 +477,15 @@ sp<MediaSource> OMXCodec::Create( const char *matchComponentName, uint32_t flags, const sp<ANativeWindow> &nativeWindow) { + int32_t requiresSecureBuffers; + if (source->getFormat()->findInt32( + kKeyRequiresSecureBuffers, + &requiresSecureBuffers) + && requiresSecureBuffers) { + flags |= kIgnoreCodecSpecificData; + flags |= kUseSecureInputBuffers; + } + const char *mime; bool success = meta->findCString(kKeyMIMEType, &mime); CHECK(success); @@ -530,17 +539,17 @@ sp<MediaSource> OMXCodec::Create( LOGV("Successfully allocated OMX node '%s'", componentName); sp<OMXCodec> codec = new OMXCodec( - omx, node, quirks, + omx, node, quirks, flags, createEncoder, mime, componentName, source, nativeWindow); observer->setCodec(codec); - err = codec->configureCodec(meta, flags); + err = codec->configureCodec(meta); if (err == OK) { if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) { - codec->mOnlySubmitOneBufferAtOneTime = true; + codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime; } return codec; @@ -553,24 +562,11 @@ sp<MediaSource> OMXCodec::Create( return NULL; } -status_t OMXCodec::configureCodec(const sp<MetaData> &meta, uint32_t flags) { - mIsMetaDataStoredInVideoBuffers = false; - if (flags & kStoreMetaDataInVideoBuffers) { - mIsMetaDataStoredInVideoBuffers = true; - } - - mOnlySubmitOneBufferAtOneTime = false; - if (flags & kOnlySubmitOneInputBufferAtOneTime) { - mOnlySubmitOneBufferAtOneTime = true; - } +status_t OMXCodec::configureCodec(const sp<MetaData> &meta) { + LOGV("configureCodec protected=%d", + (mFlags & kEnableGrallocUsageProtected) ? 1 : 0); - mEnableGrallocUsageProtected = false; - if (flags & kEnableGrallocUsageProtected) { - mEnableGrallocUsageProtected = true; - } - LOGV("configureCodec protected=%d", mEnableGrallocUsageProtected); - - if (!(flags & kIgnoreCodecSpecificData)) { + if (!(mFlags & kIgnoreCodecSpecificData)) { uint32_t type; const void *data; size_t size; @@ -745,7 +741,7 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta, uint32_t flags) { initOutputFormat(meta); - if ((flags & kClientNeedsFramebuffer) + if ((mFlags & kClientNeedsFramebuffer) && !strncmp(mComponentName, "OMX.SEC.", 8)) { OMX_INDEXTYPE index; @@ -1468,7 +1464,8 @@ status_t OMXCodec::setVideoOutputFormat( } OMXCodec::OMXCodec( - const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks, + const sp<IOMX> &omx, IOMX::node_id node, + uint32_t quirks, uint32_t flags, bool isEncoder, const char *mime, const char *componentName, @@ -1478,6 +1475,7 @@ OMXCodec::OMXCodec( mOMXLivesLocally(omx->livesLocally(getpid())), mNode(node), mQuirks(quirks), + mFlags(flags), mIsEncoder(isEncoder), mMIME(strdup(mime)), mComponentName(strdup(componentName)), @@ -1645,13 +1643,14 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { return allocateOutputBuffersFromNativeWindow(); } - if (mEnableGrallocUsageProtected && portIndex == kPortIndexOutput) { + if ((mFlags & kEnableGrallocUsageProtected) && portIndex == kPortIndexOutput) { LOGE("protected output buffers must be stent to an ANativeWindow"); return PERMISSION_DENIED; } status_t err = OK; - if (mIsMetaDataStoredInVideoBuffers && portIndex == kPortIndexInput) { + if ((mFlags & kStoreMetaDataInVideoBuffers) + && portIndex == kPortIndexInput) { err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE); if (err != OK) { LOGE("Storing meta data in video buffers is not supported"); @@ -1687,7 +1686,8 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { IOMX::buffer_id buffer; if (portIndex == kPortIndexInput - && (mQuirks & kRequiresAllocateBufferOnInputPorts)) { + && ((mQuirks & kRequiresAllocateBufferOnInputPorts) + || (mFlags & kUseSecureInputBuffers))) { if (mOMXLivesLocally) { mem.clear(); @@ -1748,6 +1748,31 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { // dumpPortStatus(portIndex); + if (portIndex == kPortIndexInput && (mFlags & kUseSecureInputBuffers)) { + Vector<MediaBuffer *> buffers; + for (size_t i = 0; i < def.nBufferCountActual; ++i) { + const BufferInfo &info = mPortBuffers[kPortIndexInput].itemAt(i); + + MediaBuffer *mbuf = new MediaBuffer(info.mData, info.mSize); + buffers.push(mbuf); + } + + status_t err = mSource->setBuffers(buffers); + + if (err != OK) { + for (size_t i = 0; i < def.nBufferCountActual; ++i) { + buffers.editItemAt(i)->release(); + } + buffers.clear(); + + CODEC_LOGE( + "Codec requested to use secure input buffers but " + "upstream source didn't support that."); + + return err; + } + } + return OK; } @@ -1815,7 +1840,7 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { // XXX: Currently this error is logged, but not fatal. usage = 0; } - if (mEnableGrallocUsageProtected) { + if (mFlags & kEnableGrallocUsageProtected) { usage |= GRALLOC_USAGE_PROTECTED; } @@ -2067,7 +2092,12 @@ void OMXCodec::on_message(const omx_message &msg) { } else if (mState != ERROR && mPortStatus[kPortIndexInput] != SHUTTING_DOWN) { CHECK_EQ((int)mPortStatus[kPortIndexInput], (int)ENABLED); - drainInputBuffer(&buffers->editItemAt(i)); + + if (mFlags & kUseSecureInputBuffers) { + drainAnyInputBuffer(); + } else { + drainInputBuffer(&buffers->editItemAt(i)); + } } break; } @@ -2804,32 +2834,81 @@ void OMXCodec::fillOutputBuffers() { void OMXCodec::drainInputBuffers() { CHECK(mState == EXECUTING || mState == RECONFIGURING); - Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput]; - for (size_t i = 0; i < buffers->size(); ++i) { - BufferInfo *info = &buffers->editItemAt(i); + if (mFlags & kUseSecureInputBuffers) { + Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput]; + for (size_t i = 0; i < buffers->size(); ++i) { + if (!drainAnyInputBuffer() + || (mFlags & kOnlySubmitOneInputBufferAtOneTime)) { + break; + } + } + } else { + Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput]; + for (size_t i = 0; i < buffers->size(); ++i) { + BufferInfo *info = &buffers->editItemAt(i); - if (info->mStatus != OWNED_BY_US) { - continue; + if (info->mStatus != OWNED_BY_US) { + continue; + } + + if (!drainInputBuffer(info)) { + break; + } + + if (mFlags & kOnlySubmitOneInputBufferAtOneTime) { + break; + } } + } +} - if (!drainInputBuffer(info)) { - break; +bool OMXCodec::drainAnyInputBuffer() { + return drainInputBuffer((BufferInfo *)NULL); +} + +OMXCodec::BufferInfo *OMXCodec::findInputBufferByDataPointer(void *ptr) { + Vector<BufferInfo> *infos = &mPortBuffers[kPortIndexInput]; + for (size_t i = 0; i < infos->size(); ++i) { + BufferInfo *info = &infos->editItemAt(i); + + if (info->mData == ptr) { + CODEC_LOGV( + "input buffer data ptr = %p, buffer_id = %p", + ptr, + info->mBuffer); + + return info; } + } - if (mOnlySubmitOneBufferAtOneTime) { - break; + TRESPASS(); +} + +OMXCodec::BufferInfo *OMXCodec::findEmptyInputBuffer() { + Vector<BufferInfo> *infos = &mPortBuffers[kPortIndexInput]; + for (size_t i = 0; i < infos->size(); ++i) { + BufferInfo *info = &infos->editItemAt(i); + + if (info->mStatus == OWNED_BY_US) { + return info; } } + + TRESPASS(); } bool OMXCodec::drainInputBuffer(BufferInfo *info) { - CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US); + if (info != NULL) { + CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US); + } if (mSignalledEOS) { return false; } if (mCodecSpecificDataIndex < mCodecSpecificData.size()) { + CHECK(!(mFlags & kUseSecureInputBuffers)); + const CodecSpecificData *specific = mCodecSpecificData[mCodecSpecificDataIndex]; @@ -2925,6 +3004,11 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) { break; } + if (mFlags & kUseSecureInputBuffers) { + info = findInputBufferByDataPointer(srcBuffer->data()); + CHECK(info != NULL); + } + size_t remainingBytes = info->mSize - offset; if (srcBuffer->range_length() > remainingBytes) { @@ -2960,14 +3044,24 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) { releaseBuffer = false; info->mMediaBuffer = srcBuffer; } else { - if (mIsMetaDataStoredInVideoBuffers) { + if (mFlags & kStoreMetaDataInVideoBuffers) { releaseBuffer = false; info->mMediaBuffer = srcBuffer; } - memcpy((uint8_t *)info->mData + offset, - (const uint8_t *)srcBuffer->data() - + srcBuffer->range_offset(), - srcBuffer->range_length()); + + if (mFlags & kUseSecureInputBuffers) { + // Data in "info" is already provided at this time. + + releaseBuffer = false; + + CHECK(info->mMediaBuffer == NULL); + info->mMediaBuffer = srcBuffer; + } else { + memcpy((uint8_t *)info->mData + offset, + (const uint8_t *)srcBuffer->data() + + srcBuffer->range_offset(), + srcBuffer->range_length()); + } } int64_t lastBufferTimeUs; @@ -3036,6 +3130,16 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) { info->mBuffer, offset, timestampUs, timestampUs / 1E6); + if (info == NULL) { + CHECK(mFlags & kUseSecureInputBuffers); + CHECK(signalEOS); + + // This is fishy, there's still a MediaBuffer corresponding to this + // info available to the source at this point even though we're going + // to use it to signal EOS to the codec. + info = findEmptyInputBuffer(); + } + err = mOMX->emptyBuffer( mNode, info->mBuffer, 0, offset, flags, timestampUs); diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp index 7072d58d6cce..26eda0c4cfb1 100644 --- a/media/libstagefright/WVMExtractor.cpp +++ b/media/libstagefright/WVMExtractor.cpp @@ -33,25 +33,26 @@ #include <utils/Errors.h> +/* The extractor lifetime is short - just long enough to get + * the media sources constructed - so the shared lib needs to remain open + * beyond the lifetime of the extractor. So keep the handle as a global + * rather than a member of the extractor + */ +void *gVendorLibHandle = NULL; + namespace android { -Mutex WVMExtractor::sMutex; -uint32_t WVMExtractor::sActiveExtractors = 0; -void *WVMExtractor::sVendorLibHandle = NULL; +static Mutex gWVMutex; WVMExtractor::WVMExtractor(const sp<DataSource> &source) : mDataSource(source) { { - Mutex::Autolock autoLock(sMutex); - - if (sVendorLibHandle == NULL) { - CHECK(sActiveExtractors == 0); - sVendorLibHandle = dlopen("libwvm.so", RTLD_NOW); + Mutex::Autolock autoLock(gWVMutex); + if (gVendorLibHandle == NULL) { + gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW); } - sActiveExtractors++; - - if (sVendorLibHandle == NULL) { + if (gVendorLibHandle == NULL) { LOGE("Failed to open libwvm.so"); return; } @@ -59,7 +60,7 @@ WVMExtractor::WVMExtractor(const sp<DataSource> &source) typedef WVMLoadableExtractor *(*GetInstanceFunc)(sp<DataSource>); GetInstanceFunc getInstanceFunc = - (GetInstanceFunc) dlsym(sVendorLibHandle, + (GetInstanceFunc) dlsym(gVendorLibHandle, "_ZN7android11GetInstanceENS_2spINS_10DataSourceEEE"); if (getInstanceFunc) { @@ -71,17 +72,6 @@ WVMExtractor::WVMExtractor(const sp<DataSource> &source) } WVMExtractor::~WVMExtractor() { - Mutex::Autolock autoLock(sMutex); - - CHECK(sActiveExtractors > 0); - sActiveExtractors--; - - // Close lib after last use - if (sActiveExtractors == 0) { - if (sVendorLibHandle != NULL) - dlclose(sVendorLibHandle); - sVendorLibHandle = NULL; - } } size_t WVMExtractor::countTracks() { diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp index 967f126c8adf..f4b36688f4cd 100644 --- a/media/libstagefright/chromium_http/support.cpp +++ b/media/libstagefright/chromium_http/support.cpp @@ -115,31 +115,31 @@ SfRequestContext::SfRequestContext() { mUserAgent = ua.c_str(); - net_log_ = new SfNetLog; + set_net_log(new SfNetLog()); - host_resolver_ = + set_host_resolver( net::CreateSystemHostResolver( net::HostResolver::kDefaultParallelism, NULL /* resolver_proc */, - net_log_); + net_log())); - ssl_config_service_ = - net::SSLConfigService::CreateSystemSSLConfigService(); + set_ssl_config_service( + net::SSLConfigService::CreateSystemSSLConfigService()); - proxy_service_ = net::ProxyService::CreateWithoutProxyResolver( - new net::ProxyConfigServiceAndroid, net_log_); + set_proxy_service(net::ProxyService::CreateWithoutProxyResolver( + new net::ProxyConfigServiceAndroid, net_log())); - http_transaction_factory_ = new net::HttpCache( - host_resolver_, + set_http_transaction_factory(new net::HttpCache( + host_resolver(), new net::CertVerifier(), - dnsrr_resolver_, - dns_cert_checker_.get(), - proxy_service_.get(), - ssl_config_service_.get(), - net::HttpAuthHandlerFactory::CreateDefault(host_resolver_), - network_delegate_, - net_log_, - NULL); // backend_factory + dnsrr_resolver(), + dns_cert_checker(), + proxy_service(), + ssl_config_service(), + net::HttpAuthHandlerFactory::CreateDefault(host_resolver()), + network_delegate(), + net_log(), + NULL)); // backend_factory } const std::string &SfRequestContext::GetUserAgent(const GURL &url) const { diff --git a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp index e3292e63c679..009676011714 100644 --- a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp +++ b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp @@ -475,7 +475,9 @@ status_t AVCEncoder::read( } status_t err = mSource->read(&mInputBuffer, options); if (err != OK) { - LOGE("Failed to read input video frame: %d", err); + if (err != ERROR_END_OF_STREAM) { + LOGE("Failed to read input video frame: %d", err); + } outputBuffer->release(); return err; } diff --git a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp index 15ed2193ae61..d7249c1ebb4f 100644 --- a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp +++ b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp @@ -398,10 +398,13 @@ status_t M4vH263Encoder::read( } // Ready for accepting an input video frame - if (OK != mSource->read(&mInputBuffer, options)) { - LOGE("Failed to read from data source"); + status_t err = mSource->read(&mInputBuffer, options); + if (OK != err) { + if (err != ERROR_END_OF_STREAM) { + LOGE("Failed to read from data source"); + } outputBuffer->release(); - return UNKNOWN_ERROR; + return err; } if (mInputBuffer->size() - ((mVideoWidth * mVideoHeight * 3) >> 1) != 0) { diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 165683e986b6..f1a2a60b9495 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -408,13 +408,20 @@ rinse_repeat: if (firstTime) { Mutex::Autolock autoLock(mLock); - int32_t targetDuration; - if (!mPlaylist->isComplete() - || !mPlaylist->meta()->findInt32( - "target-duration", &targetDuration)) { + if (!mPlaylist->isComplete()) { mDurationUs = -1; } else { - mDurationUs = 1000000ll * targetDuration * mPlaylist->size(); + mDurationUs = 0; + for (size_t i = 0; i < mPlaylist->size(); ++i) { + sp<AMessage> itemMeta; + CHECK(mPlaylist->itemAt( + i, NULL /* uri */, &itemMeta)); + + int64_t itemDurationUs; + CHECK(itemMeta->findInt64("durationUs", &itemDurationUs)); + + mDurationUs += itemDurationUs; + } } } @@ -431,14 +438,26 @@ rinse_repeat: bool bandwidthChanged = false; if (mSeekTimeUs >= 0) { - int32_t targetDuration; - if (mPlaylist->isComplete() && - mPlaylist->meta()->findInt32( - "target-duration", &targetDuration)) { - int64_t seekTimeSecs = (mSeekTimeUs + 500000ll) / 1000000ll; - int64_t index = seekTimeSecs / targetDuration; - - if (index >= 0 && index < mPlaylist->size()) { + if (mPlaylist->isComplete()) { + size_t index = 0; + int64_t segmentStartUs = 0; + while (index < mPlaylist->size()) { + sp<AMessage> itemMeta; + CHECK(mPlaylist->itemAt( + index, NULL /* uri */, &itemMeta)); + + int64_t itemDurationUs; + CHECK(itemMeta->findInt64("durationUs", &itemDurationUs)); + + if (mSeekTimeUs < segmentStartUs + itemDurationUs) { + break; + } + + segmentStartUs += itemDurationUs; + ++index; + } + + if (index < mPlaylist->size()) { int32_t newSeqNumber = firstSeqNumberInPlaylist + index; if (newSeqNumber != mSeqNumber) { diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 765f79565d5a..123fbf8b23e4 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -64,14 +64,21 @@ size_t M3UParser::size() { } bool M3UParser::itemAt(size_t index, AString *uri, sp<AMessage> *meta) { - uri->clear(); - if (meta) { *meta = NULL; } + if (uri) { + uri->clear(); + } + + if (meta) { + *meta = NULL; + } if (index >= mItems.size()) { return false; } - *uri = mItems.itemAt(index).mURI; + if (uri) { + *uri = mItems.itemAt(index).mURI; + } if (meta) { *meta = mItems.itemAt(index).mMeta; diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h index 0817babb45e0..deecd2543a92 100644 --- a/media/libstagefright/include/WVMExtractor.h +++ b/media/libstagefright/include/WVMExtractor.h @@ -18,7 +18,6 @@ #define WVM_EXTRACTOR_H_ -#include <media/stagefright/DataSource.h> #include <media/stagefright/MediaExtractor.h> #include <utils/Errors.h> @@ -68,10 +67,6 @@ private: WVMExtractor(const WVMExtractor &); WVMExtractor &operator=(const WVMExtractor &); - - static Mutex sMutex; - static uint32_t sActiveExtractors; - static void *sVendorLibHandle; }; } // namespace android diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 7a4ac5d816f6..5298f2e66927 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -36,10 +36,6 @@ <!-- Whether or not we show the number in the bar. --> <bool name="config_statusBarShowNumber">true</bool> - <!-- Whether a software navigation bar should be shown. NOTE: in the future this may be - autodetected from the Configuration. --> - <bool name="config_showNavigationBar">false</bool> - <!-- How many icons may be shown at once in the system bar. Includes any slots that may be reused for things like IME control. --> <integer name="config_maxNotificationIcons">5</integer> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index d8474db3c2ef..4c7b0dd2ca54 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -246,7 +246,7 @@ public class PhoneStatusBar extends StatusBar { mIntruderAlertView.setClickable(true); try { - boolean showNav = res.getBoolean(R.bool.config_showNavigationBar); + boolean showNav = res.getBoolean(com.android.internal.R.bool.config_showNavigationBar); if (showNav) { mNavigationBarView = (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null); diff --git a/packages/VpnDialogs/Android.mk b/packages/VpnDialogs/Android.mk index 89f010aaebcb..ac84125f8f4e 100644 --- a/packages/VpnDialogs/Android.mk +++ b/packages/VpnDialogs/Android.mk @@ -20,6 +20,8 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional +LOCAL_CERTIFICATE := platform + LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := VpnDialogs diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml index 4e6784ce0884..c0b0a08067cf 100644 --- a/packages/VpnDialogs/AndroidManifest.xml +++ b/packages/VpnDialogs/AndroidManifest.xml @@ -1,5 +1,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.vpndialogs"> + package="com.android.vpndialogs" + android:sharedUserId="android.uid.system"> <application android:label="VpnDialogs"> <activity android:name=".ConfirmDialog" diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml index 8186e2629173..df6d36bd2814 100644 --- a/packages/VpnDialogs/res/values/strings.xml +++ b/packages/VpnDialogs/res/values/strings.xml @@ -29,6 +29,7 @@ <string name="accept">I trust this application.</string> + <string name="legacy_title">VPN is connected</string> <string name="configure">Configure</string> <string name="disconnect">Disconnect</string> diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java index ba3f3448f066..c076ba0bfd2f 100644 --- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java +++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java @@ -64,9 +64,6 @@ public class ManageDialog extends Activity implements Handler.Callback, mService = IConnectivityManager.Stub.asInterface( ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); - PackageManager pm = getPackageManager(); - ApplicationInfo app = pm.getApplicationInfo(mConfig.packageName, 0); - View view = View.inflate(this, R.layout.manage, null); if (mConfig.sessionName != null) { ((TextView) view.findViewById(R.id.session)).setText(mConfig.sessionName); @@ -75,15 +72,29 @@ public class ManageDialog extends Activity implements Handler.Callback, mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted); mDataReceived = (TextView) view.findViewById(R.id.data_received); - mDialog = new AlertDialog.Builder(this) - .setIcon(app.loadIcon(pm)) - .setTitle(app.loadLabel(pm)) - .setView(view) - .setNeutralButton(R.string.disconnect, this) - .setNegativeButton(android.R.string.cancel, this) - .create(); + if (mConfig.packageName == null) { + // Legacy VPN does not have a package name. + mDialog = new AlertDialog.Builder(this) + .setIcon(android.R.drawable.ic_dialog_info) + .setTitle(R.string.legacy_title) + .setView(view) + .setNeutralButton(R.string.disconnect, this) + .setNegativeButton(android.R.string.cancel, this) + .create(); + } else { + PackageManager pm = getPackageManager(); + ApplicationInfo app = pm.getApplicationInfo(mConfig.packageName, 0); + + mDialog = new AlertDialog.Builder(this) + .setIcon(app.loadIcon(pm)) + .setTitle(app.loadLabel(pm)) + .setView(view) + .setNeutralButton(R.string.disconnect, this) + .setNegativeButton(android.R.string.cancel, this) + .create(); + } - if (mConfig.configureActivity != null) { + if (mConfig.configureIntent != null) { mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getText(R.string.configure), this); } @@ -113,9 +124,7 @@ public class ManageDialog extends Activity implements Handler.Callback, public void onClick(DialogInterface dialog, int which) { try { if (which == AlertDialog.BUTTON_POSITIVE) { - Intent intent = new Intent(); - intent.setClassName(mConfig.packageName, mConfig.configureActivity); - startActivity(intent); + mConfig.configureIntent.send(); } else if (which == AlertDialog.BUTTON_NEUTRAL) { mService.prepareVpn(""); } diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index 95b8a5723e2f..ca2540bfad20 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -212,8 +212,8 @@ status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, struct input_absinfo info; if(ioctl(device->fd, EVIOCGABS(axis), &info)) { - LOGW("Error reading absolute controller %d for device %s fd %d\n", - axis, device->identifier.name.string(), device->fd); + LOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", + axis, device->identifier.name.string(), device->fd, errno); return -errno; } @@ -335,6 +335,33 @@ int32_t EventHub::getSwitchStateLocked(Device* device, int32_t sw) const { return AKEY_STATE_UNKNOWN; } +status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const { + if (axis >= 0 && axis <= ABS_MAX) { + AutoMutex _l(mLock); + + Device* device = getDeviceLocked(deviceId); + if (device != NULL) { + return getAbsoluteAxisValueLocked(device, axis, outValue); + } + } + *outValue = 0; + return -1; +} + +status_t EventHub::getAbsoluteAxisValueLocked(Device* device, int32_t axis, + int32_t* outValue) const { + struct input_absinfo info; + + if(ioctl(device->fd, EVIOCGABS(axis), &info)) { + LOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", + axis, device->identifier.name.string(), device->fd, errno); + return -errno; + } + + *outValue = info.value; + return OK; +} + bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const { AutoMutex _l(mLock); diff --git a/services/input/EventHub.h b/services/input/EventHub.h index 0a34e45a565c..695dfdfb25e6 100644 --- a/services/input/EventHub.h +++ b/services/input/EventHub.h @@ -186,6 +186,8 @@ public: virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0; virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0; virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0; + virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, + int32_t* outValue) const = 0; /* * Examine key input devices for specific framework keycode support @@ -237,6 +239,7 @@ public: virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const; virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const; virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const; + virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const; virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const; @@ -305,6 +308,7 @@ private: int32_t getScanCodeStateLocked(Device* device, int32_t scanCode) const; int32_t getKeyCodeStateLocked(Device* device, int32_t keyCode) const; int32_t getSwitchStateLocked(Device* device, int32_t sw) const; + int32_t getAbsoluteAxisValueLocked(Device* device, int32_t axis, int32_t* outValue) const; bool markSupportedKeyCodesLocked(Device* device, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const; diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index 85ce38ae2020..10b9083549f2 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -1239,8 +1239,9 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const InputWindow* newHoverWindow = NULL; bool isSplit = mTouchState.split; - bool switchedDevice = mTouchState.deviceId != entry->deviceId - || mTouchState.source != entry->source; + bool switchedDevice = mTouchState.deviceId >= 0 + && (mTouchState.deviceId != entry->deviceId + || mTouchState.source != entry->source); bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 82c3af370ea8..79218a5581ca 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -5394,7 +5394,6 @@ void SingleTouchInputMapper::configureRawAxes() { MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : TouchInputMapper(device), mSlotCount(0), mUsingSlotsProtocol(false) { - clearState(); } MultiTouchInputMapper::~MultiTouchInputMapper() { @@ -5404,6 +5403,24 @@ void MultiTouchInputMapper::clearState() { mAccumulator.clearSlots(mSlotCount); mAccumulator.clearButtons(); mButtonState = 0; + + if (mUsingSlotsProtocol) { + // Query the driver for the current slot index and use it as the initial slot + // before we start reading events from the device. It is possible that the + // current slot index will not be the same as it was when the first event was + // written into the evdev buffer, which means the input mapper could start + // out of sync with the initial state of the events in the evdev buffer. + // In the extremely unlikely case that this happens, the data from + // two slots will be confused until the next ABS_MT_SLOT event is received. + // This can cause the touch point to "jump", but at least there will be + // no stuck touches. + status_t status = getEventHub()->getAbsoluteAxisValue(getDeviceId(), ABS_MT_SLOT, + &mAccumulator.currentSlot); + if (status) { + LOGW("Could not retrieve current multitouch slot index. status=%d", status); + mAccumulator.currentSlot = -1; + } + } } void MultiTouchInputMapper::reset() { @@ -5682,6 +5699,8 @@ void MultiTouchInputMapper::configureRawAxes() { } mAccumulator.allocateSlots(mSlotCount); + + clearState(); } diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index e349248b1c5a..d3c5ece7cbef 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -429,6 +429,7 @@ class FakeEventHub : public EventHubInterface { KeyedVector<int32_t, int32_t> keyCodeStates; KeyedVector<int32_t, int32_t> scanCodeStates; KeyedVector<int32_t, int32_t> switchStates; + KeyedVector<int32_t, int32_t> absoluteAxisValue; KeyedVector<int32_t, KeyInfo> keys; KeyedVector<int32_t, bool> leds; Vector<VirtualKeyDefinition> virtualKeys; @@ -514,6 +515,11 @@ public: device->switchStates.replaceValueFor(switchCode, state); } + void setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value) { + Device* device = getDevice(deviceId); + device->absoluteAxisValue.replaceValueFor(axis, value); + } + void addKey(int32_t deviceId, int32_t scanCode, int32_t keyCode, uint32_t flags) { Device* device = getDevice(deviceId); KeyInfo info; @@ -677,6 +683,20 @@ private: return AKEY_STATE_UNKNOWN; } + virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, + int32_t* outValue) const { + Device* device = getDevice(deviceId); + if (device) { + ssize_t index = device->absoluteAxisValue.indexOfKey(axis); + if (index >= 0) { + *outValue = device->absoluteAxisValue.valueAt(index); + return OK; + } + } + *outValue = 0; + return -1; + } + virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const { bool result = false; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 8fb6274a7afb..663f4f47f56e 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2533,7 +2533,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private VpnCallback() { } - public synchronized void override(String[] dnsServers) { + public synchronized void override(List<String> dnsServers, List<String> searchDomains) { // TODO: override DNS servers and http proxy. } diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index adc65708d5ef..1c150f8a65ea 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -16,10 +16,11 @@ package com.android.server; +import static android.Manifest.permission.MANAGE_NETWORK_POLICY; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; -import static android.Manifest.permission.MANAGE_NETWORK_POLICY; +import static android.provider.Settings.Secure.NETSTATS_ENABLED; import android.content.Context; import android.content.pm.PackageManager; @@ -35,6 +36,7 @@ import android.os.Binder; import android.os.INetworkManagementService; import android.os.SystemClock; import android.os.SystemProperties; +import android.provider.Settings; import android.util.Log; import android.util.Slog; import android.util.SparseBooleanArray; @@ -123,6 +125,8 @@ class NetworkManagementService extends INetworkManagementService.Stub { /** Set of UIDs with active reject rules. */ private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray(); + private boolean mBandwidthControlEnabled; + /** * Constructs a new NetworkManagementService instance * @@ -161,6 +165,29 @@ class NetworkManagementService extends INetworkManagementService.Stub { return new NetworkManagementService(context, procRoot); } + public void systemReady() { + + // only enable bandwidth control when support exists, and requested by + // system setting. + // TODO: eventually migrate to be always enabled + final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists(); + final boolean shouldEnable = + Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 0) != 0; + + mBandwidthControlEnabled = false; + if (hasKernelSupport && shouldEnable) { + Slog.d(TAG, "enabling bandwidth control"); + try { + mConnector.doCommand("bandwidth enable"); + mBandwidthControlEnabled = true; + } catch (NativeDaemonConnectorException e) { + Slog.e(TAG, "problem enabling bandwidth controls", e); + } + } else { + Slog.d(TAG, "not enabling bandwidth control"); + } + } + public void registerObserver(INetworkManagementEventObserver obs) { Slog.d(TAG, "Registering observer"); mObservers.add(obs); @@ -919,7 +946,7 @@ class NetworkManagementService extends INetworkManagementService.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); - if (mProcStatsNetfilter.exists()) { + if (mBandwidthControlEnabled) { return getNetworkStatsDetailNetfilter(UID_ALL); } else { return getNetworkStatsDetailUidstat(UID_ALL); @@ -930,6 +957,10 @@ class NetworkManagementService extends INetworkManagementService.Stub { public void setInterfaceQuota(String iface, long quota) { mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); + // silently discard when control disabled + // TODO: eventually migrate to be always enabled + if (!mBandwidthControlEnabled) return; + synchronized (mInterfaceQuota) { if (mInterfaceQuota.contains(iface)) { // TODO: eventually consider throwing @@ -953,6 +984,10 @@ class NetworkManagementService extends INetworkManagementService.Stub { public void removeInterfaceQuota(String iface) { mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); + // silently discard when control disabled + // TODO: eventually migrate to be always enabled + if (!mBandwidthControlEnabled) return; + synchronized (mInterfaceQuota) { if (!mInterfaceQuota.contains(iface)) { // TODO: eventually consider throwing @@ -976,6 +1011,10 @@ class NetworkManagementService extends INetworkManagementService.Stub { public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) { mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); + // silently discard when control disabled + // TODO: eventually migrate to be always enabled + if (!mBandwidthControlEnabled) return; + synchronized (mUidRejectOnQuota) { final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false); if (oldRejectOnQuota == rejectOnQuotaInterfaces) { @@ -1011,7 +1050,7 @@ class NetworkManagementService extends INetworkManagementService.Stub { android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); } - if (mProcStatsNetfilter.exists()) { + if (mBandwidthControlEnabled) { return getNetworkStatsDetailNetfilter(uid); } else { return getNetworkStatsDetailUidstat(uid); @@ -1151,12 +1190,6 @@ class NetworkManagementService extends INetworkManagementService.Stub { return getInterfaceThrottle(iface, false); } - @Override - public void setBandwidthControlEnabled(boolean enabled) { - mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); - mConnector.doCommand(String.format("bandwidth %s", (enabled ? "enable" : "disable"))); - } - /** * Split given line into {@link ArrayList}. */ diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index dbfd145bc65f..8c7e279b7132 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -523,6 +523,7 @@ class ServerThread extends Thread { // These are needed to propagate to the runnable below. final Context contextF = context; final BatteryService batteryF = battery; + final NetworkManagementService networkManagementF = networkManagement; final NetworkStatsService networkStatsF = networkStats; final NetworkPolicyManagerService networkPolicyF = networkPolicy; final ConnectivityService connectivityF = connectivity; @@ -550,6 +551,7 @@ class ServerThread extends Thread { startSystemUi(contextF); if (batteryF != null) batteryF.systemReady(); + if (networkManagementF != null) networkManagementF.systemReady(); if (networkStatsF != null) networkStatsF.systemReady(); if (networkPolicyF != null) networkPolicyF.systemReady(); if (connectivityF != null) connectivityF.systemReady(); diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java index 54bddb258aaf..a8be916427f3 100644 --- a/services/java/com/android/server/connectivity/Vpn.java +++ b/services/java/com/android/server/connectivity/Vpn.java @@ -40,9 +40,9 @@ import com.android.internal.R; import com.android.internal.net.VpnConfig; import com.android.server.ConnectivityService.VpnCallback; -import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charsets; +import java.util.Arrays; /** * @hide @@ -77,11 +77,13 @@ public class Vpn extends INetworkManagementEventObserver.Stub { return mPackageName; } - // Check the permission of the caller. - PackageManager pm = mContext.getPackageManager(); - VpnConfig.enforceCallingPackage(pm.getNameForUid(Binder.getCallingUid())); + // Only system user can call this method. + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("Unauthorized Caller"); + } // Check the permission of the given package. + PackageManager pm = mContext.getPackageManager(); if (packageName.isEmpty()) { packageName = null; } else if (pm.checkPermission(VPN, packageName) != PackageManager.PERMISSION_GRANTED) { @@ -104,6 +106,12 @@ public class Vpn extends INetworkManagementEventObserver.Stub { mContext.sendBroadcast(intent); } + // Stop legacy VPN if it has been started. + if (mLegacyVpnRunner != null) { + mLegacyVpnRunner.exit(); + mLegacyVpnRunner = null; + } + Log.i(TAG, "Switched from " + mPackageName + " to " + packageName); mPackageName = packageName; return mPackageName; @@ -132,7 +140,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub { /** * Configure a TUN interface and return its file descriptor. * - * @param configuration The parameters to configure the interface. + * @param config The parameters to configure the interface. * @return The file descriptor of the interface. */ public synchronized ParcelFileDescriptor establish(VpnConfig config) { @@ -151,11 +159,25 @@ public class Vpn extends INetworkManagementEventObserver.Stub { return null; } - // Create and configure the interface. + // Load the label. + String label = app.loadLabel(pm).toString(); + + // Load the icon and convert it into a bitmap. + Drawable icon = app.loadIcon(pm); + Bitmap bitmap = null; + if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) { + int width = mContext.getResources().getDimensionPixelSize( + android.R.dimen.notification_large_icon_width); + int height = mContext.getResources().getDimensionPixelSize( + android.R.dimen.notification_large_icon_height); + icon.setBounds(0, 0, width, height); + bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + icon.draw(new Canvas(bitmap)); + } + + // Create the interface and abort if any of the following steps fails. ParcelFileDescriptor descriptor = ParcelFileDescriptor.adoptFd(jniCreateInterface(config.mtu)); - - // Abort if any of the following steps fails. try { String name = jniGetInterfaceName(descriptor.getFd()); if (jniSetAddresses(name, config.addresses) < 1) { @@ -177,12 +199,15 @@ public class Vpn extends INetworkManagementEventObserver.Stub { throw e; } - String dnsServers = (config.dnsServers == null) ? "" : config.dnsServers.trim(); - mCallback.override(dnsServers.isEmpty() ? null : dnsServers.split(" ")); + // Override DNS servers and search domains. + mCallback.override(config.dnsServers, config.searchDomains); + // Fill more values. config.packageName = mPackageName; config.interfaceName = mInterfaceName; - showNotification(pm, app, config); + + // Show the notification! + showNotification(config, label, bitmap); return descriptor; } @@ -202,41 +227,26 @@ public class Vpn extends INetworkManagementEventObserver.Stub { public synchronized void interfaceRemoved(String name) { if (name.equals(mInterfaceName) && jniCheckInterface(name) == 0) { hideNotification(); - mInterfaceName = null; mCallback.restore(); + mInterfaceName = null; } } - private void showNotification(PackageManager pm, ApplicationInfo app, VpnConfig config) { + private void showNotification(VpnConfig config, String label, Bitmap icon) { NotificationManager nm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); if (nm != null) { - // Load the icon and convert it into a bitmap. - Drawable icon = app.loadIcon(pm); - Bitmap bitmap = null; - if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) { - int width = mContext.getResources().getDimensionPixelSize( - android.R.dimen.notification_large_icon_width); - int height = mContext.getResources().getDimensionPixelSize( - android.R.dimen.notification_large_icon_height); - icon.setBounds(0, 0, width, height); - bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - icon.draw(new Canvas(bitmap)); - } - - // Load the label. - String label = app.loadLabel(pm).toString(); - - // Build the notification. + String title = (label == null) ? mContext.getString(R.string.vpn_title) : + mContext.getString(R.string.vpn_title_long, label); String text = (config.sessionName == null) ? mContext.getString(R.string.vpn_text) : mContext.getString(R.string.vpn_text_long, config.sessionName); + long identity = Binder.clearCallingIdentity(); Notification notification = new Notification.Builder(mContext) .setSmallIcon(R.drawable.vpn_connected) - .setLargeIcon(bitmap) - .setTicker(mContext.getString(R.string.vpn_ticker, label)) - .setContentTitle(mContext.getString(R.string.vpn_title, label)) + .setLargeIcon(icon) + .setContentTitle(title) .setContentText(text) .setContentIntent(VpnConfig.getIntentForNotification(mContext, config)) .setDefaults(Notification.DEFAULT_ALL) @@ -267,27 +277,22 @@ public class Vpn extends INetworkManagementEventObserver.Stub { private native void jniProtectSocket(int fd, String name); /** - * Handle legacy VPN requests. This method stops the services and restart + * Handle legacy VPN requests. This method stops the daemons and restart * them if their arguments are not null. Heavy things are offloaded to * another thread, so callers will not be blocked too long. * * @param raoocn The arguments to be passed to racoon. * @param mtpd The arguments to be passed to mtpd. */ - public synchronized void doLegacyVpn(String[] racoon, String[] mtpd) { - // Currently only system user is allowed. - if (Binder.getCallingUid() != Process.SYSTEM_UID) { - throw new SecurityException("Unauthorized Caller"); - } + public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) { + // Stop the current VPN just like a normal VPN application. + prepare(""); - // If the previous runner is still alive, interrupt it. - if (mLegacyVpnRunner != null && mLegacyVpnRunner.isAlive()) { - mLegacyVpnRunner.interrupt(); - } + // Legacy VPN does not have a package name. + config.packageName = null; // Start a new runner and we are done! - mLegacyVpnRunner = new LegacyVpnRunner( - new String[] {"racoon", "mtpd"}, racoon, mtpd); + mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd); mLegacyVpnRunner.start(); } @@ -300,17 +305,25 @@ public class Vpn extends INetworkManagementEventObserver.Stub { */ private class LegacyVpnRunner extends Thread { private static final String TAG = "LegacyVpnRunner"; - private static final String NONE = "--"; - private final String[] mServices; + private final VpnConfig mConfig; + private final String[] mDaemons; private final String[][] mArguments; private long mTimer = -1; - public LegacyVpnRunner(String[] services, String[]... arguments) { + public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) { super(TAG); - mServices = services; - mArguments = arguments; + mConfig = config; + mDaemons = new String[] {"racoon", "mtpd"}; + mArguments = new String[][] {racoon, mtpd}; + } + + public void exit() { + for (String daemon : mDaemons) { + SystemProperties.set("ctl.stop", daemon); + } + interrupt(); } @Override @@ -318,9 +331,9 @@ public class Vpn extends INetworkManagementEventObserver.Stub { // Wait for the previous thread since it has been interrupted. Log.v(TAG, "wait"); synchronized (TAG) { - Log.v(TAG, "run"); + Log.v(TAG, "begin"); execute(); - Log.v(TAG, "exit"); + Log.v(TAG, "end"); } } @@ -342,14 +355,14 @@ public class Vpn extends INetworkManagementEventObserver.Stub { // Initialize the timer. checkpoint(false); - // First stop the services. - for (String service : mServices) { - SystemProperties.set("ctl.stop", service); + // First stop the daemons. + for (String daemon : mDaemons) { + SystemProperties.set("ctl.stop", daemon); } - // Wait for the services to stop. - for (String service : mServices) { - String key = "init.svc." + service; + // Wait for the daemons to stop. + for (String daemon : mDaemons) { + String key = "init.svc." + daemon; while (!"stopped".equals(SystemProperties.get(key))) { checkpoint(true); } @@ -363,7 +376,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub { checkpoint(true); } - // Check if we need to restart some services. + // Check if we need to restart some daemons. boolean restart = false; for (String[] arguments : mArguments) { restart = restart || (arguments != null); @@ -372,19 +385,19 @@ public class Vpn extends INetworkManagementEventObserver.Stub { return; } - // Start the service with arguments. - for (int i = 0; i < mServices.length; ++i) { + // Start the daemon with arguments. + for (int i = 0; i < mDaemons.length; ++i) { String[] arguments = mArguments[i]; if (arguments == null) { continue; } - // Start the service. - String service = mServices[i]; - SystemProperties.set("ctl.start", service); + // Start the daemon. + String daemon = mDaemons[i]; + SystemProperties.set("ctl.start", daemon); - // Wait for the service to start. - String key = "init.svc." + service; + // Wait for the daemon to start. + String key = "init.svc." + daemon; while (!"running".equals(SystemProperties.get(key))) { checkpoint(true); } @@ -392,7 +405,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub { // Create the control socket. LocalSocket socket = new LocalSocket(); LocalSocketAddress address = new LocalSocketAddress( - service, LocalSocketAddress.Namespace.RESERVED); + daemon, LocalSocketAddress.Namespace.RESERVED); // Wait for the socket to connect. while (true) { @@ -407,22 +420,22 @@ public class Vpn extends INetworkManagementEventObserver.Stub { socket.setSoTimeout(500); // Send over the arguments. - OutputStream output = socket.getOutputStream(); + OutputStream out = socket.getOutputStream(); for (String argument : arguments) { byte[] bytes = argument.getBytes(Charsets.UTF_8); if (bytes.length >= 0xFFFF) { throw new IllegalArgumentException("argument too large"); } - output.write(bytes.length >> 8); - output.write(bytes.length); - output.write(bytes); + out.write(bytes.length >> 8); + out.write(bytes.length); + out.write(bytes); checkpoint(false); } // Send End-Of-Arguments. - output.write(0xFF); - output.write(0xFF); - output.flush(); + out.write(0xFF); + out.write(0xFF); + out.flush(); socket.close(); } @@ -433,25 +446,47 @@ public class Vpn extends INetworkManagementEventObserver.Stub { while (NONE.equals(SystemProperties.get("vpn.dns")) || NONE.equals(SystemProperties.get("vpn.via"))) { - // Check if a running service is dead. - for (int i = 0; i < mServices.length; ++i) { - String service = mServices[i]; + // Check if a running daemon is dead. + for (int i = 0; i < mDaemons.length; ++i) { + String daemon = mDaemons[i]; if (mArguments[i] != null && !"running".equals( - SystemProperties.get("init.svc." + service))) { - throw new IllegalArgumentException(service + " is dead"); + SystemProperties.get("init.svc." + daemon))) { + throw new IllegalArgumentException(daemon + " is dead"); } } checkpoint(true); } - // Great! Now we are connected! - Log.i(TAG, "connected!"); - // TODO: + // Now we are connected. Get the interface. + mConfig.interfaceName = SystemProperties.get("vpn.via"); + + // Get the DNS servers if they are not set in config. + if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) { + String dnsServers = SystemProperties.get("vpn.dns").trim(); + if (!dnsServers.isEmpty()) { + mConfig.dnsServers = Arrays.asList(dnsServers.split(" ")); + } + } + + // TODO: support routes and search domains for IPSec Mode-CFG. + + // This is it! Here is the end of our journey! + synchronized (Vpn.this) { + // Check if the thread is interrupted while we are waiting. + checkpoint(false); + if (mConfig.routes != null) { + jniSetRoutes(mConfig.interfaceName, mConfig.routes); + } + mInterfaceName = mConfig.interfaceName; + mCallback.override(mConfig.dnsServers, mConfig.searchDomains); + showNotification(mConfig, null, null); + } + Log.i(TAG, "Connected!"); } catch (Exception e) { - Log.i(TAG, e.getMessage()); - for (String service : mServices) { - SystemProperties.set("ctl.stop", service); + Log.i(TAG, "Abort due to " + e.getMessage()); + for (String daemon : mDaemons) { + SystemProperties.set("ctl.stop", daemon); } } } diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index 1f2ec2ca8279..2a17cbe7afda 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -1044,8 +1044,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // TODO: only dispatch when rules actually change - // record rule locally to dispatch to new listeners - mUidRules.put(uid, uidRules); + if (uidRules == RULE_ALLOW_ALL) { + mUidRules.delete(uid); + } else { + mUidRules.put(uid, uidRules); + } final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0; setUidNetworkRules(uid, rejectMetered); diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 7610a1181d60..b4bd17690605 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -134,7 +134,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Settings that can be changed externally. */ public interface NetworkStatsSettings { - public boolean getEnabled(); public long getPollInterval(); public long getPersistThreshold(); public long getNetworkBucketDuration(); @@ -207,20 +206,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public void systemReady() { - if (mSettings.getEnabled()) { - try { - // enable low-level bandwidth stats and control - // TODO: consider shipping with this enabled by default - mNetworkManager.setBandwidthControlEnabled(true); - } catch (RemoteException e) { - Slog.e(TAG, "problem talking to netd while enabling bandwidth controls", e); - } catch (NativeDaemonConnectorException ndce) { - Slog.e(TAG, "problem enabling bandwidth controls", ndce); - } - } else { - Slog.w(TAG, "detailed network stats disabled"); - } - synchronized (mStatsLock) { // read historical network stats from disk, since policy service // might need them right away. we delay loading detailed UID stats @@ -389,6 +374,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + @Override + public void forceUpdate() { + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + + synchronized (mStatsLock) { + performPollLocked(true, false); + } + } + /** * Receiver that watches for {@link IConnectivityManager} to claim network * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()} @@ -905,6 +899,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { argSet.add(arg); } + final boolean fullHistory = argSet.contains("full"); + synchronized (mStatsLock) { // TODO: remove this testing code, since it corrupts stats if (argSet.contains("generate")) { @@ -930,7 +926,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (NetworkIdentitySet ident : mNetworkStats.keySet()) { final NetworkStatsHistory history = mNetworkStats.get(ident); pw.print(" ident="); pw.println(ident.toString()); - history.dump(" ", pw); + history.dump(" ", pw, fullHistory); } if (argSet.contains("detail")) { @@ -950,7 +946,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsHistory history = uidStats.valueAt(i); pw.print(" UID="); pw.print(uid); pw.print(" tag="); pw.println(tag); - history.dump(" ", pw); + history.dump(" ", pw, fullHistory); } } } @@ -1058,15 +1054,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return Settings.Secure.getLong(mResolver, name, def); } - public boolean getEnabled() { - if (!new File("/proc/net/xt_qtaguid/ctrl").exists()) { - Slog.w(TAG, "kernel does not support bandwidth control"); - return false; - } - // TODO: once things stabilize, enable by default. - // For now: ./vendor/google/tools/override-gservices secure:netstats_enabled=1 - return Settings.Secure.getInt(mResolver, NETSTATS_ENABLED, 0) != 0; - } public long getPollInterval() { return getSecureLong(NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS); } diff --git a/services/jni/com_android_server_connectivity_Vpn.cpp b/services/jni/com_android_server_connectivity_Vpn.cpp index a0ea92b91a03..62d7636321c0 100644 --- a/services/jni/com_android_server_connectivity_Vpn.cpp +++ b/services/jni/com_android_server_connectivity_Vpn.cpp @@ -244,7 +244,7 @@ static int set_routes(const char *name, const char *routes) break; } - in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 1; + in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0x80000000; *as_in_addr(&rt4.rt_genmask) = htonl(mask); if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) { count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; @@ -394,7 +394,7 @@ static jint setRoutes(JNIEnv *env, jobject thiz, jstring jName, } count = set_routes(name, routes); if (count < 0) { - throwException(env, count, "Cannot set address"); + throwException(env, count, "Cannot set route"); count = -1; } diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index 903f2b0b6f66..f2c28bb538c8 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -610,9 +610,6 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mAlarmManager.setInexactRepeating( eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), isA(PendingIntent.class)); expectLastCall().atLeastOnce(); - - mNetManager.setBandwidthControlEnabled(true); - expectLastCall().atLeastOnce(); } private void expectNetworkState(NetworkState... state) throws Exception { @@ -633,7 +630,6 @@ public class NetworkStatsServiceTest extends AndroidTestCase { private void expectSettings(long persistThreshold, long bucketDuration, long maxHistory) throws Exception { - expect(mSettings.getEnabled()).andReturn(true).anyTimes(); expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes(); expect(mSettings.getPersistThreshold()).andReturn(persistThreshold).anyTimes(); expect(mSettings.getNetworkBucketDuration()).andReturn(bucketDuration).anyTimes(); diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index fce7cdc82440..2f010e57b161 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -473,8 +473,8 @@ public class ServiceState implements Parcelable { + " EmergOnly=" + mIsEmergencyOnly); } - public void setStateOutOfService() { - mState = STATE_OUT_OF_SERVICE; + private void setNullState(int state) { + mState = state; mRoaming = false; mOperatorAlphaLong = null; mOperatorAlphaShort = null; @@ -491,23 +491,12 @@ public class ServiceState implements Parcelable { mIsEmergencyOnly = false; } - // TODO - can't this be combined with the above method? + public void setStateOutOfService() { + setNullState(STATE_OUT_OF_SERVICE); + } + public void setStateOff() { - mState = STATE_POWER_OFF; - mRoaming = false; - mOperatorAlphaLong = null; - mOperatorAlphaShort = null; - mOperatorNumeric = null; - mIsManualNetworkSelection = false; - mRadioTechnology = 0; - mCssIndicator = false; - mNetworkId = -1; - mSystemId = -1; - mCdmaRoamingIndicator = -1; - mCdmaDefaultRoamingIndicator = -1; - mCdmaEriIconIndex = -1; - mCdmaEriIconMode = -1; - mIsEmergencyOnly = false; + setNullState(STATE_POWER_OFF); } public void setState(int state) { diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java index 910905aa4543..aa7568b108f8 100644 --- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -21,6 +21,7 @@ import android.net.LinkProperties; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; +import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.util.Log; @@ -55,8 +56,13 @@ public class DefaultPhoneNotifier implements PhoneNotifier { } public void notifyServiceState(Phone sender) { + ServiceState ss = sender.getServiceState(); + if (ss == null) { + ss = new ServiceState(); + ss.setStateOutOfService(); + } try { - mRegistry.notifyServiceState(sender.getServiceState()); + mRegistry.notifyServiceState(ss); } catch (RemoteException ex) { // system process is dead } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index 5fc0bf9b51e2..a6b131a91106 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -556,6 +556,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (DBG) log("onDataConnectionAttached: start polling notify attached"); startNetStatPoll(); notifyDataConnection(Phone.REASON_DATA_ATTACHED); + } else { + // update APN availability so that APN can be enabled. + notifyDataAvailability(Phone.REASON_DATA_ATTACHED); } setupDataOnReadyApns(Phone.REASON_DATA_ATTACHED); @@ -785,13 +788,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext); apnContext.getDataConnection().tearDown(apnContext.getReason(), msg); apnContext.setState(State.DISCONNECTING); - } else { - // apn is connected but no reference to dcac. - // Should not be happen, but reset the state in case. - apnContext.setState(State.IDLE); - mPhone.notifyDataConnection(apnContext.getReason(), - apnContext.getApnType()); } + } else { + // apn is connected but no reference to dcac. + // Should not be happen, but reset the state in case. + apnContext.setState(State.IDLE); + mPhone.notifyDataConnection(apnContext.getReason(), + apnContext.getApnType()); } } } else { @@ -1528,13 +1531,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { createAllApnList(); if (mRadioAvailable) { if (DBG) log("onRecordsLoaded: notifying data availability"); - notifyDataAvailability(null); + notifyDataAvailability(Phone.REASON_SIM_LOADED); } setupDataOnReadyApns(Phone.REASON_SIM_LOADED); } @Override protected void onSetDependencyMet(String apnType, boolean met) { + // don't allow users to tweak hipri to work around default dependency not met + if (Phone.APN_TYPE_HIPRI.equals(apnType)) return; + ApnContext apnContext = mApnContexts.get(apnType); if (apnContext == null) { loge("onSetDependencyMet: ApnContext not found in onSetDependencyMet(" + @@ -1542,6 +1548,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return; } applyNewState(apnContext, apnContext.isEnabled(), met); + if (Phone.APN_TYPE_DEFAULT.equals(apnType)) { + // tie actions on default to similar actions on HIPRI regarding dependencyMet + apnContext = mApnContexts.get(Phone.APN_TYPE_HIPRI); + if (apnContext != null) applyNewState(apnContext, apnContext.isEnabled(), met); + } } private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) { @@ -1627,11 +1638,17 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { @Override protected void onRoamingOff() { if (DBG) log("onRoamingOff"); + // Notify data availability so APN can be enabled. + notifyDataAvailability(Phone.REASON_ROAMING_OFF); + setupDataOnReadyApns(Phone.REASON_ROAMING_OFF); } @Override protected void onRoamingOn() { + // Notify data availability so APN can be enabled. + notifyDataAvailability(Phone.REASON_ROAMING_ON); + if (getDataOnRoamingEnabled()) { if (DBG) log("onRoamingOn: setup data on roaming"); setupDataOnReadyApns(Phone.REASON_ROAMING_ON); diff --git a/voip/java/com/android/server/sip/SipWakeupTimer.java b/voip/java/com/android/server/sip/SipWakeupTimer.java index 76780c02b3df..00d47ac63ce6 100644 --- a/voip/java/com/android/server/sip/SipWakeupTimer.java +++ b/voip/java/com/android/server/sip/SipWakeupTimer.java @@ -83,7 +83,7 @@ class SipWakeupTimer extends BroadcastReceiver { mEventQueue = null; } - private synchronized boolean stopped() { + private boolean stopped() { if (mEventQueue == null) { Log.w(TAG, "Timer stopped"); return true; @@ -233,7 +233,7 @@ class SipWakeupTimer extends BroadcastReceiver { } @Override - public void onReceive(Context context, Intent intent) { + public synchronized void onReceive(Context context, Intent intent) { // This callback is already protected by AlarmManager's wake lock. String action = intent.getAction(); if (getAction().equals(action) @@ -261,7 +261,7 @@ class SipWakeupTimer extends BroadcastReceiver { } } - private synchronized void execute(long triggerTime) { + private void execute(long triggerTime) { if (DEBUG_TIMER) Log.d(TAG, "time's up, triggerTime = " + showTime(triggerTime) + ": " + mEventQueue.size()); if (stopped() || mEventQueue.isEmpty()) return; |