Merge "Close the DRM session in the destructor of ChromiumHTTPDataSource. Fix for bug 5015079."
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 5fe3644..57e0583 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -32,10 +32,9 @@
/**
* 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 61a12ee..ce3dd13 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -349,7 +349,8 @@
return true;
}
}
- return false;
+ // Also return true if we're currently running the startDelay animator
+ return (mDelayAnim != null && mDelayAnim.isRunning());
}
/**
@@ -487,7 +488,6 @@
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 90d676e..c22306a 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -186,6 +186,16 @@
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 @@
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 @@
// 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 @@
// 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 @@
@Override
public boolean isRunning() {
- return (mPlayingState == RUNNING);
+ return (mPlayingState == RUNNING || mStarted);
}
/**
@@ -1000,7 +1013,7 @@
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 @@
tmpListeners.get(i).onAnimationEnd(this);
}
}
+ mStarted = false;
}
/**
diff --git a/core/java/android/net/DnsPinger.java b/core/java/android/net/DnsPinger.java
index f2d84eb..81738f3 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 @@
* 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 @@
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 @@
}
}
- /**
- * @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 c41d182..b65506c 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -24,9 +24,9 @@
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/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 0e8e7fc..f2fcb8f 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -58,7 +58,7 @@
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 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 @@
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 @@
rxPackets = parcel.createLongArray();
txBytes = parcel.createLongArray();
txPackets = parcel.createLongArray();
- operations = parcel.createIntArray();
+ operations = parcel.createLongArray();
}
/** {@inheritDoc} */
@@ -123,16 +128,16 @@
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 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 7a4b811..c917af9 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -19,11 +19,11 @@
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 @@
*/
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 @@
rxPackets = readLongArray(in);
txBytes = readLongArray(in);
txPackets = readLongArray(in);
- operations = readIntArray(in);
+ operations = readLongArray(in);
bucketCount = bucketStart.length;
}
@@ -109,21 +120,31 @@
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 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 @@
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 @@
@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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* @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 @@
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 @@
}
};
+ 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 @@
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 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,6 +588,10 @@
}
public static void writeLongArray(Parcel out, long[] values, int size) {
+ if (values == null) {
+ out.writeInt(-1);
+ return;
+ }
if (size > values.length) {
throw new IllegalArgumentException("size larger than length");
}
@@ -503,25 +600,6 @@
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();
- }
- 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]);
- }
- }
}
}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 3704248..bc4e00c 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -240,6 +240,11 @@
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/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index 9ecd29f..0cadb16 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -49,5 +49,6 @@
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 cbe72dd..36f0246 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -1226,6 +1226,12 @@
* 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/tests/coretests/src/android/animation/EventsTest.java b/core/tests/coretests/src/android/animation/EventsTest.java
index f970ffc..6ea2845 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.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 @@
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 @@
// 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() {
- mAnim.cancel();
+ 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() {
+ try {
+ mAnim.end();
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
}
};
@@ -76,6 +108,23 @@
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 void run() {
mFuture.release();
}
- }, ANIM_MID_DURATION);
+ }, FUTURE_RELEASE_DELAY);
}
};
@@ -92,7 +141,6 @@
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 @@
// 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 @@
// 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 @@
mRunning = false;
mCanceled = false;
+ mStarted = false;
}
/**
@@ -144,26 +204,104 @@
}
/**
+ * 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);
+ }
+
+ /**
+ * 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
*/
- @UiThreadTest
@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 @@
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();
+ 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(TIMEOUT, TimeUnit.MILLISECONDS);
}
/**
@@ -204,13 +365,91 @@
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();
+ 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(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 @@
}
}
});
- 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 @@
}
}
});
- 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 242057c..4db4ea5 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 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
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 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 @@
// 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 @@
}
}
+ 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 @@
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/drm/libdrmframework/plugins/common/util/include/SessionMap.h b/drm/libdrmframework/plugins/common/util/include/SessionMap.h
index 3dff58c..e563894 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;
-
- if (map.size() > index) {
- value = map.valueAt(index);
+ /**
+ * 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();
}
- return value;
-}
+ /**
+ * 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);
-/**
- * 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) {
- return (0 <= map.indexOfKey(key));
-}
-
-/**
- * empty the entire session table. It releases all the memory for session objects.
- */
-void destroyMap() {
- int size = map.size();
- int i = 0;
-
- for (i = 0; i < size; i++) {
- deleteValue(map.valueAt(i));
+ if (map.size() > index) {
+ value = map.valueAt(index);
+ }
+ return value;
}
- map.clear();
-}
+ /**
+ * 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);
+ }
-/**
- * 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 isCreated(int key) {
+ Mutex::Autolock lock(mLock);
+ return isCreatedInternal(key);
+ }
+ SessionMap<TValue> & operator=(const SessionMap<TValue> & objectCopy) {
+ Mutex::Autolock lock(mLock);
+
+ destroyMap();
+ map = objectCopy.map;
+ return *this;
+ }
+
+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;
+ }
+
+ /**
+ * 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();
+ }
+
+ /**
+ * 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 4ee903e..57ef799 100644
--- a/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
+++ b/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
@@ -22,6 +22,13 @@
#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_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 @@
* 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;
- }
- 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);
+ 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;
}
- pMimeItem++;
+ pGroup++;
}
- }
- LOGI("convertMimeType got mimetype %s, converted into mimetype %s",
- pMimeType, result.string());
- }
+ /* 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++;
+ }
+ }
+ } else {
+ result = String8(mime_type_unsupported);
+ }
+ 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 9805a40..e359dbd 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
@@ -17,6 +17,9 @@
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 31c3c14..e184545 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 @@
}
FwdLockEngine::FwdLockEngine() {
- LOGV("FwdLockEngine Construction");
+ LOG_VERBOSE("FwdLockEngine Construction");
}
FwdLockEngine::~FwdLockEngine() {
- LOGV("FwdLockEngine Destruction");
+ LOG_VERBOSE("FwdLockEngine Destruction");
- convertSessionMap.destroyMap();
- decodeSessionMap.destroyMap();
+ int size = decodeSessionMap.getSize();
+
+ 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 @@
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 @@
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 @@
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 @@
}
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::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 @@
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 = new DrmInfoStatus((int)DrmInfoStatus::STATUS_OK, 0, NULL, String8(""));
- LOGV("FwdLockEngine::onProcessDrmInfo");
+ LOG_VERBOSE("FwdLockEngine::onProcessDrmInfo");
return drmInfoStatus;
}
@@ -193,7 +210,7 @@
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* drmInfo = NULL;
// Nothing to be done for Forward Lock file
- LOGV("FwdLockEngine::onAcquireDrmInfo");
+ LOG_VERBOSE("FwdLockEngine::onAcquireDrmInfo");
return drmInfo;
}
@@ -211,7 +228,7 @@
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 @@
int action,
bool reserve) {
// No rights consumption
- LOGV("FwdLockEngine::onConsumeRights");
+ LOG_VERBOSE("FwdLockEngine::onConsumeRights");
return DRM_NO_ERROR;
}
@@ -249,14 +266,14 @@
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 @@
const String8& mimeType) {
String8 mimeStr = String8(mimeType);
- LOGV("FwdLockEngine::onGetDrmObjectType");
+ LOG_VERBOSE("FwdLockEngine::onGetDrmObjectType");
mimeStr.toLower();
@@ -301,13 +318,13 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
::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::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 @@
decryptHandle = NULL;
}
- LOGV("FwdLockEngine::onCloseDecryptSession Exit");
+ LOG_VERBOSE("FwdLockEngine::onCloseDecryptSession Exit");
return result;
}
@@ -533,13 +550,13 @@
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 @@
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 @@
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 14ea9e9..299116d 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 @@
}
/**
- * 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 @@
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 @@
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 @@
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 98284e72..dacf00e 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 @@
}
/**
- * 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 @@
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 @@
} 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 @@
} 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/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index c1c4f94..3d79596 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 @@
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 @@
void *mData;
size_t mSize, mRangeOffset, mRangeLength;
sp<GraphicBuffer> mGraphicBuffer;
+ sp<ABuffer> mBuffer;
bool mOwnsData;
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index a8fadf2c..0b14f1e 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 @@
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/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 59de17e..2e66a2c 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -105,12 +105,10 @@
int64_t timeUs;
CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
+ MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+
mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
- // hexdump(buffer->data(), buffer->size());
-
- 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 a02591f..4ecb92f 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -628,14 +628,12 @@
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/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index a59b6c0..30de385 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -1231,6 +1231,13 @@
}
}
+ @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/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 24188ca..deca7a9 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.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 @@
}
@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 @@
}
@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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
*/
@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;
+ 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;
- long uidEnd = System.currentTimeMillis();
- long uidStart = uidEnd - mSettings.getUidMaxHistory();
- long uidRx = 500 * MB_IN_BYTES;
- long uidTx = 100 * MB_IN_BYTES;
+ 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 @@
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 @@
* 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/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index cf69fd5..8eb9cc3 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.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 @@
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 @@
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 @@
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/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index be9dfcf..168c68b 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -44,9 +44,11 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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...");
+
+ 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;
}
-
- long pingResponseTime = mDnsPinger.pingDns(mDnsPinger.getDns(),
- mDnsPingTimeoutMs);
-
+ ids.remove(pingID);
dnsCheckTries++;
if (pingResponseTime >= 0)
dnsCheckSuccesses++;
@@ -730,11 +739,15 @@
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 @@
}
return true;
}
-
- private void sendCheckStepMessage(long delay) {
- sendMessageDelayed(obtainMessage(MESSAGE_CHECK_STEP, mNetEventCounter, 0), delay);
- }
-
}
class OnlineWatchState extends State {
@@ -779,12 +787,15 @@
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 @@
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 @@
return NOT_HANDLED;
}
+ @Override
+ public void exit() {
+ mDnsPinger.cancelPings();
+ }
+
/**
* Times a dns check with an interval based on {@link #signalUnstable}
*/