• 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 checkResourceMismatch = (CheckBox) findViewById(R.id.policy_resource_mismatch);
366         final CheckBox checkPenaltyLog = (CheckBox) findViewById(R.id.policy_penalty_log);
367         final CheckBox checkPenaltyDialog = (CheckBox) findViewById(R.id.policy_penalty_dialog);
368         final CheckBox checkPenaltyDeath = (CheckBox) findViewById(R.id.policy_penalty_death);
369         final CheckBox checkPenaltyDropBox = (CheckBox) findViewById(R.id.policy_penalty_dropbox);
370         final CheckBox checkPenaltyFlash = (CheckBox) findViewById(R.id.policy_penalty_flash);
371         final CheckBox checkPenaltyNetworkDeath = (CheckBox) findViewById(R.id.policy_penalty_network_death);
372 
373         View.OnClickListener changePolicy = new View.OnClickListener() {
374                 public void onClick(View v) {
375                     StrictMode.ThreadPolicy.Builder newPolicy = new StrictMode.ThreadPolicy.Builder();
376                     if (checkNoWrite.isChecked()) newPolicy.detectDiskWrites();
377                     if (checkNoRead.isChecked()) newPolicy.detectDiskReads();
378                     if (checkNoNetwork.isChecked()) newPolicy.detectNetwork();
379                     if (checkCustom.isChecked()) newPolicy.detectCustomSlowCalls();
380                     if (checkResourceMismatch.isChecked()) newPolicy.detectResourceMismatches();
381                     if (checkPenaltyLog.isChecked()) newPolicy.penaltyLog();
382                     if (checkPenaltyDialog.isChecked()) newPolicy.penaltyDialog();
383                     if (checkPenaltyDeath.isChecked()) newPolicy.penaltyDeath();
384                     if (checkPenaltyDropBox.isChecked()) newPolicy.penaltyDropBox();
385                     if (checkPenaltyFlash.isChecked()) newPolicy.penaltyFlashScreen();
386                     if (checkPenaltyNetworkDeath.isChecked()) newPolicy.penaltyDeathOnNetwork();
387                     StrictMode.ThreadPolicy policy = newPolicy.build();
388                     Log.v(TAG, "Changing policy to: " + policy);
389                     StrictMode.setThreadPolicy(policy);
390                 }
391             };
392         checkNoWrite.setOnClickListener(changePolicy);
393         checkNoRead.setOnClickListener(changePolicy);
394         checkNoNetwork.setOnClickListener(changePolicy);
395         checkCustom.setOnClickListener(changePolicy);
396         checkResourceMismatch.setOnClickListener(changePolicy);
397         checkPenaltyLog.setOnClickListener(changePolicy);
398         checkPenaltyDialog.setOnClickListener(changePolicy);
399         checkPenaltyDeath.setOnClickListener(changePolicy);
400         checkPenaltyDropBox.setOnClickListener(changePolicy);
401         checkPenaltyFlash.setOnClickListener(changePolicy);
402         checkPenaltyNetworkDeath.setOnClickListener(changePolicy);
403     }
404 
405     @Override
onDestroy()406     public void onDestroy() {
407         super.onDestroy();
408         mDb.close();
409         mDb = null;
410     }
411 
closeWithLinger(boolean linger)412     private void closeWithLinger(boolean linger) {
413         Log.d(TAG, "Socket linger test; linger=" + linger);
414         try {
415             Socket socket = new Socket();
416             socket.setSoLinger(linger, 5);
417             socket.close();
418         } catch (IOException e) {
419             Log.e(TAG, "Error with linger close", e);
420         }
421     }
422 
fileReadLoop()423     private void fileReadLoop() {
424         RandomAccessFile raf = null;
425         File filename = getFileStreamPath("test.dat");
426         try {
427             long sumNanos = 0;
428             byte[] buf = new byte[512];
429 
430             //raf = new RandomAccessFile(filename, "rw");
431             //raf.write(buf);
432             //raf.close();
433             //raf = null;
434 
435             // The data's almost certainly cached -- it's not clear what we're testing here
436             raf = new RandomAccessFile(filename, "r");
437             raf.seek(0);
438             raf.read(buf);
439         } catch (IOException e) {
440             Log.e(TAG, "File read failed", e);
441         } finally {
442             try { if (raf != null) raf.close(); } catch (IOException e) {}
443         }
444     }
445 
446     // Returns milliseconds taken, or -1 on failure.
settingsWrite(int mode)447     private long settingsWrite(int mode) {
448         Cursor c = null;
449         long startTime = SystemClock.uptimeMillis();
450         // The database will take care of replacing duplicates.
451         try {
452             ContentValues values = new ContentValues();
453             values.put("name", "dummy_for_testing");
454             values.put("value", "" + startTime);
455             Uri uri = cr.insert(SYSTEM_SETTINGS_URI, values);
456             Log.v(TAG, "inserted uri: " + uri);
457         } catch (SQLException e) {
458             Log.w(TAG, "sqliteexception during write: " + e);
459             return -1;
460         }
461         long duration = SystemClock.uptimeMillis() - startTime;
462         return duration;
463     }
464 
onResume()465     @Override public void onResume() {
466         super.onResume();
467         bindService(new Intent(this, LocalService.class),
468                     mLocalServiceConn, Context.BIND_AUTO_CREATE);
469         bindService(new Intent(this, RemoteService.class),
470                     mRemoteServiceConn, Context.BIND_AUTO_CREATE);
471     }
472 
onPause()473     @Override public void onPause() {
474         super.onPause();
475         unbindService(mLocalServiceConn);
476         unbindService(mRemoteServiceConn);
477     }
478 
479     private static class DummyObject {
480         int foo;
481     }
482 }
483