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 dalvik.system;
18
19import java.io.FileDescriptor;
20import java.io.FileNotFoundException;
21import java.io.FileOutputStream;
22import java.io.IOException;
23import java.math.BigInteger;
24import 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 */
39public 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         */
56        void onWriteToDisk();
57
58        /**
59         * Called on disk reads.
60         */
61        void onReadFromDisk();
62
63        /**
64         * Called on network operations.
65         */
66        void onNetwork();
67
68        /**
69         * Called on unbuffered input/ouput operations.
70         */
71        void onUnbufferedIO();
72
73        /**
74         * Returns the policy bitmask, for shipping over Binder calls
75         * to remote threads/processes and reinstantiating the policy
76         * there.  The bits in the mask are from the DISALLOW_* and
77         * PENALTY_* constants.
78         */
79        int getPolicyMask();
80    }
81
82    public static class BlockGuardPolicyException extends RuntimeException {
83        // bitmask of DISALLOW_*, PENALTY_*, etc flags
84        private final int mPolicyState;
85        private final int mPolicyViolated;
86        private final String mMessage;   // may be null
87
88        public BlockGuardPolicyException(int policyState, int policyViolated) {
89            this(policyState, policyViolated, null);
90        }
91
92        public BlockGuardPolicyException(int policyState, int policyViolated, String message) {
93            mPolicyState = policyState;
94            mPolicyViolated = policyViolated;
95            mMessage = message;
96            fillInStackTrace();
97        }
98
99        public int getPolicy() {
100            return mPolicyState;
101        }
102
103        public int getPolicyViolation() {
104            return mPolicyViolated;
105        }
106
107        public String getMessage() {
108            // Note: do not change this format casually.  It's
109            // somewhat unfortunately Parceled and passed around
110            // Binder calls and parsed back into an Exception by
111            // Android's StrictMode.  This was the least invasive
112            // option and avoided a gross mix of Java Serialization
113            // combined with Parcels.
114            return "policy=" + mPolicyState + " violation=" + mPolicyViolated +
115                    (mMessage == null ? "" : (" msg=" + mMessage));
116        }
117    }
118
119    /**
120     * The default, permissive policy that doesn't prevent any operations.
121     */
122    public static final Policy LAX_POLICY = new Policy() {
123            public void onWriteToDisk() {}
124            public void onReadFromDisk() {}
125            public void onNetwork() {}
126            public void onUnbufferedIO() {}
127            public int getPolicyMask() {
128                return 0;
129            }
130        };
131
132    private static ThreadLocal<Policy> threadPolicy = new ThreadLocal<Policy>() {
133        @Override protected Policy initialValue() {
134            return LAX_POLICY;
135        }
136    };
137
138    /**
139     * Get the current thread's policy.
140     *
141     * @return the current thread's policy.  Never returns null.
142     *     Will return the LAX_POLICY instance if nothing else is set.
143     */
144    public static Policy getThreadPolicy() {
145        return threadPolicy.get();
146    }
147
148    /**
149     * Sets the current thread's block guard policy.
150     *
151     * @param policy policy to set.  May not be null.  Use the public LAX_POLICY
152     *   if you want to unset the active policy.
153     */
154    public static void setThreadPolicy(Policy policy) {
155        if (policy == null) {
156            throw new NullPointerException("policy == null");
157        }
158        threadPolicy.set(policy);
159    }
160
161    private BlockGuard() {}
162}
163