summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/animation/Animator.java7
-rw-r--r--core/java/android/animation/AnimatorSet.java4
-rwxr-xr-xcore/java/android/animation/ValueAnimator.java20
-rw-r--r--core/java/android/hardware/Camera.java2
-rw-r--r--core/java/android/net/DnsPinger.java319
-rw-r--r--core/java/android/net/INetworkStatsService.aidl4
-rw-r--r--core/java/android/net/NetworkPolicyManager.java3
-rw-r--r--core/java/android/net/NetworkStats.java23
-rw-r--r--core/java/android/net/NetworkStatsHistory.java296
-rw-r--r--core/java/android/net/VpnBuilder.java413
-rw-r--r--core/java/android/os/INetworkManagementService.aidl5
-rw-r--r--core/java/android/provider/VoicemailContract.java2
-rw-r--r--core/java/android/text/TextDirectionHeuristics.java1
-rw-r--r--core/java/android/widget/AbsListView.java21
-rw-r--r--core/java/android/widget/AdapterView.java1
-rw-r--r--core/java/android/widget/FastScroller.java9
-rw-r--r--core/java/android/widget/TextView.java11
-rw-r--r--core/java/com/android/internal/net/VpnConfig.java8
-rw-r--r--core/java/com/android/internal/util/Protocol.java1
-rw-r--r--core/java/com/android/internal/util/StateMachine.java6
-rw-r--r--core/java/com/android/internal/widget/ActionBarView.java2
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/android/graphics/TextLayoutCache.cpp8
-rw-r--r--core/res/AndroidManifest.xml20
-rwxr-xr-xcore/res/res/values/strings.xml16
-rw-r--r--core/tests/coretests/src/android/animation/EventsTest.java324
-rw-r--r--core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java176
-rw-r--r--docs/html/guide/developing/tools/draw9patch.jd2
-rw-r--r--drm/libdrmframework/plugins/common/util/include/SessionMap.h238
-rw-r--r--drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp62
-rw-r--r--drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk3
-rw-r--r--drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp99
-rw-r--r--drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c26
-rw-r--r--drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c12
-rw-r--r--graphics/java/android/graphics/ImageFormat.java14
-rw-r--r--include/camera/CameraParameters.h3
-rw-r--r--include/media/stagefright/MediaBuffer.h4
-rw-r--r--libs/camera/CameraParameters.cpp1
-rw-r--r--media/java/android/media/AudioManager.java24
-rw-r--r--media/java/android/media/AudioService.java4
-rw-r--r--media/java/android/media/IAudioService.aidl2
-rw-r--r--media/libstagefright/MediaBuffer.cpp15
-rw-r--r--media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp6
-rw-r--r--media/libstagefright/chromium_http/support.cpp10
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp35
-rw-r--r--media/libstagefright/mpeg2ts/AnotherPacketSource.cpp6
-rw-r--r--media/libstagefright/rtsp/APacketSource.cpp4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java4
-rw-r--r--packages/VpnDialogs/AndroidManifest.xml1
-rw-r--r--packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java6
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java6
-rw-r--r--services/java/com/android/server/NetworkManagementService.java7
-rw-r--r--services/java/com/android/server/SystemServer.java2
-rw-r--r--services/java/com/android/server/connectivity/Vpn.java86
-rwxr-xr-xservices/java/com/android/server/location/GpsLocationProvider.java35
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java61
-rwxr-xr-xservices/jni/com_android_server_location_GpsLocationProvider.cpp12
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java71
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java10
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/BridgeResources.java16
-rw-r--r--wifi/java/android/net/wifi/WifiStateMachine.java2
-rw-r--r--wifi/java/android/net/wifi/WifiWatchdogStateMachine.java76
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pService.java13
66 files changed, 1581 insertions, 1115 deletions
diff --git a/api/current.txt b/api/current.txt
index 11804400dd35..bdc695ff8771 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -84,7 +84,6 @@ package android {
field public static final java.lang.String READ_SMS = "android.permission.READ_SMS";
field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
field public static final java.lang.String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
- field public static final java.lang.String READ_WRITE_OWN_VOICEMAIL = "com.android.voicemail.permission.READ_WRITE_OWN_VOICEMAIL";
field public static final java.lang.String REBOOT = "android.permission.REBOOT";
field public static final java.lang.String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED";
field public static final java.lang.String RECEIVE_MMS = "android.permission.RECEIVE_MMS";
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 5fe3644f1297..57e0583a8b2c 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -32,10 +32,9 @@ public abstract class Animator implements Cloneable {
/**
* Starts this animation. If the animation has a nonzero startDelay, the animation will start
- * running after that delay elapses. Note that the animation does not start synchronously with
- * this call, because all animation events are posted to a central timing loop so that animation
- * times are all synchronized on a single timing pulse on the UI thread. So the animation will
- * start the next time that event handler processes events.
+ * running after that delay elapses. A non-delayed animation will have its initial
+ * value(s) set immediately, followed by calls to
+ * {@link AnimatorListener#onAnimationStart(Animator)} for any listeners of this animator.
*
* <p>The animation started by calling this method will be run on the thread that called
* this method. This thread should have a Looper on it (a runtime exception will be thrown if
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 61a12eec6baa..ce3dd13e4dfb 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -349,7 +349,8 @@ public final class AnimatorSet extends Animator {
return true;
}
}
- return false;
+ // Also return true if we're currently running the startDelay animator
+ return (mDelayAnim != null && mDelayAnim.isRunning());
}
/**
@@ -487,7 +488,6 @@ public final class AnimatorSet extends Animator {
mPlayingSet.add(node.animation);
}
} else {
- // TODO: Need to cancel out of the delay appropriately
mDelayAnim = ValueAnimator.ofFloat(0f, 1f);
mDelayAnim.setDuration(mStartDelay);
mDelayAnim.addListener(new AnimatorListenerAdapter() {
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 90d676ea2904..c22306abcdc7 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -186,6 +186,16 @@ public class ValueAnimator extends Animator {
int mPlayingState = STOPPED;
/**
+ * Additional playing state to indicate whether an animator has been start()'d. There is
+ * some lag between a call to start() and the first animation frame. We should still note
+ * that the animation has been started, even if it's first animation frame has not yet
+ * happened, and reflect that state in isRunning().
+ * Note that delayed animations are different: they are not started until their first
+ * animation frame, which occurs after their delay elapses.
+ */
+ private boolean mStarted = false;
+
+ /**
* Flag that denotes whether the animation is set up and ready to go. Used to
* set up animation that has not yet been started.
*/
@@ -618,6 +628,7 @@ public class ValueAnimator extends Animator {
for (int i = 0; i < numReadyAnims; ++i) {
ValueAnimator anim = readyAnims.get(i);
anim.startAnimation();
+ anim.mStarted = true;
delayedAnims.remove(anim);
}
readyAnims.clear();
@@ -908,6 +919,7 @@ public class ValueAnimator extends Animator {
// This sets the initial value of the animation, prior to actually starting it running
setCurrentPlayTime(getCurrentPlayTime());
mPlayingState = STOPPED;
+ mStarted = true;
if (mListeners != null) {
ArrayList<AnimatorListener> tmpListeners =
@@ -937,7 +949,8 @@ public class ValueAnimator extends Animator {
// to run
if (mPlayingState != STOPPED || sPendingAnimations.get().contains(this) ||
sDelayedAnims.get().contains(this)) {
- if (mListeners != null) {
+ // Only notify listeners if the animator has actually started
+ if (mStarted && mListeners != null) {
ArrayList<AnimatorListener> tmpListeners =
(ArrayList<AnimatorListener>) mListeners.clone();
for (AnimatorListener listener : tmpListeners) {
@@ -969,7 +982,7 @@ public class ValueAnimator extends Animator {
@Override
public boolean isRunning() {
- return (mPlayingState == RUNNING);
+ return (mPlayingState == RUNNING || mStarted);
}
/**
@@ -1000,7 +1013,7 @@ public class ValueAnimator extends Animator {
sPendingAnimations.get().remove(this);
sDelayedAnims.get().remove(this);
mPlayingState = STOPPED;
- if (mListeners != null) {
+ if (mStarted && mListeners != null) {
ArrayList<AnimatorListener> tmpListeners =
(ArrayList<AnimatorListener>) mListeners.clone();
int numListeners = tmpListeners.size();
@@ -1008,6 +1021,7 @@ public class ValueAnimator extends Animator {
tmpListeners.get(i).onAnimationEnd(this);
}
}
+ mStarted = false;
}
/**
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 6767747705db..58c79fccd557 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1708,6 +1708,7 @@ public class Camera {
private static final String PIXEL_FORMAT_YUV420P = "yuv420p";
private static final String PIXEL_FORMAT_RGB565 = "rgb565";
private static final String PIXEL_FORMAT_JPEG = "jpeg";
+ private static final String PIXEL_FORMAT_BAYER_RGGB = "bayer-rggb";
private HashMap<String, String> mMap;
@@ -2258,6 +2259,7 @@ public class Camera {
case ImageFormat.YV12: return PIXEL_FORMAT_YUV420P;
case ImageFormat.RGB_565: return PIXEL_FORMAT_RGB565;
case ImageFormat.JPEG: return PIXEL_FORMAT_JPEG;
+ case ImageFormat.BAYER_RGGB: return PIXEL_FORMAT_BAYER_RGGB;
default: return null;
}
}
diff --git a/core/java/android/net/DnsPinger.java b/core/java/android/net/DnsPinger.java
index f2d84ebc9889..81738f3827e9 100644
--- a/core/java/android/net/DnsPinger.java
+++ b/core/java/android/net/DnsPinger.java
@@ -17,20 +17,27 @@
package android.net;
import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.LinkProperties;
-import android.net.NetworkUtils;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Slog;
+import com.android.internal.util.Protocol;
+
+import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketTimeoutException;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Performs a simple DNS "ping" by sending a "server status" query packet to the
@@ -40,42 +47,174 @@ import java.util.Random;
* API may not differentiate between a time out and a failure lookup (which we
* really care about).
* <p>
- * TODO : More general API. Socket does not bind to specified connection type
- * TODO : Choice of DNS query location - current looks up www.android.com
*
* @hide
*/
-public final class DnsPinger {
+public final class DnsPinger extends Handler {
private static final boolean V = true;
- /** Number of bytes for the query */
- private static final int DNS_QUERY_BASE_SIZE = 32;
-
- /** The DNS port */
+ private static final int RECEIVE_POLL_INTERVAL_MS = 30;
private static final int DNS_PORT = 53;
+ /** Short socket timeout so we don't block one any 'receive' call */
+ private static final int SOCKET_TIMEOUT_MS = 1;
+
/** Used to generate IDs */
- private static Random sRandom = new Random();
+ private static final Random sRandom = new Random();
+ private static final AtomicInteger sCounter = new AtomicInteger();
private ConnectivityManager mConnectivityManager = null;
- private Context mContext;
- private int mConnectionType;
- private InetAddress mDefaultDns;
-
+ private final Context mContext;
+ private final int mConnectionType;
+ private final Handler mTarget;
+ private final InetAddress mDefaultDns;
private String TAG;
+ private static final int BASE = Protocol.BASE_DNS_PINGER;
+
/**
- * @param connectionType The connection type from {@link ConnectivityManager}
+ * Async response packet for dns pings.
+ * arg1 is the ID of the ping, also returned by {@link #pingDnsAsync(InetAddress, int, int)}
+ * arg2 is the delay, or is negative on error.
*/
- public DnsPinger(String TAG, Context context, int connectionType) {
+ public static final int DNS_PING_RESULT = BASE;
+ /** An error code for a {@link #DNS_PING_RESULT} packet */
+ public static final int TIMEOUT = -1;
+ /** An error code for a {@link #DNS_PING_RESULT} packet */
+ public static final int SOCKET_EXCEPTION = -2;
+
+ /**
+ * Send a new ping via a socket. arg1 is ID, arg2 is timeout, obj is InetAddress to ping
+ */
+ private static final int ACTION_PING_DNS = BASE + 1;
+ private static final int ACTION_LISTEN_FOR_RESPONSE = BASE + 2;
+ private static final int ACTION_CANCEL_ALL_PINGS = BASE + 3;
+
+ private List<ActivePing> mActivePings = new ArrayList<ActivePing>();
+ private int mEventCounter;
+
+ private class ActivePing {
+ DatagramSocket socket;
+ int internalId;
+ short packetId;
+ int timeout;
+ Integer result;
+ long start = SystemClock.elapsedRealtime();
+ }
+
+ public DnsPinger(Context context, String TAG, Looper looper,
+ Handler target, int connectionType) {
+ super(looper);
+ this.TAG = TAG;
mContext = context;
+ mTarget = target;
mConnectionType = connectionType;
if (!ConnectivityManager.isNetworkTypeValid(connectionType)) {
- Slog.e(TAG, "Invalid connectionType in constructor: " + connectionType);
+ throw new IllegalArgumentException("Invalid connectionType in constructor: "
+ + connectionType);
}
- this.TAG = TAG;
-
mDefaultDns = getDefaultDns();
+ mEventCounter = 0;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case ACTION_PING_DNS:
+ try {
+ ActivePing newActivePing = new ActivePing();
+ InetAddress dnsAddress = (InetAddress) msg.obj;
+ newActivePing.internalId = msg.arg1;
+ newActivePing.timeout = msg.arg2;
+ newActivePing.socket = new DatagramSocket();
+ // Set some socket properties
+ newActivePing.socket.setSoTimeout(SOCKET_TIMEOUT_MS);
+
+ // Try to bind but continue ping if bind fails
+ try {
+ newActivePing.socket.setNetworkInterface(NetworkInterface.getByName(
+ getCurrentLinkProperties().getInterfaceName()));
+ } catch (Exception e) {
+ Slog.w(TAG,"sendDnsPing::Error binding to socket", e);
+ }
+
+ newActivePing.packetId = (short) sRandom.nextInt();
+ byte[] buf = mDnsQuery.clone();
+ buf[0] = (byte) (newActivePing.packetId >> 8);
+ buf[1] = (byte) newActivePing.packetId;
+
+ // Send the DNS query
+ DatagramPacket packet = new DatagramPacket(buf,
+ buf.length, dnsAddress, DNS_PORT);
+ if (V) {
+ Slog.v(TAG, "Sending a ping to " + dnsAddress.getHostAddress()
+ + " with ID " + newActivePing.packetId + ".");
+ }
+
+ newActivePing.socket.send(packet);
+ mActivePings.add(newActivePing);
+ mEventCounter++;
+ sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
+ RECEIVE_POLL_INTERVAL_MS);
+ } catch (IOException e) {
+ sendResponse((short) msg.arg1, SOCKET_EXCEPTION);
+ }
+ break;
+ case ACTION_LISTEN_FOR_RESPONSE:
+ if (msg.arg1 != mEventCounter) {
+ break;
+ }
+ for (ActivePing curPing : mActivePings) {
+ try {
+ /** Each socket will block for {@link #SOCKET_TIMEOUT_MS} in receive() */
+ byte[] responseBuf = new byte[2];
+ DatagramPacket replyPacket = new DatagramPacket(responseBuf, 2);
+ curPing.socket.receive(replyPacket);
+ // Check that ID field matches (we're throwing out the rest of the packet)
+ if (responseBuf[0] == (byte) (curPing.packetId >> 8) &&
+ responseBuf[1] == (byte) curPing.packetId) {
+ curPing.result =
+ (int) (SystemClock.elapsedRealtime() - curPing.start);
+ } else {
+ if (V) {
+ Slog.v(TAG, "response ID didn't match, ignoring packet");
+ }
+ }
+ } catch (SocketTimeoutException e) {
+ // A timeout here doesn't mean anything - squelsh this exception
+ } catch (Exception e) {
+ if (V) {
+ Slog.v(TAG, "DnsPinger.pingDns got socket exception: ", e);
+ }
+ curPing.result = SOCKET_EXCEPTION;
+ }
+ }
+ Iterator<ActivePing> iter = mActivePings.iterator();
+ while (iter.hasNext()) {
+ ActivePing curPing = iter.next();
+ if (curPing.result != null) {
+ sendResponse(curPing.internalId, curPing.result);
+ curPing.socket.close();
+ iter.remove();
+ } else if (SystemClock.elapsedRealtime() >
+ curPing.start + curPing.timeout) {
+ sendResponse(curPing.internalId, TIMEOUT);
+ curPing.socket.close();
+ iter.remove();
+ }
+ }
+ if (!mActivePings.isEmpty()) {
+ sendMessageDelayed(obtainMessage(ACTION_LISTEN_FOR_RESPONSE, mEventCounter, 0),
+ RECEIVE_POLL_INTERVAL_MS);
+ }
+ break;
+ case ACTION_CANCEL_ALL_PINGS:
+ for (ActivePing activePing : mActivePings)
+ activePing.socket.close();
+ mActivePings.clear();
+ removeMessages(ACTION_PING_DNS);
+ break;
+ }
}
/**
@@ -99,6 +238,30 @@ public final class DnsPinger {
return dnses.iterator().next();
}
+ /**
+ * Send a ping. The response will come via a {@link #DNS_PING_RESULT} to the handler
+ * specified at creation.
+ * @param dns address of dns server to ping
+ * @param timeout timeout for ping
+ * @return an ID field, which will also be included in the {@link #DNS_PING_RESULT} message.
+ */
+ public int pingDnsAsync(InetAddress dns, int timeout, int delay) {
+ int id = sCounter.incrementAndGet();
+ sendMessageDelayed(obtainMessage(ACTION_PING_DNS, id, timeout, dns), delay);
+ return id;
+ }
+
+ public void cancelPings() {
+ obtainMessage(ACTION_CANCEL_ALL_PINGS).sendToTarget();
+ }
+
+ private void sendResponse(int internalId, int responseVal) {
+ if(V) {
+ Slog.v(TAG, "Responding with id " + internalId + " and val " + responseVal);
+ }
+ mTarget.sendMessage(obtainMessage(DNS_PING_RESULT, internalId, responseVal));
+ }
+
private LinkProperties getCurrentLinkProperties() {
if (mConnectivityManager == null) {
mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
@@ -123,106 +286,18 @@ public final class DnsPinger {
}
}
- /**
- * @return time to response. Negative value on error.
- */
- public long pingDns(InetAddress dnsAddress, int timeout) {
- DatagramSocket socket = null;
- try {
- socket = new DatagramSocket();
-
- // Set some socket properties
- socket.setSoTimeout(timeout);
-
- // Try to bind but continue ping if bind fails
- try {
- socket.setNetworkInterface(NetworkInterface.getByName(
- getCurrentLinkProperties().getInterfaceName()));
- } catch (Exception e) {
- Slog.d(TAG,"pingDns::Error binding to socket", e);
- }
-
- byte[] buf = constructQuery();
-
- // Send the DNS query
-
- DatagramPacket packet = new DatagramPacket(buf,
- buf.length, dnsAddress, DNS_PORT);
- long start = SystemClock.elapsedRealtime();
- socket.send(packet);
-
- // Wait for reply (blocks for the above timeout)
- DatagramPacket replyPacket = new DatagramPacket(buf, buf.length);
- socket.receive(replyPacket);
-
- // If a timeout occurred, an exception would have been thrown. We
- // got a reply!
- return SystemClock.elapsedRealtime() - start;
-
- } catch (SocketTimeoutException e) {
- // Squelch this exception.
- return -1;
- } catch (Exception e) {
- if (V) {
- Slog.v(TAG, "DnsPinger.pingDns got socket exception: ", e);
- }
- return -2;
- } finally {
- if (socket != null) {
- socket.close();
- }
- }
-
- }
-
- /**
- * @return google.com DNS query packet
- */
- private static byte[] constructQuery() {
- byte[] buf = new byte[DNS_QUERY_BASE_SIZE];
-
- // [0-1] bytes are an ID, generate random ID for this query
- buf[0] = (byte) sRandom.nextInt(256);
- buf[1] = (byte) sRandom.nextInt(256);
-
- // [2-3] bytes are for flags.
- buf[2] = 0x01; // Recursion desired
-
- // [4-5] bytes are for number of queries (QCOUNT)
- buf[5] = 0x01;
-
- // [6-7] [8-9] [10-11] are all counts of other fields we don't use
-
- // [12-15] for www
- writeString(buf, 12, "www");
-
- // [16-22] for google
- writeString(buf, 16, "google");
-
- // [23-26] for com
- writeString(buf, 23, "com");
-
- // [27] is a null byte terminator byte for the url
-
- // [28-29] bytes are for QTYPE, set to 1 = A (host address)
- buf[29] = 0x01;
-
- // [30-31] bytes are for QCLASS, set to 1 = IN (internet)
- buf[31] = 0x01;
-
- return buf;
- }
-
- /**
- * Writes the string's length and its contents to the buffer
- */
- private static void writeString(byte[] buf, int startPos, String string) {
- int pos = startPos;
-
- // Write the length first
- buf[pos++] = (byte) string.length();
- for (int i = 0; i < string.length(); i++) {
- buf[pos++] = (byte) string.charAt(i);
- }
- }
+ private static final byte[] mDnsQuery = new byte[] {
+ 0, 0, // [0-1] is for ID (will set each time)
+ 0, 0, // [2-3] are flags. Set byte[2] = 1 for recursion desired (RD) on. Currently off.
+ 0, 1, // [4-5] bytes are for number of queries (QCOUNT)
+ 0, 0, // [6-7] unused count field for dns response packets
+ 0, 0, // [8-9] unused count field for dns response packets
+ 0, 0, // [10-11] unused count field for dns response packets
+ 3, 'w', 'w', 'w',
+ 6, 'g', 'o', 'o', 'g', 'l', 'e',
+ 3, 'c', 'o', 'm',
+ 0, // null terminator of address (also called empty TLD)
+ 0, 1, // QTYPE, set to 1 = A (host address)
+ 0, 1 // QCLASS, set to 1 = IN (internet)
+ };
}
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index c41d182cfa11..b65506c411e8 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -24,9 +24,9 @@ import android.net.NetworkTemplate;
interface INetworkStatsService {
/** Return historical network layer stats for traffic that matches template. */
- NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template);
+ NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields);
/** Return historical network layer stats for specific UID traffic that matches template. */
- NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int tag);
+ NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int tag, int fields);
/** Return network layer usage summary for traffic that matches template. */
NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 1e9d81319297..9d253c73614c 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -189,9 +189,10 @@ public class NetworkPolicyManager {
*/
public static void snapToCycleDay(Time time, int cycleDay) {
if (cycleDay > time.getActualMaximum(MONTH_DAY)) {
- // cycle day isn't valid this month; snap to 1st of next month
+ // cycle day isn't valid this month; snap to last second of month
time.month += 1;
time.monthDay = 1;
+ time.second = -1;
} else {
time.monthDay = cycleDay;
}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 0e8e7fc5ecfe..f2fcb8fad852 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -58,7 +58,7 @@ public class NetworkStats implements Parcelable {
private long[] rxPackets;
private long[] txBytes;
private long[] txPackets;
- private int[] operations;
+ private long[] operations;
public static class Entry {
public String iface;
@@ -68,13 +68,18 @@ public class NetworkStats implements Parcelable {
public long rxPackets;
public long txBytes;
public long txPackets;
- public int operations;
+ public long operations;
public Entry() {
+ this(IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
+ }
+
+ public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
+ this(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, operations);
}
public Entry(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes,
- long txPackets, int operations) {
+ long txPackets, long operations) {
this.iface = iface;
this.uid = uid;
this.tag = tag;
@@ -96,7 +101,7 @@ public class NetworkStats implements Parcelable {
this.rxPackets = new long[initialSize];
this.txBytes = new long[initialSize];
this.txPackets = new long[initialSize];
- this.operations = new int[initialSize];
+ this.operations = new long[initialSize];
}
public NetworkStats(Parcel parcel) {
@@ -109,7 +114,7 @@ public class NetworkStats implements Parcelable {
rxPackets = parcel.createLongArray();
txBytes = parcel.createLongArray();
txPackets = parcel.createLongArray();
- operations = parcel.createIntArray();
+ operations = parcel.createLongArray();
}
/** {@inheritDoc} */
@@ -123,16 +128,16 @@ public class NetworkStats implements Parcelable {
dest.writeLongArray(rxPackets);
dest.writeLongArray(txBytes);
dest.writeLongArray(txPackets);
- dest.writeIntArray(operations);
+ dest.writeLongArray(operations);
}
public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
long txBytes, long txPackets) {
- return addValues(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, 0);
+ return addValues(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, 0L);
}
public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
- long txBytes, long txPackets, int operations) {
+ long txBytes, long txPackets, long operations) {
return addValues(
new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
}
@@ -197,7 +202,7 @@ public class NetworkStats implements Parcelable {
}
public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
- long txBytes, long txPackets, int operations) {
+ long txBytes, long txPackets, long operations) {
return combineValues(
new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
}
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 7a4b811763aa..c917af919e28 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -19,11 +19,11 @@ package android.net;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkStatsHistory.DataStreamUtils.readLongArray;
-import static android.net.NetworkStatsHistory.DataStreamUtils.writeLongArray;
-import static android.net.NetworkStatsHistory.ParcelUtils.readIntArray;
+import static android.net.NetworkStatsHistory.DataStreamUtils.readFullLongArray;
+import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLongArray;
+import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray;
+import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
-import static android.net.NetworkStatsHistory.ParcelUtils.writeIntArray;
import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
import android.os.Parcel;
@@ -51,42 +51,53 @@ import java.util.Random;
*/
public class NetworkStatsHistory implements Parcelable {
private static final int VERSION_INIT = 1;
+ private static final int VERSION_ADD_PACKETS = 2;
- // TODO: teach about varint encoding to use less disk space
- // TODO: teach about omitting entire fields to reduce parcel pressure
- // TODO: persist/restore packet and operation counts
+ public static final int FIELD_RX_BYTES = 0x01;
+ public static final int FIELD_RX_PACKETS = 0x02;
+ public static final int FIELD_TX_BYTES = 0x04;
+ public static final int FIELD_TX_PACKETS = 0x08;
+ public static final int FIELD_OPERATIONS = 0x10;
- private final long bucketDuration;
+ public static final int FIELD_ALL = 0xFFFFFFFF;
+
+ private long bucketDuration;
private int bucketCount;
private long[] bucketStart;
private long[] rxBytes;
private long[] rxPackets;
private long[] txBytes;
private long[] txPackets;
- private int[] operations;
+ private long[] operations;
public static class Entry {
+ public static final long UNKNOWN = -1;
+
public long bucketStart;
public long bucketDuration;
public long rxBytes;
public long rxPackets;
public long txBytes;
public long txPackets;
- public int operations;
+ public long operations;
}
public NetworkStatsHistory(long bucketDuration) {
- this(bucketDuration, 10);
+ this(bucketDuration, 10, FIELD_ALL);
}
public NetworkStatsHistory(long bucketDuration, int initialSize) {
+ this(bucketDuration, initialSize, FIELD_ALL);
+ }
+
+ public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) {
this.bucketDuration = bucketDuration;
bucketStart = new long[initialSize];
- rxBytes = new long[initialSize];
- rxPackets = new long[initialSize];
- txBytes = new long[initialSize];
- txPackets = new long[initialSize];
- operations = new int[initialSize];
+ if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize];
+ if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize];
+ if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize];
+ if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize];
+ if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize];
bucketCount = 0;
}
@@ -97,7 +108,7 @@ public class NetworkStatsHistory implements Parcelable {
rxPackets = readLongArray(in);
txBytes = readLongArray(in);
txPackets = readLongArray(in);
- operations = readIntArray(in);
+ operations = readLongArray(in);
bucketCount = bucketStart.length;
}
@@ -109,21 +120,31 @@ public class NetworkStatsHistory implements Parcelable {
writeLongArray(out, rxPackets, bucketCount);
writeLongArray(out, txBytes, bucketCount);
writeLongArray(out, txPackets, bucketCount);
- writeIntArray(out, operations, bucketCount);
+ writeLongArray(out, operations, bucketCount);
}
public NetworkStatsHistory(DataInputStream in) throws IOException {
- // TODO: read packet and operation counts
final int version = in.readInt();
switch (version) {
case VERSION_INIT: {
bucketDuration = in.readLong();
- bucketStart = readLongArray(in);
- rxBytes = readLongArray(in);
+ bucketStart = readFullLongArray(in);
+ rxBytes = readFullLongArray(in);
rxPackets = new long[bucketStart.length];
- txBytes = readLongArray(in);
+ txBytes = readFullLongArray(in);
txPackets = new long[bucketStart.length];
- operations = new int[bucketStart.length];
+ operations = new long[bucketStart.length];
+ bucketCount = bucketStart.length;
+ break;
+ }
+ case VERSION_ADD_PACKETS: {
+ bucketDuration = in.readLong();
+ bucketStart = readVarLongArray(in);
+ rxBytes = readVarLongArray(in);
+ rxPackets = readVarLongArray(in);
+ txBytes = readVarLongArray(in);
+ txPackets = readVarLongArray(in);
+ operations = readVarLongArray(in);
bucketCount = bucketStart.length;
break;
}
@@ -134,12 +155,14 @@ public class NetworkStatsHistory implements Parcelable {
}
public void writeToStream(DataOutputStream out) throws IOException {
- // TODO: write packet and operation counts
- out.writeInt(VERSION_INIT);
+ out.writeInt(VERSION_ADD_PACKETS);
out.writeLong(bucketDuration);
- writeLongArray(out, bucketStart, bucketCount);
- writeLongArray(out, rxBytes, bucketCount);
- writeLongArray(out, txBytes, bucketCount);
+ writeVarLongArray(out, bucketStart, bucketCount);
+ writeVarLongArray(out, rxBytes, bucketCount);
+ writeVarLongArray(out, rxPackets, bucketCount);
+ writeVarLongArray(out, txBytes, bucketCount);
+ writeVarLongArray(out, txPackets, bucketCount);
+ writeVarLongArray(out, operations, bucketCount);
}
/** {@inheritDoc} */
@@ -178,11 +201,11 @@ public class NetworkStatsHistory implements Parcelable {
final Entry entry = recycle != null ? recycle : new Entry();
entry.bucketStart = bucketStart[i];
entry.bucketDuration = bucketDuration;
- entry.rxBytes = rxBytes[i];
- entry.rxPackets = rxPackets[i];
- entry.txBytes = txBytes[i];
- entry.txPackets = txPackets[i];
- entry.operations = operations[i];
+ entry.rxBytes = getLong(rxBytes, i, UNKNOWN);
+ entry.rxPackets = getLong(rxPackets, i, UNKNOWN);
+ entry.txBytes = getLong(txBytes, i, UNKNOWN);
+ entry.txPackets = getLong(txPackets, i, UNKNOWN);
+ entry.operations = getLong(operations, i, UNKNOWN);
return entry;
}
@@ -193,7 +216,7 @@ public class NetworkStatsHistory implements Parcelable {
@Deprecated
public void recordData(long start, long end, long rxBytes, long txBytes) {
recordData(start, end,
- new NetworkStats.Entry(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0));
+ new NetworkStats.Entry(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L));
}
/**
@@ -230,11 +253,11 @@ public class NetworkStatsHistory implements Parcelable {
final long fracTxPackets = entry.txPackets * overlap / duration;
final int fracOperations = (int) (entry.operations * overlap / duration);
- rxBytes[i] += fracRxBytes; entry.rxBytes -= fracRxBytes;
- rxPackets[i] += fracRxPackets; entry.rxPackets -= fracRxPackets;
- txBytes[i] += fracTxBytes; entry.txBytes -= fracTxBytes;
- txPackets[i] += fracTxPackets; entry.txPackets -= fracTxPackets;
- operations[i] += fracOperations; entry.operations -= fracOperations;
+ addLong(rxBytes, i, fracRxBytes); entry.rxBytes -= fracRxBytes;
+ addLong(rxPackets, i, fracRxPackets); entry.rxPackets -= fracRxPackets;
+ addLong(txBytes, i, fracTxBytes); entry.txBytes -= fracTxBytes;
+ addLong(txPackets, i, fracTxPackets); entry.txPackets -= fracTxPackets;
+ addLong(operations, i, fracOperations); entry.operations -= fracOperations;
duration -= overlap;
}
@@ -246,16 +269,16 @@ public class NetworkStatsHistory implements Parcelable {
*/
public void recordEntireHistory(NetworkStatsHistory input) {
final NetworkStats.Entry entry = new NetworkStats.Entry(
- IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0);
+ IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
for (int i = 0; i < input.bucketCount; i++) {
final long start = input.bucketStart[i];
final long end = start + input.bucketDuration;
- entry.rxBytes = input.rxBytes[i];
- entry.rxPackets = input.rxPackets[i];
- entry.txBytes = input.txBytes[i];
- entry.txPackets = input.txPackets[i];
- entry.operations = input.operations[i];
+ entry.rxBytes = getLong(input.rxBytes, i, 0L);
+ entry.rxPackets = getLong(input.rxPackets, i, 0L);
+ entry.txBytes = getLong(input.txBytes, i, 0L);
+ entry.txPackets = getLong(input.txPackets, i, 0L);
+ entry.operations = getLong(input.operations, i, 0L);
recordData(start, end, entry);
}
@@ -287,11 +310,11 @@ public class NetworkStatsHistory implements Parcelable {
if (bucketCount >= bucketStart.length) {
final int newLength = Math.max(bucketStart.length, 10) * 3 / 2;
bucketStart = Arrays.copyOf(bucketStart, newLength);
- rxBytes = Arrays.copyOf(rxBytes, newLength);
- rxPackets = Arrays.copyOf(rxPackets, newLength);
- txBytes = Arrays.copyOf(txBytes, newLength);
- txPackets = Arrays.copyOf(txPackets, newLength);
- operations = Arrays.copyOf(operations, newLength);
+ if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength);
+ if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength);
+ if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength);
+ if (txPackets != null) txPackets = Arrays.copyOf(txPackets, newLength);
+ if (operations != null) operations = Arrays.copyOf(operations, newLength);
}
// create gap when inserting bucket in middle
@@ -300,19 +323,19 @@ public class NetworkStatsHistory implements Parcelable {
final int length = bucketCount - index;
System.arraycopy(bucketStart, index, bucketStart, dstPos, length);
- System.arraycopy(rxBytes, index, rxBytes, dstPos, length);
- System.arraycopy(rxPackets, index, rxPackets, dstPos, length);
- System.arraycopy(txBytes, index, txBytes, dstPos, length);
- System.arraycopy(txPackets, index, txPackets, dstPos, length);
- System.arraycopy(operations, index, operations, dstPos, length);
+ if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length);
+ if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length);
+ if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length);
+ if (txPackets != null) System.arraycopy(txPackets, index, txPackets, dstPos, length);
+ if (operations != null) System.arraycopy(operations, index, operations, dstPos, length);
}
bucketStart[index] = start;
- rxBytes[index] = 0;
- rxPackets[index] = 0;
- txBytes[index] = 0;
- txPackets[index] = 0;
- operations[index] = 0;
+ setLong(rxBytes, index, 0L);
+ setLong(rxPackets, index, 0L);
+ setLong(txBytes, index, 0L);
+ setLong(txPackets, index, 0L);
+ setLong(operations, index, 0L);
bucketCount++;
}
@@ -333,11 +356,11 @@ public class NetworkStatsHistory implements Parcelable {
if (i > 0) {
final int length = bucketStart.length;
bucketStart = Arrays.copyOfRange(bucketStart, i, length);
- rxBytes = Arrays.copyOfRange(rxBytes, i, length);
- rxPackets = Arrays.copyOfRange(rxPackets, i, length);
- txBytes = Arrays.copyOfRange(txBytes, i, length);
- txPackets = Arrays.copyOfRange(txPackets, i, length);
- operations = Arrays.copyOfRange(operations, i, length);
+ if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length);
+ if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length);
+ if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length);
+ if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length);
+ if (operations != null) operations = Arrays.copyOfRange(operations, i, length);
bucketCount -= i;
}
}
@@ -358,11 +381,11 @@ public class NetworkStatsHistory implements Parcelable {
final Entry entry = recycle != null ? recycle : new Entry();
entry.bucketStart = start;
entry.bucketDuration = end - start;
- entry.rxBytes = 0;
- entry.rxPackets = 0;
- entry.txBytes = 0;
- entry.txPackets = 0;
- entry.operations = 0;
+ entry.rxBytes = rxBytes != null ? 0 : UNKNOWN;
+ entry.rxPackets = rxPackets != null ? 0 : UNKNOWN;
+ entry.txBytes = txBytes != null ? 0 : UNKNOWN;
+ entry.txPackets = txPackets != null ? 0 : UNKNOWN;
+ entry.operations = operations != null ? 0 : UNKNOWN;
for (int i = bucketCount - 1; i >= 0; i--) {
final long curStart = bucketStart[i];
@@ -380,11 +403,11 @@ public class NetworkStatsHistory implements Parcelable {
if (overlap <= 0) continue;
// integer math each time is faster than floating point
- entry.rxBytes += rxBytes[i] * overlap / bucketDuration;
- entry.rxPackets += rxPackets[i] * overlap / bucketDuration;
- entry.txBytes += txBytes[i] * overlap / bucketDuration;
- entry.txPackets += txPackets[i] * overlap / bucketDuration;
- entry.operations += operations[i] * overlap / bucketDuration;
+ if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketDuration;
+ if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketDuration;
+ if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketDuration;
+ if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration;
+ if (operations != null) entry.operations += operations[i] * overlap / bucketDuration;
}
return entry;
@@ -394,19 +417,29 @@ public class NetworkStatsHistory implements Parcelable {
* @deprecated only for temporary testing
*/
@Deprecated
- public void generateRandom(long start, long end, long rx, long tx) {
+ public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes,
+ long txPackets, long operations) {
ensureBuckets(start, end);
final NetworkStats.Entry entry = new NetworkStats.Entry(
- IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0);
+ IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
final Random r = new Random();
- while (rx > 1024 && tx > 1024) {
+ while (rxBytes > 1024 && rxPackets > 128 && txBytes > 1024 && txPackets > 128
+ && operations > 32) {
final long curStart = randomLong(r, start, end);
final long curEnd = randomLong(r, curStart, end);
- entry.rxBytes = randomLong(r, 0, rx);
- entry.txBytes = randomLong(r, 0, tx);
- rx -= entry.rxBytes;
- tx -= entry.txBytes;
+
+ entry.rxBytes = randomLong(r, 0, rxBytes);
+ entry.rxPackets = randomLong(r, 0, rxPackets);
+ entry.txBytes = randomLong(r, 0, txBytes);
+ entry.txPackets = randomLong(r, 0, txPackets);
+ entry.operations = randomLong(r, 0, operations);
+
+ rxBytes -= entry.rxBytes;
+ rxPackets -= entry.rxPackets;
+ txBytes -= entry.txBytes;
+ txPackets -= entry.txPackets;
+ operations -= entry.operations;
recordData(curStart, curEnd, entry);
}
@@ -429,11 +462,12 @@ public class NetworkStatsHistory implements Parcelable {
for (int i = start; i < bucketCount; i++) {
pw.print(prefix);
pw.print(" bucketStart="); pw.print(bucketStart[i]);
- pw.print(" rxBytes="); pw.print(rxBytes[i]);
- pw.print(" rxPackets="); pw.print(rxPackets[i]);
- pw.print(" txBytes="); pw.print(txBytes[i]);
- pw.print(" txPackets="); pw.print(txPackets[i]);
- pw.print(" operations="); pw.println(operations[i]);
+ if (rxBytes != null) pw.print(" rxBytes="); pw.print(rxBytes[i]);
+ if (rxPackets != null) pw.print(" rxPackets="); pw.print(rxPackets[i]);
+ if (txBytes != null) pw.print(" txBytes="); pw.print(txBytes[i]);
+ if (txPackets != null) pw.print(" txPackets="); pw.print(txPackets[i]);
+ if (operations != null) pw.print(" operations="); pw.print(operations[i]);
+ pw.println();
}
}
@@ -454,12 +488,25 @@ public class NetworkStatsHistory implements Parcelable {
}
};
+ private static long getLong(long[] array, int i, long value) {
+ return array != null ? array[i] : value;
+ }
+
+ private static void setLong(long[] array, int i, long value) {
+ if (array != null) array[i] = value;
+ }
+
+ private static void addLong(long[] array, int i, long value) {
+ if (array != null) array[i] += value;
+ }
+
/**
* Utility methods for interacting with {@link DataInputStream} and
* {@link DataOutputStream}, mostly dealing with writing partial arrays.
*/
public static class DataStreamUtils {
- public static long[] readLongArray(DataInputStream in) throws IOException {
+ @Deprecated
+ public static long[] readFullLongArray(DataInputStream in) throws IOException {
final int size = in.readInt();
final long[] values = new long[size];
for (int i = 0; i < values.length; i++) {
@@ -468,14 +515,59 @@ public class NetworkStatsHistory implements Parcelable {
return values;
}
- public static void writeLongArray(DataOutputStream out, long[] values, int size)
+ /**
+ * Read variable-length {@link Long} using protobuf-style approach.
+ */
+ public static long readVarLong(DataInputStream in) throws IOException {
+ int shift = 0;
+ long result = 0;
+ while (shift < 64) {
+ byte b = in.readByte();
+ result |= (long) (b & 0x7F) << shift;
+ if ((b & 0x80) == 0)
+ return result;
+ shift += 7;
+ }
+ throw new ProtocolException("malformed long");
+ }
+
+ /**
+ * Write variable-length {@link Long} using protobuf-style approach.
+ */
+ public static void writeVarLong(DataOutputStream out, long value) throws IOException {
+ while (true) {
+ if ((value & ~0x7FL) == 0) {
+ out.writeByte((int) value);
+ return;
+ } else {
+ out.writeByte(((int) value & 0x7F) | 0x80);
+ value >>>= 7;
+ }
+ }
+ }
+
+ public static long[] readVarLongArray(DataInputStream in) throws IOException {
+ final int size = in.readInt();
+ if (size == -1) return null;
+ final long[] values = new long[size];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = readVarLong(in);
+ }
+ return values;
+ }
+
+ public static void writeVarLongArray(DataOutputStream out, long[] values, int size)
throws IOException {
+ if (values == null) {
+ out.writeInt(-1);
+ return;
+ }
if (size > values.length) {
throw new IllegalArgumentException("size larger than length");
}
out.writeInt(size);
for (int i = 0; i < size; i++) {
- out.writeLong(values[i]);
+ writeVarLong(out, values[i]);
}
}
}
@@ -487,6 +579,7 @@ public class NetworkStatsHistory implements Parcelable {
public static class ParcelUtils {
public static long[] readLongArray(Parcel in) {
final int size = in.readInt();
+ if (size == -1) return null;
final long[] values = new long[size];
for (int i = 0; i < values.length; i++) {
values[i] = in.readLong();
@@ -495,31 +588,16 @@ public class NetworkStatsHistory implements Parcelable {
}
public static void writeLongArray(Parcel out, long[] values, int size) {
- if (size > values.length) {
- throw new IllegalArgumentException("size larger than length");
- }
- out.writeInt(size);
- for (int i = 0; i < size; i++) {
- out.writeLong(values[i]);
- }
- }
-
- public static int[] readIntArray(Parcel in) {
- final int size = in.readInt();
- final int[] values = new int[size];
- for (int i = 0; i < values.length; i++) {
- values[i] = in.readInt();
+ if (values == null) {
+ out.writeInt(-1);
+ return;
}
- return values;
- }
-
- public static void writeIntArray(Parcel out, int[] values, int size) {
if (size > values.length) {
throw new IllegalArgumentException("size larger than length");
}
out.writeInt(size);
for (int i = 0; i < size; i++) {
- out.writeInt(values[i]);
+ out.writeLong(values[i]);
}
}
}
diff --git a/core/java/android/net/VpnBuilder.java b/core/java/android/net/VpnBuilder.java
deleted file mode 100644
index 458252345152..000000000000
--- a/core/java/android/net/VpnBuilder.java
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-
-import com.android.internal.net.VpnConfig;
-
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.DatagramSocket;
-import java.net.Socket;
-import java.util.ArrayList;
-
-/**
- * VpnBuilder is a framework which enables applications to build their
- * own VPN solutions. In general, it creates a virtual network interface,
- * configures addresses and routing rules, and returns a file descriptor
- * to the application. Each read from the descriptor retrieves an outgoing
- * packet which was routed to the interface. Each write to the descriptor
- * injects an incoming packet just like it was received from the interface.
- * The framework is running on Internet Protocol (IP), so packets are
- * always started with IP headers. The application then completes a VPN
- * connection by processing and exchanging packets with a remote server
- * over a secured tunnel.
- *
- * <p>Letting applications intercept packets raises huge security concerns.
- * Besides, a VPN application can easily break the network, and two of them
- * may conflict with each other. The framework takes several actions to
- * address these issues. Here are some key points:
- * <ul>
- * <li>User action is required to create a VPN connection.</li>
- * <li>There can be only one VPN connection running at the same time. The
- * existing interface is deactivated when a new one is created.</li>
- * <li>A system-managed notification is shown during the lifetime of a
- * VPN connection.</li>
- * <li>A system-managed dialog gives the information of the current VPN
- * connection. It also provides a button to disconnect.</li>
- * <li>The network is restored automatically when the file descriptor is
- * closed. It also covers the cases when a VPN application is crashed
- * or killed by the system.</li>
- * </ul>
- *
- * <p>There are two primary methods in this class: {@link #prepare} and
- * {@link #establish}. The former deals with the user action and stops
- * the existing VPN connection created by another application. The latter
- * creates a VPN interface using the parameters supplied to this builder.
- * An application must call {@link #prepare} to grant the right to create
- * an interface, and it can be revoked at any time by another application.
- * The application got revoked is notified by an {@link #ACTION_VPN_REVOKED}
- * broadcast. Here are the general steps to create a VPN connection:
- * <ol>
- * <li>When the user press the button to connect, call {@link #prepare}
- * and launch the intent if necessary.</li>
- * <li>Register a receiver for {@link #ACTION_VPN_REVOKED} broadcasts.
- * <li>Connect to the remote server and negotiate the network parameters
- * of the VPN connection.</li>
- * <li>Use those parameters to configure a VpnBuilder and create a VPN
- * interface by calling {@link #establish}.</li>
- * <li>Start processing packets between the returned file descriptor and
- * the VPN tunnel.</li>
- * <li>When an {@link #ACTION_VPN_REVOKED} broadcast is received, the
- * interface is already deactivated by the framework. Close the file
- * descriptor and shut down the VPN tunnel gracefully.
- * </ol>
- * Methods in this class can be used in activities and services. However,
- * the intent returned from {@link #prepare} must be launched from an
- * activity. The broadcast receiver can be registered at any time, but doing
- * it before calling {@link #establish} effectively avoids race conditions.
- *
- * <p class="note">Using this class requires
- * {@link android.Manifest.permission#VPN} permission.
- * @hide
- */
-public class VpnBuilder {
-
- /**
- * Broadcast intent action indicating that the VPN application has been
- * revoked. This can be only received by the target application on the
- * receiver explicitly registered using {@link Context#registerReceiver}.
- *
- * <p>This is a protected intent that can only be sent by the system.
- */
- public static final String ACTION_VPN_REVOKED = VpnConfig.ACTION_VPN_REVOKED;
-
- /**
- * Use IConnectivityManager instead since those methods are hidden and
- * not available in ConnectivityManager.
- */
- private static IConnectivityManager getService() {
- return IConnectivityManager.Stub.asInterface(
- ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
- }
-
- /**
- * Prepare to establish a VPN connection. This method returns {@code null}
- * if the VPN application is already prepared. Otherwise, it returns an
- * {@link Intent} to a system activity. The application should launch the
- * activity using {@link Activity#startActivityForResult} to get itself
- * prepared. The activity may pop up a dialog to require user action, and
- * the result will come back to the application through its
- * {@link Activity#onActivityResult}. The application becomes prepared if
- * the result is {@link Activity#RESULT_OK}, and it is granted to create a
- * VPN interface by calling {@link #establish}.
- *
- * <p>Only one application can be granted at the same time. The right
- * is revoked when another application is granted. The application
- * losing the right will be notified by an {@link #ACTION_VPN_REVOKED}
- * broadcast, and its VPN interface will be deactivated by the system.
- * The application should then notify the remote server and disconnect
- * gracefully. Unless the application becomes prepared again, subsequent
- * calls to {@link #establish} will return {@code null}.
- *
- * @see #establish
- * @see #ACTION_VPN_REVOKED
- */
- public static Intent prepare(Context context) {
- try {
- if (getService().prepareVpn(context.getPackageName(), null)) {
- return null;
- }
- } catch (RemoteException e) {
- // ignore
- }
- return VpnConfig.getIntentForConfirmation();
- }
-
- private VpnConfig mConfig = new VpnConfig();
- private StringBuilder mAddresses = new StringBuilder();
- private StringBuilder mRoutes = new StringBuilder();
-
- /**
- * Set the name of this session. It will be displayed in system-managed
- * dialogs and notifications. This is recommended not required.
- */
- public VpnBuilder setSession(String session) {
- mConfig.session = session;
- return this;
- }
-
- /**
- * Set the {@link PendingIntent} to an activity for users to configure
- * the VPN connection. If it is not set, the button to configure will
- * not be shown in system-managed dialogs.
- */
- public VpnBuilder setConfigureIntent(PendingIntent intent) {
- mConfig.configureIntent = intent;
- return this;
- }
-
- /**
- * Set the maximum transmission unit (MTU) of the VPN interface. If it
- * is not set, the default value in the operating system will be used.
- *
- * @throws IllegalArgumentException if the value is not positive.
- */
- public VpnBuilder setMtu(int mtu) {
- if (mtu <= 0) {
- throw new IllegalArgumentException("Bad mtu");
- }
- mConfig.mtu = mtu;
- return this;
- }
-
- /**
- * Private method to validate address and prefixLength.
- */
- private static void check(InetAddress address, int prefixLength) {
- if (address.isLoopbackAddress()) {
- throw new IllegalArgumentException("Bad address");
- }
- if (address instanceof Inet4Address) {
- if (prefixLength < 0 || prefixLength > 32) {
- throw new IllegalArgumentException("Bad prefixLength");
- }
- } else if (address instanceof Inet6Address) {
- if (prefixLength < 0 || prefixLength > 128) {
- throw new IllegalArgumentException("Bad prefixLength");
- }
- } else {
- throw new IllegalArgumentException("Unsupported family");
- }
- }
-
- /**
- * Convenience method to add a network address to the VPN interface
- * using a numeric address string. See {@link InetAddress} for the
- * definitions of numeric address formats.
- *
- * @throws IllegalArgumentException if the address is invalid.
- * @see #addAddress(InetAddress, int)
- */
- public VpnBuilder addAddress(String address, int prefixLength) {
- return addAddress(InetAddress.parseNumericAddress(address), prefixLength);
- }
-
- /**
- * Add a network address to the VPN interface. Both IPv4 and IPv6
- * addresses are supported. At least one address must be set before
- * calling {@link #establish}.
- *
- * @throws IllegalArgumentException if the address is invalid.
- */
- public VpnBuilder addAddress(InetAddress address, int prefixLength) {
- check(address, prefixLength);
-
- if (address.isAnyLocalAddress()) {
- throw new IllegalArgumentException("Bad address");
- }
-
- mAddresses.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
- return this;
- }
-
- /**
- * Convenience method to add a network route to the VPN interface
- * using a numeric address string. See {@link InetAddress} for the
- * definitions of numeric address formats.
- *
- * @see #addRoute(InetAddress, int)
- * @throws IllegalArgumentException if the route is invalid.
- */
- public VpnBuilder addRoute(String address, int prefixLength) {
- return addRoute(InetAddress.parseNumericAddress(address), prefixLength);
- }
-
- /**
- * Add a network route to the VPN interface. Both IPv4 and IPv6
- * routes are supported.
- *
- * @throws IllegalArgumentException if the route is invalid.
- */
- public VpnBuilder addRoute(InetAddress address, int prefixLength) {
- check(address, prefixLength);
-
- int offset = prefixLength / 8;
- byte[] bytes = address.getAddress();
- if (offset < bytes.length) {
- if ((byte)(bytes[offset] << (prefixLength % 8)) != 0) {
- throw new IllegalArgumentException("Bad address");
- }
- while (++offset < bytes.length) {
- if (bytes[offset] != 0) {
- throw new IllegalArgumentException("Bad address");
- }
- }
- }
-
- mRoutes.append(String.format(" %s/%d", address.getHostAddress(), prefixLength));
- return this;
- }
-
- /**
- * Convenience method to add a DNS server to the VPN connection
- * using a numeric address string. See {@link InetAddress} for the
- * definitions of numeric address formats.
- *
- * @throws IllegalArgumentException if the address is invalid.
- * @see #addDnsServer(InetAddress)
- */
- public VpnBuilder addDnsServer(String address) {
- return addDnsServer(InetAddress.parseNumericAddress(address));
- }
-
- /**
- * Add a DNS server to the VPN connection. Both IPv4 and IPv6
- * addresses are supported. If none is set, the DNS servers of
- * the default network will be used.
- *
- * @throws IllegalArgumentException if the address is invalid.
- */
- public VpnBuilder addDnsServer(InetAddress address) {
- if (address.isLoopbackAddress() || address.isAnyLocalAddress()) {
- throw new IllegalArgumentException("Bad address");
- }
- if (mConfig.dnsServers == null) {
- mConfig.dnsServers = new ArrayList<String>();
- }
- mConfig.dnsServers.add(address.getHostAddress());
- return this;
- }
-
- /**
- * Add a search domain to the DNS resolver.
- */
- public VpnBuilder addSearchDomain(String domain) {
- if (mConfig.searchDomains == null) {
- mConfig.searchDomains = new ArrayList<String>();
- }
- mConfig.searchDomains.add(domain);
- return this;
- }
-
- /**
- * Create a VPN interface using the parameters supplied to this builder.
- * The interface works on IP packets, and a file descriptor is returned
- * for the application to access them. Each read retrieves an outgoing
- * packet which was routed to the interface. Each write injects an
- * incoming packet just like it was received from the interface. The file
- * descriptor is put into non-blocking mode by default to avoid blocking
- * Java threads. To use the file descriptor completely in native space,
- * see {@link ParcelFileDescriptor#detachFd()}. The application MUST
- * close the file descriptor when the VPN connection is terminated. The
- * VPN interface will be removed and the network will be restored by the
- * framework automatically.
- *
- * <p>To avoid conflicts, there can be only one active VPN interface at
- * the same time. Usually network parameters are never changed during the
- * lifetime of a VPN connection. It is also common for an application to
- * create a new file descriptor after closing the previous one. However,
- * it is rare but not impossible to have two interfaces while performing a
- * seamless handover. In this case, the old interface will be deactivated
- * when the new one is configured successfully. Both file descriptors are
- * valid but now outgoing packets will be routed to the new interface.
- * Therefore, after draining the old file descriptor, the application MUST
- * close it and start using the new file descriptor. If the new interface
- * cannot be created, the existing interface and its file descriptor remain
- * untouched.
- *
- * <p>An exception will be thrown if the interface cannot be created for
- * any reason. However, this method returns {@code null} if the application
- * is not prepared or is revoked by another application. This helps solve
- * possible race conditions while handling {@link #ACTION_VPN_REVOKED}
- * broadcasts.
- *
- * @return {@link ParcelFileDescriptor} of the VPN interface, or
- * {@code null} if the application is not prepared.
- * @throws IllegalArgumentException if a parameter is not accepted by the
- * operating system.
- * @throws IllegalStateException if a parameter cannot be applied by the
- * operating system.
- * @see #prepare
- */
- public ParcelFileDescriptor establish() {
- mConfig.addresses = mAddresses.toString();
- mConfig.routes = mRoutes.toString();
-
- try {
- return getService().establishVpn(mConfig);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
- }
-
- /**
- * Protect a socket from VPN connections. The socket will be bound to the
- * current default network interface, so its traffic will not be forwarded
- * through VPN. This method is useful if some connections need to be kept
- * outside of VPN. For example, a VPN tunnel should protect itself if its
- * destination is covered by VPN routes. Otherwise its outgoing packets
- * will be sent back to the VPN interface and cause an infinite loop.
- *
- * <p>The socket is NOT closed by this method.
- *
- * @return {@code true} on success.
- */
- public static boolean protect(int socket) {
- ParcelFileDescriptor dup = null;
- try {
- dup = ParcelFileDescriptor.fromFd(socket);
- return getService().protectVpn(dup);
- } catch (Exception e) {
- return false;
- } finally {
- try {
- dup.close();
- } catch (Exception e) {
- // ignore
- }
- }
- }
-
- /**
- * Protect a {@link Socket} from VPN connections.
- *
- * @return {@code true} on success.
- * @see #protect(int)
- */
- public static boolean protect(Socket socket) {
- return protect(socket.getFileDescriptor$().getInt$());
- }
-
- /**
- * Protect a {@link DatagramSocket} from VPN connections.
- *
- * @return {@code true} on success.
- * @see #protect(int)
- */
- public static boolean protect(DatagramSocket socket) {
- return protect(socket.getFileDescriptor$().getInt$());
- }
-}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 3704248e8076..bc4e00cc4d21 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -240,6 +240,11 @@ interface INetworkManagementService
void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces);
/**
+ * Return status of bandwidth control module.
+ */
+ boolean isBandwidthControlEnabled();
+
+ /**
* Configures bandwidth throttling on an interface.
*/
void setInterfaceThrottle(String iface, int rxKbps, int txKbps);
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 521762479181..814f50ba5646 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -41,7 +41,7 @@ import android.provider.CallLog.Calls;
* </ul>
*
* <P> The minimum permission needed to access this content provider is
- * {@link Manifest.permission#READ_WRITE_OWN_VOICEMAIL}
+ * {@link Manifest.permission#ADD_VOICEMAIL}
*
* <P>Voicemails are inserted by what is called as a "voicemail source"
* application, which is responsible for syncing voicemail data between a remote
diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java
index 5f9ffc5bf2f0..20170bf9615d 100644
--- a/core/java/android/text/TextDirectionHeuristics.java
+++ b/core/java/android/text/TextDirectionHeuristics.java
@@ -164,6 +164,7 @@ public class TextDirectionHeuristics {
case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
+ case Character.DIRECTIONALITY_ARABIC_NUMBER:
return TriState.TRUE;
default:
return TriState.UNKNOWN;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index cadf2aba0cec..9737a5a9bc07 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -628,6 +628,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private int mGlowPaddingLeft;
private int mGlowPaddingRight;
+ private int mLastAccessibilityScrollEventFromIndex;
+ private int mLastAccessibilityScrollEventToIndex;
+
/**
* Interface definition for a callback to be invoked when the list or grid
* has been scrolled.
@@ -1265,6 +1268,24 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
@Override
+ public void sendAccessibilityEvent(int eventType) {
+ // Since this class calls onScrollChanged even if the mFirstPosition and the
+ // child count have not changed we will avoid sending duplicate accessibility
+ // events.
+ if (eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
+ final int lastPosition = mFirstPosition + getChildCount();
+ if (mLastAccessibilityScrollEventFromIndex == mFirstPosition
+ && mLastAccessibilityScrollEventToIndex == lastPosition) {
+ return;
+ } else {
+ mLastAccessibilityScrollEventFromIndex = mFirstPosition;
+ mLastAccessibilityScrollEventToIndex = lastPosition;
+ }
+ }
+ super.sendAccessibilityEvent(eventType);
+ }
+
+ @Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setScrollable(true);
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 00c75a947a2a..9f5737e21f90 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -277,6 +277,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
* called, false otherwise is returned.
*/
public boolean performItemClick(View view, int position, long id) {
+ view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
if (mOnItemClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
mOnItemClickListener.onItemClick(this, view, position, id);
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 00ebe0d8976a..7ad5d6c94853 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -116,6 +116,8 @@ class FastScroller {
private int mOverlayPosition;
+ private boolean mMatchDragPosition;
+
private static final int FADE_TIMEOUT = 1500;
private final Rect mTmpRect = new Rect();
@@ -262,6 +264,9 @@ class FastScroller {
ta.recycle();
+ mMatchDragPosition = context.getApplicationInfo().targetSdkVersion >=
+ android.os.Build.VERSION_CODES.HONEYCOMB;
+
setScrollbarPosition(mList.getVerticalScrollbarPosition());
}
@@ -417,7 +422,7 @@ class FastScroller {
}
return;
}
- if (totalItemCount - visibleItemCount > 0 && mState != STATE_DRAGGING ) {
+ if (totalItemCount - visibleItemCount > 0 && mState != STATE_DRAGGING) {
mThumbY = getThumbPositionForListPosition(firstVisibleItem, visibleItemCount,
totalItemCount);
if (mChangedBounds) {
@@ -595,7 +600,7 @@ class FastScroller {
if (mSectionIndexer == null) {
getSectionsFromIndexer();
}
- if (mSectionIndexer == null) {
+ if (mSectionIndexer == null || !mMatchDragPosition) {
return ((mList.getHeight() - mThumbH) * firstVisibleItem)
/ (totalItemCount - visibleItemCount);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 968d61215bc7..04cf69b48925 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8449,6 +8449,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
info.setPassword(isPassword);
}
+ @Override
+ public void sendAccessibilityEvent(int eventType) {
+ // Do not send scroll events since first they are not interesting for
+ // accessibility and second such events a generated too frequently.
+ // For details see the implementation of bringTextIntoView().
+ if (eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
+ return;
+ }
+ super.sendAccessibilityEvent(eventType);
+ }
+
void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText,
int fromIndex, int removedCount, int addedCount) {
AccessibilityEvent event =
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index d36be10e0038..d61a5795fb85 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -32,7 +32,7 @@ import java.util.List;
*/
public class VpnConfig implements Parcelable {
- public static final String ACTION_VPN_REVOKED = "android.net.vpn.action.REVOKED";
+ public static final String SERVICE_INTERFACE = "android.net.VpnService";
public static final String LEGACY_VPN = "[Legacy VPN]";
@@ -52,7 +52,7 @@ public class VpnConfig implements Parcelable {
PendingIntent.FLAG_NO_CREATE : PendingIntent.FLAG_CANCEL_CURRENT);
}
- public String packagz;
+ public String user;
public String interfaze;
public String session;
public int mtu = -1;
@@ -70,7 +70,7 @@ public class VpnConfig implements Parcelable {
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeString(packagz);
+ out.writeString(user);
out.writeString(interfaze);
out.writeString(session);
out.writeInt(mtu);
@@ -87,7 +87,7 @@ public class VpnConfig implements Parcelable {
@Override
public VpnConfig createFromParcel(Parcel in) {
VpnConfig config = new VpnConfig();
- config.packagz = in.readString();
+ config.user = in.readString();
config.interfaze = in.readString();
config.session = in.readString();
config.mtu = in.readInt();
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index 9ecd29ff81b9..0cadb1625c65 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -49,5 +49,6 @@ public class Protocol {
public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
public static final int BASE_DATA_CONNECTION_TRACKER = 0x00042000;
+ public static final int BASE_DNS_PINGER = 0x00050000;
//TODO: define all used protocols
}
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index cbe72dd2ada4..36f02469ae6a 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -1226,6 +1226,12 @@ public class StateMachine {
* be executed and upon the next message arriving
* destState.enter will be invoked.
*
+ * this function can also be called inside the enter function of the
+ * previous transition target, but the behavior is undefined when it is
+ * called mid-way through a previous transition (for example, calling this
+ * in the enter() routine of a intermediate node when the current transition
+ * target is one of the nodes descendants).
+ *
* @param destState will be the state that receives the next message.
*/
protected final void transitionTo(IState destState) {
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 4878b0f088ac..61df5c79b277 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -583,7 +583,7 @@ public class ActionBarView extends AbsActionBarView {
}
public void setLogo(int resId) {
- mContext.getResources().getDrawable(resId);
+ setLogo(mContext.getResources().getDrawable(resId));
}
/**
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 6e7388955986..170957cf9783 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -178,6 +178,7 @@ LOCAL_C_INCLUDES += \
external/icu4c/i18n \
external/icu4c/common \
external/jpeg \
+ external/harfbuzz/contrib \
external/harfbuzz/src \
external/zlib \
frameworks/opt/emoji \
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 30fe298207a2..a29eb3898a92 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -17,6 +17,10 @@
#include "TextLayoutCache.h"
#include "TextLayout.h"
+extern "C" {
+#include "harfbuzz-unicode.h"
+}
+
namespace android {
TextLayoutCache::TextLayoutCache() :
@@ -355,7 +359,9 @@ void TextLayoutCacheValue::setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec
shaperItem->item.pos = start;
shaperItem->item.length = count;
shaperItem->item.bidiLevel = isRTL;
- shaperItem->item.script = isRTL ? HB_Script_Arabic : HB_Script_Common;
+
+ ssize_t iter = 0;
+ shaperItem->item.script = code_point_to_script(utf16_to_code_point(chars, count, &iter));
shaperItem->string = chars;
shaperItem->stringLength = contextCount;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 21c3f1e2d4c3..57b686a0a23a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -63,7 +63,7 @@
<protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
<protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
-
+
<protected-broadcast android:name="android.backup.intent.RUN" />
<protected-broadcast android:name="android.backup.intent.CLEAR" />
<protected-broadcast android:name="android.backup.intent.INIT" />
@@ -292,16 +292,6 @@
android:description="@string/permdesc_setAlarm"
android:protectionLevel="normal" />
- <!-- Allows an application to read/write the voicemails owned by its own
- package. -->
- <!-- TODO: delete this permission when dependent content provider &
- application code has been migrated to use ADD_VOICEMAIL instead -->
- <permission android:name="com.android.voicemail.permission.READ_WRITE_OWN_VOICEMAIL"
- android:permissionGroup="android.permission-group.PERSONAL_INFO"
- android:protectionLevel="dangerous"
- android:label="@string/permlab_readWriteOwnVoicemail"
- android:description="@string/permdesc_readWriteOwnVoicemail" />
-
<!-- Allows an application to add voicemails into the system. -->
<permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
@@ -402,14 +392,6 @@
android:description="@string/permdesc_nfc"
android:label="@string/permlab_nfc" />
- <!-- Allows applications to provide VPN functionality.
- @hide Pending API council approval -->
- <permission android:name="android.permission.VPN"
- android:permissionGroup="android.permission-group.NETWORK"
- android:protectionLevel="dangerous"
- android:description="@string/permdesc_vpn"
- android:label="@string/permlab_vpn" />
-
<!-- Allows an application to use SIP service -->
<permission android:name="android.permission.USE_SIP"
android:permissionGroup="android.permission-group.NETWORK"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a6c92f2e26b8..6a3c2d588f9a 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1358,14 +1358,6 @@
with Near Field Communication (NFC) tags, cards, and readers.</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_vpn">intercept and modify all network traffic</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_vpn">Allows an application to intercept and
- inspect all network traffic to establish a VPN connection.
- Malicious applications may monitor, redirect, or modify network packets
- without your knowledge.</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_disableKeyguard">disable keylock</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_disableKeyguard">Allows an application to disable
@@ -2159,14 +2151,6 @@
<!-- Title of an application permission, listed so the user can choose whether
they want to allow the application to do this. [CHAR LIMIT=NONE] -->
- <string name="permlab_readWriteOwnVoicemail">Access voicemails managed by this application</string>
- <!-- Description of an application permission, listed so the user can choose whether
- they want to allow the application to do this. [CHAR LIMIT=NONE] -->
- <string name="permdesc_readWriteOwnVoicemail">Allows the application to store and retrieve only
- voicemails that its associated service can access.</string>
-
- <!-- Title of an application permission, listed so the user can choose whether
- they want to allow the application to do this. [CHAR LIMIT=NONE] -->
<string name="permlab_addVoicemail">add voicemail</string>
<!-- Description of an application permission, listed so the user can choose whether
they want to allow the application to do this. [CHAR LIMIT=NONE] -->
diff --git a/core/tests/coretests/src/android/animation/EventsTest.java b/core/tests/coretests/src/android/animation/EventsTest.java
index f970ffc59806..6ea28452c961 100644
--- a/core/tests/coretests/src/android/animation/EventsTest.java
+++ b/core/tests/coretests/src/android/animation/EventsTest.java
@@ -21,6 +21,8 @@ import android.test.UiThreadTest;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
+import java.util.concurrent.TimeUnit;
+
/**
* Tests for the various lifecycle events of Animators. This abstract class is subclassed by
* concrete implementations that provide the actual Animator objects being tested. All of the
@@ -40,7 +42,10 @@ public abstract class EventsTest
private static final int ANIM_DELAY = 100;
private static final int ANIM_MID_DURATION = ANIM_DURATION / 2;
private static final int ANIM_MID_DELAY = ANIM_DELAY / 2;
+ private static final int FUTURE_RELEASE_DELAY = 50;
+ private static final int TIMEOUT = ANIM_DURATION + ANIM_DELAY + FUTURE_RELEASE_DELAY;
+ private boolean mStarted; // tracks whether we've received the onAnimationStart() callback
private boolean mRunning; // tracks whether we've started the animator
private boolean mCanceled; // trackes whether we've canceled the animator
private Animator.AnimatorListener mFutureListener; // mechanism for delaying the end of the test
@@ -51,17 +56,44 @@ public abstract class EventsTest
// setup() method prior to calling the superclass setup()
/**
- * Cancels the given animator. Used to delay cancelation until some later time (after the
+ * Cancels the given animator. Used to delay cancellation until some later time (after the
* animator has started playing).
*/
static class Canceler implements Runnable {
Animator mAnim;
- public Canceler(Animator anim) {
+ FutureWaiter mFuture;
+ public Canceler(Animator anim, FutureWaiter future) {
+ mAnim = anim;
+ mFuture = future;
+ }
+ @Override
+ public void run() {
+ try {
+ mAnim.cancel();
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ };
+
+ /**
+ * Ends the given animator. Used to delay ending until some later time (after the
+ * animator has started playing).
+ */
+ static class Ender implements Runnable {
+ Animator mAnim;
+ FutureWaiter mFuture;
+ public Ender(Animator anim, FutureWaiter future) {
mAnim = anim;
+ mFuture = future;
}
@Override
public void run() {
- mAnim.cancel();
+ try {
+ mAnim.end();
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
}
};
@@ -76,6 +108,23 @@ public abstract class EventsTest
public FutureReleaseListener(FutureWaiter future) {
mFuture = future;
}
+
+ /**
+ * Variant constructor that auto-releases the FutureWaiter after the specified timeout.
+ * @param future
+ * @param timeout
+ */
+ public FutureReleaseListener(FutureWaiter future, long timeout) {
+ mFuture = future;
+ Handler handler = new Handler();
+ handler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mFuture.release();
+ }
+ }, timeout);
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
Handler handler = new Handler();
@@ -84,7 +133,7 @@ public abstract class EventsTest
public void run() {
mFuture.release();
}
- }, ANIM_MID_DURATION);
+ }, FUTURE_RELEASE_DELAY);
}
};
@@ -92,7 +141,6 @@ public abstract class EventsTest
super(BasicAnimatorActivity.class);
}
-
/**
* Sets up the fields used by each test. Subclasses must override this method to create
* the protected mAnimator object used in all tests. Overrides must create that animator
@@ -107,11 +155,20 @@ public abstract class EventsTest
// are embedded in the listener callbacks that it implements.
mListener = new AnimatorListenerAdapter() {
@Override
+ public void onAnimationStart(Animator animation) {
+ // This should only be called on an animation that has not yet been started
+ assertFalse(mStarted);
+ assertTrue(mRunning);
+ mStarted = true;
+ }
+
+ @Override
public void onAnimationCancel(Animator animation) {
// This should only be called on an animation that has been started and not
// yet canceled or ended
assertFalse(mCanceled);
assertTrue(mRunning);
+ assertTrue(mStarted);
mCanceled = true;
}
@@ -120,7 +177,9 @@ public abstract class EventsTest
// This should only be called on an animation that has been started and not
// yet ended
assertTrue(mRunning);
+ assertTrue(mStarted);
mRunning = false;
+ mStarted = false;
super.onAnimationEnd(animation);
}
};
@@ -132,6 +191,7 @@ public abstract class EventsTest
mRunning = false;
mCanceled = false;
+ mStarted = false;
}
/**
@@ -144,26 +204,104 @@ public abstract class EventsTest
}
/**
+ * Verify that calling end on an unstarted animator does nothing.
+ */
+ @UiThreadTest
+ @SmallTest
+ public void testEnd() throws Exception {
+ mAnimator.end();
+ }
+
+ /**
* Verify that calling cancel on a started animator does the right thing.
*/
@UiThreadTest
@SmallTest
public void testStartCancel() throws Exception {
- mRunning = true;
- mAnimator.start();
- mAnimator.cancel();
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.cancel();
+ mFuture.release();
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
}
/**
- * Same as testStartCancel, but with a startDelayed animator
+ * Verify that calling end on a started animator does the right thing.
*/
@UiThreadTest
@SmallTest
+ public void testStartEnd() throws Exception {
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.end();
+ mFuture.release();
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Same as testStartCancel, but with a startDelayed animator
+ */
+ @SmallTest
public void testStartDelayedCancel() throws Exception {
+ mFutureListener = new FutureReleaseListener(mFuture);
mAnimator.setStartDelay(ANIM_DELAY);
- mRunning = true;
- mAnimator.start();
- mAnimator.cancel();
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.cancel();
+ mFuture.release();
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Same as testStartEnd, but with a startDelayed animator
+ */
+ @SmallTest
+ public void testStartDelayedEnd() throws Exception {
+ mFutureListener = new FutureReleaseListener(mFuture);
+ mAnimator.setStartDelay(ANIM_DELAY);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.end();
+ mFuture.release();
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
}
/**
@@ -180,13 +318,36 @@ public abstract class EventsTest
mAnimator.addListener(mFutureListener);
mRunning = true;
mAnimator.start();
- handler.postDelayed(new Canceler(mAnimator), ANIM_MID_DURATION);
+ handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Verify that ending an animator that is playing does the right thing.
+ */
+ @MediumTest
+ public void testPlayingEnd() throws Exception {
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Handler handler = new Handler();
+ mAnimator.addListener(mFutureListener);
+ mRunning = true;
+ mAnimator.start();
+ handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DURATION);
} catch (junit.framework.AssertionFailedError e) {
mFuture.setException(new RuntimeException(e));
}
}
});
- mFuture.get();
+ mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
}
/**
@@ -204,13 +365,91 @@ public abstract class EventsTest
mAnimator.addListener(mFutureListener);
mRunning = true;
mAnimator.start();
- handler.postDelayed(new Canceler(mAnimator), ANIM_MID_DURATION);
+ handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DURATION);
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Same as testPlayingEnd, but with a startDelayed animator
+ */
+ @MediumTest
+ public void testPlayingDelayedEnd() throws Exception {
+ mAnimator.setStartDelay(ANIM_DELAY);
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Handler handler = new Handler();
+ mAnimator.addListener(mFutureListener);
+ mRunning = true;
+ mAnimator.start();
+ handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DURATION);
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Same as testPlayingDelayedCancel, but cancel during the startDelay period
+ */
+ @MediumTest
+ public void testPlayingDelayedCancelMidDelay() throws Exception {
+ mAnimator.setStartDelay(ANIM_DELAY);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // Set the listener to automatically timeout after an uncanceled animation
+ // would have finished. This tests to make sure that we're not calling
+ // the listeners with cancel/end callbacks since they won't be called
+ // with the start event.
+ mFutureListener = new FutureReleaseListener(mFuture, TIMEOUT);
+ Handler handler = new Handler();
+ mRunning = true;
+ mAnimator.start();
+ handler.postDelayed(new Canceler(mAnimator, mFuture), ANIM_MID_DELAY);
} catch (junit.framework.AssertionFailedError e) {
mFuture.setException(new RuntimeException(e));
}
}
});
- mFuture.get();
+ mFuture.get(TIMEOUT + 100, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Same as testPlayingDelayedEnd, but end during the startDelay period
+ */
+ @MediumTest
+ public void testPlayingDelayedEndMidDelay() throws Exception {
+ mAnimator.setStartDelay(ANIM_DELAY);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // Set the listener to automatically timeout after an uncanceled animation
+ // would have finished. This tests to make sure that we're not calling
+ // the listeners with cancel/end callbacks since they won't be called
+ // with the start event.
+ mFutureListener = new FutureReleaseListener(mFuture, TIMEOUT);
+ Handler handler = new Handler();
+ mRunning = true;
+ mAnimator.start();
+ handler.postDelayed(new Ender(mAnimator, mFuture), ANIM_MID_DELAY);
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get(TIMEOUT + 100, TimeUnit.MILLISECONDS);
}
/**
@@ -234,7 +473,31 @@ public abstract class EventsTest
}
}
});
- mFuture.get();
+ mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Verifies that ending a started animation after it has already been ended
+ * does nothing.
+ */
+ @MediumTest
+ public void testStartDoubleEnd() throws Exception {
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.end();
+ mAnimator.end();
+ mFuture.release();
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
}
/**
@@ -258,8 +521,31 @@ public abstract class EventsTest
}
}
});
- mFuture.get();
- }
+ mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+ /**
+ * Same as testStartDoubleEnd, but with a startDelayed animator
+ */
+ @MediumTest
+ public void testStartDelayedDoubleEnd() throws Exception {
+ mAnimator.setStartDelay(ANIM_DELAY);
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.end();
+ mAnimator.end();
+ mFuture.release();
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
+ }
}
diff --git a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
index 242057cf963d..4db4ea52d527 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
@@ -16,6 +16,14 @@
package android.net;
+import static android.net.NetworkStatsHistory.FIELD_ALL;
+import static android.net.NetworkStatsHistory.FIELD_OPERATIONS;
+import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
+import static android.net.NetworkStatsHistory.FIELD_RX_PACKETS;
+import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
+import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLong;
+import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLong;
+import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
@@ -30,7 +38,10 @@ import android.util.Log;
import com.android.frameworks.coretests.R;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
+import java.io.DataOutputStream;
import java.util.Random;
@SmallTest
@@ -39,6 +50,10 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
private static final long TEST_START = 1194220800000L;
+ private static final long KB_IN_BYTES = 1024;
+ private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
+ private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
+
private NetworkStatsHistory stats;
@Override
@@ -80,10 +95,11 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
stats = new NetworkStatsHistory(BUCKET_SIZE);
// record data into narrow window to get single bucket
- stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 1024L, 2048L);
+ stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
+ new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
assertEquals(1, stats.size());
- assertValues(stats, 0, 1024L, 2048L);
+ assertValues(stats, 0, 1024L, 10L, 2048L, 20L, 2L);
}
public void testRecordEqualBuckets() throws Exception {
@@ -92,11 +108,12 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
// split equally across two buckets
final long recordStart = TEST_START + (bucketDuration / 2);
- stats.recordData(recordStart, recordStart + bucketDuration, 1024L, 128L);
+ stats.recordData(recordStart, recordStart + bucketDuration,
+ new NetworkStats.Entry(1024L, 10L, 128L, 2L, 2L));
assertEquals(2, stats.size());
- assertValues(stats, 0, 512L, 64L);
- assertValues(stats, 1, 512L, 64L);
+ assertValues(stats, 0, 512L, 5L, 64L, 1L, 1L);
+ assertValues(stats, 1, 512L, 5L, 64L, 1L, 1L);
}
public void testRecordTouchingBuckets() throws Exception {
@@ -107,15 +124,16 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
// overlap into neighboring buckets. total record is 20 minutes.
final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS;
final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4);
- stats.recordData(recordStart, recordEnd, 1000L, 5000L);
+ stats.recordData(recordStart, recordEnd,
+ new NetworkStats.Entry(1000L, 2000L, 5000L, 10000L, 100L));
assertEquals(3, stats.size());
// first bucket should have (1/20 of value)
- assertValues(stats, 0, 50L, 250L);
+ assertValues(stats, 0, 50L, 100L, 250L, 500L, 5L);
// second bucket should have (15/20 of value)
- assertValues(stats, 1, 750L, 3750L);
+ assertValues(stats, 1, 750L, 1500L, 3750L, 7500L, 75L);
// final bucket should have (4/20 of value)
- assertValues(stats, 2, 200L, 1000L);
+ assertValues(stats, 2, 200L, 400L, 1000L, 2000L, 20L);
}
public void testRecordGapBuckets() throws Exception {
@@ -125,25 +143,28 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
// record some data today and next week with large gap
final long firstStart = TEST_START;
final long lastStart = TEST_START + WEEK_IN_MILLIS;
- stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS, 128L, 256L);
- stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS, 64L, 512L);
+ stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS,
+ new NetworkStats.Entry(128L, 2L, 256L, 4L, 1L));
+ stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS,
+ new NetworkStats.Entry(64L, 1L, 512L, 8L, 2L));
// we should have two buckets, far apart from each other
assertEquals(2, stats.size());
- assertValues(stats, 0, 128L, 256L);
- assertValues(stats, 1, 64L, 512L);
+ assertValues(stats, 0, 128L, 2L, 256L, 4L, 1L);
+ assertValues(stats, 1, 64L, 1L, 512L, 8L, 2L);
// now record something in middle, spread across two buckets
final long middleStart = TEST_START + DAY_IN_MILLIS;
final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2);
- stats.recordData(middleStart, middleEnd, 2048L, 2048L);
+ stats.recordData(middleStart, middleEnd,
+ new NetworkStats.Entry(2048L, 4L, 2048L, 4L, 2L));
// now should have four buckets, with new record in middle two buckets
assertEquals(4, stats.size());
- assertValues(stats, 0, 128L, 256L);
- assertValues(stats, 1, 1024L, 1024L);
- assertValues(stats, 2, 1024L, 1024L);
- assertValues(stats, 3, 64L, 512L);
+ assertValues(stats, 0, 128L, 2L, 256L, 4L, 1L);
+ assertValues(stats, 1, 1024L, 2L, 1024L, 2L, 1L);
+ assertValues(stats, 2, 1024L, 2L, 1024L, 2L, 1L);
+ assertValues(stats, 3, 64L, 1L, 512L, 8L, 2L);
}
public void testRecordOverlapBuckets() throws Exception {
@@ -151,14 +172,16 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
stats = new NetworkStatsHistory(BUCKET_SIZE);
// record some data in one bucket, and another overlapping buckets
- stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 256L, 256L);
+ stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
+ new NetworkStats.Entry(256L, 2L, 256L, 2L, 1L));
final long midStart = TEST_START + (HOUR_IN_MILLIS / 2);
- stats.recordData(midStart, midStart + HOUR_IN_MILLIS, 1024L, 1024L);
+ stats.recordData(midStart, midStart + HOUR_IN_MILLIS,
+ new NetworkStats.Entry(1024L, 10L, 1024L, 10L, 10L));
// should have two buckets, with some data mixed together
assertEquals(2, stats.size());
- assertValues(stats, 0, 768L, 768L);
- assertValues(stats, 1, 512L, 512L);
+ assertValues(stats, 0, 768L, 7L, 768L, 7L, 6L);
+ assertValues(stats, 1, 512L, 5L, 512L, 5L, 5L);
}
public void testRecordEntireGapIdentical() throws Exception {
@@ -283,6 +306,7 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
public void testFuzzing() throws Exception {
try {
// fuzzing with random events, looking for crashes
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
final Random r = new Random();
for (int i = 0; i < 500; i++) {
stats = new NetworkStatsHistory(r.nextLong());
@@ -291,7 +315,12 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
// add range
final long start = r.nextLong();
final long end = start + r.nextInt();
- stats.recordData(start, end, r.nextLong(), r.nextLong());
+ entry.rxBytes = nextPositiveLong(r);
+ entry.rxPackets = nextPositiveLong(r);
+ entry.txBytes = nextPositiveLong(r);
+ entry.txPackets = nextPositiveLong(r);
+ entry.operations = nextPositiveLong(r);
+ stats.recordData(start, end, entry);
} else {
// trim something
stats.removeBucketsBefore(r.nextLong());
@@ -305,6 +334,88 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
}
}
+ private static long nextPositiveLong(Random r) {
+ final long value = r.nextLong();
+ return value < 0 ? -value : value;
+ }
+
+ public void testIgnoreFields() throws Exception {
+ final NetworkStatsHistory history = new NetworkStatsHistory(
+ MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES);
+
+ history.recordData(0, MINUTE_IN_MILLIS,
+ new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
+ history.recordData(0, MINUTE_IN_MILLIS * 2,
+ new NetworkStats.Entry(2L, 2L, 2L, 2L, 2L));
+
+ assertValues(
+ history, Long.MIN_VALUE, Long.MAX_VALUE, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN);
+ }
+
+ public void testIgnoreFieldsRecordIn() throws Exception {
+ final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
+ final NetworkStatsHistory partial = new NetworkStatsHistory(
+ MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
+
+ full.recordData(0, MINUTE_IN_MILLIS,
+ new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
+ partial.recordEntireHistory(full);
+
+ assertValues(partial, Long.MIN_VALUE, Long.MAX_VALUE, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L);
+ }
+
+ public void testIgnoreFieldsRecordOut() throws Exception {
+ final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
+ final NetworkStatsHistory partial = new NetworkStatsHistory(
+ MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
+
+ partial.recordData(0, MINUTE_IN_MILLIS,
+ new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
+ full.recordEntireHistory(partial);
+
+ assertValues(full, Long.MIN_VALUE, Long.MAX_VALUE, 0L, 10L, 0L, 0L, 4L);
+ }
+
+ public void testSerialize() throws Exception {
+ final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL);
+ before.recordData(0, MINUTE_IN_MILLIS * 4,
+ new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
+ before.recordData(DAY_IN_MILLIS, DAY_IN_MILLIS + MINUTE_IN_MILLIS,
+ new NetworkStats.Entry(10L, 20L, 30L, 40L, 50L));
+
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ before.writeToStream(new DataOutputStream(out));
+ out.close();
+
+ final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+ final NetworkStatsHistory after = new NetworkStatsHistory(new DataInputStream(in));
+
+ // must have identical totals before and after
+ assertValues(before, Long.MIN_VALUE, Long.MAX_VALUE, 1034L, 30L, 2078L, 60L, 54L);
+ assertValues(after, Long.MIN_VALUE, Long.MAX_VALUE, 1034L, 30L, 2078L, 60L, 54L);
+ }
+
+ public void testVarLong() throws Exception {
+ assertEquals(0L, performVarLong(0L));
+ assertEquals(-1L, performVarLong(-1L));
+ assertEquals(1024L, performVarLong(1024L));
+ assertEquals(-1024L, performVarLong(-1024L));
+ assertEquals(40 * MB_IN_BYTES, performVarLong(40 * MB_IN_BYTES));
+ assertEquals(512 * GB_IN_BYTES, performVarLong(512 * GB_IN_BYTES));
+ assertEquals(Long.MIN_VALUE, performVarLong(Long.MIN_VALUE));
+ assertEquals(Long.MAX_VALUE, performVarLong(Long.MAX_VALUE));
+ assertEquals(Long.MIN_VALUE + 40, performVarLong(Long.MIN_VALUE + 40));
+ assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
+ }
+
+ private static long performVarLong(long before) throws Exception {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ writeVarLong(new DataOutputStream(out), before);
+
+ final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+ return readVarLong(new DataInputStream(in));
+ }
+
private static void assertConsistent(NetworkStatsHistory stats) {
// verify timestamps are monotonic
long lastStart = Long.MIN_VALUE;
@@ -330,4 +441,23 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
}
+ private static void assertValues(NetworkStatsHistory stats, int index, long rxBytes,
+ long rxPackets, long txBytes, long txPackets, long operations) {
+ final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
+ assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
+ assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
+ assertEquals("unexpected txBytes", txBytes, entry.txBytes);
+ assertEquals("unexpected txPackets", txPackets, entry.txPackets);
+ assertEquals("unexpected operations", operations, entry.operations);
+ }
+
+ private static void assertValues(NetworkStatsHistory stats, long start, long end, long rxBytes,
+ long rxPackets, long txBytes, long txPackets, long operations) {
+ final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
+ assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
+ assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
+ assertEquals("unexpected txBytes", txBytes, entry.txBytes);
+ assertEquals("unexpected txPackets", txPackets, entry.txPackets);
+ assertEquals("unexpected operations", operations, entry.operations);
+ }
}
diff --git a/docs/html/guide/developing/tools/draw9patch.jd b/docs/html/guide/developing/tools/draw9patch.jd
index 1d9de4f1f4ca..7cf0e4b1d861 100644
--- a/docs/html/guide/developing/tools/draw9patch.jd
+++ b/docs/html/guide/developing/tools/draw9patch.jd
@@ -41,7 +41,7 @@ You'll need the PNG image with which you'd like to create a NinePatch.</p>
A previously saved 9-patch file (<code>*.9.png</code>) will be loaded as-is,
with no drawing area added, because it already exists.</p>
-<img src="{@docRoot}images/draw9patch-bad.png" style="float:right" alt="" height="300" width="341"
+<img src="{@docRoot}images/draw9patch-bad.png" style="float:right;clear:both" alt="" height="300" width="341"
/>
<p>Optional controls include:</p>
diff --git a/drm/libdrmframework/plugins/common/util/include/SessionMap.h b/drm/libdrmframework/plugins/common/util/include/SessionMap.h
index 3dff58c17ef7..e5638942c234 100644
--- a/drm/libdrmframework/plugins/common/util/include/SessionMap.h
+++ b/drm/libdrmframework/plugins/common/util/include/SessionMap.h
@@ -13,141 +13,175 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#ifndef __SESSIONMAP_H__
#define __SESSIONMAP_H__
#include <utils/KeyedVector.h>
+#include <utils/threads.h>
namespace android {
/**
- * A wrapper template class for handling DRM Engine sessions.
+ * A thread safe wrapper template class for session handlings for Drm Engines. It wraps a
+ * pointer type over KeyedVector. It keeps pointer as data in the vector and free up memory
+ * allocated pointer can be of any type of structure/class meant for keeping session data.
+ * so session object here means pointer to the session data.
*/
-template <typename NODE>
+template <typename TValue>
class SessionMap {
public:
- KeyedVector<int, NODE> map;
-
SessionMap() {}
virtual ~SessionMap() {
+ Mutex::Autolock lock(mLock);
destroyMap();
}
-/**
- * Adds a new value in the session map table. It expects memory to be allocated already
- * for the session object
- *
- * @param key - key or Session ID
- * @param value - session object to add
- *
- * @return boolean result of adding value. returns false if key is already exist.
- */
-bool addValue(int key, NODE value) {
- bool result = false;
-
- if (!isCreated(key)) {
- map.add(key, value);
- result = true;
+ /**
+ * Adds a new value in the session map table. It expects memory to be allocated already
+ * for the session object
+ *
+ * @param key - key or Session ID
+ * @param value - session object to add
+ *
+ * @return boolean result of adding value. returns false if key is already exist.
+ */
+ bool addValue(int key, TValue value) {
+ Mutex::Autolock lock(mLock);
+ if (!isCreatedInternal(key)) {
+ map.add(key, value);
+ return true;
+ }
+ return false;
}
- return result;
-}
-
-
-/**
- * returns the session object by the key
- *
- * @param key - key or Session ID
- *
- * @return session object as per the key
- */
-NODE getValue(int key) {
- NODE value = NULL;
-
- if (isCreated(key)) {
- value = (NODE) map.valueFor(key);
+ /**
+ * returns the session object by the key
+ *
+ * @param key - key or Session ID
+ *
+ * @return session object as per the key
+ */
+ TValue getValue(int key) {
+ Mutex::Autolock lock(mLock);
+ return getValueInternal(key);
}
- return value;
-}
-
-/**
- * returns the number of objects in the session map table
- *
- * @return count of number of session objects.
- */
-int getSize() {
- return map.size();
-}
-
-/**
- * returns the session object by the index in the session map table
- *
- * @param index - index of the value required
- *
- * @return session object as per the index
- */
-NODE getValueAt(unsigned int index) {
- NODE value = NULL;
+ /**
+ * returns the number of objects in the session map table
+ *
+ * @return count of number of session objects.
+ */
+ int getSize() {
+ Mutex::Autolock lock(mLock);
+ return map.size();
+ }
- if (map.size() > index) {
- value = map.valueAt(index);
+ /**
+ * returns the session object by the index in the session map table
+ *
+ * @param index - index of the value required
+ *
+ * @return session object as per the index
+ */
+ TValue getValueAt(unsigned int index) {
+ TValue value = NULL;
+ Mutex::Autolock lock(mLock);
+
+ if (map.size() > index) {
+ value = map.valueAt(index);
+ }
+ return value;
}
- return value;
-}
+ /**
+ * deletes the object from session map. It also frees up memory for the session object.
+ *
+ * @param key - key of the value to be deleted
+ *
+ */
+ void removeValue(int key) {
+ Mutex::Autolock lock(mLock);
+ deleteValue(getValueInternal(key));
+ map.removeItem(key);
+ }
-/**
- * deletes the object from session map. It also frees up memory for the session object.
- *
- * @param key - key of the value to be deleted
- *
- */
-void removeValue(int key) {
- deleteValue(getValue(key));
- map.removeItem(key);
-}
+ /**
+ * decides if session is already created.
+ *
+ * @param key - key of the value for the session
+ *
+ * @return boolean result of whether session is created
+ */
+ bool isCreated(int key) {
+ Mutex::Autolock lock(mLock);
+ return isCreatedInternal(key);
+ }
-/**
- * decides if session is already created.
- *
- * @param key - key of the value for the session
- *
- * @return boolean result of whether session is created
- */
-bool isCreated(int key) {
- return (0 <= map.indexOfKey(key));
-}
+ SessionMap<TValue> & operator=(const SessionMap<TValue> & objectCopy) {
+ Mutex::Autolock lock(mLock);
-/**
- * empty the entire session table. It releases all the memory for session objects.
- */
-void destroyMap() {
- int size = map.size();
- int i = 0;
+ destroyMap();
+ map = objectCopy.map;
+ return *this;
+ }
- for (i = 0; i < size; i++) {
- deleteValue(map.valueAt(i));
+private:
+ KeyedVector<int, TValue> map;
+ Mutex mLock;
+
+ /**
+ * free up the memory for the session object.
+ * Make sure if any reference to the session object anywhere, otherwise it will be a
+ * dangle pointer after this call.
+ *
+ * @param value - session object to free
+ *
+ */
+ void deleteValue(TValue value) {
+ delete value;
}
- map.clear();
-}
+ /**
+ * free up the memory for the entire map.
+ * free up any resources in the sessions before calling this funtion.
+ *
+ */
+ void destroyMap() {
+ int size = map.size();
+
+ for (int i = 0; i < size; i++) {
+ deleteValue(map.valueAt(i));
+ }
+ map.clear();
+ }
-/**
- * free up the memory for the session object.
- * Make sure if any reference to the session object anywhere, otherwise it will be a
- * dangle pointer after this call.
- *
- * @param value - session object to free
- *
- */
-void deleteValue(NODE value) {
- delete value;
-}
+ /**
+ * decides if session is already created.
+ *
+ * @param key - key of the value for the session
+ *
+ * @return boolean result of whether session is created
+ */
+ bool isCreatedInternal(int key) {
+ return(0 <= map.indexOfKey(key));
+ }
+ /**
+ * returns the session object by the key
+ *
+ * @param key - key or Session ID
+ *
+ * @return session object as per the key
+ */
+ TValue getValueInternal(int key) {
+ TValue value = NULL;
+ if (isCreatedInternal(key)) {
+ value = (TValue) map.valueFor(key);
+ }
+ return value;
+ }
};
};
diff --git a/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp b/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
index 4ee903ef01d2..57ef7992fd04 100644
--- a/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
+++ b/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
@@ -22,6 +22,13 @@ namespace android {
#undef LOG_TAG
#define LOG_TAG "MimeTypeUtil"
+#ifdef DRM_OMA_FL_ENGINE_DEBUG
+#define LOG_NDEBUG 0
+#define LOG_DEBUG(...) LOGD(__VA_ARGS__)
+#else
+#define LOG_DEBUG(...)
+#endif
+
enum {
MIMETYPE_AUDIO = 0,
MIMETYPE_APPLICATION = 1,
@@ -59,6 +66,7 @@ static const char mime_group_audio[] = "audio/";
static const char mime_group_application[] = "application/";
static const char mime_group_image[] = "image/";
static const char mime_group_video[] = "video/";
+static const char mime_type_unsupported[] = "unsupported/drm.mimetype";
static struct MimeGroup mimeGroup[] = {
{MIMETYPE_AUDIO, mime_group_audio, sizeof(mime_group_audio)-1},
@@ -107,48 +115,52 @@ static struct MimeTypeList mimeTypeList[] = {
* replacement mimetype otherwise the original mimetype
* is returned.
*
+ * If the mimetype is of unsupported group i.e. application/*
+ * then "unsupported/drm.mimetype" will be returned.
+ *
* @param mimeType - mimetype in lower case to convert.
*
- * @return mimetype or null.
+ * @return mimetype or "unsupported/drm.mimetype".
*/
String8 MimeTypeUtil::convertMimeType(String8& mimeType) {
String8 result = mimeType;
- const char* pTmp;
const char* pMimeType;
struct MimeGroup* pGroup;
struct MimeTypeList* pMimeItem;
int len;
-
pMimeType = mimeType.string();
if (NULL != pMimeType) {
- /* Check which group the mimetype is */
- pGroup = mimeGroup;
-
- while (MIMETYPE_LAST != pGroup->type) {
- if (0 == strncmp(pMimeType, pGroup->pGroup, pGroup->size)) {
- break;
+ if ((0 == strncmp(pMimeType, mime_group_audio, (sizeof mime_group_audio) - 1)) ||
+ (0 == strncmp(pMimeType, mime_group_video, (sizeof mime_group_video) - 1))) {
+ /* Check which group the mimetype is */
+ pGroup = mimeGroup;
+ while (MIMETYPE_LAST != pGroup->type) {
+ if (0 == strncmp(pMimeType, pGroup->pGroup, pGroup->size)) {
+ break;
+ }
+ pGroup++;
}
- pGroup++;
- }
-
- /* Go through the mimetype list. Only check items of the correct group */
- if (MIMETYPE_LAST != pGroup->type) {
- pMimeItem = mimeTypeList;
- len = strlen (pMimeType+pGroup->size);
- while (MIMETYPE_LAST != pMimeItem->type) {
- if ((len == pMimeItem->size) &&
- (0 == strcmp(pMimeType+pGroup->size, pMimeItem->pMimeExt))) {
- result = String8(pMimeItem->pMimeType);
- break;
+ /* Go through the mimetype list. Only check items of the correct group */
+ if (MIMETYPE_LAST != pGroup->type) {
+ pMimeItem = mimeTypeList;
+ len = strlen (pMimeType+pGroup->size);
+ while (MIMETYPE_LAST != pMimeItem->type) {
+ if ((pGroup->type == pMimeItem->type) &&
+ (len == pMimeItem->size) &&
+ (0 == strcmp(pMimeType+pGroup->size, pMimeItem->pMimeExt))) {
+ result = String8(pMimeItem->pMimeType);
+ break;
+ }
+ pMimeItem++;
}
- pMimeItem++;
}
+ } else {
+ result = String8(mime_type_unsupported);
}
- LOGI("convertMimeType got mimetype %s, converted into mimetype %s",
- pMimeType, result.string());
+ LOG_DEBUG("convertMimeType got mimetype %s, converted into mimetype %s",
+ pMimeType, result.string());
}
-
return result;
}
};
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
index 9805a4094c06..e359dbd81fce 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
@@ -17,6 +17,9 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+# The flag below turns on local debug printouts
+#LOCAL_CFLAGS += -DDRM_OMA_FL_ENGINE_DEBUG
+
base := frameworks/base
# Determine whether the DRM framework uses 64-bit data types for file offsets and do the same.
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
index 31c3c1451e99..e1845454d361 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
@@ -41,6 +41,13 @@
#undef LOG_TAG
#define LOG_TAG "FwdLockEngine"
+#ifdef DRM_OMA_FL_ENGINE_DEBUG
+#define LOG_NDEBUG 0
+#define LOG_VERBOSE(...) LOGV(__VA_ARGS__)
+#else
+#define LOG_VERBOSE(...)
+#endif
+
using namespace android;
// This extern "C" is mandatory to be managed by TPlugInManager
extern "C" IDrmEngine* create() {
@@ -53,14 +60,25 @@ extern "C" void destroy(IDrmEngine* plugIn) {
}
FwdLockEngine::FwdLockEngine() {
- LOGV("FwdLockEngine Construction");
+ LOG_VERBOSE("FwdLockEngine Construction");
}
FwdLockEngine::~FwdLockEngine() {
- LOGV("FwdLockEngine Destruction");
+ LOG_VERBOSE("FwdLockEngine Destruction");
+
+ int size = decodeSessionMap.getSize();
- convertSessionMap.destroyMap();
- decodeSessionMap.destroyMap();
+ for (int i = 0; i < size; i++) {
+ DecodeSession *session = (DecodeSession*) decodeSessionMap.getValueAt(i);
+ FwdLockFile_detach(session->fileDesc);
+ ::close(session->fileDesc);
+ }
+
+ size = convertSessionMap.getSize();
+ for (int i = 0; i < size; i++) {
+ ConvertSession *convSession = (ConvertSession*) convertSessionMap.getValueAt(i);
+ FwdLockConv_CloseSession(convSession->uniqueId, &(convSession->output));
+ }
}
int FwdLockEngine::getConvertedStatus(FwdLockConv_Status_t status) {
@@ -74,12 +92,12 @@ int FwdLockEngine::getConvertedStatus(FwdLockConv_Status_t status) {
case FwdLockConv_Status_InvalidArgument:
case FwdLockConv_Status_UnsupportedFileFormat:
case FwdLockConv_Status_UnsupportedContentTransferEncoding:
- LOGD("FwdLockEngine getConvertedStatus: file conversion Error %d. " \
+ LOGE("FwdLockEngine getConvertedStatus: file conversion Error %d. "
"Returning STATUS_INPUTDATA_ERROR", status);
retStatus = DrmConvertedStatus::STATUS_INPUTDATA_ERROR;
break;
default:
- LOGD("FwdLockEngine getConvertedStatus: file conversion Error %d. " \
+ LOGE("FwdLockEngine getConvertedStatus: file conversion Error %d. "
"Returning STATUS_ERROR", status);
retStatus = DrmConvertedStatus::STATUS_ERROR;
break;
@@ -91,7 +109,7 @@ int FwdLockEngine::getConvertedStatus(FwdLockConv_Status_t status) {
DrmConstraints* FwdLockEngine::onGetConstraints(int uniqueId, const String8* path, int action) {
DrmConstraints* drmConstraints = NULL;
- LOGV("FwdLockEngine::onGetConstraints");
+ LOG_VERBOSE("FwdLockEngine::onGetConstraints");
if (NULL != path &&
(RightsStatus::RIGHTS_VALID == onCheckRightsStatus(uniqueId, *path, action))) {
@@ -105,7 +123,7 @@ DrmConstraints* FwdLockEngine::onGetConstraints(int uniqueId, const String8* pat
DrmMetadata* FwdLockEngine::onGetMetadata(int uniqueId, const String8* path) {
DrmMetadata* drmMetadata = NULL;
- LOGV("FwdLockEngine::onGetMetadata");
+ LOG_VERBOSE("FwdLockEngine::onGetMetadata");
if (NULL != path) {
// Returns empty metadata to show no error condition.
@@ -116,13 +134,12 @@ DrmMetadata* FwdLockEngine::onGetMetadata(int uniqueId, const String8* path) {
}
android::status_t FwdLockEngine::onInitialize(int uniqueId) {
- LOGV("FwdLockEngine::onInitialize");
-
+ LOG_VERBOSE("FwdLockEngine::onInitialize");
if (FwdLockGlue_InitializeKeyEncryption()) {
- LOGV("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption succeeded");
+ LOG_VERBOSE("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption succeeded");
} else {
- LOGD("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption failed:"
+ LOGE("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption failed:"
"errno = %d", errno);
}
@@ -132,13 +149,13 @@ android::status_t FwdLockEngine::onInitialize(int uniqueId) {
android::status_t
FwdLockEngine::onSetOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener) {
// Not used
- LOGV("FwdLockEngine::onSetOnInfoListener");
+ LOG_VERBOSE("FwdLockEngine::onSetOnInfoListener");
return DRM_NO_ERROR;
}
android::status_t FwdLockEngine::onTerminate(int uniqueId) {
- LOGV("FwdLockEngine::onTerminate");
+ LOG_VERBOSE("FwdLockEngine::onTerminate");
return DRM_NO_ERROR;
}
@@ -146,7 +163,7 @@ android::status_t FwdLockEngine::onTerminate(int uniqueId) {
DrmSupportInfo* FwdLockEngine::onGetSupportInfo(int uniqueId) {
DrmSupportInfo* pSupportInfo = new DrmSupportInfo();
- LOGV("FwdLockEngine::onGetSupportInfo");
+ LOG_VERBOSE("FwdLockEngine::onGetSupportInfo");
// fill all Forward Lock mimetypes and extensions
if (NULL != pSupportInfo) {
@@ -182,7 +199,7 @@ DrmInfoStatus* FwdLockEngine::onProcessDrmInfo(int uniqueId, const DrmInfo* drmI
drmInfoStatus = new DrmInfoStatus((int)DrmInfoStatus::STATUS_OK, 0, NULL, String8(""));
- LOGV("FwdLockEngine::onProcessDrmInfo");
+ LOG_VERBOSE("FwdLockEngine::onProcessDrmInfo");
return drmInfoStatus;
}
@@ -193,7 +210,7 @@ status_t FwdLockEngine::onSaveRights(
const String8& rightsPath,
const String8& contentPath) {
// No rights to save. Return
- LOGV("FwdLockEngine::onSaveRights");
+ LOG_VERBOSE("FwdLockEngine::onSaveRights");
return DRM_ERROR_UNKNOWN;
}
@@ -201,7 +218,7 @@ DrmInfo* FwdLockEngine::onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drm
DrmInfo* drmInfo = NULL;
// Nothing to be done for Forward Lock file
- LOGV("FwdLockEngine::onAcquireDrmInfo");
+ LOG_VERBOSE("FwdLockEngine::onAcquireDrmInfo");
return drmInfo;
}
@@ -211,7 +228,7 @@ int FwdLockEngine::onCheckRightsStatus(int uniqueId,
int action) {
int result = RightsStatus::RIGHTS_INVALID;
- LOGV("FwdLockEngine::onCheckRightsStatus");
+ LOG_VERBOSE("FwdLockEngine::onCheckRightsStatus");
// Only Transfer action is not allowed for forward Lock files.
if (onCanHandle(uniqueId, path)) {
@@ -241,7 +258,7 @@ status_t FwdLockEngine::onConsumeRights(int uniqueId,
int action,
bool reserve) {
// No rights consumption
- LOGV("FwdLockEngine::onConsumeRights");
+ LOG_VERBOSE("FwdLockEngine::onConsumeRights");
return DRM_NO_ERROR;
}
@@ -249,14 +266,14 @@ bool FwdLockEngine::onValidateAction(int uniqueId,
const String8& path,
int action,
const ActionDescription& description) {
- LOGV("FwdLockEngine::onValidateAction");
+ LOG_VERBOSE("FwdLockEngine::onValidateAction");
// For the forwardlock engine checkRights and ValidateAction are the same.
return (onCheckRightsStatus(uniqueId, path, action) == RightsStatus::RIGHTS_VALID);
}
String8 FwdLockEngine::onGetOriginalMimeType(int uniqueId, const String8& path) {
- LOGV("FwdLockEngine::onGetOriginalMimeType");
+ LOG_VERBOSE("FwdLockEngine::onGetOriginalMimeType");
String8 mimeString = String8("");
int fileDesc = FwdLockFile_open(path.string());
@@ -280,7 +297,7 @@ int FwdLockEngine::onGetDrmObjectType(int uniqueId,
const String8& mimeType) {
String8 mimeStr = String8(mimeType);
- LOGV("FwdLockEngine::onGetDrmObjectType");
+ LOG_VERBOSE("FwdLockEngine::onGetDrmObjectType");
mimeStr.toLower();
@@ -301,13 +318,13 @@ int FwdLockEngine::onGetDrmObjectType(int uniqueId,
status_t FwdLockEngine::onRemoveRights(int uniqueId, const String8& path) {
// No Rights to remove
- LOGV("FwdLockEngine::onRemoveRights");
+ LOG_VERBOSE("FwdLockEngine::onRemoveRights");
return DRM_NO_ERROR;
}
status_t FwdLockEngine::onRemoveAllRights(int uniqueId) {
// No rights to remove
- LOGV("FwdLockEngine::onRemoveAllRights");
+ LOG_VERBOSE("FwdLockEngine::onRemoveAllRights");
return DRM_NO_ERROR;
}
@@ -319,14 +336,14 @@ status_t FwdLockEngine::onSetPlaybackStatus(int uniqueId, DecryptHandle* decrypt
int playbackStatus, int position) {
#endif
// Not used
- LOGV("FwdLockEngine::onSetPlaybackStatus");
+ LOG_VERBOSE("FwdLockEngine::onSetPlaybackStatus");
return DRM_NO_ERROR;
}
status_t FwdLockEngine::onOpenConvertSession(int uniqueId,
int convertId) {
status_t result = DRM_ERROR_UNKNOWN;
- LOGV("FwdLockEngine::onOpenConvertSession");
+ LOG_VERBOSE("FwdLockEngine::onOpenConvertSession");
if (!convertSessionMap.isCreated(convertId)) {
ConvertSession *newSession = new ConvertSession();
if (FwdLockConv_Status_OK ==
@@ -334,7 +351,7 @@ status_t FwdLockEngine::onOpenConvertSession(int uniqueId,
convertSessionMap.addValue(convertId, newSession);
result = DRM_NO_ERROR;
} else {
- LOGD("FwdLockEngine::onOpenConvertSession -- FwdLockConv_OpenSession failed.");
+ LOGE("FwdLockEngine::onOpenConvertSession -- FwdLockConv_OpenSession failed.");
delete newSession;
}
}
@@ -383,7 +400,7 @@ DrmConvertedStatus* FwdLockEngine::onCloseConvertSession(int uniqueId,
DrmBuffer *convResult = new DrmBuffer(NULL, 0);
int offset = -1;
- LOGV("FwdLockEngine::onCloseConvertSession");
+ LOG_VERBOSE("FwdLockEngine::onCloseConvertSession");
if (convertSessionMap.isCreated(convertId)) {
ConvertSession *convSession = convertSessionMap.getValue(convertId);
@@ -424,14 +441,14 @@ status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
status_t result = DRM_ERROR_CANNOT_HANDLE;
int fileDesc = -1;
- LOGV("FwdLockEngine::onOpenDecryptSession");
+ LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession");
if ((-1 < fd) &&
(NULL != decryptHandle) &&
(!decodeSessionMap.isCreated(decryptHandle->decryptId))) {
fileDesc = dup(fd);
} else {
- LOGD("FwdLockEngine::onOpenDecryptSession parameter error");
+ LOGE("FwdLockEngine::onOpenDecryptSession parameter error");
return result;
}
@@ -453,7 +470,7 @@ status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
decryptHandle->decryptInfo = NULL;
result = DRM_NO_ERROR;
} else {
- LOGD("FwdLockEngine::onOpenDecryptSession Integrity Check failed for the fd");
+ LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession Integrity Check failed for the fd");
FwdLockFile_detach(fileDesc);
delete decodeSession;
}
@@ -463,7 +480,7 @@ status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
::close(fileDesc);
}
- LOGV("FwdLockEngine::onOpenDecryptSession Exit. result = %d", result);
+ LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession Exit. result = %d", result);
return result;
}
@@ -500,7 +517,7 @@ status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
status_t FwdLockEngine::onCloseDecryptSession(int uniqueId,
DecryptHandle* decryptHandle) {
status_t result = DRM_ERROR_UNKNOWN;
- LOGV("FwdLockEngine::onCloseDecryptSession");
+ LOG_VERBOSE("FwdLockEngine::onCloseDecryptSession");
if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
@@ -525,7 +542,7 @@ status_t FwdLockEngine::onCloseDecryptSession(int uniqueId,
decryptHandle = NULL;
}
- LOGV("FwdLockEngine::onCloseDecryptSession Exit");
+ LOG_VERBOSE("FwdLockEngine::onCloseDecryptSession Exit");
return result;
}
@@ -533,13 +550,13 @@ status_t FwdLockEngine::onInitializeDecryptUnit(int uniqueId,
DecryptHandle* decryptHandle,
int decryptUnitId,
const DrmBuffer* headerInfo) {
- LOGV("FwdLockEngine::onInitializeDecryptUnit");
+ LOGE("FwdLockEngine::onInitializeDecryptUnit is not supported for this DRM scheme");
return DRM_ERROR_UNKNOWN;
}
status_t FwdLockEngine::onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
- LOGV("FwdLockEngine::onDecrypt");
+ LOGE("FwdLockEngine::onDecrypt is not supported for this DRM scheme");
return DRM_ERROR_UNKNOWN;
}
@@ -548,14 +565,14 @@ status_t FwdLockEngine::onDecrypt(int uniqueId,
int decryptUnitId,
const DrmBuffer* encBuffer,
DrmBuffer** decBuffer) {
- LOGV("FwdLockEngine::onDecrypt");
+ LOGE("FwdLockEngine::onDecrypt is not supported for this DRM scheme");
return DRM_ERROR_UNKNOWN;
}
status_t FwdLockEngine::onFinalizeDecryptUnit(int uniqueId,
DecryptHandle* decryptHandle,
int decryptUnitId) {
- LOGV("FwdLockEngine::onFinalizeDecryptUnit");
+ LOGE("FwdLockEngine::onFinalizeDecryptUnit is not supported for this DRM scheme");
return DRM_ERROR_UNKNOWN;
}
@@ -633,11 +650,11 @@ ssize_t FwdLockEngine::onPread(int uniqueId,
if (((off_t)-1) != decoderSession->offset) {
bytesRead = onRead(uniqueId, decryptHandle, buffer, numBytes);
if (bytesRead < 0) {
- LOGD("FwdLockEngine::onPread error reading");
+ LOGE("FwdLockEngine::onPread error reading");
}
}
} else {
- LOGD("FwdLockEngine::onPread decryptId not found");
+ LOGE("FwdLockEngine::onPread decryptId not found");
}
return bytesRead;
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c
index 14ea9e909fd2..299116deb469 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c
@@ -275,17 +275,18 @@ static int FwdLockConv_DeriveKeys(FwdLockConv_Session_t *pSession) {
}
/**
- * Checks whether a given character is valid in a boundary. Note that the boundary may contain
- * leading and internal spaces.
+ * Checks whether a given character is valid in a boundary. Allows some non-standard characters that
+ * are invalid according to RFC 2046 but nevertheless used by one vendor's DRM packager. Note that
+ * the boundary may contain leading and internal spaces.
*
* @param[in] ch The character to check.
*
* @return A Boolean value indicating whether the given character is valid in a boundary.
*/
static int FwdLockConv_IsBoundaryChar(int ch) {
- return isalnum(ch) || ch == '\'' ||
- ch == '(' || ch == ')' || ch == '+' || ch == '_' || ch == ',' || ch == '-' ||
- ch == '.' || ch == '/' || ch == ':' || ch == '=' || ch == '?' || ch == ' ';
+ return isalnum(ch) || ch == '\'' || ch == '(' || ch == ')' || ch == '+' || ch == '_' ||
+ ch == ',' || ch == '-' || ch == '.' || ch == '/' || ch == ':' || ch == '=' ||
+ ch == '?' || ch == ' ' || ch == '%' || ch == '[' || ch == '&' || ch == '*' || ch == '^';
}
/**
@@ -1085,6 +1086,13 @@ static FwdLockConv_Status_t FwdLockConv_PushChar(FwdLockConv_Session_t *pSession
status = FwdLockConv_MatchBinaryEncodedData(pSession, ch, pOutput);
break;
case FwdLockConv_ParserState_WantsBase64EncodedData:
+ if (ch == '\n' && pSession->scannerState != FwdLockConv_ScannerState_WantsLF) {
+ // Repair base64-encoded data that doesn't have carriage returns in its line breaks.
+ status = FwdLockConv_MatchBase64EncodedData(pSession, '\r', pOutput);
+ if (status != FwdLockConv_Status_OK) {
+ break;
+ }
+ }
status = FwdLockConv_MatchBase64EncodedData(pSession, ch, pOutput);
break;
case FwdLockConv_ParserState_Done:
@@ -1199,7 +1207,7 @@ FwdLockConv_Status_t FwdLockConv_CloseSession(int sessionId, FwdLockConv_Output_
status = FwdLockConv_Status_SyntaxError;
} else {
// Finalize the data signature.
- size_t signatureSize;
+ unsigned int signatureSize = SHA1_HASH_SIZE;
HMAC_Final(&pSession->signingContext, pOutput->fromCloseSession.signatures,
&signatureSize);
if (signatureSize != SHA1_HASH_SIZE) {
@@ -1214,9 +1222,9 @@ FwdLockConv_Status_t FwdLockConv_CloseSession(int sessionId, FwdLockConv_Output_
HMAC_Update(&pSession->signingContext, pSession->pEncryptedSessionKey,
pSession->encryptedSessionKeyLength);
HMAC_Update(&pSession->signingContext, pOutput->fromCloseSession.signatures,
- signatureSize);
- HMAC_Final(&pSession->signingContext, &pOutput->fromCloseSession.
- signatures[signatureSize], &signatureSize);
+ SHA1_HASH_SIZE);
+ HMAC_Final(&pSession->signingContext,
+ &pOutput->fromCloseSession.signatures[SHA1_HASH_SIZE], &signatureSize);
if (signatureSize != SHA1_HASH_SIZE) {
status = FwdLockConv_Status_ProgramError;
} else {
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c
index 98284e722571..dacf00efaf13 100644
--- a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c
@@ -114,7 +114,7 @@ static int FwdLockFile_AcquireSession(int fileDesc) {
}
/**
- * Finds the file session associated to the given file descriptor.
+ * Finds the file session associated with the given file descriptor.
*
* @param[in] fileDesc A file descriptor.
*
@@ -389,7 +389,7 @@ int FwdLockFile_CheckDataIntegrity(int fileDesc) {
result = FALSE;
} else {
ssize_t numBytesRead;
- size_t signatureSize = SHA1_HASH_SIZE;
+ unsigned int signatureSize = SHA1_HASH_SIZE;
while ((numBytesRead =
read(pSession->fileDesc, pData->buffer, SIG_CALC_BUFFER_SIZE)) > 0) {
HMAC_Update(&pSession->signingContext, pData->buffer, (size_t)numBytesRead);
@@ -399,7 +399,7 @@ int FwdLockFile_CheckDataIntegrity(int fileDesc) {
} else {
HMAC_Final(&pSession->signingContext, pData->signature, &signatureSize);
assert(signatureSize == SHA1_HASH_SIZE);
- result = memcmp(pData->signature, pSession->dataSignature, signatureSize) == 0;
+ result = memcmp(pData->signature, pSession->dataSignature, SHA1_HASH_SIZE) == 0;
}
HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL);
(void)lseek64(pSession->fileDesc, pSession->dataOffset + pSession->filePos,
@@ -419,16 +419,16 @@ int FwdLockFile_CheckHeaderIntegrity(int fileDesc) {
} else {
FwdLockFile_Session_t *pSession = sessionPtrs[sessionId];
unsigned char signature[SHA1_HASH_SIZE];
- size_t signatureSize = SHA1_HASH_SIZE;
+ unsigned int signatureSize = SHA1_HASH_SIZE;
HMAC_Update(&pSession->signingContext, pSession->topHeader, TOP_HEADER_SIZE);
HMAC_Update(&pSession->signingContext, (unsigned char *)pSession->pContentType,
pSession->contentTypeLength);
HMAC_Update(&pSession->signingContext, pSession->pEncryptedSessionKey,
pSession->encryptedSessionKeyLength);
- HMAC_Update(&pSession->signingContext, pSession->dataSignature, signatureSize);
+ HMAC_Update(&pSession->signingContext, pSession->dataSignature, SHA1_HASH_SIZE);
HMAC_Final(&pSession->signingContext, signature, &signatureSize);
assert(signatureSize == SHA1_HASH_SIZE);
- result = memcmp(signature, pSession->headerSignature, signatureSize) == 0;
+ result = memcmp(signature, pSession->headerSignature, SHA1_HASH_SIZE) == 0;
HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL);
}
return result;
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index b8e9384c1de8..7269a71d91c0 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -84,9 +84,19 @@ public class ImageFormat {
public static final int JPEG = 0x100;
/**
+ * Raw bayer format used for images, which is 10 bit precision samples
+ * stored in 16 bit words. The filter pattern is RGGB. Whether this format
+ * is supported by the camera hardware can be determined by
+ * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}.
+ *
+ * @hide
+ */
+ public static final int BAYER_RGGB = 0x200;
+
+ /**
* Use this function to retrieve the number of bits per pixel of an
* ImageFormat.
- *
+ *
* @param format
* @return the number of bits per pixel of the given format or -1 if the
* format doesn't exist or is not supported.
@@ -103,6 +113,8 @@ public class ImageFormat {
return 12;
case NV21:
return 12;
+ case BAYER_RGGB:
+ return 16;
}
return -1;
}
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 48483fda548e..b6614965b0f5 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -573,6 +573,9 @@ public:
static const char PIXEL_FORMAT_RGB565[];
static const char PIXEL_FORMAT_RGBA8888[];
static const char PIXEL_FORMAT_JPEG[];
+ // Raw bayer format used for images, which is 10 bit precision samples
+ // stored in 16 bit words. The filter pattern is RGGB.
+ static const char PIXEL_FORMAT_BAYER_RGGB[];
// Values for focus mode settings.
// Auto-focus mode. Applications should call
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index c1c4f9498ad3..3d79596f3f46 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -25,6 +25,7 @@
namespace android {
+struct ABuffer;
class GraphicBuffer;
class MediaBuffer;
class MediaBufferObserver;
@@ -51,6 +52,8 @@ public:
MediaBuffer(const sp<GraphicBuffer>& graphicBuffer);
+ MediaBuffer(const sp<ABuffer> &buffer);
+
// Decrements the reference count and returns the buffer to its
// associated MediaBufferGroup if the reference count drops to 0.
void release();
@@ -100,6 +103,7 @@ private:
void *mData;
size_t mSize, mRangeOffset, mRangeLength;
sp<GraphicBuffer> mGraphicBuffer;
+ sp<ABuffer> mBuffer;
bool mOwnsData;
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 251615d5f026..51b96c1fe9dd 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -151,6 +151,7 @@ const char CameraParameters::PIXEL_FORMAT_YUV420P[] = "yuv420p";
const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565";
const char CameraParameters::PIXEL_FORMAT_RGBA8888[] = "rgba8888";
const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg";
+const char CameraParameters::PIXEL_FORMAT_BAYER_RGGB[] = "bayer-rggb";
// Values for focus mode settings.
const char CameraParameters::FOCUS_MODE_AUTO[] = "auto";
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 731d1f38e75d..e7a306b78028 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1802,36 +1802,20 @@ public class AudioManager {
/**
* @hide
- * FIXME to be changed to address Neel's comments
- * Force a refresh of the remote control client associated with the event receiver.
+ * Notifies the users of the associated remote control client that the information to display
+ * has changed.
* @param eventReceiver
*/
- public void refreshRemoteControlDisplay(ComponentName eventReceiver) {
+ public void notifyRemoteControlInformationChanged(ComponentName eventReceiver) {
IAudioService service = getService();
try {
- service.refreshRemoteControlDisplay(eventReceiver);
+ service.notifyRemoteControlInformationChanged(eventReceiver);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in refreshRemoteControlDisplay"+e);
}
}
/**
- * @hide
- * FIXME API to be used by implementors of remote controls, not a candidate for SDK
- */
- public void registerRemoteControlObserver() {
-
- }
-
- /**
- * @hide
- * FIXME API to be used by implementors of remote controls, not a candidate for SDK
- */
- public void unregisterRemoteControlObserver() {
-
- }
-
- /**
* @hide
* Reload audio settings. This method is called by Settings backup
* agent when audio settings are restored and causes the AudioService
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index cd55b0e9c2f1..bf1585dceed3 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -3200,8 +3200,8 @@ public class AudioService extends IAudioService.Stub {
}
}
- /** see AudioManager.refreshRemoteControlDisplay(ComponentName er) */
- public void refreshRemoteControlDisplay(ComponentName eventReceiver) {
+ /** see AudioManager.notifyRemoteControlInformationChanged(ComponentName er) */
+ public void notifyRemoteControlInformationChanged(ComponentName eventReceiver) {
synchronized(mAudioFocusLock) {
synchronized(mRCStack) {
// only refresh if the eventReceiver is at the top of the stack
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 1a05f15248b7..9afe55326e68 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -93,7 +93,7 @@ interface IAudioService {
void registerRemoteControlClient(in ComponentName eventReceiver,
in IRemoteControlClient rcClient, in String callingPackageName);
- void refreshRemoteControlDisplay(in ComponentName eventReceiver);
+ void notifyRemoteControlInformationChanged(in ComponentName eventReceiver);
void startBluetoothSco(IBinder cb);
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index a8fadf2c3a8f..0b14f1ecfbf6 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -21,6 +21,7 @@
#include <pthread.h>
#include <stdlib.h>
+#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
@@ -70,6 +71,20 @@ MediaBuffer::MediaBuffer(const sp<GraphicBuffer>& graphicBuffer)
mOriginal(NULL) {
}
+MediaBuffer::MediaBuffer(const sp<ABuffer> &buffer)
+ : mObserver(NULL),
+ mNextBuffer(NULL),
+ mRefCount(0),
+ mData(buffer->data()),
+ mSize(buffer->size()),
+ mRangeOffset(0),
+ mRangeLength(mSize),
+ mBuffer(buffer),
+ mOwnsData(false),
+ mMetaData(new MetaData),
+ mOriginal(NULL) {
+}
+
void MediaBuffer::release() {
if (mObserver == NULL) {
CHECK_EQ(mRefCount, 0);
diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
index 07a9eb892c5d..887fe7c4e4e6 100644
--- a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
+++ b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
@@ -47,6 +47,8 @@ ChromiumHTTPDataSource::~ChromiumHTTPDataSource() {
delete mDelegate;
mDelegate = NULL;
+ clearDRMState_l();
+
if (mDrmManagerClient != NULL) {
delete mDrmManagerClient;
mDrmManagerClient = NULL;
@@ -116,8 +118,6 @@ void ChromiumHTTPDataSource::onConnectionFailed(status_t err) {
// mURI.clear();
mIOResult = err;
-
- clearDRMState_l();
}
void ChromiumHTTPDataSource::disconnect() {
@@ -251,8 +251,6 @@ void ChromiumHTTPDataSource::onDisconnectComplete() {
// mURI.clear();
mCondition.broadcast();
-
- clearDRMState_l();
}
sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization() {
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
index eb10ab76b582..26c3eda8b058 100644
--- a/media/libstagefright/chromium_http/support.cpp
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -183,19 +183,19 @@ void SfDelegate::setOwner(ChromiumHTTPDataSource *owner) {
void SfDelegate::OnReceivedRedirect(
net::URLRequest *request, const GURL &new_url, bool *defer_redirect) {
- MY_LOGI("OnReceivedRedirect");
+ MY_LOGV("OnReceivedRedirect");
}
void SfDelegate::OnAuthRequired(
net::URLRequest *request, net::AuthChallengeInfo *auth_info) {
- MY_LOGI("OnAuthRequired");
+ MY_LOGV("OnAuthRequired");
inherited::OnAuthRequired(request, auth_info);
}
void SfDelegate::OnCertificateRequested(
net::URLRequest *request, net::SSLCertRequestInfo *cert_request_info) {
- MY_LOGI("OnCertificateRequested");
+ MY_LOGV("OnCertificateRequested");
inherited::OnCertificateRequested(request, cert_request_info);
}
@@ -208,7 +208,7 @@ void SfDelegate::OnSSLCertificateError(
}
void SfDelegate::OnGetCookies(net::URLRequest *request, bool blocked_by_policy) {
- MY_LOGI("OnGetCookies");
+ MY_LOGV("OnGetCookies");
}
void SfDelegate::OnSetCookie(
@@ -216,7 +216,7 @@ void SfDelegate::OnSetCookie(
const std::string &cookie_line,
const net::CookieOptions &options,
bool blocked_by_policy) {
- MY_LOGI("OnSetCookie");
+ MY_LOGV("OnSetCookie");
}
void SfDelegate::OnResponseStarted(net::URLRequest *request) {
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 2578d2dbd2a5..f67cdace819c 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -617,23 +617,32 @@ rinse_repeat:
goto rinse_repeat;
}
- if (!mPlaylist->isComplete()
- && mSeqNumber > lastSeqNumberInPlaylist
- && mNumRetries < kMaxNumRetries) {
+ if (!mPlaylist->isComplete() && mNumRetries < kMaxNumRetries) {
++mNumRetries;
- mLastPlaylistFetchTimeUs = -1;
- postMonitorQueue(3000000ll);
- return;
- }
+ if (mSeqNumber > lastSeqNumberInPlaylist) {
+ mLastPlaylistFetchTimeUs = -1;
+ postMonitorQueue(3000000ll);
+ return;
+ }
- LOGE("Cannot find sequence number %d in playlist "
- "(contains %d - %d)",
- mSeqNumber, firstSeqNumberInPlaylist,
- firstSeqNumberInPlaylist + mPlaylist->size() - 1);
+ // we've missed the boat, let's start from the lowest sequence
+ // number available and signal a discontinuity.
- mDataSource->queueEOS(ERROR_END_OF_STREAM);
- return;
+ LOGI("We've missed the boat, restarting playback.");
+ mSeqNumber = lastSeqNumberInPlaylist;
+ explicitDiscontinuity = true;
+
+ // fall through
+ } else {
+ LOGE("Cannot find sequence number %d in playlist "
+ "(contains %d - %d)",
+ mSeqNumber, firstSeqNumberInPlaylist,
+ firstSeqNumberInPlaylist + mPlaylist->size() - 1);
+
+ mDataSource->queueEOS(ERROR_END_OF_STREAM);
+ return;
+ }
}
mNumRetries = 0;
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 59de17eb7bf5..2e66a2cf1d5f 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -105,12 +105,10 @@ status_t AnotherPacketSource::read(
int64_t timeUs;
CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
- mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+ MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
- // hexdump(buffer->data(), buffer->size());
+ mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
- memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
*out = mediaBuffer;
return OK;
}
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index a02591f70941..4ecb92f02c5f 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -628,14 +628,12 @@ status_t APacketSource::read(
updateNormalPlayTime_l(buffer);
- MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
-
int64_t timeUs;
CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
+ MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
- memcpy(mediaBuffer->data(), buffer->data(), buffer->size());
*out = mediaBuffer;
mBuffers.erase(mBuffers.begin());
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 7bb8277ffb48..25eab26af403 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1873,7 +1873,7 @@ public class PhoneStatusBar extends StatusBar {
}
void updateExpandedSize() {
- if (mExpandedDialog != null) {
+ if (mExpandedDialog != null && mExpandedParams != null) {
mExpandedParams.width = mDisplaySize.x;
mExpandedParams.height = getExpandedHeight(mDisplaySize.y);
if (!mExpandedVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index f32c6021386f..97b629870c1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -61,6 +61,7 @@ public class NetworkController extends BroadcastReceiver {
// debug
static final String TAG = "StatusBar.NetworkController";
static final boolean DEBUG = false;
+ static final boolean CHATTY = true; // additional diagnostics, but not logspew
// telephony
boolean mHspaDataDistinguishable;
@@ -286,7 +287,7 @@ public class NetworkController extends BroadcastReceiver {
@Override
public void onDataConnectionStateChanged(int state, int networkType) {
- if (DEBUG) {
+ if (DEBUG || CHATTY) {
Slog.d(TAG, "onDataConnectionStateChanged: state=" + state
+ " type=" + networkType);
}
@@ -682,10 +683,19 @@ public class NetworkController extends BroadcastReceiver {
// ===== Full or limited Internet connectivity ==================================
private void updateConnectivity(Intent intent) {
+ if (CHATTY) {
+ Slog.d(TAG, "updateConnectivity: intent=" + intent);
+ }
+
NetworkInfo info = (NetworkInfo)(intent.getParcelableExtra(
ConnectivityManager.EXTRA_NETWORK_INFO));
int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
+ if (CHATTY) {
+ Slog.d(TAG, "updateConnectivity: networkInfo=" + info);
+ Slog.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
+ }
+
int inetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
switch (info.getType()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index dc7e3137386c..c7b6f2094ac8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -1606,6 +1606,10 @@ public class TabletStatusBar extends StatusBar implements
}
return;
+ } else if (0 != (mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) {
+ // if icons are disabled but we're not in DND mode, this is probably Setup and we should
+ // just leave the area totally empty
+ return;
}
int N = mNotificationData.size();
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index bd5f739945b7..8e062b7870d2 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -5,7 +5,6 @@
<application android:label="VpnDialogs"
android:allowBackup="false" >
<activity android:name=".ConfirmDialog"
- android:permission="android.permission.VPN"
android:theme="@style/transparent">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 40c0a02e7912..d668e98f0f27 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -79,7 +79,7 @@ public class ManageDialog extends Activity implements Handler.Callback,
mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted);
mDataReceived = (TextView) view.findViewById(R.id.data_received);
- if (mConfig.packagz.equals(VpnConfig.LEGACY_VPN)) {
+ if (mConfig.user.equals(VpnConfig.LEGACY_VPN)) {
mDialog = new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_info)
.setTitle(R.string.legacy_title)
@@ -89,7 +89,7 @@ public class ManageDialog extends Activity implements Handler.Callback,
.create();
} else {
PackageManager pm = getPackageManager();
- ApplicationInfo app = pm.getApplicationInfo(mConfig.packagz, 0);
+ ApplicationInfo app = pm.getApplicationInfo(mConfig.user, 0);
mDialog = new AlertDialog.Builder(this)
.setIcon(app.loadIcon(pm))
.setTitle(app.loadLabel(pm))
@@ -131,7 +131,7 @@ public class ManageDialog extends Activity implements Handler.Callback,
if (which == AlertDialog.BUTTON_POSITIVE) {
mConfig.configureIntent.send();
} else if (which == AlertDialog.BUTTON_NEUTRAL) {
- mService.prepareVpn(mConfig.packagz, VpnConfig.LEGACY_VPN);
+ mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
}
} catch (Exception e) {
Log.e(TAG, "onClick", e);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index bdc37ef4a570..a2dbb788623a 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3018,7 +3018,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- Runnable mScreenSaverActivator = new Runnable() {
+ Runnable mScreenSaverActivator = null;
+ /*new Runnable() {
public void run() {
synchronized (this) {
if (!(mScreenSaverEnabled && mScreenOn)) {
@@ -3049,9 +3050,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
};
+ */
// Must call while holding mLock
private void updateScreenSaverTimeoutLocked() {
+ if (mScreenSaverActivator == null) return;
+
synchronized (mScreenSaverActivator) {
mHandler.removeCallbacks(mScreenSaverActivator);
if (mScreenSaverEnabled && mScreenOn && mScreenSaverTimeout > 0) {
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index a59b6c07f356..30de385f305a 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -1231,6 +1231,13 @@ class NetworkManagementService extends INetworkManagementService.Stub {
}
}
+ @Override
+ public boolean isBandwidthControlEnabled() {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+ return mBandwidthControlEnabled;
+ }
+
+ @Override
public NetworkStats getNetworkStatsUidDetail(int uid) {
if (Binder.getCallingUid() != uid) {
mContext.enforceCallingOrSelfPermission(
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f15eca67d70d..4a0dcdfd3b68 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -27,6 +27,7 @@ import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.res.Configuration;
import android.media.AudioService;
+import android.net.wifi.p2p.WifiP2pService;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -37,7 +38,6 @@ import android.provider.Settings;
import android.server.BluetoothA2dpService;
import android.server.BluetoothService;
import android.server.search.SearchManagerService;
-import android.server.WifiP2pService;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Slog;
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index ecbad09909d0..b69cc31c1d26 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -54,7 +54,6 @@ import java.util.Arrays;
public class Vpn extends INetworkManagementEventObserver.Stub {
private final static String TAG = "Vpn";
- private final static String VPN = android.Manifest.permission.VPN;
private final Context mContext;
private final VpnCallback mCallback;
@@ -69,18 +68,6 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
}
/**
- * Protect a socket from routing changes by binding it to the given
- * interface. The socket is NOT closed by this method.
- *
- * @param socket The socket to be bound.
- * @param name The name of the interface.
- */
- public void protect(ParcelFileDescriptor socket, String interfaze) {
- mContext.enforceCallingPermission(VPN, "protect");
- jniProtect(socket.getFd(), interfaze);
- }
-
- /**
* Prepare for a VPN application. This method is designed to solve
* race conditions. It first compares the current prepared package
* with {@code oldPackage}. If they are the same, the prepared
@@ -115,13 +102,6 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
throw new SecurityException("Unauthorized Caller");
}
- // Check the permission of the given package.
- PackageManager pm = mContext.getPackageManager();
- if (!newPackage.equals(VpnConfig.LEGACY_VPN) &&
- pm.checkPermission(VPN, newPackage) != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(newPackage + " does not have " + VPN);
- }
-
// Reset the interface and hide the notification.
if (mInterface != null) {
jniReset(mInterface);
@@ -130,12 +110,9 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
mInterface = null;
}
- // Send out the broadcast or stop LegacyVpnRunner.
+ // Revoke the connection or stop LegacyVpnRunner.
if (!mPackage.equals(VpnConfig.LEGACY_VPN)) {
- Intent intent = new Intent(VpnConfig.ACTION_VPN_REVOKED);
- intent.setPackage(mPackage);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mContext.sendBroadcast(intent);
+ // TODO
} else if (mLegacyVpnRunner != null) {
mLegacyVpnRunner.exit();
mLegacyVpnRunner = null;
@@ -147,6 +124,22 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
}
/**
+ * Protect a socket from routing changes by binding it to the given
+ * interface. The socket is NOT closed by this method.
+ *
+ * @param socket The socket to be bound.
+ * @param name The name of the interface.
+ */
+ public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
+ PackageManager pm = mContext.getPackageManager();
+ ApplicationInfo app = pm.getApplicationInfo(mPackage, 0);
+ if (Binder.getCallingUid() != app.uid) {
+ throw new SecurityException("Unauthorized Caller");
+ }
+ jniProtect(socket.getFd(), interfaze);
+ }
+
+ /**
* Establish a VPN network and return the file descriptor of the VPN
* interface. This methods returns {@code null} if the application is
* revoked or not prepared.
@@ -155,9 +148,6 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
* @return The file descriptor of the VPN interface.
*/
public synchronized ParcelFileDescriptor establish(VpnConfig config) {
- // Check the permission of the caller.
- mContext.enforceCallingPermission(VPN, "establish");
-
// Check if the caller is already prepared.
PackageManager pm = mContext.getPackageManager();
ApplicationInfo app = null;
@@ -170,6 +160,9 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
return null;
}
+ // Check if the service is properly declared.
+ // TODO
+
// Load the label.
String label = app.loadLabel(pm).toString();
@@ -198,6 +191,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
if (config.routes != null) {
jniSetRoutes(interfaze, config.routes);
}
+ // TODO: bind the service
if (mInterface != null && !mInterface.equals(interfaze)) {
jniReset(mInterface);
}
@@ -211,23 +205,25 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
throw e;
}
- // Override DNS servers and search domains.
- mCallback.override(config.dnsServers, config.searchDomains);
-
// Fill more values.
- config.packagz = mPackage;
+ config.user = mPackage;
config.interfaze = mInterface;
- // Show the notification!
+ // Override DNS servers and show the notification.
+ long identity = Binder.clearCallingIdentity();
+ mCallback.override(config.dnsServers, config.searchDomains);
showNotification(config, label, bitmap);
+ Binder.restoreCallingIdentity(identity);
return tun;
}
// INetworkManagementEventObserver.Stub
+ @Override
public void interfaceAdded(String interfaze) {
}
// INetworkManagementEventObserver.Stub
+ @Override
public synchronized void interfaceStatusChanged(String interfaze, boolean up) {
if (!up && mLegacyVpnRunner != null) {
mLegacyVpnRunner.check(interfaze);
@@ -235,22 +231,28 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
}
// INetworkManagementEventObserver.Stub
- public synchronized void interfaceLinkStateChanged(String interfaze, boolean up) {
- if (!up && mLegacyVpnRunner != null) {
- mLegacyVpnRunner.check(interfaze);
- }
+ @Override
+ public void interfaceLinkStateChanged(String interfaze, boolean up) {
+ interfaceStatusChanged(interfaze, up);
}
// INetworkManagementEventObserver.Stub
+ @Override
public synchronized void interfaceRemoved(String interfaze) {
if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
+ long identity = Binder.clearCallingIdentity();
mCallback.restore();
hideNotification();
+ Binder.restoreCallingIdentity(identity);
mInterface = null;
+ // TODO: unbind the service
}
}
- public void limitReached(String limitName, String iface) {}
+ // INetworkManagementEventObserver.Stub
+ @Override
+ public void limitReached(String limit, String interfaze) {
+ }
private void showNotification(VpnConfig config, String label, Bitmap icon) {
NotificationManager nm = (NotificationManager)
@@ -263,7 +265,6 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
mContext.getString(R.string.vpn_text_long, config.session);
config.startTime = SystemClock.elapsedRealtime();
- long identity = Binder.clearCallingIdentity();
Notification notification = new Notification.Builder(mContext)
.setSmallIcon(R.drawable.vpn_connected)
.setLargeIcon(icon)
@@ -274,7 +275,6 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
.setOngoing(true)
.getNotification();
nm.notify(R.drawable.vpn_connected, notification);
- Binder.restoreCallingIdentity(identity);
}
}
@@ -283,9 +283,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
if (nm != null) {
- long identity = Binder.clearCallingIdentity();
nm.cancel(R.drawable.vpn_connected);
- Binder.restoreCallingIdentity(identity);
}
}
@@ -355,8 +353,8 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
mOuterInterface = mConfig.interfaze;
// Legacy VPN is not a real package, so we use it to carry the key.
- mInfo.key = mConfig.packagz;
- mConfig.packagz = VpnConfig.LEGACY_VPN;
+ mInfo.key = mConfig.user;
+ mConfig.user = VpnConfig.LEGACY_VPN;
}
public void check(String interfaze) {
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index b79e31fad9c0..0ce5499a1e0b 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -22,6 +22,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.Cursor;
import android.location.Criteria;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
@@ -32,6 +33,7 @@ import android.location.LocationManager;
import android.location.LocationProvider;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
+import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -45,6 +47,7 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.WorkSource;
import android.provider.Settings;
+import android.provider.Telephony.Carriers;
import android.provider.Telephony.Sms.Intents;
import android.telephony.SmsMessage;
import android.telephony.TelephonyManager;
@@ -489,8 +492,17 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
if (info != null) {
+ boolean dataEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.MOBILE_DATA, 1) == 1;
+ boolean networkAvailable = info.isAvailable() && dataEnabled;
+ String defaultApn = getSelectedApn();
+ if (defaultApn == null) {
+ defaultApn = "dummy-apn";
+ }
+
native_update_network_state(info.isConnected(), info.getType(),
- info.isRoaming(), info.getExtraInfo());
+ info.isRoaming(), networkAvailable,
+ info.getExtraInfo(), defaultApn);
}
if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL
@@ -1597,6 +1609,25 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
}
+ private String getSelectedApn() {
+ Uri uri = Uri.parse("content://telephony/carriers/preferapn");
+ String apn = null;
+
+ Cursor cursor = mContext.getContentResolver().query(uri, new String[] {"apn"},
+ null, null, Carriers.DEFAULT_SORT_ORDER);
+
+ if (null != cursor) {
+ try {
+ if (cursor.moveToFirst()) {
+ apn = cursor.getString(0);
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ return apn;
+ }
+
// for GPS SV statistics
private static final int MAX_SVS = 32;
private static final int EPHEMERIS_MASK = 0;
@@ -1655,5 +1686,5 @@ public class GpsLocationProvider implements LocationProviderInterface {
private native void native_agps_set_id(int type, String setid);
private native void native_update_network_state(boolean connected, int type,
- boolean roaming, String extraInfo);
+ boolean roaming, boolean available, String extraInfo, String defaultAPN);
}
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 24188cab76b6..deca7a91cfa4 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -16,10 +16,10 @@
package com.android.server.net;
-import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
-import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING;
+import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.content.Intent.ACTION_SHUTDOWN;
import static android.content.Intent.ACTION_UID_REMOVED;
@@ -68,7 +68,6 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
import android.telephony.TelephonyManager;
-import android.util.Log;
import android.util.LongSparseArray;
import android.util.NtpTrustedTime;
import android.util.Slog;
@@ -282,13 +281,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@Override
- public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template) {
+ public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
synchronized (mStatsLock) {
// combine all interfaces that match template
final NetworkStatsHistory combined = new NetworkStatsHistory(
- mSettings.getNetworkBucketDuration(), estimateNetworkBuckets());
+ mSettings.getNetworkBucketDuration(), estimateNetworkBuckets(), fields);
for (NetworkIdentitySet ident : mNetworkStats.keySet()) {
if (templateMatches(template, ident)) {
final NetworkStatsHistory history = mNetworkStats.get(ident);
@@ -302,7 +301,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@Override
- public NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid, int tag) {
+ public NetworkStatsHistory getHistoryForUid(
+ NetworkTemplate template, int uid, int tag, int fields) {
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
synchronized (mStatsLock) {
@@ -311,7 +311,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// combine all interfaces that match template
final NetworkStatsHistory combined = new NetworkStatsHistory(
- mSettings.getUidBucketDuration(), estimateUidBuckets());
+ mSettings.getUidBucketDuration(), estimateUidBuckets(), fields);
for (NetworkIdentitySet ident : mUidStats.keySet()) {
if (templateMatches(template, ident)) {
final NetworkStatsHistory history = mUidStats.get(ident).get(packed);
@@ -596,7 +596,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// decide if enough has changed to trigger persist
final NetworkStats persistDelta = computeStatsDelta(
- mLastPersistNetworkSnapshot, networkSnapshot);
+ mLastPersistNetworkSnapshot, networkSnapshot, true);
final long persistThreshold = mSettings.getPersistThreshold();
NetworkStats.Entry entry = null;
@@ -626,7 +626,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private void performNetworkPollLocked(NetworkStats networkSnapshot, long currentTime) {
final HashSet<String> unknownIface = Sets.newHashSet();
- final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot);
+ final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot, false);
final long timeStart = currentTime - delta.getElapsedRealtime();
NetworkStats.Entry entry = null;
@@ -661,9 +661,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) {
ensureUidStatsLoadedLocked();
- final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot);
+ final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot, false);
final NetworkStats operationsDelta = computeStatsDelta(
- mLastOperationsSnapshot, mOperations);
+ mLastOperationsSnapshot, mOperations, false);
final long timeStart = currentTime - delta.getElapsedRealtime();
NetworkStats.Entry entry = null;
@@ -932,6 +932,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
out.flush();
mNetworkFile.finishWrite(fos);
} catch (IOException e) {
+ Slog.w(TAG, "problem writing stats: ", e);
if (fos != null) {
mNetworkFile.failWrite(fos);
}
@@ -978,6 +979,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
out.flush();
mUidFile.finishWrite(fos);
} catch (IOException e) {
+ Slog.w(TAG, "problem writing stats: ", e);
if (fos != null) {
mUidFile.failWrite(fos);
}
@@ -1052,15 +1054,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
*/
@Deprecated
private void generateRandomLocked() {
- long networkEnd = System.currentTimeMillis();
- long networkStart = networkEnd - mSettings.getNetworkMaxHistory();
- long networkRx = 3 * GB_IN_BYTES;
- long networkTx = 2 * GB_IN_BYTES;
-
- long uidEnd = System.currentTimeMillis();
- long uidStart = uidEnd - mSettings.getUidMaxHistory();
- long uidRx = 500 * MB_IN_BYTES;
- long uidTx = 100 * MB_IN_BYTES;
+ final long NET_END = System.currentTimeMillis();
+ final long NET_START = NET_END - mSettings.getNetworkMaxHistory();
+ final long NET_RX_BYTES = 3 * GB_IN_BYTES;
+ final long NET_RX_PACKETS = NET_RX_BYTES / 1024;
+ final long NET_TX_BYTES = 2 * GB_IN_BYTES;
+ final long NET_TX_PACKETS = NET_TX_BYTES / 1024;
+
+ final long UID_END = System.currentTimeMillis();
+ final long UID_START = UID_END - mSettings.getUidMaxHistory();
+ final long UID_RX_BYTES = 500 * MB_IN_BYTES;
+ final long UID_RX_PACKETS = UID_RX_BYTES / 1024;
+ final long UID_TX_BYTES = 100 * MB_IN_BYTES;
+ final long UID_TX_PACKETS = UID_TX_BYTES / 1024;
+ final long UID_OPERATIONS = UID_RX_BYTES / 2048;
final List<ApplicationInfo> installedApps = mContext
.getPackageManager().getInstalledApplications(0);
@@ -1068,13 +1075,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mNetworkStats.clear();
mUidStats.clear();
for (NetworkIdentitySet ident : mActiveIfaces.values()) {
- findOrCreateNetworkStatsLocked(ident).generateRandom(
- networkStart, networkEnd, networkRx, networkTx);
+ findOrCreateNetworkStatsLocked(ident).generateRandom(NET_START, NET_END, NET_RX_BYTES,
+ NET_RX_PACKETS, NET_TX_BYTES, NET_TX_PACKETS, 0L);
for (ApplicationInfo info : installedApps) {
final int uid = info.uid;
- findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom(
- uidStart, uidEnd, uidRx, uidTx);
+ findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom(UID_START, UID_END,
+ UID_RX_BYTES, UID_RX_PACKETS, UID_TX_BYTES, UID_TX_PACKETS, UID_OPERATIONS);
}
}
}
@@ -1083,9 +1090,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
* Return the delta between two {@link NetworkStats} snapshots, where {@code
* before} can be {@code null}.
*/
- private static NetworkStats computeStatsDelta(NetworkStats before, NetworkStats current) {
+ private static NetworkStats computeStatsDelta(
+ NetworkStats before, NetworkStats current, boolean collectStale) {
if (before != null) {
return current.subtractClamped(before);
+ } else if (collectStale) {
+ // caller is okay collecting stale stats for first call.
+ return current;
} else {
// this is first snapshot; to prevent from double-counting we only
// observe traffic occuring between known snapshots.
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index c29be3a1591c..c823da56708c 100755
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -543,7 +543,7 @@ static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* e
}
static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject obj,
- jboolean connected, int type, jboolean roaming, jstring extraInfo)
+ jboolean connected, int type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn)
{
if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) {
@@ -554,6 +554,14 @@ static void android_location_GpsLocationProvider_update_network_state(JNIEnv* en
} else {
sAGpsRilInterface->update_network_state(connected, type, roaming, NULL);
}
+
+ // update_network_availability callback was not included in original AGpsRilInterface
+ if (sAGpsRilInterface->size >= sizeof(AGpsRilInterface)
+ && sAGpsRilInterface->update_network_availability) {
+ const char *c_apn = env->GetStringUTFChars(apn, NULL);
+ sAGpsRilInterface->update_network_availability(available, c_apn);
+ env->ReleaseStringUTFChars(apn, c_apn);
+ }
}
}
@@ -582,7 +590,7 @@ static JNINativeMethod sMethods[] = {
{"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
{"native_agps_ni_message", "([BI)V", (void *)android_location_GpsLocationProvider_agps_send_ni_message},
{"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
- {"native_update_network_state", "(ZIZLjava/lang/String;)V", (void*)android_location_GpsLocationProvider_update_network_state },
+ {"native_update_network_state", "(ZIZZLjava/lang/String;Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_update_network_state },
};
int register_android_server_location_GpsLocationProvider(JNIEnv* env)
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 91fef22fbd21..09f8ff39c97e 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -20,14 +20,18 @@ import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
+import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
+import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
+import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
@@ -79,6 +83,7 @@ import org.easymock.EasyMock;
import org.easymock.IAnswer;
import java.io.File;
+import java.util.LinkedHashSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@@ -402,7 +407,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
final NetworkPolicy policy = new NetworkPolicy(
sTemplateWifi, 5, 1024L, 1024L, SNOOZE_NEVER);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
- assertEquals(expectedCycle, actualCycle);
+ assertTimeEquals(expectedCycle, actualCycle);
}
public void testLastCycleBoundaryLastMonth() throws Exception {
@@ -413,7 +418,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
final NetworkPolicy policy = new NetworkPolicy(
sTemplateWifi, 20, 1024L, 1024L, SNOOZE_NEVER);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
- assertEquals(expectedCycle, actualCycle);
+ assertTimeEquals(expectedCycle, actualCycle);
}
public void testLastCycleBoundaryThisMonthFebruary() throws Exception {
@@ -424,18 +429,48 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
final NetworkPolicy policy = new NetworkPolicy(
sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
- assertEquals(expectedCycle, actualCycle);
+ assertTimeEquals(expectedCycle, actualCycle);
}
public void testLastCycleBoundaryLastMonthFebruary() throws Exception {
// assume cycle day of "30th" in february, which should clamp
final long currentTime = parseTime("2007-03-14T00:00:00.000Z");
- final long expectedCycle = parseTime("2007-03-01T00:00:00.000Z");
+ final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z");
final NetworkPolicy policy = new NetworkPolicy(
sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
- assertEquals(expectedCycle, actualCycle);
+ assertTimeEquals(expectedCycle, actualCycle);
+ }
+
+ public void testNextCycleSane() throws Exception {
+ final NetworkPolicy policy = new NetworkPolicy(
+ sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER);
+ final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
+
+ // walk forwards, ensuring that cycle boundaries don't get stuck
+ long currentCycle = computeNextCycleBoundary(parseTime("2011-08-01T00:00:00.000Z"), policy);
+ for (int i = 0; i < 128; i++) {
+ long nextCycle = computeNextCycleBoundary(currentCycle, policy);
+ assertEqualsFuzzy(DAY_IN_MILLIS * 30, nextCycle - currentCycle, DAY_IN_MILLIS * 3);
+ assertUnique(seen, nextCycle);
+ currentCycle = nextCycle;
+ }
+ }
+
+ public void testLastCycleSane() throws Exception {
+ final NetworkPolicy policy = new NetworkPolicy(
+ sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER);
+ final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
+
+ // walk backwards, ensuring that cycle boundaries look sane
+ long currentCycle = computeLastCycleBoundary(parseTime("2011-08-04T00:00:00.000Z"), policy);
+ for (int i = 0; i < 128; i++) {
+ long lastCycle = computeLastCycleBoundary(currentCycle, policy);
+ assertEqualsFuzzy(DAY_IN_MILLIS * 30, currentCycle - lastCycle, DAY_IN_MILLIS * 3);
+ assertUnique(seen, lastCycle);
+ currentCycle = lastCycle;
+ }
}
public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
@@ -734,6 +769,32 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
}
}
+ private static void assertTimeEquals(long expected, long actual) {
+ if (expected != actual) {
+ fail("expected " + formatTime(expected) + " but was actually " + formatTime(actual));
+ }
+ }
+
+ private static String formatTime(long millis) {
+ final Time time = new Time(Time.TIMEZONE_UTC);
+ time.set(millis);
+ return time.format3339(false);
+ }
+
+ private static void assertEqualsFuzzy(long expected, long actual, long fuzzy) {
+ final long low = expected - fuzzy;
+ final long high = expected + fuzzy;
+ if (actual < low || actual > high) {
+ fail("value " + actual + " is outside [" + low + "," + high + "]");
+ }
+ }
+
+ private static void assertUnique(LinkedHashSet<Long> seen, Long value) {
+ if (!seen.add(value)) {
+ fail("found duplicate time " + value + " in series " + seen.toString());
+ }
+ }
+
private static void assertNotificationType(int expected, String actualTag) {
assertEquals(
Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1));
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index cf69fd546552..8eb9cc305397 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -25,6 +25,7 @@ import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
+import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateWifi;
import static android.net.TrafficStats.UID_REMOVED;
@@ -302,7 +303,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
// verify service recorded history
- history = mService.getHistoryForNetwork(sTemplateWifi);
+ history = mService.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
assertEquals(HOUR_IN_MILLIS, history.getBucketDuration());
assertEquals(2, history.size());
@@ -319,7 +320,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
// verify identical stats, but spread across 4 buckets now
- history = mService.getHistoryForNetwork(sTemplateWifi);
+ history = mService.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration());
assertEquals(4, history.size());
@@ -631,14 +632,15 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long rxPackets,
long txBytes, long txPackets, int operations) {
- final NetworkStatsHistory history = mService.getHistoryForNetwork(template);
+ final NetworkStatsHistory history = mService.getHistoryForNetwork(template, FIELD_ALL);
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
txPackets, operations);
}
private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets,
long txBytes, long txPackets, int operations) {
- final NetworkStatsHistory history = mService.getHistoryForUid(template, uid, TAG_NONE);
+ final NetworkStatsHistory history = mService.getHistoryForUid(
+ template, uid, TAG_NONE, FIELD_ALL);
assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
txPackets, operations);
}
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
index 625b40d7f279..0928ec572540 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
@@ -417,6 +417,22 @@ public final class BridgeResources extends Resources {
}
@Override
+ public boolean getBoolean(int id) throws NotFoundException {
+ Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
+
+ if (value != null && value.getSecond().getValue() != null) {
+ String v = value.getSecond().getValue();
+ return Boolean.parseBoolean(v);
+ }
+
+ // id was not found or not resolved. Throw a NotFoundException.
+ throwException(id);
+
+ // this is not used since the method above always throws
+ return false;
+ }
+
+ @Override
public String getResourceEntryName(int resid) throws NotFoundException {
throw new UnsupportedOperationException();
}
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index de49eb4f7011..331d5c0ad8db 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -57,6 +57,7 @@ import android.net.NetworkInfo.DetailedState;
import android.net.NetworkUtils;
import android.net.wifi.WpsResult.Status;
import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.p2p.WifiP2pService;
import android.net.wifi.StateChangeResult;
import android.os.Binder;
import android.os.IBinder;
@@ -69,7 +70,6 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.WorkSource;
-import android.server.WifiP2pService;
import android.provider.Settings;
import android.util.EventLog;
import android.util.Log;
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index be9dfcf81ef8..168c68b41df1 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -44,9 +44,11 @@ import com.android.internal.util.StateMachine;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
+import java.net.InetAddress;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* {@link WifiWatchdogStateMachine} monitors the initial connection to a Wi-Fi
@@ -82,7 +84,6 @@ public class WifiWatchdogStateMachine extends StateMachine {
private static final int DEFAULT_MAX_SSID_BLACKLISTS = 7;
private static final int DEFAULT_NUM_DNS_PINGS = 5;
private static final int DEFAULT_MIN_DNS_RESPONSES = 3;
- private static final long DNS_PING_INTERVAL_MS = 100;
private static final int DEFAULT_DNS_PING_TIMEOUT_MS = 2000;
@@ -92,6 +93,7 @@ public class WifiWatchdogStateMachine extends StateMachine {
private static final String DEFAULT_WALLED_GARDEN_URL =
"http://clients3.google.com/generate_204";
private static final int WALLED_GARDEN_SOCKET_TIMEOUT_MS = 10000;
+ private static final int DNS_INTRATEST_PING_INTERVAL = 20;
private static final int BASE = Protocol.BASE_WIFI_WATCHDOG;
@@ -114,9 +116,8 @@ public class WifiWatchdogStateMachine extends StateMachine {
private static final int EVENT_WIFI_RADIO_STATE_CHANGE = BASE + 5;
private static final int EVENT_WATCHDOG_SETTINGS_CHANGE = BASE + 6;
- private static final int MESSAGE_CHECK_STEP = BASE + 100;
- private static final int MESSAGE_HANDLE_WALLED_GARDEN = BASE + 101;
- private static final int MESSAGE_HANDLE_BAD_AP = BASE + 102;
+ private static final int MESSAGE_HANDLE_WALLED_GARDEN = BASE + 100;
+ private static final int MESSAGE_HANDLE_BAD_AP = BASE + 101;
/**
* arg1 == mOnlineWatchState.checkCount
*/
@@ -189,8 +190,9 @@ public class WifiWatchdogStateMachine extends StateMachine {
mContext = context;
mContentResolver = context.getContentResolver();
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- mDnsPinger = new DnsPinger("WifiWatchdogServer.DnsPinger", context,
- ConnectivityManager.TYPE_WIFI);
+ mDnsPinger = new DnsPinger(mContext, "WifiWatchdogStateMachine.DnsPinger",
+ this.getHandler().getLooper(), this.getHandler(),
+ ConnectivityManager.TYPE_WIFI);
setupNetworkReceiver();
@@ -637,36 +639,43 @@ public class WifiWatchdogStateMachine extends StateMachine {
}
class DnsCheckingState extends State {
- int dnsCheckTries = 0;
int dnsCheckSuccesses = 0;
+ int dnsCheckTries = 0;
String dnsCheckLogStr = "";
+ Set<Integer> ids = new HashSet<Integer>();
@Override
public void enter() {
dnsCheckSuccesses = 0;
dnsCheckTries = 0;
+ ids.clear();
+ InetAddress dns = mDnsPinger.getDns();
if (DBG) {
Slog.d(WWSM_TAG, "Starting DNS pings at " + SystemClock.elapsedRealtime());
dnsCheckLogStr = String.format("Pinging %s on ssid [%s]: ",
- mDnsPinger.getDns(), mInitialConnInfo.getSSID());
+ dns, mInitialConnInfo.getSSID());
}
- sendCheckStepMessage(0);
+ for (int i=0; i < mNumDnsPings; i++) {
+ ids.add(mDnsPinger.pingDnsAsync(dns, mDnsPingTimeoutMs,
+ DNS_INTRATEST_PING_INTERVAL * i));
+ }
}
@Override
public boolean processMessage(Message msg) {
- if (msg.what != MESSAGE_CHECK_STEP) {
+ if (msg.what != DnsPinger.DNS_PING_RESULT) {
return NOT_HANDLED;
}
- if (msg.arg1 != mNetEventCounter) {
- Slog.d(WWSM_TAG, "Check step out of sync, ignoring...");
- return HANDLED;
- }
- long pingResponseTime = mDnsPinger.pingDns(mDnsPinger.getDns(),
- mDnsPingTimeoutMs);
+ int pingID = msg.arg1;
+ int pingResponseTime = msg.arg2;
+ if (!ids.contains(pingID)) {
+ Slog.w(WWSM_TAG, "Received a Dns response with unknown ID!");
+ return HANDLED;
+ }
+ ids.remove(pingID);
dnsCheckTries++;
if (pingResponseTime >= 0)
dnsCheckSuccesses++;
@@ -730,11 +739,15 @@ public class WifiWatchdogStateMachine extends StateMachine {
return HANDLED;
}
- // Still in dns check step
- sendCheckStepMessage(DNS_PING_INTERVAL_MS);
return HANDLED;
}
+ @Override
+ public void exit() {
+ mDnsPinger.cancelPings();
+ }
+
+
private boolean shouldCheckWalledGarden() {
if (!mWalledGardenTestEnabled) {
if (VDBG)
@@ -752,11 +765,6 @@ public class WifiWatchdogStateMachine extends StateMachine {
}
return true;
}
-
- private void sendCheckStepMessage(long delay) {
- sendMessageDelayed(obtainMessage(MESSAGE_CHECK_STEP, mNetEventCounter, 0), delay);
- }
-
}
class OnlineWatchState extends State {
@@ -779,12 +787,15 @@ public class WifiWatchdogStateMachine extends StateMachine {
int checkGuard = 0;
Long lastCheckTime = null;
+ int curPingID = 0;
+
@Override
public void enter() {
lastCheckTime = SystemClock.elapsedRealtime();
signalUnstable = false;
checkGuard++;
unstableSignalChecks = false;
+ curPingID = 0;
triggerSingleDnsCheck();
}
@@ -820,8 +831,18 @@ public class WifiWatchdogStateMachine extends StateMachine {
return HANDLED;
}
lastCheckTime = SystemClock.elapsedRealtime();
- long responseTime = mDnsPinger.pingDns(mDnsPinger.getDns(),
- mDnsPingTimeoutMs);
+ curPingID = mDnsPinger.pingDnsAsync(mDnsPinger.getDns(),
+ mDnsPingTimeoutMs, 0);
+ return HANDLED;
+ case DnsPinger.DNS_PING_RESULT:
+ if ((short) msg.arg1 != curPingID) {
+ if (VDBG) {
+ Slog.v(WWSM_TAG, "Received non-matching DnsPing w/ id: " +
+ msg.arg1);
+ }
+ return HANDLED;
+ }
+ int responseTime = msg.arg2;
if (responseTime >= 0) {
if (VDBG) {
Slog.v(WWSM_TAG, "Ran a single DNS ping. Response time: "
@@ -842,6 +863,11 @@ public class WifiWatchdogStateMachine extends StateMachine {
return NOT_HANDLED;
}
+ @Override
+ public void exit() {
+ mDnsPinger.cancelPings();
+ }
+
/**
* Times a dns check with an interval based on {@link #signalUnstable}
*/
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 4988f0b8573e..28afd44ed104 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.server;
+package android.net.wifi.p2p;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
@@ -31,20 +31,13 @@ import android.net.wifi.WifiNative;
import android.net.wifi.WifiStateMachine;
import android.net.wifi.WpsConfiguration;
import android.net.wifi.WpsConfiguration.Setup;
-import android.net.wifi.p2p.IWifiP2pManager;
-import android.net.wifi.p2p.WifiP2pConfig;
-import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDevice.Status;
-import android.net.wifi.p2p.WifiP2pDeviceList;
-import android.net.wifi.p2p.WifiP2pGroup;
-import android.net.wifi.p2p.WifiP2pManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.Handler;
-import android.os.Messenger;
import android.os.HandlerThread;
-import android.os.IBinder;
import android.os.Message;
+import android.os.Messenger;
import android.util.Slog;
import android.view.LayoutInflater;
import android.view.View;
@@ -55,9 +48,9 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Collection;
+import com.android.internal.R;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
-import com.android.internal.R;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;