StrictModeActivity.java revision 9b6c0ab8ab190f3430a395edf689bf4d56c7c57d
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
17package com.android.strictmodetest;
18
19import android.app.Activity;
20import android.content.ComponentName;
21import android.content.ContentQueryMap;
22import android.content.ContentResolver;
23import android.content.ContentValues;
24import android.content.Context;
25import android.content.IContentProvider;
26import android.content.Intent;
27import android.content.ServiceConnection;
28import android.content.pm.PackageManager;
29import android.content.pm.ResolveInfo;
30import android.content.res.Configuration;
31import android.content.res.Resources;
32import android.database.Cursor;
33import android.database.Cursor;
34import android.database.SQLException;
35import android.database.sqlite.SQLiteDatabase;
36import android.net.LocalSocket;
37import android.net.LocalSocketAddress;
38import android.net.Uri;
39import android.os.Bundle;
40import android.os.Debug;
41import android.os.Handler;
42import android.os.IBinder;
43import android.os.Parcel;
44import android.os.RemoteException;
45import android.os.ServiceManager;
46import android.os.StrictMode;
47import android.os.SystemClock;
48import android.telephony.TelephonyManager;
49import android.text.TextUtils;
50import android.util.AndroidException;
51import android.util.Config;
52import android.util.Log;
53import android.view.View;
54import android.widget.Button;
55import android.widget.CheckBox;
56import android.widget.TextView;
57
58import org.apache.http.HttpResponse;
59import org.apache.http.client.methods.HttpUriRequest;
60import org.apache.http.client.methods.HttpGet;
61import org.apache.http.impl.client.DefaultHttpClient;
62
63import java.io.File;
64import java.io.FileInputStream;
65import java.io.FileOutputStream;
66import java.io.IOException;
67import java.io.InputStream;
68import java.io.OutputStream;
69import java.io.RandomAccessFile;
70import java.net.InetAddress;
71import java.net.URL;
72
73public class StrictModeActivity extends Activity {
74
75    private static final String TAG = "StrictModeActivity";
76    private static final Uri SYSTEM_SETTINGS_URI = Uri.parse("content://settings/system");
77
78    private ContentResolver cr;
79
80    private final static class SimpleConnection implements ServiceConnection {
81        public IService stub = null;
82        public void onServiceConnected(ComponentName name, IBinder service) {
83            stub = IService.Stub.asInterface(service);
84            Log.v(TAG, "Service connected: " + name);
85        }
86        public void onServiceDisconnected(ComponentName name) {
87            stub = null;
88            Log.v(TAG, "Service disconnected: " + name);
89        }
90    }
91
92    private final SimpleConnection mLocalServiceConn = new SimpleConnection();
93    private final SimpleConnection mRemoteServiceConn = new SimpleConnection();
94
95    /** Called when the activity is first created. */
96    @Override
97    public void onCreate(Bundle savedInstanceState) {
98        super.onCreate(savedInstanceState);
99        setContentView(R.layout.main);
100
101        cr = getContentResolver();
102        final SQLiteDatabase db = openOrCreateDatabase("foo.db", MODE_PRIVATE, null);
103
104        final Button readButton = (Button) findViewById(R.id.read_button);
105        readButton.setOnClickListener(new View.OnClickListener() {
106                public void onClick(View v) {
107                    Cursor c = null;
108                    try {
109                        c = db.rawQuery("SELECT * FROM foo", null);
110                    } finally {
111                        if (c != null) c.close();
112                    }
113                }
114            });
115
116        final Button writeButton = (Button) findViewById(R.id.write_button);
117        writeButton.setOnClickListener(new View.OnClickListener() {
118                public void onClick(View v) {
119                    db.execSQL("CREATE TABLE IF NOT EXISTS FOO (a INT)");
120                }
121            });
122
123        final Button dnsButton = (Button) findViewById(R.id.dns_button);
124        dnsButton.setOnClickListener(new View.OnClickListener() {
125                public void onClick(View v) {
126                    Log.d(TAG, "Doing DNS lookup for www.l.google.com... "
127                          + "(may be cached by InetAddress)");
128                    try {
129                        InetAddress[] addrs = InetAddress.getAllByName("www.l.google.com");
130                        for (int i = 0; i < addrs.length; ++i) {
131                            Log.d(TAG, "got: " + addrs[i]);
132                        }
133                    } catch (java.net.UnknownHostException e) {
134                        Log.d(TAG, "DNS error: " + e);
135                    }
136                }
137            });
138
139        final Button httpButton = (Button) findViewById(R.id.http_button);
140        httpButton.setOnClickListener(new View.OnClickListener() {
141                public void onClick(View v) {
142                    try {
143                        // Note: not using AndroidHttpClient, as that comes with its
144                        // own pre-StrictMode network-on-Looper thread check.  The
145                        // intent of this test is that we test the network stack's
146                        // instrumentation for StrictMode instead.
147                        DefaultHttpClient httpClient = new DefaultHttpClient();
148                        HttpResponse res = httpClient.execute(
149                            new HttpGet("http://www.android.com/favicon.ico"));
150                        Log.d(TAG, "Fetched http response: " + res);
151                    } catch (IOException e) {
152                        Log.d(TAG, "HTTP fetch error: " + e);
153                    }
154                }
155            });
156
157        final Button http2Button = (Button) findViewById(R.id.http2_button);
158        http2Button.setOnClickListener(new View.OnClickListener() {
159                public void onClick(View v) {
160                    try {
161                        // Usually this ends up tripping in DNS resolution,
162                        // so see http3Button below, which connects directly to an IP
163                        InputStream is = new URL("http://www.android.com/")
164                                .openConnection()
165                                .getInputStream();
166                        Log.d(TAG, "Got input stream: " + is);
167                    } catch (IOException e) {
168                        Log.d(TAG, "HTTP fetch error: " + e);
169                    }
170                }
171            });
172
173        final Button http3Button = (Button) findViewById(R.id.http3_button);
174        http3Button.setOnClickListener(new View.OnClickListener() {
175                public void onClick(View v) {
176                    try {
177                        // One of Google's web IPs, as of 2010-06-16....
178                        InputStream is = new URL("http://74.125.19.14/")
179                                .openConnection()
180                                .getInputStream();
181                        Log.d(TAG, "Got input stream: " + is);
182                    } catch (IOException e) {
183                        Log.d(TAG, "HTTP fetch error: " + e);
184                    }
185                }
186            });
187
188        final Button binderLocalButton = (Button) findViewById(R.id.binder_local_button);
189        binderLocalButton.setOnClickListener(new View.OnClickListener() {
190                public void onClick(View v) {
191                    try {
192                        boolean value = mLocalServiceConn.stub.doDiskWrite(123 /* dummy */);
193                        Log.d(TAG, "local writeToDisk returned: " + value);
194                    } catch (RemoteException e) {
195                        Log.d(TAG, "local binderButton error: " + e);
196                    }
197                }
198            });
199
200        final Button binderRemoteButton = (Button) findViewById(R.id.binder_remote_button);
201        binderRemoteButton.setOnClickListener(new View.OnClickListener() {
202                public void onClick(View v) {
203                    try {
204                        boolean value = mRemoteServiceConn.stub.doDiskWrite(123 /* dummy */);
205                        Log.d(TAG, "remote writeToDisk returned: " + value);
206                    } catch (RemoteException e) {
207                        Log.d(TAG, "remote binderButton error: " + e);
208                    }
209                }
210            });
211
212        final Button binderCheckButton = (Button) findViewById(R.id.binder_check_button);
213        binderCheckButton.setOnClickListener(new View.OnClickListener() {
214                public void onClick(View v) {
215                    int policy;
216                    try {
217                        policy = mLocalServiceConn.stub.getThreadPolicy();
218                        Log.d(TAG, "local service policy: " + policy);
219                        policy = mRemoteServiceConn.stub.getThreadPolicy();
220                        Log.d(TAG, "remote service policy: " + policy);
221                    } catch (RemoteException e) {
222                        Log.d(TAG, "binderCheckButton error: " + e);
223                    }
224                }
225            });
226
227        final Button serviceDumpButton = (Button) findViewById(R.id.service_dump);
228        serviceDumpButton.setOnClickListener(new View.OnClickListener() {
229                public void onClick(View v) {
230                    Log.d(TAG, "About to do a service dump...");
231                    File file = new File("/sdcard/strictmode-service-dump.txt");
232                    FileOutputStream output = null;
233                    final int oldPolicy = StrictMode.getThreadBlockingPolicy();
234                    try {
235                        StrictMode.setThreadBlockingPolicy(0);
236                        output = new FileOutputStream(file);
237                        StrictMode.setThreadBlockingPolicy(oldPolicy);
238                        boolean dumped = Debug.dumpService("cpuinfo",
239                                                           output.getFD(), new String[0]);
240                        Log.d(TAG, "Dumped = " + dumped);
241                    } catch (IOException e) {
242                        Log.e(TAG, "Can't dump service", e);
243                    } finally {
244                        StrictMode.setThreadBlockingPolicy(oldPolicy);
245                    }
246                    Log.d(TAG, "Did service dump.");
247                }
248            });
249
250        final CheckBox checkNoWrite = (CheckBox) findViewById(R.id.policy_no_write);
251        final CheckBox checkNoRead = (CheckBox) findViewById(R.id.policy_no_reads);
252        final CheckBox checkNoNetwork = (CheckBox) findViewById(R.id.policy_no_network);
253        final CheckBox checkPenaltyLog = (CheckBox) findViewById(R.id.policy_penalty_log);
254        final CheckBox checkPenaltyDialog = (CheckBox) findViewById(R.id.policy_penalty_dialog);
255        final CheckBox checkPenaltyDeath = (CheckBox) findViewById(R.id.policy_penalty_death);
256        final CheckBox checkPenaltyDropBox = (CheckBox) findViewById(R.id.policy_penalty_dropbox);
257
258        View.OnClickListener changePolicy = new View.OnClickListener() {
259                public void onClick(View v) {
260                    int newPolicy = 0;
261                    if (checkNoWrite.isChecked()) newPolicy |= StrictMode.DISALLOW_DISK_WRITE;
262                    if (checkNoRead.isChecked()) newPolicy |= StrictMode.DISALLOW_DISK_READ;
263                    if (checkNoNetwork.isChecked()) newPolicy |= StrictMode.DISALLOW_NETWORK;
264                    if (checkPenaltyLog.isChecked()) newPolicy |= StrictMode.PENALTY_LOG;
265                    if (checkPenaltyDialog.isChecked()) newPolicy |= StrictMode.PENALTY_DIALOG;
266                    if (checkPenaltyDeath.isChecked()) newPolicy |= StrictMode.PENALTY_DEATH;
267                    if (checkPenaltyDropBox.isChecked()) newPolicy |= StrictMode.PENALTY_DROPBOX;
268                    Log.v(TAG, "Changing policy to: " + newPolicy);
269                    StrictMode.setThreadBlockingPolicy(newPolicy);
270                }
271            };
272        checkNoWrite.setOnClickListener(changePolicy);
273        checkNoRead.setOnClickListener(changePolicy);
274        checkNoNetwork.setOnClickListener(changePolicy);
275        checkPenaltyLog.setOnClickListener(changePolicy);
276        checkPenaltyDialog.setOnClickListener(changePolicy);
277        checkPenaltyDeath.setOnClickListener(changePolicy);
278        checkPenaltyDropBox.setOnClickListener(changePolicy);
279    }
280
281    private void fileReadLoop() {
282        RandomAccessFile raf = null;
283        File filename = getFileStreamPath("test.dat");
284        try {
285            long sumNanos = 0;
286            byte[] buf = new byte[512];
287
288            //raf = new RandomAccessFile(filename, "rw");
289            //raf.write(buf);
290            //raf.close();
291            //raf = null;
292
293            // The data's almost certainly cached -- it's not clear what we're testing here
294            raf = new RandomAccessFile(filename, "r");
295            raf.seek(0);
296            raf.read(buf);
297        } catch (IOException e) {
298            Log.e(TAG, "File read failed", e);
299        } finally {
300            try { if (raf != null) raf.close(); } catch (IOException e) {}
301        }
302    }
303
304    // Returns milliseconds taken, or -1 on failure.
305    private long settingsWrite(int mode) {
306        Cursor c = null;
307        long startTime = SystemClock.uptimeMillis();
308        // The database will take care of replacing duplicates.
309        try {
310            ContentValues values = new ContentValues();
311            values.put("name", "dummy_for_testing");
312            values.put("value", "" + startTime);
313            Uri uri = cr.insert(SYSTEM_SETTINGS_URI, values);
314            Log.v(TAG, "inserted uri: " + uri);
315        } catch (SQLException e) {
316            Log.w(TAG, "sqliteexception during write: " + e);
317            return -1;
318        }
319        long duration = SystemClock.uptimeMillis() - startTime;
320        return duration;
321    }
322
323    @Override public void onResume() {
324        super.onResume();
325        bindService(new Intent(this, LocalService.class),
326                    mLocalServiceConn, Context.BIND_AUTO_CREATE);
327        bindService(new Intent(this, RemoteService.class),
328                    mRemoteServiceConn, Context.BIND_AUTO_CREATE);
329    }
330
331    @Override public void onPause() {
332        super.onPause();
333        unbindService(mLocalServiceConn);
334        unbindService(mRemoteServiceConn);
335    }
336}
337