StrictMode.java revision 46d42387464a651268648659e91d022566d4844c
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 26import java.util.HashMap; 27 28/** 29 * <p>StrictMode lets you impose stricter rules under which your 30 * application runs.</p> 31 */ 32public final class StrictMode { 33 private static final String TAG = "StrictMode"; 34 35 // Only log a duplicate stack trace to the logs every second. 36 private static final long MIN_LOG_INTERVAL_MS = 1000; 37 38 // Only show an annoying dialog at most every 30 seconds 39 private static final long MIN_DIALOG_INTERVAL_MS = 30000; 40 41 private StrictMode() {} 42 43 public static final int DISALLOW_DISK_WRITE = 0x01; 44 public static final int DISALLOW_DISK_READ = 0x02; 45 public static final int DISALLOW_NETWORK = 0x04; 46 47 /** @hide */ 48 public static final int DISALLOW_MASK = 49 DISALLOW_DISK_WRITE | DISALLOW_DISK_READ | DISALLOW_NETWORK; 50 51 /** 52 * Flag to log to the system log. 53 */ 54 public static final int PENALTY_LOG = 0x10; // normal android.util.Log 55 56 /** 57 * Show an annoying dialog to the user. Will be rate-limited to be only 58 * a little annoying. 59 */ 60 public static final int PENALTY_DIALOG = 0x20; 61 62 /** 63 * Crash hard if policy is violated. 64 */ 65 public static final int PENALTY_DEATH = 0x40; 66 67 /** 68 * Log a stacktrace to the DropBox on policy violation. 69 */ 70 public static final int PENALTY_DROPBOX = 0x80; 71 72 /** @hide */ 73 public static final int PENALTY_MASK = 74 PENALTY_LOG | PENALTY_DIALOG | 75 PENALTY_DROPBOX | PENALTY_DEATH; 76 77 /** 78 * Sets the policy for what actions the current thread is denied, 79 * as well as the penalty for violating the policy. 80 * 81 * @param policyMask a bitmask of DISALLOW_* and PENALTY_* values. 82 */ 83 public static void setThreadBlockingPolicy(final int policyMask) { 84 if (policyMask == 0) { 85 BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY); 86 return; 87 } 88 BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); 89 if (!(policy instanceof AndroidBlockGuardPolicy)) { 90 BlockGuard.setThreadPolicy(new AndroidBlockGuardPolicy(policyMask)); 91 } else { 92 AndroidBlockGuardPolicy androidPolicy = (AndroidBlockGuardPolicy) policy; 93 androidPolicy.setPolicyMask(policyMask); 94 } 95 } 96 97 /** 98 * Returns the bitmask of the current thread's blocking policy. 99 * 100 * @return the bitmask of all the DISALLOW_* and PENALTY_* bits currently enabled 101 */ 102 public static int getThreadBlockingPolicy() { 103 return BlockGuard.getThreadPolicy().getPolicyMask(); 104 } 105 106 private static class AndroidBlockGuardPolicy implements BlockGuard.Policy { 107 private int mPolicyMask; 108 109 // Map from violation stacktrace hashcode -> uptimeMillis of 110 // last violation. No locking needed, as this is only 111 // accessed by the same thread. 112 private final HashMap<Integer, Long> mLastViolationTime = new HashMap<Integer, Long>(); 113 114 public AndroidBlockGuardPolicy(final int policyMask) { 115 mPolicyMask = policyMask; 116 } 117 118 // Part of BlockGuard.Policy interface: 119 public int getPolicyMask() { 120 return mPolicyMask; 121 } 122 123 // Part of BlockGuard.Policy interface: 124 public void onWriteToDisk() { 125 if ((mPolicyMask & DISALLOW_DISK_WRITE) == 0) { 126 return; 127 } 128 handleViolation(DISALLOW_DISK_WRITE); 129 } 130 131 // Part of BlockGuard.Policy interface: 132 public void onReadFromDisk() { 133 if ((mPolicyMask & DISALLOW_DISK_READ) == 0) { 134 return; 135 } 136 handleViolation(DISALLOW_DISK_READ); 137 } 138 139 // Part of BlockGuard.Policy interface: 140 public void onNetwork() { 141 if ((mPolicyMask & DISALLOW_NETWORK) == 0) { 142 return; 143 } 144 handleViolation(DISALLOW_NETWORK); 145 } 146 147 public void setPolicyMask(int policyMask) { 148 mPolicyMask = policyMask; 149 } 150 151 private void handleViolation(int violationBit) { 152 final BlockGuard.BlockGuardPolicyException violation = 153 new BlockGuard.BlockGuardPolicyException(mPolicyMask, violationBit); 154 violation.fillInStackTrace(); 155 156 Looper looper = Looper.myLooper(); 157 if (looper == null) { 158 // Without a Looper, we're unable to time how long the 159 // violation takes place. This case should be rare, 160 // as most users will care about timing violations 161 // that happen on their main UI thread. 162 handleViolationWithTime(violation, -1L /* no time */); 163 } else { 164 MessageQueue queue = Looper.myQueue(); 165 final long violationTime = SystemClock.uptimeMillis(); 166 queue.addIdleHandler(new MessageQueue.IdleHandler() { 167 public boolean queueIdle() { 168 long afterViolationTime = SystemClock.uptimeMillis(); 169 handleViolationWithTime(violation, afterViolationTime - violationTime); 170 return false; // remove this idle handler from the array 171 } 172 }); 173 } 174 } 175 176 private void handleViolationWithTime( 177 BlockGuard.BlockGuardPolicyException violation, 178 long durationMillis) { 179 180 // It's possible (even quite likely) that mPolicyMask has 181 // changed from the time the violation fired and now 182 // (after the violating code ran) due to people who 183 // push/pop temporary policy in regions of code. So use 184 // the old policy here. 185 int policy = violation.getPolicy(); 186 187 // Not _really_ a Crash, but we use the same data structure... 188 ApplicationErrorReport.CrashInfo crashInfo = 189 new ApplicationErrorReport.CrashInfo(violation); 190 191 // Not perfect, but fast and good enough for dup suppression. 192 Integer crashFingerprint = crashInfo.stackTrace.hashCode(); 193 long lastViolationTime = 0; 194 if (mLastViolationTime.containsKey(crashFingerprint)) { 195 lastViolationTime = mLastViolationTime.get(crashFingerprint); 196 } 197 long now = SystemClock.uptimeMillis(); 198 mLastViolationTime.put(crashFingerprint, now); 199 long timeSinceLastViolationMillis = lastViolationTime == 0 ? 200 Long.MAX_VALUE : (now - lastViolationTime); 201 202 if ((policy & PENALTY_LOG) != 0 && 203 timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { 204 if (durationMillis != -1) { 205 Log.d(TAG, "StrictMode policy violation; ~duration=" + durationMillis + " ms", 206 violation); 207 } else { 208 Log.d(TAG, "StrictMode policy violation.", violation); 209 } 210 } 211 212 // The violationMask, passed to ActivityManager, is a 213 // subset of the original StrictMode policy bitmask, with 214 // only the bit violated and penalty bits to be executed 215 // by the ActivityManagerService remaining set. 216 int violationMask = 0; 217 218 if ((policy & PENALTY_DIALOG) != 0 && 219 timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) { 220 violationMask |= PENALTY_DIALOG; 221 } 222 223 if ((policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) { 224 violationMask |= PENALTY_DROPBOX; 225 } 226 227 if (violationMask != 0) { 228 violationMask |= violation.getPolicyViolation(); 229 try { 230 ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( 231 RuntimeInit.getApplicationObject(), 232 violationMask, 233 new ApplicationErrorReport.CrashInfo(violation)); 234 } catch (RemoteException e) { 235 Log.e(TAG, "RemoteException trying to handle StrictMode violation", e); 236 } 237 } 238 239 if ((policy & PENALTY_DEATH) != 0) { 240 System.err.println("StrictMode policy violation with POLICY_DEATH; shutting down."); 241 Process.killProcess(Process.myPid()); 242 System.exit(10); 243 } 244 } 245 } 246} 247