2 * Copyright (C) 2010 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.strictmodetest;
19 import android.app.Activity;
20 import android.content.ComponentName;
21 import android.content.ContentQueryMap;
22 import android.content.ContentResolver;
23 import android.content.ContentValues;
24 import android.content.Context;
25 import android.content.IContentProvider;
26 import android.content.Intent;
27 import android.content.ServiceConnection;
28 import android.content.pm.PackageManager;
29 import android.content.pm.ResolveInfo;
30 import android.content.res.Configuration;
31 import android.content.res.Resources;
32 import android.database.Cursor;
33 import android.database.SQLException;
34 import android.database.sqlite.SQLiteDatabase;
35 import android.net.LocalSocket;
36 import android.net.LocalSocketAddress;
37 import android.net.Uri;
38 import android.os.Bundle;
39 import android.os.Debug;
40 import android.os.Handler;
41 import android.os.IBinder;
42 import android.os.Parcel;
43 import android.os.RemoteException;
44 import android.os.ServiceManager;
45 import android.os.StrictMode;
46 import android.os.SystemClock;
47 import android.telephony.TelephonyManager;
48 import android.text.TextUtils;
49 import android.util.AndroidException;
50 import android.util.Config;
51 import android.util.Log;
52 import android.view.View;
53 import android.widget.Button;
54 import android.widget.CheckBox;
55 import android.widget.TextView;
57 import dalvik.system.BlockGuard;
59 import org.apache.http.HttpResponse;
60 import org.apache.http.client.methods.HttpUriRequest;
61 import org.apache.http.client.methods.HttpGet;
62 import org.apache.http.impl.client.DefaultHttpClient;
65 import java.io.FileInputStream;
66 import java.io.FileOutputStream;
67 import java.io.IOException;
68 import java.io.InputStream;
69 import java.io.OutputStream;
70 import java.io.RandomAccessFile;
71 import java.net.InetAddress;
72 import java.net.Socket;
75 public class StrictModeActivity extends Activity {
77 private static final String TAG = "StrictModeActivity";
78 private static final Uri SYSTEM_SETTINGS_URI = Uri.parse("content://settings/system");
80 private ContentResolver cr;
82 private final static class SimpleConnection implements ServiceConnection {
83 public IService stub = null;
84 public void onServiceConnected(ComponentName name, IBinder service) {
85 stub = IService.Stub.asInterface(service);
86 Log.v(TAG, "Service connected: " + name);
88 public void onServiceDisconnected(ComponentName name) {
90 Log.v(TAG, "Service disconnected: " + name);
94 private final SimpleConnection mLocalServiceConn = new SimpleConnection();
95 private final SimpleConnection mRemoteServiceConn = new SimpleConnection();
97 /** Called when the activity is first created. */
99 public void onCreate(Bundle savedInstanceState) {
100 super.onCreate(savedInstanceState);
101 setContentView(R.layout.main);
103 cr = getContentResolver();
104 final SQLiteDatabase db = openOrCreateDatabase("foo.db", MODE_PRIVATE, null);
106 final Button readButton = (Button) findViewById(R.id.read_button);
107 readButton.setOnClickListener(new View.OnClickListener() {
108 public void onClick(View v) {
111 c = db.rawQuery("SELECT * FROM foo", null);
113 if (c != null) c.close();
118 final Button writeButton = (Button) findViewById(R.id.write_button);
119 writeButton.setOnClickListener(new View.OnClickListener() {
120 public void onClick(View v) {
121 db.execSQL("CREATE TABLE IF NOT EXISTS FOO (a INT)");
125 final Button writeLoopButton = (Button) findViewById(R.id.write_loop_button);
126 writeLoopButton.setOnClickListener(new View.OnClickListener() {
127 public void onClick(View v) {
128 long startTime = SystemClock.uptimeMillis();
130 BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
131 for (int i = 0; i < iters; ++i) {
132 policy.onWriteToDisk();
134 long endTime = SystemClock.uptimeMillis();
135 Log.d(TAG, "Time for " + iters + ": " + (endTime - startTime) + ", avg=" +
136 (endTime - startTime) / (double) iters);
140 final Button dnsButton = (Button) findViewById(R.id.dns_button);
141 dnsButton.setOnClickListener(new View.OnClickListener() {
142 public void onClick(View v) {
143 Log.d(TAG, "Doing DNS lookup for www.l.google.com... "
144 + "(may be cached by InetAddress)");
146 InetAddress[] addrs = InetAddress.getAllByName("www.l.google.com");
147 for (int i = 0; i < addrs.length; ++i) {
148 Log.d(TAG, "got: " + addrs[i]);
150 } catch (java.net.UnknownHostException e) {
151 Log.d(TAG, "DNS error: " + e);
156 final Button httpButton = (Button) findViewById(R.id.http_button);
157 httpButton.setOnClickListener(new View.OnClickListener() {
158 public void onClick(View v) {
160 // Note: not using AndroidHttpClient, as that comes with its
161 // own pre-StrictMode network-on-Looper thread check. The
162 // intent of this test is that we test the network stack's
163 // instrumentation for StrictMode instead.
164 DefaultHttpClient httpClient = new DefaultHttpClient();
165 HttpResponse res = httpClient.execute(
166 new HttpGet("http://www.android.com/favicon.ico"));
167 Log.d(TAG, "Fetched http response: " + res);
168 } catch (IOException e) {
169 Log.d(TAG, "HTTP fetch error: " + e);
174 final Button http2Button = (Button) findViewById(R.id.http2_button);
175 http2Button.setOnClickListener(new View.OnClickListener() {
176 public void onClick(View v) {
178 // Usually this ends up tripping in DNS resolution,
179 // so see http3Button below, which connects directly to an IP
180 InputStream is = new URL("http://www.android.com/")
183 Log.d(TAG, "Got input stream: " + is);
184 } catch (IOException e) {
185 Log.d(TAG, "HTTP fetch error: " + e);
190 final Button http3Button = (Button) findViewById(R.id.http3_button);
191 http3Button.setOnClickListener(new View.OnClickListener() {
192 public void onClick(View v) {
194 // One of Google's web IPs, as of 2010-06-16....
195 InputStream is = new URL("http://74.125.19.14/")
198 Log.d(TAG, "Got input stream: " + is);
199 } catch (IOException e) {
200 Log.d(TAG, "HTTP fetch error: " + e);
205 final Button binderLocalButton = (Button) findViewById(R.id.binder_local_button);
206 binderLocalButton.setOnClickListener(new View.OnClickListener() {
207 public void onClick(View v) {
209 boolean value = mLocalServiceConn.stub.doDiskWrite(123 /* dummy */);
210 Log.d(TAG, "local writeToDisk returned: " + value);
211 } catch (RemoteException e) {
212 Log.d(TAG, "local binderButton error: " + e);
217 final Button binderRemoteButton = (Button) findViewById(R.id.binder_remote_button);
218 binderRemoteButton.setOnClickListener(new View.OnClickListener() {
219 public void onClick(View v) {
221 boolean value = mRemoteServiceConn.stub.doDiskWrite(1);
222 Log.d(TAG, "remote writeToDisk #1 returned: " + value);
223 value = mRemoteServiceConn.stub.doDiskWrite(2);
224 Log.d(TAG, "remote writeToDisk #2 returned: " + value);
225 } catch (RemoteException e) {
226 Log.d(TAG, "remote binderButton error: " + e);
231 final Button binderOneWayButton = (Button) findViewById(R.id.binder_oneway_button);
232 binderOneWayButton.setOnClickListener(new View.OnClickListener() {
233 public void onClick(View v) {
235 Log.d(TAG, "doing oneway disk write over Binder.");
236 mRemoteServiceConn.stub.doDiskOneWay();
237 } catch (RemoteException e) {
238 Log.d(TAG, "remote binderButton error: " + e);
243 final Button binderCheckButton = (Button) findViewById(R.id.binder_check_button);
244 binderCheckButton.setOnClickListener(new View.OnClickListener() {
245 public void onClick(View v) {
248 policy = mLocalServiceConn.stub.getThreadPolicy();
249 Log.d(TAG, "local service policy: " + policy);
250 policy = mRemoteServiceConn.stub.getThreadPolicy();
251 Log.d(TAG, "remote service policy: " + policy);
252 } catch (RemoteException e) {
253 Log.d(TAG, "binderCheckButton error: " + e);
258 final Button serviceDumpButton = (Button) findViewById(R.id.service_dump);
259 serviceDumpButton.setOnClickListener(new View.OnClickListener() {
260 public void onClick(View v) {
261 Log.d(TAG, "About to do a service dump...");
262 File file = new File("/sdcard/strictmode-service-dump.txt");
263 FileOutputStream output = null;
264 final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
266 StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.LAX);
267 output = new FileOutputStream(file);
268 StrictMode.setThreadPolicy(oldPolicy);
269 boolean dumped = Debug.dumpService("cpuinfo",
270 output.getFD(), new String[0]);
271 Log.d(TAG, "Dumped = " + dumped);
272 } catch (IOException e) {
273 Log.e(TAG, "Can't dump service", e);
275 StrictMode.setThreadPolicy(oldPolicy);
277 Log.d(TAG, "Did service dump.");
281 final Button lingerCloseButton = (Button) findViewById(R.id.linger_close_button);
282 lingerCloseButton.setOnClickListener(new View.OnClickListener() {
283 public void onClick(View v) {
284 closeWithLinger(true);
288 final Button nonlingerCloseButton = (Button) findViewById(R.id.nonlinger_close_button);
289 nonlingerCloseButton.setOnClickListener(new View.OnClickListener() {
290 public void onClick(View v) {
291 closeWithLinger(false);
295 final Button leakCursorButton = (Button) findViewById(R.id.leak_cursor_button);
296 leakCursorButton.setOnClickListener(new View.OnClickListener() {
297 public void onClick(View v) {
298 final StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
300 StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
301 .detectLeakedSqlLiteObjects()
305 db.execSQL("CREATE TABLE IF NOT EXISTS FOO (a INT)");
306 Cursor c = db.rawQuery("SELECT * FROM foo", null);
307 c = null; // never close it
308 Runtime.getRuntime().gc();
310 StrictMode.setVmPolicy(oldPolicy);
316 final CheckBox checkNoWrite = (CheckBox) findViewById(R.id.policy_no_write);
317 final CheckBox checkNoRead = (CheckBox) findViewById(R.id.policy_no_reads);
318 final CheckBox checkNoNetwork = (CheckBox) findViewById(R.id.policy_no_network);
319 final CheckBox checkPenaltyLog = (CheckBox) findViewById(R.id.policy_penalty_log);
320 final CheckBox checkPenaltyDialog = (CheckBox) findViewById(R.id.policy_penalty_dialog);
321 final CheckBox checkPenaltyDeath = (CheckBox) findViewById(R.id.policy_penalty_death);
322 final CheckBox checkPenaltyDropBox = (CheckBox) findViewById(R.id.policy_penalty_dropbox);
324 View.OnClickListener changePolicy = new View.OnClickListener() {
325 public void onClick(View v) {
326 StrictMode.ThreadPolicy.Builder newPolicy = new StrictMode.ThreadPolicy.Builder();
327 if (checkNoWrite.isChecked()) newPolicy.detectDiskWrites();
328 if (checkNoRead.isChecked()) newPolicy.detectDiskReads();
329 if (checkNoNetwork.isChecked()) newPolicy.detectNetwork();
330 if (checkPenaltyLog.isChecked()) newPolicy.penaltyLog();
331 if (checkPenaltyDialog.isChecked()) newPolicy.penaltyDialog();
332 if (checkPenaltyDeath.isChecked()) newPolicy.penaltyDeath();
333 if (checkPenaltyDropBox.isChecked()) newPolicy.penaltyDropBox();
334 StrictMode.ThreadPolicy policy = newPolicy.build();
335 Log.v(TAG, "Changing policy to: " + policy);
336 StrictMode.setThreadPolicy(policy);
339 checkNoWrite.setOnClickListener(changePolicy);
340 checkNoRead.setOnClickListener(changePolicy);
341 checkNoNetwork.setOnClickListener(changePolicy);
342 checkPenaltyLog.setOnClickListener(changePolicy);
343 checkPenaltyDialog.setOnClickListener(changePolicy);
344 checkPenaltyDeath.setOnClickListener(changePolicy);
345 checkPenaltyDropBox.setOnClickListener(changePolicy);
348 private void closeWithLinger(boolean linger) {
349 Log.d(TAG, "Socket linger test; linger=" + linger);
351 Socket socket = new Socket();
352 socket.setSoLinger(linger, 5);
354 } catch (IOException e) {
355 Log.e(TAG, "Error with linger close", e);
359 private void fileReadLoop() {
360 RandomAccessFile raf = null;
361 File filename = getFileStreamPath("test.dat");
364 byte[] buf = new byte[512];
366 //raf = new RandomAccessFile(filename, "rw");
371 // The data's almost certainly cached -- it's not clear what we're testing here
372 raf = new RandomAccessFile(filename, "r");
375 } catch (IOException e) {
376 Log.e(TAG, "File read failed", e);
378 try { if (raf != null) raf.close(); } catch (IOException e) {}
382 // Returns milliseconds taken, or -1 on failure.
383 private long settingsWrite(int mode) {
385 long startTime = SystemClock.uptimeMillis();
386 // The database will take care of replacing duplicates.
388 ContentValues values = new ContentValues();
389 values.put("name", "dummy_for_testing");
390 values.put("value", "" + startTime);
391 Uri uri = cr.insert(SYSTEM_SETTINGS_URI, values);
392 Log.v(TAG, "inserted uri: " + uri);
393 } catch (SQLException e) {
394 Log.w(TAG, "sqliteexception during write: " + e);
397 long duration = SystemClock.uptimeMillis() - startTime;
401 @Override public void onResume() {
403 bindService(new Intent(this, LocalService.class),
404 mLocalServiceConn, Context.BIND_AUTO_CREATE);
405 bindService(new Intent(this, RemoteService.class),
406 mRemoteServiceConn, Context.BIND_AUTO_CREATE);
409 @Override public void onPause() {
411 unbindService(mLocalServiceConn);
412 unbindService(mRemoteServiceConn);