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.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;
     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 
     75 public class StrictModeActivity extends Activity {
     76 
     77     private static final String TAG = "StrictModeActivity";
     78     private static final Uri SYSTEM_SETTINGS_URI = Uri.parse("content://settings/system");
     79 
     80     private ContentResolver cr;
     81 
     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);
     87         }
     88         public void onServiceDisconnected(ComponentName name) {
     89             stub = null;
     90             Log.v(TAG, "Service disconnected: " + name);
     91         }
     92     }
     93 
     94     private final SimpleConnection mLocalServiceConn = new SimpleConnection();
     95     private final SimpleConnection mRemoteServiceConn = new SimpleConnection();
     96 
     97     /** Called when the activity is first created. */
     98     @Override
     99     public void onCreate(Bundle savedInstanceState) {
    100         super.onCreate(savedInstanceState);
    101         setContentView(R.layout.main);
    102 
    103         cr = getContentResolver();
    104         final SQLiteDatabase db = openOrCreateDatabase("foo.db", MODE_PRIVATE, null);
    105 
    106         final Button readButton = (Button) findViewById(R.id.read_button);
    107         readButton.setOnClickListener(new View.OnClickListener() {
    108                 public void onClick(View v) {
    109                     Cursor c = null;
    110                     try {
    111                         c = db.rawQuery("SELECT * FROM foo", null);
    112                     } finally {
    113                         if (c != null) c.close();
    114                     }
    115                 }
    116             });
    117 
    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)");
    122                 }
    123             });
    124 
    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();
    129                     int iters = 1000;
    130                     BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
    131                     for (int i = 0; i < iters; ++i) {
    132                         policy.onWriteToDisk();
    133                     }
    134                     long endTime = SystemClock.uptimeMillis();
    135                     Log.d(TAG, "Time for " + iters + ": " + (endTime - startTime) + ", avg=" +
    136                           (endTime - startTime) / (double) iters);
    137                 }
    138             });
    139 
    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)");
    145                     try {
    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]);
    149                         }
    150                     } catch (java.net.UnknownHostException e) {
    151                         Log.d(TAG, "DNS error: " + e);
    152                     }
    153                 }
    154             });
    155 
    156         final Button httpButton = (Button) findViewById(R.id.http_button);
    157         httpButton.setOnClickListener(new View.OnClickListener() {
    158                 public void onClick(View v) {
    159                     try {
    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);
    170                     }
    171                 }
    172             });
    173 
    174         final Button http2Button = (Button) findViewById(R.id.http2_button);
    175         http2Button.setOnClickListener(new View.OnClickListener() {
    176                 public void onClick(View v) {
    177                     try {
    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/")
    181                                 .openConnection()
    182                                 .getInputStream();
    183                         Log.d(TAG, "Got input stream: " + is);
    184                     } catch (IOException e) {
    185                         Log.d(TAG, "HTTP fetch error: " + e);
    186                     }
    187                 }
    188             });
    189 
    190         final Button http3Button = (Button) findViewById(R.id.http3_button);
    191         http3Button.setOnClickListener(new View.OnClickListener() {
    192                 public void onClick(View v) {
    193                     try {
    194                         // One of Google's web IPs, as of 2010-06-16....
    195                         InputStream is = new URL("http://74.125.19.14/")
    196                                 .openConnection()
    197                                 .getInputStream();
    198                         Log.d(TAG, "Got input stream: " + is);
    199                     } catch (IOException e) {
    200                         Log.d(TAG, "HTTP fetch error: " + e);
    201                     }
    202                 }
    203             });
    204 
    205         final Button binderLocalButton = (Button) findViewById(R.id.binder_local_button);
    206         binderLocalButton.setOnClickListener(new View.OnClickListener() {
    207                 public void onClick(View v) {
    208                     try {
    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);
    213                     }
    214                 }
    215             });
    216 
    217         final Button binderRemoteButton = (Button) findViewById(R.id.binder_remote_button);
    218         binderRemoteButton.setOnClickListener(new View.OnClickListener() {
    219                 public void onClick(View v) {
    220                     try {
    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);
    227                     }
    228                 }
    229             });
    230 
    231         final Button binderOneWayButton = (Button) findViewById(R.id.binder_oneway_button);
    232         binderOneWayButton.setOnClickListener(new View.OnClickListener() {
    233                 public void onClick(View v) {
    234                     try {
    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);
    239                     }
    240                 }
    241             });
    242 
    243         final Button binderCheckButton = (Button) findViewById(R.id.binder_check_button);
    244         binderCheckButton.setOnClickListener(new View.OnClickListener() {
    245                 public void onClick(View v) {
    246                     int policy;
    247                     try {
    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);
    254                     }
    255                 }
    256             });
    257 
    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();
    265                     try {
    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);
    274                     } finally {
    275                         StrictMode.setThreadPolicy(oldPolicy);
    276                     }
    277                     Log.d(TAG, "Did service dump.");
    278                 }
    279             });
    280 
    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);
    285                 }
    286             });
    287 
    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);
    292                 }
    293             });
    294 
    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();
    299                     try {
    300                         StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
    301                                                .detectLeakedSqlLiteObjects()
    302                                                .penaltyLog()
    303                                                .penaltyDropBox()
    304                                                .build());
    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();
    309                     } finally {
    310                         StrictMode.setVmPolicy(oldPolicy);
    311                     }
    312 
    313                 }
    314             });
    315 
    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);
    323 
    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);
    337                 }
    338             };
    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);
    346     }
    347 
    348     private void closeWithLinger(boolean linger) {
    349         Log.d(TAG, "Socket linger test; linger=" + linger);
    350         try {
    351             Socket socket = new Socket();
    352             socket.setSoLinger(linger, 5);
    353             socket.close();
    354         } catch (IOException e) {
    355             Log.e(TAG, "Error with linger close", e);
    356         }
    357     }
    358 
    359     private void fileReadLoop() {
    360         RandomAccessFile raf = null;
    361         File filename = getFileStreamPath("test.dat");
    362         try {
    363             long sumNanos = 0;
    364             byte[] buf = new byte[512];
    365 
    366             //raf = new RandomAccessFile(filename, "rw");
    367             //raf.write(buf);
    368             //raf.close();
    369             //raf = null;
    370 
    371             // The data's almost certainly cached -- it's not clear what we're testing here
    372             raf = new RandomAccessFile(filename, "r");
    373             raf.seek(0);
    374             raf.read(buf);
    375         } catch (IOException e) {
    376             Log.e(TAG, "File read failed", e);
    377         } finally {
    378             try { if (raf != null) raf.close(); } catch (IOException e) {}
    379         }
    380     }
    381 
    382     // Returns milliseconds taken, or -1 on failure.
    383     private long settingsWrite(int mode) {
    384         Cursor c = null;
    385         long startTime = SystemClock.uptimeMillis();
    386         // The database will take care of replacing duplicates.
    387         try {
    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);
    395             return -1;
    396         }
    397         long duration = SystemClock.uptimeMillis() - startTime;
    398         return duration;
    399     }
    400 
    401     @Override public void onResume() {
    402         super.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);
    407     }
    408 
    409     @Override public void onPause() {
    410         super.onPause();
    411         unbindService(mLocalServiceConn);
    412         unbindService(mRemoteServiceConn);
    413     }
    414 }
    415