Home | History | Annotate | Download | only in strictmodetest
      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;
     85         public void onServiceConnected(ComponentName name, IBinder service) {
     86             stub = IService.Stub.asInterface(service);
     87             Log.v(TAG, "Service connected: " + name);
     88         }
     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
    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
    403     public void onDestroy() {
    404         super.onDestroy();
    405         mDb.close();
    406         mDb = null;
    407     }
    408 
    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 
    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.
    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 
    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 
    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