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 dalvik.system;
18 
19 import java.io.FileDescriptor;
20 import java.io.FileNotFoundException;
21 import java.io.FileOutputStream;
22 import java.io.IOException;
23 import java.math.BigInteger;
24 import java.net.SocketException;
25 
26 /**
27  * Mechanism to let threads set restrictions on what code is allowed
28  * to do in their thread.
29  *
30  * <p>This is meant for applications to prevent certain blocking
31  * operations from running on their main event loop (or "UI") threads.
32  *
33  * <p>Note that this is all best-effort to catch most accidental mistakes
34  * and isn't intended to be a perfect mechanism, nor provide any sort of
35  * security.
36  *
37  * @hide
38  */
39 public final class BlockGuard {
40 
41     // TODO: refactor class name to something more generic, since its scope is
42     // growing beyond just blocking/logging.
43 
44     public static final int DISALLOW_DISK_WRITE = 0x01;
45     public static final int DISALLOW_DISK_READ = 0x02;
46     public static final int DISALLOW_NETWORK = 0x04;
47     public static final int PASS_RESTRICTIONS_VIA_RPC = 0x08;
48     public static final int PENALTY_LOG = 0x10;
49     public static final int PENALTY_DIALOG = 0x20;
50     public static final int PENALTY_DEATH = 0x40;
51 
52     public interface Policy {
53         /**
54          * Called on disk writes.
55          */
onWriteToDisk()56         void onWriteToDisk();
57 
58         /**
59          * Called on disk reads.
60          */
onReadFromDisk()61         void onReadFromDisk();
62 
63         /**
64          * Called on network operations.
65          */
onNetwork()66         void onNetwork();
67 
68         /**
69          * Returns the policy bitmask, for shipping over Binder calls
70          * to remote threads/processes and reinstantiating the policy
71          * there.  The bits in the mask are from the DISALLOW_* and
72          * PENALTY_* constants.
73          */
getPolicyMask()74         int getPolicyMask();
75     }
76 
77     public static class BlockGuardPolicyException extends RuntimeException {
78         // bitmask of DISALLOW_*, PENALTY_*, etc flags
79         private final int mPolicyState;
80         private final int mPolicyViolated;
81         private final String mMessage;   // may be null
82 
BlockGuardPolicyException(int policyState, int policyViolated)83         public BlockGuardPolicyException(int policyState, int policyViolated) {
84             this(policyState, policyViolated, null);
85         }
86 
BlockGuardPolicyException(int policyState, int policyViolated, String message)87         public BlockGuardPolicyException(int policyState, int policyViolated, String message) {
88             mPolicyState = policyState;
89             mPolicyViolated = policyViolated;
90             mMessage = message;
91             fillInStackTrace();
92         }
93 
getPolicy()94         public int getPolicy() {
95             return mPolicyState;
96         }
97 
getPolicyViolation()98         public int getPolicyViolation() {
99             return mPolicyViolated;
100         }
101 
getMessage()102         public String getMessage() {
103             // Note: do not change this format casually.  It's
104             // somewhat unfortunately Parceled and passed around
105             // Binder calls and parsed back into an Exception by
106             // Android's StrictMode.  This was the least invasive
107             // option and avoided a gross mix of Java Serialization
108             // combined with Parcels.
109             return "policy=" + mPolicyState + " violation=" + mPolicyViolated +
110                     (mMessage == null ? "" : (" msg=" + mMessage));
111         }
112     }
113 
114     /**
115      * The default, permissive policy that doesn't prevent any operations.
116      */
117     public static final Policy LAX_POLICY = new Policy() {
118             public void onWriteToDisk() {}
119             public void onReadFromDisk() {}
120             public void onNetwork() {}
121             public int getPolicyMask() {
122                 return 0;
123             }
124         };
125 
126     private static ThreadLocal<Policy> threadPolicy = new ThreadLocal<Policy>() {
127         @Override protected Policy initialValue() {
128             return LAX_POLICY;
129         }
130     };
131 
132     /**
133      * Get the current thread's policy.
134      *
135      * @return the current thread's policy.  Never returns null.
136      *     Will return the LAX_POLICY instance if nothing else is set.
137      */
getThreadPolicy()138     public static Policy getThreadPolicy() {
139         return threadPolicy.get();
140     }
141 
142     /**
143      * Sets the current thread's block guard policy.
144      *
145      * @param policy policy to set.  May not be null.  Use the public LAX_POLICY
146      *   if you want to unset the active policy.
147      */
setThreadPolicy(Policy policy)148     public static void setThreadPolicy(Policy policy) {
149         if (policy == null) {
150             throw new NullPointerException("policy == null");
151         }
152         threadPolicy.set(policy);
153     }
154 
BlockGuard()155     private BlockGuard() {}
156 }
157