| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.misc;  | 
 | 
 | 
 | 
import java.security.AccessControlContext;  | 
 | 
import java.security.AccessController;  | 
 | 
import java.security.ProtectionDomain;  | 
 | 
import java.security.PrivilegedAction;  | 
 | 
import java.util.concurrent.atomic.AtomicInteger;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
public final class InnocuousThread extends Thread { | 
 | 
    private static final Unsafe UNSAFE;  | 
 | 
    private static final long THREAD_LOCALS;  | 
 | 
    private static final long INHERITABLE_THREAD_LOCALS;  | 
 | 
    private static final ThreadGroup INNOCUOUSTHREADGROUP;  | 
 | 
    private static final AccessControlContext ACC;  | 
 | 
    private static final long INHERITEDACCESSCONTROLCONTEXT;  | 
 | 
    private static final long CONTEXTCLASSLOADER;  | 
 | 
 | 
 | 
    private static final AtomicInteger threadNumber = new AtomicInteger(1);  | 
 | 
    private static String newName() { | 
 | 
        return "InnocuousThread-" + threadNumber.getAndIncrement();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static Thread newSystemThread(Runnable target) { | 
 | 
        return newSystemThread(newName(), target);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public static Thread newSystemThread(String name, Runnable target) { | 
 | 
        return new InnocuousThread(INNOCUOUSTHREADGROUP,  | 
 | 
                                   target, name, null);  | 
 | 
    }  | 
 | 
 | 
 | 
    public InnocuousThread(Runnable target) { | 
 | 
        super(INNOCUOUSTHREADGROUP, target, newName());  | 
 | 
        UNSAFE.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, ACC);  | 
 | 
        eraseThreadLocals();  | 
 | 
    }  | 
 | 
 | 
 | 
    private InnocuousThread(ThreadGroup group, Runnable target, String name, ClassLoader tccl) { | 
 | 
        super(group, target, name, 0L);  | 
 | 
        UNSAFE.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, ACC);  | 
 | 
        UNSAFE.putOrderedObject(this, CONTEXTCLASSLOADER, tccl);  | 
 | 
        eraseThreadLocals();  | 
 | 
    }  | 
 | 
 | 
 | 
    @Override  | 
 | 
    public ClassLoader getContextClassLoader() { | 
 | 
          | 
 | 
        return ClassLoader.getSystemClassLoader();  | 
 | 
    }  | 
 | 
 | 
 | 
    @Override  | 
 | 
    public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { | 
 | 
        // silently fail  | 
 | 
    }  | 
 | 
 | 
 | 
    @Override  | 
 | 
    public void setContextClassLoader(ClassLoader cl) { | 
 | 
        throw new SecurityException("setContextClassLoader"); | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private volatile boolean hasRun;  | 
 | 
 | 
 | 
    @Override  | 
 | 
    public void run() { | 
 | 
        if (Thread.currentThread() == this && !hasRun) { | 
 | 
            hasRun = true;  | 
 | 
            super.run();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public void eraseThreadLocals() { | 
 | 
        UNSAFE.putObject(this, THREAD_LOCALS, null);  | 
 | 
        UNSAFE.putObject(this, INHERITABLE_THREAD_LOCALS, null);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    static { | 
 | 
        try { | 
 | 
            ACC = new AccessControlContext(new ProtectionDomain[] { | 
 | 
                new ProtectionDomain(null, null)  | 
 | 
            });  | 
 | 
 | 
 | 
              | 
 | 
            UNSAFE = Unsafe.getUnsafe();  | 
 | 
            Class<?> tk = Thread.class;  | 
 | 
            Class<?> gk = ThreadGroup.class;  | 
 | 
 | 
 | 
            THREAD_LOCALS = UNSAFE.objectFieldOffset  | 
 | 
                (tk.getDeclaredField("threadLocals")); | 
 | 
            INHERITABLE_THREAD_LOCALS = UNSAFE.objectFieldOffset  | 
 | 
                (tk.getDeclaredField("inheritableThreadLocals")); | 
 | 
            INHERITEDACCESSCONTROLCONTEXT = UNSAFE.objectFieldOffset  | 
 | 
                (tk.getDeclaredField("inheritedAccessControlContext")); | 
 | 
            CONTEXTCLASSLOADER = UNSAFE.objectFieldOffset  | 
 | 
                (tk.getDeclaredField("contextClassLoader")); | 
 | 
 | 
 | 
            long tg = UNSAFE.objectFieldOffset(tk.getDeclaredField("group")); | 
 | 
            long gp = UNSAFE.objectFieldOffset(gk.getDeclaredField("parent")); | 
 | 
            ThreadGroup group = (ThreadGroup)  | 
 | 
                UNSAFE.getObject(Thread.currentThread(), tg);  | 
 | 
 | 
 | 
            while (group != null) { | 
 | 
                ThreadGroup parent = (ThreadGroup)UNSAFE.getObject(group, gp);  | 
 | 
                if (parent == null)  | 
 | 
                    break;  | 
 | 
                group = parent;  | 
 | 
            }  | 
 | 
            final ThreadGroup root = group;  | 
 | 
            INNOCUOUSTHREADGROUP = AccessController.doPrivileged(  | 
 | 
                new PrivilegedAction<ThreadGroup>() { | 
 | 
                    @Override  | 
 | 
                    public ThreadGroup run() { | 
 | 
                        return new ThreadGroup(root, "InnocuousThreadGroup");  | 
 | 
                    }  | 
 | 
                });  | 
 | 
        } catch (Exception e) { | 
 | 
            throw new Error(e);  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |