summaryrefslogtreecommitdiffstats
path: root/core/java/com/google/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/com/google/android')
-rw-r--r--core/java/com/google/android/net/GoogleHttpClient.java67
-rw-r--r--core/java/com/google/android/net/NetStats.java47
-rw-r--r--core/java/com/google/android/net/NetworkStatsEntity.java85
-rw-r--r--core/java/com/google/android/util/SimplePullParser.java25
4 files changed, 159 insertions, 65 deletions
diff --git a/core/java/com/google/android/net/GoogleHttpClient.java b/core/java/com/google/android/net/GoogleHttpClient.java
index 4656aff..2fcb0c3 100644
--- a/core/java/com/google/android/net/GoogleHttpClient.java
+++ b/core/java/com/google/android/net/GoogleHttpClient.java
@@ -16,18 +16,28 @@
package com.google.android.net;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.net.http.AndroidHttpClient;
+import android.os.Build;
+import android.os.NetStat;
+import android.os.SystemClock;
+import android.provider.Checkin;
+import android.util.Config;
+import android.util.Log;
+import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolException;
-import org.apache.http.impl.client.RequestWrapper;
-import org.apache.http.impl.client.EntityEnclosingRequestWrapper;
-import org.apache.http.client.HttpClient;
import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.impl.client.EntityEnclosingRequestWrapper;
+import org.apache.http.impl.client.RequestWrapper;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
@@ -35,25 +45,13 @@ import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.os.SystemClock;
-import android.os.Build;
-import android.net.http.AndroidHttpClient;
-import android.provider.Checkin;
-import android.util.Config;
-import android.util.Log;
-
/**
* {@link AndroidHttpClient} wrapper that uses {@link UrlRules} to rewrite URLs
* and otherwise tweak HTTP requests.
*/
public class GoogleHttpClient implements HttpClient {
- private static final String TAG = "GoogleHttpClient";
- private final AndroidHttpClient mClient;
- private final ContentResolver mResolver;
- private final String mUserAgent;
+ private static final String TAG = "GoogleHttpClient";
/** Exception thrown when a request is blocked by the URL rules. */
public static class BlockedRequestException extends IOException {
@@ -63,6 +61,10 @@ public class GoogleHttpClient implements HttpClient {
mRule = rule;
}
}
+
+ private final AndroidHttpClient mClient;
+ private final ContentResolver mResolver;
+ private final String mUserAgent;
/**
* Create an HTTP client. Normally one client is shared throughout an app.
@@ -120,8 +122,37 @@ public class GoogleHttpClient implements HttpClient {
String code = "Error";
long start = SystemClock.elapsedRealtime();
try {
- HttpResponse response = mClient.execute(request, context);
- code = Integer.toString(response.getStatusLine().getStatusCode());
+ HttpResponse response;
+ // TODO: if we're logging network stats, and if the apache library is configured
+ // to follow redirects, count each redirect as an additional round trip.
+
+ // see if we're logging network stats.
+ boolean logNetworkStats = NetworkStatsEntity.shouldLogNetworkStats();
+
+ if (logNetworkStats) {
+ int uid = android.os.Process.myUid();
+ long startTx = NetStat.getUidTxBytes(uid);
+ long startRx = NetStat.getUidRxBytes(uid);
+
+ response = mClient.execute(request, context);
+ code = Integer.toString(response.getStatusLine().getStatusCode());
+
+ HttpEntity origEntity = response == null ? null : response.getEntity();
+ if (origEntity != null) {
+ // yeah, we compute the same thing below. we do need to compute this here
+ // so we can wrap the HttpEntity in the response.
+ long now = SystemClock.elapsedRealtime();
+ long elapsed = now - start;
+ NetworkStatsEntity entity = new NetworkStatsEntity(origEntity,
+ mUserAgent, uid, startTx, startRx,
+ elapsed /* response latency */, now /* processing start time */);
+ response.setEntity(entity);
+ }
+ } else {
+ response = mClient.execute(request, context);
+ code = Integer.toString(response.getStatusLine().getStatusCode());
+ }
+
return response;
} catch (IOException e) {
code = "IOException";
diff --git a/core/java/com/google/android/net/NetStats.java b/core/java/com/google/android/net/NetStats.java
deleted file mode 100644
index fee8219..0000000
--- a/core/java/com/google/android/net/NetStats.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.google.android.net;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
-
-/**
- * Gets network send/receive statistics for this process.
- * The statistics come from /proc/pid/stat, using the ATOP kernel modification.
- */
-public class NetStats {
- private static String statsFile = "/proc/" + android.os.Process.myPid() + "/stat";
-
- private static String TAG = "netstat";
-
- /**
- * Returns network stats for this process.
- * Returns stats of 0 if problem encountered.
- *
- * @return [bytes sent, bytes received]
- */
- public static long[] getStats() {
- long result[] = new long[2];
-
- try {
- BufferedReader br = new BufferedReader(new FileReader(statsFile), 512);
- String line = br.readLine(); // Skip first line
- line = br.readLine();
- StringTokenizer st = new StringTokenizer(line);
- st.nextToken(); // disk read
- st.nextToken(); // disk sectors
- st.nextToken(); // disk write
- st.nextToken(); // disk sectors
- st.nextToken(); // tcp send
- result[0] = Long.parseLong(st.nextToken()); // tcp bytes sent
- st.nextToken(); //tcp recv
- result[1] = Long.parseLong(st.nextToken()); // tcp bytes recv
- } catch (IOException e) {
- // Probably wrong kernel; no point logging exception
- } catch (NoSuchElementException e) {
- } catch (NullPointerException e) {
- }
- return result;
- }
-}
diff --git a/core/java/com/google/android/net/NetworkStatsEntity.java b/core/java/com/google/android/net/NetworkStatsEntity.java
new file mode 100644
index 0000000..f5d2349
--- /dev/null
+++ b/core/java/com/google/android/net/NetworkStatsEntity.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.net;
+
+import android.os.NetStat;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.util.EventLog;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.entity.HttpEntityWrapper;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+public class NetworkStatsEntity extends HttpEntityWrapper {
+
+ private static final int HTTP_STATS_EVENT = 52001;
+
+ private class NetworkStatsInputStream extends FilterInputStream {
+
+ public NetworkStatsInputStream(InputStream wrapped) {
+ super(wrapped);
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ super.close();
+ } finally {
+ long processingTime = SystemClock.elapsedRealtime() - mProcessingStartTime;
+ long tx = NetStat.getUidTxBytes(mUid);
+ long rx = NetStat.getUidRxBytes(mUid);
+
+ EventLog.writeEvent(HTTP_STATS_EVENT, mUa, mResponseLatency, processingTime,
+ tx - mStartTx, rx - mStartRx);
+ }
+ }
+ }
+
+ private final String mUa;
+ private final int mUid;
+ private final long mStartTx;
+ private final long mStartRx;
+ private final long mResponseLatency;
+ private final long mProcessingStartTime;
+
+ public NetworkStatsEntity(HttpEntity orig, String ua,
+ int uid, long startTx, long startRx, long responseLatency,
+ long processingStartTime) {
+ super(orig);
+ this.mUa = ua;
+ this.mUid = uid;
+ this.mStartTx = startTx;
+ this.mStartRx = startRx;
+ this.mResponseLatency = responseLatency;
+ this.mProcessingStartTime = processingStartTime;
+ }
+
+ public static boolean shouldLogNetworkStats() {
+ return "1".equals(SystemProperties.get("googlehttpclient.logstats"));
+ }
+
+ @Override
+ public InputStream getContent() throws IOException {
+ InputStream orig = super.getContent();
+ return new NetworkStatsInputStream(orig);
+ }
+}
diff --git a/core/java/com/google/android/util/SimplePullParser.java b/core/java/com/google/android/util/SimplePullParser.java
index 95f2ddb..031790b 100644
--- a/core/java/com/google/android/util/SimplePullParser.java
+++ b/core/java/com/google/android/util/SimplePullParser.java
@@ -23,6 +23,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.Reader;
+import java.io.Closeable;
import android.util.Xml;
import android.util.Log;
@@ -41,6 +42,7 @@ public class SimplePullParser {
private String mLogTag = null;
private final XmlPullParser mParser;
+ private Closeable source;
private String mCurrentStartTag;
/**
@@ -56,6 +58,7 @@ public class SimplePullParser {
moveToStartDocument(parser);
mParser = parser;
mCurrentStartTag = null;
+ source = stream;
} catch (XmlPullParserException e) {
throw new ParseException(e);
}
@@ -68,6 +71,7 @@ public class SimplePullParser {
public SimplePullParser(XmlPullParser parser) {
mParser = parser;
mCurrentStartTag = null;
+ source = null;
}
/**
@@ -89,6 +93,7 @@ public class SimplePullParser {
moveToStartDocument(parser);
mParser = parser;
mCurrentStartTag = null;
+ source = reader;
} catch (XmlPullParserException e) {
throw new ParseException(e);
}
@@ -171,6 +176,12 @@ public class SimplePullParser {
}
if (eventType == XmlPullParser.END_DOCUMENT && parentDepth == 0) {
+ // we could just rely on the caller calling close(), which it should, but try
+ // to auto-close for clients that might have missed doing so.
+ if (source != null) {
+ source.close();
+ source = null;
+ }
return null;
}
@@ -333,6 +344,20 @@ public class SimplePullParser {
}
/**
+ * Close this SimplePullParser and any underlying resources (e.g., its InputStream or
+ * Reader source) used by this SimplePullParser.
+ */
+ public void close() {
+ if (source != null) {
+ try {
+ source.close();
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+ }
+
+ /**
* Returns the string value of the named attribute. An exception will
* be thrown if the attribute is not present or is not a valid long.
*