• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 package com.android.strictmodetest;
18 
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.SharedPreferences;
28 import android.content.ServiceConnection;
29 import android.content.pm.PackageManager;
30 import android.content.pm.ResolveInfo;
31 import android.content.res.Configuration;
32 import android.content.res.Resources;
33 import android.database.Cursor;
34 import android.database.SQLException;
35 import android.database.sqlite.SQLiteDatabase;
36 import android.net.LocalSocket;
37 import android.net.LocalSocketAddress;
38 import android.net.Uri;
39 import android.os.Bundle;
40 import android.os.Debug;
41 import android.os.Handler;
42 import android.os.IBinder;
43 import android.os.Parcel;
44 import android.os.RemoteException;
45 import android.os.ServiceManager;
46 import android.os.StrictMode;
47 import android.os.SystemClock;
48 import android.telephony.TelephonyManager;
49 import android.text.TextUtils;
50 import android.util.AndroidException;
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;
56 
57 import dalvik.system.BlockGuard;
58 
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;
63 
64 import java.io.File;
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;
73 import java.net.URL;
74 import java.util.ArrayList;
75 
76 public class StrictModeActivity extends Activity {
77 
78     private static final String TAG = "StrictModeActivity";
79     private static final Uri SYSTEM_SETTINGS_URI = Uri.parse("content://settings/system");
80 
81     private ContentResolver cr;
82 
83     private final static class SimpleConnection implements ServiceConnection {
84         public IService stub = null;
onServiceConnected(ComponentName name, IBinder service)85         public void onServiceConnected(ComponentName name, IBinder service) {
86             stub = IService.Stub.asInterface(service);
87             Log.v(TAG, "Service connected: " + name);
88         }
onServiceDisconnected(ComponentName name)89         public void onServiceDisconnected(ComponentName name) {
90             stub = null;
91             Log.v(TAG, "Service disconnected: " + name);
92         }
93     }
94 
95     private final SimpleConnection mLocalServiceConn = new SimpleConnection();
96     private final SimpleConnection mRemoteServiceConn = new SimpleConnection();
97 
98     private SQLiteDatabase mDb;
99 
100     /** Called when the activity is first created. */
101     @Override
onCreate(Bundle savedInstanceState)102     public void onCreate(Bundle savedInstanceState) {
103         super.onCreate(savedInstanceState);
104         setContentView(R.layout.main);
105 
106         cr = getContentResolver();
107         mDb = openOrCreateDatabase("foo.db", MODE_PRIVATE, null);
108 
109         final Button readButton = (Button) findViewById(R.id.read_button);
110         readButton.setOnClickListener(new View.OnClickListener() {
111                 public void onClick(View v) {
112                     SharedPreferences prefs = getSharedPreferences("foo", 0);
113                     try {
114                         Cursor c = null;
115                         try {
116                             c = mDb.rawQuery("SELECT * FROM foo", null);
117                         } finally {
118                             if (c != null) c.close();
119                         }
120                     } catch (android.database.sqlite.SQLiteException e) {
121                         Log.e(TAG, "SQLiteException: " + e);
122                     }
123                 }
124             });
125 
126         final Button writeButton = (Button) findViewById(R.id.write_button);
127         writeButton.setOnClickListener(new View.OnClickListener() {
128                 public void onClick(View v) {
129                     mDb.execSQL("CREATE TABLE IF NOT EXISTS FOO (a INT)");
130                     SharedPreferences prefs = getSharedPreferences("foo", 0);
131                     prefs.edit().putLong("time", System.currentTimeMillis()).commit();
132                 }
133             });
134 
135         final Button writeLoopButton = (Button) findViewById(R.id.write_loop_button);
136         writeLoopButton.setOnClickListener(new View.OnClickListener() {
137                 public void onClick(View v) {
138                     long startTime = SystemClock.uptimeMillis();
139                     int iters = 1000;
140                     BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
141                     for (int i = 0; i < iters; ++i) {
142                         policy.onWriteToDisk();
143                     }
144                     long endTime = SystemClock.uptimeMillis();
145                     Log.d(TAG, "Time for " + iters + ": " + (endTime - startTime) + ", avg=" +
146                           (endTime - startTime) / (double) iters);
147                 }
148             });
149 
150         final Button dnsButton = (Button) findViewById(R.id.dns_button);
151         dnsButton.setOnClickListener(new View.OnClickListener() {
152                 public void onClick(View v) {
153                     Log.d(TAG, "Doing DNS lookup for www.l.google.com... "
154                           + "(may be cached by InetAddress)");
155                     try {
156                         InetAddress[] addrs = InetAddress.getAllByName("www.l.google.com");
157                         for (int i = 0; i < addrs.length; ++i) {
158                             Log.d(TAG, "got: " + addrs[i]);
159                         }
160                     } catch (java.net.UnknownHostException e) {
161                         Log.d(TAG, "DNS error: " + e);
162                     }
163 
164                     // Now try a random hostname to evade libcore's
165                     // DNS caching.
166                     try {
167                         String random = "" + Math.random();
168                         random = random.substring(random.indexOf(".") + 1);
169                         String domain = random + ".livejournal.com";
170                         InetAddress addr = InetAddress.getByName(domain);
171                         Log.d(TAG, "for random domain " + domain + ": " + addr);
172                     } catch (java.net.UnknownHostException e) {
173                     }
174                 }
175             });
176 
177         final Button httpButton = (Button) findViewById(R.id.http_button);
178         httpButton.setOnClickListener(new View.OnClickListener() {
179                 public void onClick(View v) {
180                     try {
181                         // Note: not using AndroidHttpClient, as that comes with its
182                         // own pre-StrictMode network-on-Looper thread check.  The
183                         // intent of this test is that we test the network stack's
184                         // instrumentation for StrictMode instead.
185                         DefaultHttpClient httpClient = new DefaultHttpClient();
186                         HttpResponse res = httpClient.execute(
187                             new HttpGet("http://www.android.com/favicon.ico"));
188                         Log.d(TAG, "Fetched http response: " + res);
189                     } catch (IOException e) {
190                         Log.d(TAG, "HTTP fetch error: " + e);
191                     }
192                 }
193             });
194 
195         final Button http2Button = (Button) findViewById(R.id.http2_button);
196         http2Button.setOnClickListener(new View.OnClickListener() {
197                 public void onClick(View v) {
198                     try {
199                         // Usually this ends up tripping in DNS resolution,
200                         // so see http3Button below, which connects directly to an IP
201                         InputStream is = new URL("http://www.android.com/")
202                                 .openConnection()
203                                 .getInputStream();
204                         Log.d(TAG, "Got input stream: " + is);
205                     } catch (IOException e) {
206                         Log.d(TAG, "HTTP fetch error: " + e);
207                     }
208                 }
209             });
210 
211         final Button http3Button = (Button) findViewById(R.id.http3_button);
212         http3Button.setOnClickListener(new View.OnClickListener() {
213                 public void onClick(View v) {
214                     try {
215                         // One of Google's web IPs, as of 2010-06-16....
216                         InputStream is = new URL("http://74.125.19.14/")
217                                 .openConnection()
218                                 .getInputStream();
219                         Log.d(TAG, "Got input stream: " + is);
220                     } catch (IOException e) {
221                         Log.d(TAG, "HTTP fetch error: " + e);
222                     }
223                 }
224             });
225 
226         final Button binderLocalButton = (Button) findViewById(R.id.binder_local_button);
227         binderLocalButton.setOnClickListener(new View.OnClickListener() {
228                 public void onClick(View v) {
229                     try {
230                         boolean value = mLocalServiceConn.stub.doDiskWrite(123 /* dummy */);
231                         Log.d(TAG, "local writeToDisk returned: " + value);
232                     } catch (RemoteException e) {
233                         Log.d(TAG, "local binderButton error: " + e);
234                     }
235                 }
236             });
237 
238         final Button binderRemoteButton = (Button) findViewById(R.id.binder_remote_button);
239         binderRemoteButton.setOnClickListener(new View.OnClickListener() {
240                 public void onClick(View v) {
241                     try {
242                         boolean value = mRemoteServiceConn.stub.doDiskWrite(1);
243                         Log.d(TAG, "remote writeToDisk #1 returned: " + value);
244                         value = mRemoteServiceConn.stub.doDiskWrite(2);
245                         Log.d(TAG, "remote writeToDisk #2 returned: " + value);
246                     } catch (RemoteException e) {
247                         Log.d(TAG, "remote binderButton error: " + e);
248                     }
249                 }
250             });
251 
252         final Button binderOneWayButton = (Button) findViewById(R.id.binder_oneway_button);
253         binderOneWayButton.setOnClickListener(new View.OnClickListener() {
254                 public void onClick(View v) {
255                     try {
256                         Log.d(TAG, "doing oneway disk write over Binder.");
257                         mRemoteServiceConn.stub.doDiskOneWay();
258                     } catch (RemoteException e) {
259                         Log.d(TAG, "remote binderButton error: " + e);
260                     }
261                 }
262             });
263 
264         final Button binderCheckButton = (Button) findViewById(R.id.binder_check_button);
265         binderCheckButton.setOnClickListener(new View.OnClickListener() {
266                 public void onClick(View v) {
267                     int policy;
268                     try {
269                         policy = mLocalServiceConn.stub.getThreadPolicy();
270                         Log.d(TAG, "local service policy: " + policy);
271                         policy = mRemoteServiceConn.stub.getThreadPolicy();
272                         Log.d(TAG, "remote service policy: " + policy);
273                     } catch (RemoteException e) {
274                         Log.d(TAG, "binderCheckButton error: " + e);
275                     }
276                 }
277             });
278 
279         final Button serviceDumpButton = (Button) findViewById(R.id.service_dump);
280         serviceDumpButton.setOnClickListener(new View.OnClickListener() {
281                 public void onClick(View v) {
282                     Log.d(TAG, "About to do a service dump...");
283                     File file = new File("/sdcard/strictmode-service-dump.txt");
284                     FileOutputStream output = null;
285                     final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
286                     try {
287                         StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.LAX);
288                         output = new FileOutputStream(file);
289                         StrictMode.setThreadPolicy(oldPolicy);
290                         boolean dumped = Debug.dumpService("cpuinfo",
291                                                            output.getFD(), new String[0]);
292                         Log.d(TAG, "Dumped = " + dumped);
293                     } catch (IOException e) {
294                         Log.e(TAG, "Can't dump service", e);
295                     } finally {
296                         StrictMode.setThreadPolicy(oldPolicy);
297                     }
298                     Log.d(TAG, "Did service dump.");
299                 }
300             });
301 
302         final Button lingerCloseButton = (Button) findViewById(R.id.linger_close_button);
303         lingerCloseButton.setOnClickListener(new View.OnClickListener() {
304                 public void onClick(View v) {
305                     closeWithLinger(true);
306                 }
307             });
308 
309         final Button nonlingerCloseButton = (Button) findViewById(R.id.nonlinger_close_button);
310         nonlingerCloseButton.setOnClickListener(new View.OnClickListener() {
311                 public void onClick(View v) {
312                     closeWithLinger(false);
313                 }
314             });
315 
316         final Button leakCursorButton = (Button) findViewById(R.id.leak_cursor_button);
317         leakCursorButton.setOnClickListener(new View.OnClickListener() {
318                 public void onClick(View v) {
319                     final StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
320                     try {
321                         StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
322                                                .detectLeakedSqlLiteObjects()
323                                                .penaltyLog()
324                                                .penaltyDropBox()
325                                                .build());
326                         mDb.execSQL("CREATE TABLE IF NOT EXISTS FOO (a INT)");
327                         Cursor c = mDb.rawQuery("SELECT * FROM foo", null);
328                         c = null;  // never close it
329                         Runtime.getRuntime().gc();
330                     } finally {
331                         StrictMode.setVmPolicy(oldPolicy);
332                     }
333 
334                 }
335             });
336 
337         final Button customButton = (Button) findViewById(R.id.custom_button);
338         customButton.setOnClickListener(new View.OnClickListener() {
339                 public void onClick(View v) {
340                     StrictMode.noteSlowCall("my example call");
341                 }
342             });
343 
344         final Button gcInstanceButton = (Button) findViewById(R.id.gc_instance_button);
345         gcInstanceButton.setOnClickListener(new View.OnClickListener() {
346                 public void onClick(View v) {
347                     ArrayList<DummyObject> list = new ArrayList<DummyObject>();
348                     list.add(new DummyObject());
349                     list.add(new DummyObject());
350 
351                     StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder(StrictMode.getVmPolicy())
352                                            .setClassInstanceLimit(DummyObject.class, 1)
353                                            .penaltyLog()
354                                            .penaltyDropBox()
355                                            .build());
356                     StrictMode.conditionallyCheckInstanceCounts();
357                     list.clear();
358                 }
359             });
360 
361         final CheckBox checkNoWrite = (CheckBox) findViewById(R.id.policy_no_write);
362         final CheckBox checkNoRead = (CheckBox) findViewById(R.id.policy_no_reads);
363         final CheckBox checkNoNetwork = (CheckBox) findViewById(R.id.policy_no_network);
364         final CheckBox checkCustom = (CheckBox) findViewById(R.id.policy_custom);
365         final CheckBox checkPenaltyLog = (CheckBox) findViewById(R.id.policy_penalty_log);
366         final CheckBox checkPenaltyDialog = (CheckBox) findViewById(R.id.policy_penalty_dialog);
367         final CheckBox checkPenaltyDeath = (CheckBox) findViewById(R.id.policy_penalty_death);
368         final CheckBox checkPenaltyDropBox = (CheckBox) findViewById(R.id.policy_penalty_dropbox);
369         final CheckBox checkPenaltyFlash = (CheckBox) findViewById(R.id.policy_penalty_flash);
370         final CheckBox checkPenaltyNetworkDeath = (CheckBox) findViewById(R.id.policy_penalty_network_death);
371 
372         View.OnClickListener changePolicy = new View.OnClickListener() {
373                 public void onClick(View v) {
374                     StrictMode.ThreadPolicy.Builder newPolicy = new StrictMode.ThreadPolicy.Builder();
375                     if (checkNoWrite.isChecked()) newPolicy.detectDiskWrites();
376                     if (checkNoRead.isChecked()) newPolicy.detectDiskReads();
377                     if (checkNoNetwork.isChecked()) newPolicy.detectNetwork();
378                     if (checkCustom.isChecked()) newPolicy.detectCustomSlowCalls();
379                     if (checkPenaltyLog.isChecked()) newPolicy.penaltyLog();
380                     if (checkPenaltyDialog.isChecked()) newPolicy.penaltyDialog();
381                     if (checkPenaltyDeath.isChecked()) newPolicy.penaltyDeath();
382                     if (checkPenaltyDropBox.isChecked()) newPolicy.penaltyDropBox();
383                     if (checkPenaltyFlash.isChecked()) newPolicy.penaltyFlashScreen();
384                     if (checkPenaltyNetworkDeath.isChecked()) newPolicy.penaltyDeathOnNetwork();
385                     StrictMode.ThreadPolicy policy = newPolicy.build();
386                     Log.v(TAG, "Changing policy to: " + policy);
387                     StrictMode.setThreadPolicy(policy);
388                 }
389             };
390         checkNoWrite.setOnClickListener(changePolicy);
391         checkNoRead.setOnClickListener(changePolicy);
392         checkNoNetwork.setOnClickListener(changePolicy);
393         checkCustom.setOnClickListener(changePolicy);
394         checkPenaltyLog.setOnClickListener(changePolicy);
395         checkPenaltyDialog.setOnClickListener(changePolicy);
396         checkPenaltyDeath.setOnClickListener(changePolicy);
397         checkPenaltyDropBox.setOnClickListener(changePolicy);
398         checkPenaltyFlash.setOnClickListener(changePolicy);
399         checkPenaltyNetworkDeath.setOnClickListener(changePolicy);
400     }
401 
402     @Override
onDestroy()403     public void onDestroy() {
404         super.onDestroy();
405         mDb.close();
406         mDb = null;
407     }
408 
closeWithLinger(boolean linger)409     private void closeWithLinger(boolean linger) {
410         Log.d(TAG, "Socket linger test; linger=" + linger);
411         try {
412             Socket socket = new Socket();
413             socket.setSoLinger(linger, 5);
414             socket.close();
415         } catch (IOException e) {
416             Log.e(TAG, "Error with linger close", e);
417         }
418     }
419 
fileReadLoop()420     private void fileReadLoop() {
421         RandomAccessFile raf = null;
422         File filename = getFileStreamPath("test.dat");
423         try {
424             long sumNanos = 0;
425             byte[] buf = new byte[512];
426 
427             //raf = new RandomAccessFile(filename, "rw");
428             //raf.write(buf);
429             //raf.close();
430             //raf = null;
431 
432             // The data's almost certainly cached -- it's not clear what we're testing here
433             raf = new RandomAccessFile(filename, "r");
434             raf.seek(0);
435             raf.read(buf);
436         } catch (IOException e) {
437             Log.e(TAG, "File read failed", e);
438         } finally {
439             try { if (raf != null) raf.close(); } catch (IOException e) {}
440         }
441     }
442 
443     // Returns milliseconds taken, or -1 on failure.
settingsWrite(int mode)444     private long settingsWrite(int mode) {
445         Cursor c = null;
446         long startTime = SystemClock.uptimeMillis();
447         // The database will take care of replacing duplicates.
448         try {
449             ContentValues values = new ContentValues();
450             values.put("name", "dummy_for_testing");
451             values.put("value", "" + startTime);
452             Uri uri = cr.insert(SYSTEM_SETTINGS_URI, values);
453             Log.v(TAG, "inserted uri: " + uri);
454         } catch (SQLException e) {
455             Log.w(TAG, "sqliteexception during write: " + e);
456             return -1;
457         }
458         long duration = SystemClock.uptimeMillis() - startTime;
459         return duration;
460     }
461 
onResume()462     @Override public void onResume() {
463         super.onResume();
464         bindService(new Intent(this, LocalService.class),
465                     mLocalServiceConn, Context.BIND_AUTO_CREATE);
466         bindService(new Intent(this, RemoteService.class),
467                     mRemoteServiceConn, Context.BIND_AUTO_CREATE);
468     }
469 
onPause()470     @Override public void onPause() {
471         super.onPause();
472         unbindService(mLocalServiceConn);
473         unbindService(mRemoteServiceConn);
474     }
475 
476     private static class DummyObject {
477         int foo;
478     }
479 }
480