diff options
Diffstat (limited to 'core/java/com/google/android')
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. * |