blob: d61f0e1668ff81c4b792e7324baf326c892cc4ae [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dalvik.system;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.net.SocketException;
import java.nio.charset.Charsets;
/**
* Mechanism to let threads set restrictions on what code is allowed
* to do in their thread.
*
* <p>This is meant for applications to prevent certain blocking
* operations from running on their main event loop (or "UI") threads.
*
* <p>Note that this is all best-effort to catch most accidental mistakes
* and isn't intended to be a perfect mechanism, nor provide any sort of
* security.
*
* @hide
*/
public final class BlockGuard {
// TODO: refactor class name to something more generic, since its scope is
// growing beyond just blocking/logging.
public static final int DISALLOW_DISK_WRITE = 0x01;
public static final int DISALLOW_DISK_READ = 0x02;
public static final int DISALLOW_NETWORK = 0x04;
public static final int PASS_RESTRICTIONS_VIA_RPC = 0x08;
public static final int PENALTY_LOG = 0x10;
public static final int PENALTY_DIALOG = 0x20;
public static final int PENALTY_DEATH = 0x40;
public interface Policy {
/**
* Called on disk writes.
*/
void onWriteToDisk();
/**
* Called on disk reads.
*/
void onReadFromDisk();
/**
* Called on network operations.
*/
void onNetwork();
/**
* Returns the policy bitmask, for shipping over Binder calls
* to remote threads/processes and reinstantiating the policy
* there. The bits in the mask are from the DISALLOW_* and
* PENALTY_* constants.
*/
int getPolicyMask();
}
public static class BlockGuardPolicyException extends RuntimeException {
// bitmask of DISALLOW_*, PENALTY_*, etc flags
private final int mPolicyState;
private final int mPolicyViolated;
private final String mMessage; // may be null
public BlockGuardPolicyException(int policyState, int policyViolated) {
this(policyState, policyViolated, null);
}
public BlockGuardPolicyException(int policyState, int policyViolated, String message) {
mPolicyState = policyState;
mPolicyViolated = policyViolated;
mMessage = message;
fillInStackTrace();
}
public int getPolicy() {
return mPolicyState;
}
public int getPolicyViolation() {
return mPolicyViolated;
}
public String getMessage() {
// Note: do not change this format casually. It's
// somewhat unfortunately Parceled and passed around
// Binder calls and parsed back into an Exception by
// Android's StrictMode. This was the least invasive
// option and avoided a gross mix of Java Serialization
// combined with Parcels.
return "policy=" + mPolicyState + " violation=" + mPolicyViolated +
(mMessage == null ? "" : (" msg=" + mMessage));
}
}
/**
* The default, permissive policy that doesn't prevent any operations.
*/
public static final Policy LAX_POLICY = new Policy() {
public void onWriteToDisk() {}
public void onReadFromDisk() {}
public void onNetwork() {}
public int getPolicyMask() {
return 0;
}
};
private static ThreadLocal<Policy> threadPolicy = new ThreadLocal<Policy>() {
@Override protected Policy initialValue() {
return LAX_POLICY;
}
};
/**
* Get the current thread's policy.
*
* @return the current thread's policy. Never returns null.
* Will return the LAX_POLICY instance if nothing else is set.
*/
public static Policy getThreadPolicy() {
return threadPolicy.get();
}
/**
* Sets the current thread's block guard policy.
*
* @param policy policy to set. May not be null. Use the public LAX_POLICY
* if you want to unset the active policy.
*/
public static void setThreadPolicy(Policy policy) {
if (policy == null) {
throw new NullPointerException("policy == null");
}
threadPolicy.set(policy);
}
private BlockGuard() {}
}