Merge "On boot, advance time to at least 1970." into gingerbread
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 9494a06..c185007 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -104,6 +104,10 @@
     // Only show an annoying dialog at most every 30 seconds
     private static final long MIN_DIALOG_INTERVAL_MS = 30000;
 
+    // How many offending stacks to keep track of (and time) per loop
+    // of the Looper.
+    private static final int MAX_OFFENSES_PER_LOOP = 10;
+
     // Thread-policy:
 
     /**
@@ -680,6 +684,17 @@
         }
     }
 
+    private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed =
+            new ThreadLocal<ArrayList<ViolationInfo>>() {
+        @Override protected ArrayList<ViolationInfo> initialValue() {
+            return new ArrayList<ViolationInfo>();
+        }
+    };
+
+    private static boolean tooManyViolationsThisLoop() {
+        return violationsBeingTimed.get().size() >= MAX_OFFENSES_PER_LOOP;
+    }
+
     private static class AndroidBlockGuardPolicy implements BlockGuard.Policy {
         private int mPolicyMask;
 
@@ -707,6 +722,9 @@
             if ((mPolicyMask & DETECT_DISK_WRITE) == 0) {
                 return;
             }
+            if (tooManyViolationsThisLoop()) {
+                return;
+            }
             BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask);
             e.fillInStackTrace();
             startHandlingViolationException(e);
@@ -717,6 +735,9 @@
             if ((mPolicyMask & DETECT_DISK_READ) == 0) {
                 return;
             }
+            if (tooManyViolationsThisLoop()) {
+                return;
+            }
             BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask);
             e.fillInStackTrace();
             startHandlingViolationException(e);
@@ -727,6 +748,9 @@
             if ((mPolicyMask & DETECT_NETWORK) == 0) {
                 return;
             }
+            if (tooManyViolationsThisLoop()) {
+                return;
+            }
             BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask);
             e.fillInStackTrace();
             startHandlingViolationException(e);
@@ -747,13 +771,6 @@
             handleViolationWithTimingAttempt(info);
         }
 
-        private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed =
-                new ThreadLocal<ArrayList<ViolationInfo>>() {
-            @Override protected ArrayList<ViolationInfo> initialValue() {
-                return new ArrayList<ViolationInfo>();
-            }
-        };
-
         // Attempts to fill in the provided ViolationInfo's
         // durationMillis field if this thread has a Looper we can use
         // to measure with.  We measure from the time of violation
@@ -780,7 +797,7 @@
 
             MessageQueue queue = Looper.myQueue();
             final ArrayList<ViolationInfo> records = violationsBeingTimed.get();
-            if (records.size() >= 10) {
+            if (records.size() >= MAX_OFFENSES_PER_LOOP) {
                 // Not worth measuring.  Too many offenses in one loop.
                 return;
             }
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 05dd61b..0f4c1f3 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -28,6 +28,7 @@
 #include "ASessionDescription.h"
 
 #include <ctype.h>
+#include <cutils/properties.h>
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -35,6 +36,9 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaErrors.h>
 
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
 // If no access units are received within 3 secs, assume that the rtp
 // stream has ended and signal end of stream.
 static int64_t kAccessUnitTimeoutUs = 3000000ll;
@@ -45,6 +49,19 @@
 
 namespace android {
 
+static void MakeUserAgentString(AString *s) {
+    s->setTo("stagefright/1.1 (Linux;Android ");
+
+#if (PROPERTY_VALUE_MAX < 8)
+#error "PROPERTY_VALUE_MAX must be at least 8"
+#endif
+
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.build.version.release", value, "Unknown");
+    s->append(value);
+    s->append(")");
+}
+
 static bool GetAttribute(const char *s, const char *key, AString *value) {
     value->clear();
 
@@ -137,6 +154,131 @@
         return maxTimeUs;
     }
 
+    static void addRR(const sp<ABuffer> &buf) {
+        uint8_t *ptr = buf->data() + buf->size();
+        ptr[0] = 0x80 | 0;
+        ptr[1] = 201;  // RR
+        ptr[2] = 0;
+        ptr[3] = 1;
+        ptr[4] = 0xde;  // SSRC
+        ptr[5] = 0xad;
+        ptr[6] = 0xbe;
+        ptr[7] = 0xef;
+
+        buf->setRange(0, buf->size() + 8);
+    }
+
+    static void addSDES(int s, const sp<ABuffer> &buffer) {
+        struct sockaddr_in addr;
+        socklen_t addrSize = sizeof(addr);
+        CHECK_EQ(0, getsockname(s, (sockaddr *)&addr, &addrSize));
+
+        uint8_t *data = buffer->data() + buffer->size();
+        data[0] = 0x80 | 1;
+        data[1] = 202;  // SDES
+        data[4] = 0xde;  // SSRC
+        data[5] = 0xad;
+        data[6] = 0xbe;
+        data[7] = 0xef;
+
+        size_t offset = 8;
+
+        data[offset++] = 1;  // CNAME
+
+        AString cname = "stagefright@";
+        cname.append(inet_ntoa(addr.sin_addr));
+        data[offset++] = cname.size();
+
+        memcpy(&data[offset], cname.c_str(), cname.size());
+        offset += cname.size();
+
+        data[offset++] = 6;  // TOOL
+
+        AString tool;
+        MakeUserAgentString(&tool);
+
+        data[offset++] = tool.size();
+
+        memcpy(&data[offset], tool.c_str(), tool.size());
+        offset += tool.size();
+
+        data[offset++] = 0;
+
+        if ((offset % 4) > 0) {
+            size_t count = 4 - (offset % 4);
+            switch (count) {
+                case 3:
+                    data[offset++] = 0;
+                case 2:
+                    data[offset++] = 0;
+                case 1:
+                    data[offset++] = 0;
+            }
+        }
+
+        size_t numWords = (offset / 4) - 1;
+        data[2] = numWords >> 8;
+        data[3] = numWords & 0xff;
+
+        buffer->setRange(buffer->offset(), buffer->size() + offset);
+    }
+
+    // In case we're behind NAT, fire off two UDP packets to the remote
+    // rtp/rtcp ports to poke a hole into the firewall for future incoming
+    // packets. We're going to send an RR/SDES RTCP packet to both of them.
+    void pokeAHole(int rtpSocket, int rtcpSocket, const AString &transport) {
+        AString source;
+        AString server_port;
+        if (!GetAttribute(transport.c_str(),
+                          "source",
+                          &source)
+                || !GetAttribute(transport.c_str(),
+                                 "server_port",
+                                 &server_port)) {
+            return;
+        }
+
+        int rtpPort, rtcpPort;
+        if (sscanf(server_port.c_str(), "%d-%d", &rtpPort, &rtcpPort) != 2
+                || rtpPort <= 0 || rtpPort > 65535
+                || rtcpPort <=0 || rtcpPort > 65535
+                || rtcpPort != rtpPort + 1
+                || (rtpPort & 1) != 0) {
+            return;
+        }
+
+        struct sockaddr_in addr;
+        memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
+        addr.sin_family = AF_INET;
+        addr.sin_addr.s_addr = inet_addr(source.c_str());
+
+        if (addr.sin_addr.s_addr == INADDR_NONE) {
+            return;
+        }
+
+        // Make up an RR/SDES RTCP packet.
+        sp<ABuffer> buf = new ABuffer(65536);
+        buf->setRange(0, 0);
+        addRR(buf);
+        addSDES(rtpSocket, buf);
+
+        addr.sin_port = htons(rtpPort);
+
+        ssize_t n = sendto(
+                rtpSocket, buf->data(), buf->size(), 0,
+                (const sockaddr *)&addr, sizeof(addr));
+        CHECK_EQ(n, (ssize_t)buf->size());
+
+        addr.sin_port = htons(rtcpPort);
+
+        n = sendto(
+                rtcpSocket, buf->data(), buf->size(), 0,
+                (const sockaddr *)&addr, sizeof(addr));
+        CHECK_EQ(n, (ssize_t)buf->size());
+
+        LOGV("successfully poked holes.");
+    }
+
     virtual void onMessageReceived(const sp<AMessage> &msg) {
         switch (msg->what()) {
             case 'conn':
@@ -285,6 +427,17 @@
                         sp<AMessage> notify = new AMessage('accu', id());
                         notify->setSize("track-index", trackIndex);
 
+                        i = response->mHeaders.indexOfKey("transport");
+                        CHECK_GE(i, 0);
+
+                        if (!track->mUsingInterleavedTCP) {
+                            AString transport = response->mHeaders.valueAt(i);
+
+                            pokeAHole(track->mRTPSocket,
+                                      track->mRTCPSocket,
+                                      transport);
+                        }
+
                         mRTPConn->addStream(
                                 track->mRTPSocket, track->mRTCPSocket,
                                 mSessionDesc, index,
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 87271e7..f9c1679 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -493,6 +493,11 @@
                 + " info: " + info);
         }
 
+        if (info != null) {
+            native_update_network_state(info.isConnected(), info.getType(),
+                    info.isRoaming(), info.getExtraInfo());
+        }
+
         if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL
                 && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
             String apnName = info.getExtraInfo();
@@ -1601,4 +1606,7 @@
     private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
             int lac, int cid);
     private native void native_agps_set_id(int type, String setid);
+
+    private native void native_update_network_state(boolean connected, int type,
+            boolean roaming, String extraInfo);
 }
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index bd722d7..43e8467 100755
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -586,6 +586,23 @@
     return result;
 }
 
+static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject obj,
+        jboolean connected, int type, jboolean roaming, jstring extraInfo)
+{
+    const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj);
+    if (interface &&
+            (interface->size > ((char *)&interface->update_network_state - (char *)&interface)) &&
+            interface->update_network_state) {
+        if (extraInfo) {
+            const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL);
+            interface->update_network_state(connected, type, roaming, extraInfoStr);
+            env->ReleaseStringUTFChars(extraInfo, extraInfoStr);
+        } else {
+            interface->update_network_state(connected, type, roaming, NULL);
+        }
+    }
+}
+
 static JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
@@ -611,6 +628,7 @@
     {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
     {"native_agps_ni_message", "([BI)V", (void *)android_location_GpsLocationProvider_agps_send_ni_message},
     {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
+    {"native_update_network_state", "(ZIZLjava/lang/String;)V", (void*)android_location_GpsLocationProvider_update_network_state },
 };
 
 int register_android_server_location_GpsLocationProvider(JNIEnv* env)
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index d668e88..4fb1e61 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -91,17 +91,21 @@
                     mMessages.remove(cur);
                     break;
                 }
-                if (timeout>=0 && timeoutTime < now) {
-                    // we timed-out, return a NULL message
-                    result = 0;
-                    break;
-                }
                 nextEventTime = result->when;
                 result = 0;
             }
 
-            if (timeout >= 0 && nextEventTime > 0) {
-                if (nextEventTime > timeoutTime) {
+            if (timeout >= 0) {
+                if (timeoutTime < now) {
+                    // we timed-out, return a NULL message
+                    result = 0;
+                    break;
+                }
+                if (nextEventTime > 0) {
+                    if (nextEventTime > timeoutTime) {
+                        nextEventTime = timeoutTime;
+                    }
+                } else {
                     nextEventTime = timeoutTime;
                 }
             }