StrictMode.java revision 438d0595121a7a2cdf19741e76e3c0e21a5c173d
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 */ 16package android.os; 17 18import android.app.ActivityManagerNative; 19import android.app.ApplicationErrorReport; 20import android.util.Log; 21 22import com.android.internal.os.RuntimeInit; 23 24import dalvik.system.BlockGuard; 25 26/** 27 * <p>StrictMode lets you impose stricter rules under which your 28 * application runs.</p> 29 */ 30public final class StrictMode { 31 private static final String TAG = "StrictMode"; 32 33 private StrictMode() {} 34 35 public static final int DISALLOW_DISK_WRITE = 0x01; 36 public static final int DISALLOW_DISK_READ = 0x02; 37 public static final int DISALLOW_NETWORK = 0x04; 38 39 /** @hide */ 40 public static final int DISALLOW_MASK = 41 DISALLOW_DISK_WRITE | DISALLOW_DISK_READ | DISALLOW_NETWORK; 42 43 /** 44 * Flag to log to the system log. 45 */ 46 public static final int PENALTY_LOG = 0x10; // normal android.util.Log 47 48 /** 49 * Show an annoying dialog to the user. Will be rate-limited to be only 50 * a little annoying. 51 */ 52 public static final int PENALTY_DIALOG = 0x20; 53 54 /** 55 * Crash hard if policy is violated. 56 */ 57 public static final int PENALTY_DEATH = 0x40; 58 59 /** 60 * Log a stacktrace to the DropBox on policy violation. 61 */ 62 public static final int PENALTY_DROPBOX = 0x80; 63 64 /** @hide */ 65 public static final int PENALTY_MASK = 66 PENALTY_LOG | PENALTY_DIALOG | 67 PENALTY_DROPBOX | PENALTY_DEATH; 68 69 /** 70 * Sets the policy for what actions the current thread is denied, 71 * as well as the penalty for violating the policy. 72 * 73 * @param policyMask a bitmask of DISALLOW_* and PENALTY_* values. 74 */ 75 public static void setThreadBlockingPolicy(final int policyMask) { 76 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 77 if (!(policy instanceof AndroidBlockGuardPolicy)) { 78 BlockGuard.setThreadPolicy(new AndroidBlockGuardPolicy(policyMask)); 79 } else { 80 AndroidBlockGuardPolicy androidPolicy = (AndroidBlockGuardPolicy) policy; 81 androidPolicy.setPolicyMask(policyMask); 82 } 83 } 84 85 /** 86 * Returns the bitmask of the current thread's blocking policy. 87 * 88 * @return the bitmask of all the DISALLOW_* and PENALTY_* bits currently enabled 89 */ 90 public static int getThreadBlockingPolicy() { 91 return BlockGuard.getThreadPolicy().getPolicyMask(); 92 } 93 94 /** @hide */ 95 public static void setDropBoxManager(DropBoxManager dropBoxManager) { 96 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 97 if (!(policy instanceof AndroidBlockGuardPolicy)) { 98 policy = new AndroidBlockGuardPolicy(0); 99 BlockGuard.setThreadPolicy(policy); 100 } 101 ((AndroidBlockGuardPolicy) policy).setDropBoxManager(dropBoxManager); 102 } 103 104 private static class AndroidBlockGuardPolicy implements BlockGuard.Policy { 105 private int mPolicyMask; 106 private DropBoxManager mDropBoxManager = null; 107 108 public AndroidBlockGuardPolicy(final int policyMask) { 109 mPolicyMask = policyMask; 110 } 111 112 // Part of BlockGuard.Policy interface: 113 public int getPolicyMask() { 114 return mPolicyMask; 115 } 116 117 // Part of BlockGuard.Policy interface: 118 public void onWriteToDisk() { 119 if ((mPolicyMask & DISALLOW_DISK_WRITE) == 0) { 120 return; 121 } 122 handleViolation(DISALLOW_DISK_WRITE); 123 } 124 125 // Part of BlockGuard.Policy interface: 126 public void onReadFromDisk() { 127 if ((mPolicyMask & DISALLOW_DISK_READ) == 0) { 128 return; 129 } 130 handleViolation(DISALLOW_DISK_READ); 131 } 132 133 // Part of BlockGuard.Policy interface: 134 public void onNetwork() { 135 if ((mPolicyMask & DISALLOW_NETWORK) == 0) { 136 return; 137 } 138 handleViolation(DISALLOW_NETWORK); 139 } 140 141 public void setPolicyMask(int policyMask) { 142 mPolicyMask = policyMask; 143 } 144 145 public void setDropBoxManager(DropBoxManager dropBoxManager) { 146 mDropBoxManager = dropBoxManager; 147 } 148 149 private void handleViolation(int violationBit) { 150 final BlockGuard.BlockGuardPolicyException violation = 151 new BlockGuard.BlockGuardPolicyException(mPolicyMask, violationBit); 152 violation.fillInStackTrace(); 153 154 Looper looper = Looper.myLooper(); 155 if (looper == null) { 156 // Without a Looper, we're unable to time how long the 157 // violation takes place. This case should be rare, 158 // as most users will care about timing violations 159 // that happen on their main UI thread. 160 handleViolationWithTime(violation, -1L /* no time */); 161 } else { 162 MessageQueue queue = Looper.myQueue(); 163 final long violationTime = SystemClock.uptimeMillis(); 164 queue.addIdleHandler(new MessageQueue.IdleHandler() { 165 public boolean queueIdle() { 166 long afterViolationTime = SystemClock.uptimeMillis(); 167 handleViolationWithTime(violation, afterViolationTime - violationTime); 168 return false; // remove this idle handler from the array 169 } 170 }); 171 } 172 } 173 174 private void handleViolationWithTime( 175 BlockGuard.BlockGuardPolicyException violation, 176 long durationMillis) { 177 178 // It's possible (even quite likely) that mPolicyMask has 179 // changed from the time the violation fired and now 180 // (after the violating code ran) due to people who 181 // push/pop temporary policy in regions of code. So use 182 // the old policy here. 183 int policy = violation.getPolicy(); 184 185 if ((policy & PENALTY_LOG) != 0) { 186 if (durationMillis != -1) { 187 Log.d(TAG, "StrictMode policy violation; ~duration=" + durationMillis + " ms", 188 violation); 189 } else { 190 Log.d(TAG, "StrictMode policy violation.", violation); 191 } 192 } 193 194 if ((policy & PENALTY_DIALOG) != 0) { 195 // Currently this is just used for the dialog. 196 try { 197 ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( 198 RuntimeInit.getApplicationObject(), 199 new ApplicationErrorReport.CrashInfo(violation)); 200 } catch (RemoteException e) { 201 Log.e(TAG, "RemoteException trying to open strict mode dialog", e); 202 } 203 } 204 205 if ((policy & PENALTY_DROPBOX) != 0) { 206 // TODO: call into ActivityManagerNative to do the dropboxing. 207 // But do the first-layer signature dup-checking first client-side. 208 // This conditional should be combined with the above, too, along 209 // with PENALTY_DEATH below. 210 } 211 212 if ((policy & PENALTY_DEATH) != 0) { 213 System.err.println("StrictMode policy violation with POLICY_DEATH; shutting down."); 214 Process.killProcess(Process.myPid()); 215 System.exit(10); 216 } 217 } 218 } 219} 220