All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tencent.process.BkProcessTree Maven / Gradle / Ivy

The newest version!
/*
 * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
 *
 * Copyright (C) 2019 THL A29 Limited, a Tencent company.  All rights reserved.
 *
 * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license.
 *
 * A copy of the MIT License is included in this file.
 *
 *
 * Terms of the MIT License:
 * ---------------------------------------------------
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of
 * the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
 * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package com.tencent.process;

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.NativeLongByReference;
import com.tencent.process.ProcessTreeRemoting.IOSProcess;
import com.tencent.process.ProcessTreeRemoting.IProcessTree;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.Map.Entry;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.jvnet.winp.WinProcess;
import org.jvnet.winp.WinpException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.sun.jna.Pointer.NULL;
import static com.tencent.process.jna.GNUCLibrary.LIBC;

@SuppressWarnings("all")
public abstract class BkProcessTree implements Iterable, IProcessTree, Serializable {
    protected final Map processes;
    private transient volatile List killers;
    private static final boolean IS_LITTLE_ENDIAN = "little".equals(System.getProperty("sun.cpu.endian"));
    public static boolean enabled = !Boolean.getBoolean(BkProcessTree.class.getName() + ".disable");
    private static Logger logger = LoggerFactory.getLogger(BkProcessTree.class);

    private BkProcessTree() {
        this.processes = new HashMap<>();
    }

    public final BkProcessTree.OSProcess get(int pid) {
        return this.processes.get(pid);
    }

    public final Iterator iterator() {
        return this.processes.values().iterator();
    }

    public abstract BkProcessTree.OSProcess get(Process var1);

    public abstract void killAll(Map var1, boolean forceFlag) throws InterruptedException;

    public static void log(String msg) {
        logger.info(msg);
    }

    public void killAll(Process proc, Map modelEnvVars, boolean forceFlag) throws InterruptedException {
        log("killAll: process=" + proc + " and envs=" + modelEnvVars);
        BkProcessTree.OSProcess p = this.get(proc);
        if (p != null) {
            p.killRecursively(forceFlag);
        }

        if (modelEnvVars != null) {
            this.killAll(modelEnvVars, forceFlag);
        }

    }

    final List getKillers() throws InterruptedException {
        if (this.killers == null) {
            this.killers = Collections.emptyList();
        }

        return this.killers;
    }

    public static void log(String msg, Throwable e) {
        logger.error(msg, e);
    }

    public static BkProcessTree get() {
        try {
            if (File.pathSeparatorChar == ';') {
                return new BkProcessTree.Windows();
            }

            String os = Util.fixNull(System.getProperty("os.name"));
            if (os.equals("Linux")) {
                return new BkProcessTree.Linux();
            }

            if (os.equals("SunOS")) {
                return new BkProcessTree.Solaris();
            }

            if (os.equals("Mac OS X")) {
                return new BkProcessTree.Darwin();
            }
        } catch (Exception var1) {
            log("Failed to load winp. Reverting to the default", var1);
        }

        return new BkProcessTree.Default();
    }

    public abstract static class Local extends BkProcessTree {
        Local() {
            super();
        }
    }

    private static class Default extends BkProcessTree.Local {
        public BkProcessTree.OSProcess get(final Process proc) {
            return new BkProcessTree.OSProcess(-1) {
                public BkProcessTree.OSProcess getParent() {
                    return null;
                }

                public void killRecursively(boolean forceFlag) {
                    proc.destroy();
                }

                public void kill0(boolean forceFlag) throws InterruptedException {
                    proc.destroy();
                    this.killByKiller();
                }

                public List getArguments() {
                    return Collections.emptyList();
                }

                public EnvVars getEnvironmentVariables() {
                    return new EnvVars();
                }
            };
        }

        public void killAll(Map modelEnvVars, boolean forceFlag) {
        }
    }

    private static class Darwin extends Unix {
        Darwin() {
            String arch = System.getProperty("sun.arch.data.model");
            if ("64".equals(arch)) {
                sizeOf_kinfo_proc = sizeOf_kinfo_proc_64;
                kinfo_proc_pid_offset = kinfo_proc_pid_offset_64;
                kinfo_proc_ppid_offset = kinfo_proc_ppid_offset_64;
            } else {
                sizeOf_kinfo_proc = sizeOf_kinfo_proc_32;
                kinfo_proc_pid_offset = kinfo_proc_pid_offset_32;
                kinfo_proc_ppid_offset = kinfo_proc_ppid_offset_32;
            }
            try {
                NativeLongByReference size = new NativeLongByReference(new NativeLong(0));
                Memory m;
                int nRetry = 0;
                while (true) {
                    // find out how much memory we need to do this
                    if (LIBC.sysctl(MIB_PROC_ALL, 3, NULL, size, NULL, new NativeLong(0)) != 0)
                        throw new IOException("Failed to obtain memory requirement: " + LIBC.strerror(Native.getLastError()));

                    // now try the real call
                    m = new Memory(size.getValue().longValue());
                    if (LIBC.sysctl(MIB_PROC_ALL, 3, m, size, NULL, new NativeLong(0)) != 0) {
                        if (Native.getLastError() == ENOMEM && nRetry++ < 16)
                            continue; // retry
                        throw new IOException("Failed to call kern.proc.all: " + LIBC.strerror(Native.getLastError()));
                    }
                    break;
                }

                int count = size.getValue().intValue() / sizeOf_kinfo_proc;
                logger.info("Found " + count + " processes");

                for (int base = 0; base < size.getValue().intValue(); base += sizeOf_kinfo_proc) {
                    int pid = m.getInt(base + kinfo_proc_pid_offset);
                    int ppid = m.getInt(base + kinfo_proc_ppid_offset);

                    super.processes.put(pid, new DarwinProcess(pid, ppid));
                }
            } catch (IOException e) {
                logger.warn("Failed to obtain process list", e);
            }
        }

        private class DarwinProcess extends UnixProcess {
            private final int ppid;
            private EnvVars envVars;
            private List arguments;

            DarwinProcess(int pid, int ppid) {
                super(pid);
                this.ppid = ppid;
            }

            @Override
            public OSProcess getParent() {
                return get(ppid);
            }

            @Override
            public synchronized EnvVars getEnvironmentVariables() {
                if (envVars != null)
                    return envVars;
                parse();
                return envVars;
            }

            @Override
            public synchronized List getArguments() {
                if (arguments != null)
                    return arguments;
                parse();
                return arguments;
            }

            private void parse() {
                try {
// allocate them first, so that the parse error wil result in empty data
                    // and avoid retry.
                    arguments = new ArrayList<>();
                    envVars = new EnvVars();

                    IntByReference argmaxRef = new IntByReference(0);
                    NativeLongByReference size = new NativeLongByReference(new NativeLong(sizeOfInt));

                    // for some reason, I was never able to get sysctlbyname work.
//        if (LIBC.sysctlbyname("kern.argmax", argmaxRef.getPointer(), size, NULL, _)!=0)
                    if (LIBC.sysctl(new int[]{CTL_KERN, KERN_ARGMAX}, 2, argmaxRef.getPointer(), size, NULL, new NativeLong(0)) != 0)
                        throw new IOException("Failed to get kern.argmax: " + LIBC.strerror(Native.getLastError()));

                    int argmax = argmaxRef.getValue();

                    class StringArrayMemory extends Memory {
                        private long offset = 0;
                        private long length = 0;

                        StringArrayMemory(long l) {
                            super(l);
                            length = l;
                        }

                        void setLength(long l) {
                            length = Math.min(l, size());
                        }

                        int readInt() {
                            if (offset > length - sizeOfInt)
                                return 0;
                            int r = getInt(offset);
                            offset += sizeOfInt;
                            return r;
                        }

                        byte peek() {
                            if (offset >= length)
                                return 0;
                            return getByte(offset);
                        }

                        String readString() throws UnsupportedEncodingException {
                            ByteArrayOutputStream baos = new ByteArrayOutputStream();
                            byte ch;
                            while (offset < length && (ch = getByte(offset++)) != '\0')
                                baos.write(ch);
                            return baos.toString(StandardCharsets.UTF_8.name());
                        }

                        void skip0() {
                            // skip padding '\0's
                            while (offset < length && getByte(offset) == '\0')
                                offset++;
                        }
                    }

                    StringArrayMemory m = new StringArrayMemory(argmax);
                    m.clear();
                    size.setValue(new NativeLong(argmax));
                    if (LIBC.sysctl(new int[]{CTL_KERN, KERN_PROCARGS2, pid}, 3, m, size, NULL, new NativeLong(0)) != 0)
                        throw new IOException("Failed to obtain ken.procargs2: " + LIBC.strerror(Native.getLastError()));
                    m.setLength(size.getValue().longValue());


                    /*
                     * Make a sysctl() call to get the raw argument space of the
                     * process.  The layout is documented in start.s, which is part
                     * of the Csu project.  In summary, it looks like:
                     *
                     * /---------------\ 0x00000000
                     * :               :
                     * :               :
                     * |---------------|
                     * | argc          |
                     * |---------------|
                     * | arg[0]        |
                     * |---------------|
                     * :               :
                     * :               :
                     * |---------------|
                     * | arg[argc - 1] |
                     * |---------------|
                     * | 0             |
                     * |---------------|
                     * | env[0]        |
                     * |---------------|
                     * :               :
                     * :               :
                     * |---------------|
                     * | env[n]        |
                     * |---------------|
                     * | 0             |
                     * |---------------| <-- Beginning of data returned by sysctl() is here.
                     * | argc          |
                     * |---------------|
                     * | exec_path     |
                     * |:::::::::::::::|
                     * |               |
                     * | String area.  |
                     * |               |
                     * |---------------| <-- Top of stack.
                     * :               :
                     * :               :
                     * \---------------/ 0xffffffff
                     */

                    // I find the Darwin source code of the 'ps' command helpful in understanding how it does this:
                    // see https://opensource.apple.com/source/adv_cmds/adv_cmds-176/ps/print.c
                    int argc = m.readInt();
                    String args0 = m.readString(); // exec path
                    m.skip0();
                    try {
                        for (int i = 0; i < argc; i++) {
                            arguments.add(m.readString());
                        }
                    } catch (IndexOutOfBoundsException e) {
                        throw new IllegalStateException("Failed to parse arguments: pid=" + pid + ", arg0=" + args0 + ", arguments=" + arguments + ", nargs=" + argc + ". Please see https://www.jenkins.io/redirect/troubleshooting/darwin-failed-to-parse-arguments", e);
                    }

                    // read env vars that follow
                    while (m.peek() != 0)
                        envVars.addLine(m.readString());
                } catch (IOException e) {
                    // this happens with insufficient permissions, so just ignore the problem.
                }
            }
        }

        // local constants
        private final int sizeOf_kinfo_proc;
        private static final int sizeOf_kinfo_proc_32 = 492; // on 32bit Mac OS X.
        private static final int sizeOf_kinfo_proc_64 = 648; // on 64bit Mac OS X.
        private final int kinfo_proc_pid_offset;
        private static final int kinfo_proc_pid_offset_32 = 24;
        private static final int kinfo_proc_pid_offset_64 = 40;
        private final int kinfo_proc_ppid_offset;
        private static final int kinfo_proc_ppid_offset_32 = 416;
        private static final int kinfo_proc_ppid_offset_64 = 560;
        private static final int sizeOfInt = Native.getNativeSize(int.class);
        private static final int CTL_KERN = 1;
        private static final int KERN_PROC = 14;
        private static final int KERN_PROC_ALL = 0;
        private static final int ENOMEM = 12;
        private static int[] MIB_PROC_ALL = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
        private static final int KERN_ARGMAX = 8;
        private static final int KERN_PROCARGS2 = 49;
    }

    static class Solaris extends BkProcessTree.ProcfsUnix {
        Solaris() {
        }

        protected BkProcessTree.OSProcess createProcess(int pid) throws IOException {
            return new BkProcessTree.Solaris.SolarisProcess(pid);
        }

        private static long to64(int i) {
            return (long) i & 4294967295L;
        }

        private static int adjust(int i) {
            return BkProcessTree.IS_LITTLE_ENDIAN ? i << 24 | i << 8 & 16711680 | i >> 8 & '\uff00' | i >>> 24 : i;
        }

        private class SolarisProcess extends BkProcessTree.UnixProcess {
            private final int ppid;
            private final int envp;
            private final int argp;
            private final int argc;
            private EnvVars envVars;
            private List arguments;

            private SolarisProcess(int pid) throws IOException {
                super(pid);

                try (RandomAccessFile psinfo = new RandomAccessFile(this.getFile("psinfo"), "r")) {
                    psinfo.seek(8L);
                    if (Solaris.adjust(psinfo.readInt()) != pid) {
                        throw new IOException("psinfo PID mismatch");
                    }

                    this.ppid = Solaris.adjust(psinfo.readInt());
                    psinfo.seek(188L);
                    this.argc = Solaris.adjust(psinfo.readInt());
                    this.argp = Solaris.adjust(psinfo.readInt());
                    this.envp = Solaris.adjust(psinfo.readInt());
                }

                if (this.ppid == -1) {
                    throw new IOException("Failed to parse PPID from /proc/" + pid + "/status");
                }
            }

            public BkProcessTree.OSProcess getParent() {
                return Solaris.this.get(this.ppid);
            }

            public synchronized List getArguments() {
                if (this.arguments == null) {
                    this.arguments = new ArrayList<>(this.argc);

                    try {

                        try (RandomAccessFile as = new RandomAccessFile(this.getFile("as"), "r")) {
                            BkProcessTree.log("Reading " + this.getFile("as"));
                            for (int n = 0; n < this.argc; ++n) {
                                as.seek(Solaris.to64(this.argp + n * 4));
                                int p = Solaris.adjust(as.readInt());
                                this.arguments.add(this.readLine(as, p, "argv[" + n + "]"));
                            }
                        }
                    } catch (IOException var8) {
                        log(var8.getMessage());
                    }

                    this.arguments = Collections.unmodifiableList(this.arguments);
                }
                return this.arguments;
            }

            public synchronized EnvVars getEnvironmentVariables() {
                if (this.envVars == null) {
                    this.envVars = new EnvVars();

                    try {

                        try (RandomAccessFile as = new RandomAccessFile(this.getFile("as"), "r")) {
                            BkProcessTree.log("Reading " + this.getFile("as"));
                            int n = 0;

                            while (true) {
                                as.seek(Solaris.to64(this.envp + n * 4));
                                int p = Solaris.adjust(as.readInt());
                                if (p == 0) {
                                    break;
                                }

                                this.envVars.addLine(this.readLine(as, p, "env[" + n + "]"));
                                ++n;
                            }
                        }
                    } catch (IOException var8) {
                        log(var8.getMessage());
                    }

                }
                return this.envVars;
            }

            private String readLine(RandomAccessFile as, int p, String prefix) throws IOException {
                BkProcessTree.log("Reading " + prefix + " at " + p);
                as.seek(BkProcessTree.Solaris.to64(p));
                ByteArrayOutputStream buf = new ByteArrayOutputStream();

                int ch;
                for (int i = 0; (ch = as.read()) > 0; buf.write(ch)) {
                    ++i;
                    if (i % 100 == 0) {
                        BkProcessTree.log(prefix + " is so far " + buf.toString());
                    }
                }

                String line = buf.toString();
                BkProcessTree.log(prefix + " was " + line);
                return line;
            }
        }
    }

    static class Linux extends BkProcessTree.ProcfsUnix {
        Linux() {
        }

        protected BkProcessTree.Linux.LinuxProcess createProcess(int pid) throws IOException {
            return new BkProcessTree.Linux.LinuxProcess(pid);
        }

        public byte[] readFileToByteArray(File file) throws IOException {
            FileInputStream in = FileUtils.openInputStream(file);

            byte[] var3;
            try {
                var3 = IOUtils.toByteArray(in);
            } finally {
                in.close();
            }

            return var3;
        }

        class LinuxProcess extends BkProcessTree.UnixProcess {
            private int ppid = -1;
            private EnvVars envVars;
            private List arguments;

            LinuxProcess(int pid) throws IOException {
                super(pid);

                try (BufferedReader r = new BufferedReader(new FileReader(this.getFile("status")))) {
                    String line;
                    while ((line = r.readLine()) != null) {
                        line = line.toLowerCase(Locale.ENGLISH);
                        if (line.startsWith("ppid:")) {
                            this.ppid = Integer.parseInt(line.substring(5).trim());
                            break;
                        }
                    }
                }

                if (this.ppid == -1) {
                    throw new IOException("Failed to parse PPID from /proc/" + pid + "/status");
                }
            }

            public BkProcessTree.OSProcess getParent() {
                return Linux.this.get(this.ppid);
            }

            public synchronized List getArguments() {
                if (this.arguments == null) {
                    this.arguments = new ArrayList<>();

                    try {
                        byte[] cmdline = Linux.this.readFileToByteArray(this.getFile("cmdline"));
                        int pos = 0;

                        for (int i = 0; i < cmdline.length; ++i) {
                            byte b = cmdline[i];
                            if (b == 0) {
                                this.arguments.add(new String(cmdline, pos, i - pos));
                                pos = i + 1;
                            }
                        }
                    } catch (IOException var5) {
                        log(var5.getMessage());
                    }

                    this.arguments = Collections.unmodifiableList(this.arguments);
                }
                return this.arguments;
            }

            public synchronized EnvVars getEnvironmentVariables() {
                if (this.envVars == null) {
                    this.envVars = new EnvVars();

                    try {
                        byte[] environ = Linux.this.readFileToByteArray(this.getFile("environ"));
                        int pos = 0;

                        for (int i = 0; i < environ.length; ++i) {
                            byte b = environ[i];
                            if (b == 0) {
                                this.envVars.addLine(new String(environ, pos, i - pos));
                                pos = i + 1;
                            }
                        }
                    } catch (IOException var5) {
                        log(var5.getMessage());
                    }

                }
                return this.envVars;
            }
        }
    }

    private static final class UnixReflection {
        private static final Field PID_FIELD;
        private static final Method DESTROY_PROCESS;

        private UnixReflection() {
        }

        public static void destroy(int pid, boolean forceFlag) throws IllegalAccessException, InvocationTargetException {
            if (isPreJava8()) {
                DESTROY_PROCESS.invoke((Object) null, pid);
            } else {
                DESTROY_PROCESS.invoke((Object) null, pid, forceFlag);
            }

        }

        private static boolean isPreJava8() {
            int javaVersionAsAnInteger = Integer.parseInt(System.getProperty("java.version").replaceAll("\\.", "").replaceAll("_", "").substring(0, 2));
            return javaVersionAsAnInteger < 18;
        }

        static {
            LinkageError x;
            try {
                Class clazz = Class.forName("java.lang.UNIXProcess");
                PID_FIELD = clazz.getDeclaredField("pid");
                PID_FIELD.setAccessible(true);
                if (isPreJava8()) {
                    DESTROY_PROCESS = clazz.getDeclaredMethod("destroyProcess", Integer.TYPE);
                } else {
                    DESTROY_PROCESS = clazz.getDeclaredMethod("destroyProcess", Integer.TYPE, Boolean.TYPE);
                }

                DESTROY_PROCESS.setAccessible(true);
            } catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException e) {
                x = new LinkageError();
                x.initCause(e);
                throw x;
            }
        }
    }

    public abstract class UnixProcess extends BkProcessTree.OSProcess {
        protected UnixProcess(int pid) {
            super(pid);
        }

        protected final File getFile(String relativePath) {
            return new File(new File("/proc/" + this.getPid()), relativePath);
        }

        public void kill0(boolean forceFlag) throws InterruptedException {
            try {
                int pid = this.getPid();
                BkProcessTree.log("Killing pid=" + pid);
                BkProcessTree.UnixReflection.destroy(pid, forceFlag);
            } catch (IllegalAccessException var3) {
                IllegalAccessError x = new IllegalAccessError();
                x.initCause(var3);
                throw x;
            } catch (InvocationTargetException var4) {
                if (var4.getTargetException() instanceof Error) {
                    throw (Error) var4.getTargetException();
                }

                BkProcessTree.log("Failed to terminate pid=" + this.getPid(), var4);
            }

            this.killByKiller();
        }

        public void killRecursively(boolean forceFlag) throws InterruptedException {
            BkProcessTree.log("Recursively killing pid=" + this.getPid());

            for (OSProcess p : this.getChildren()) {
                p.killRecursively(forceFlag);
            }

            this.kill(forceFlag);
        }

        public abstract List getArguments();
    }

    abstract static class ProcfsUnix extends BkProcessTree.Unix {
        ProcfsUnix() {
            File[] processes = (new File("/proc")).listFiles(new FileFilter() {
                public boolean accept(File f) {
                    return f.isDirectory();
                }
            });
            if (processes == null) {
                log("No /proc");
            } else {
                for (File p : processes) {
                    int pid;
                    try {
                        pid = Integer.parseInt(p.getName());
                    } catch (NumberFormatException var9) {
                        continue;
                    }

                    try {
                        this.processes.put(pid, this.createProcess(pid));
                    } catch (IOException var8) {
                        log(var8.getMessage());
                    }
                }

            }
        }

        protected abstract BkProcessTree.OSProcess createProcess(int var1) throws IOException;
    }

    abstract static class Unix extends BkProcessTree.Local {
        Unix() {
        }

        public BkProcessTree.OSProcess get(Process proc) {
            try {
                return this.get((Integer) BkProcessTree.UnixReflection.PID_FIELD.get(proc));
            } catch (IllegalAccessException var4) {
                IllegalAccessError x = new IllegalAccessError();
                x.initCause(var4);
                throw x;
            }
        }

        public void killAll(Map modelEnvVars, boolean forceFlag) throws InterruptedException {

            for (OSProcess p : this) {
                if (p.hasMatchingEnvVars(modelEnvVars)) {
                    p.killRecursively(forceFlag);
                }
            }

        }
    }

    private static final class Windows extends BkProcessTree.Local {
        Windows() {

            for (WinProcess p : WinProcess.all()) {
                int pid = p.getPid();
                if (pid != 0 && pid != 4) {
                    super.processes.put(pid, new OSProcess(pid) {
                        private EnvVars env;
                        private List args;

                        public OSProcess getParent() {
                            return null;
                        }

                        public void killRecursively(boolean forceFlag) throws InterruptedException {
                            BkProcessTree.log("Killing recursively " + this.getPid());
                            p.killRecursively();
                            this.killByKiller();
                        }

                        public void kill0(boolean forceFlag) throws InterruptedException {
                            BkProcessTree.log("Killing " + this.getPid());
                            p.kill();
                            this.killByKiller();
                        }

                        public synchronized List getArguments() {
                            if (this.args == null) {
                                this.args = Arrays.asList(QuotedStringTokenizer.tokenize(p.getCommandLine()));
                            }

                            return this.args;
                        }

                        public synchronized EnvVars getEnvironmentVariables() {
                            if (this.env == null) {
                                this.env = new EnvVars();

                                try {
                                    this.env.putAll(p.getEnvironmentVariables());
                                } catch (WinpException var2) {
                                    log(var2.getMessage());
                                }

                            }
                            return this.env;
                        }
                    });
                }
            }

        }

        public BkProcessTree.OSProcess get(Process proc) {
            return this.get((new WinProcess(proc)).getPid());
        }

        public void killAll(Map modelEnvVars, boolean forceFlag) throws InterruptedException {
            Iterator var2 = this.iterator();

            while (true) {
                BkProcessTree.OSProcess p;
                do {
                    if (!var2.hasNext()) {
                        return;
                    }

                    p = var2.next();
                } while (p.getPid() < 10);

                log("Considering to kill " + p.getPid());

                boolean matched;
                try {
                    matched = p.hasMatchingEnvVars(modelEnvVars);
                } catch (WinpException var6) {
                    log("  Failed to check environment variable match", var6);
                    continue;
                }

                if (matched) {
                    p.killRecursively(forceFlag);
                } else {
                    log("Environment variable didn't match");
                }
            }
        }

        static {
            WinProcess.enableDebugPrivilege();
        }
    }

    private final class SerializedProcess implements Serializable {
        private final int pid;
        private static final long serialVersionUID = 1L;

        private SerializedProcess(int pid) {
            this.pid = pid;
        }

        Object readResolve() {
            return BkProcessTree.this.get(this.pid);
        }
    }

    public abstract class OSProcess implements IOSProcess, Serializable {
        private Set keepAlivePids = new HashSet(64);

        final int pid;

        private OSProcess(int pid) {
            this.pid = pid;
        }

        public final int getPid() {
            return this.pid;
        }

        public final void addKeepAlivePids(Collection pids) {
            keepAlivePids.addAll(pids);
        }

        public abstract BkProcessTree.OSProcess getParent();

        final BkProcessTree getTree() {
            return BkProcessTree.this;
        }

        public final List getChildren() {
            List r = new ArrayList<>();

            for (OSProcess p : BkProcessTree.this) {
                if (p.getParent() == this) {
                    if (keepAlivePids.contains(p.pid)) {
                        this.keepAlivePids.add(this.pid);
                    } else {
                        p.addKeepAlivePids(keepAlivePids);
                        r.add(p);
                    }
                }
            }

            return r;
        }

        public void kill(boolean forceFlag) throws InterruptedException {
            BkProcessTree.log("pid=" + pid + ", iskeepAlive=" + keepAlivePids.contains(pid));
            if (!keepAlivePids.contains(pid)) {
                kill0(forceFlag);
            }
        }

        public abstract void kill0(boolean forceFlag) throws InterruptedException;

        void killByKiller() throws InterruptedException {

            for (ProcessKiller killer : BkProcessTree.this.getKillers()) {
                try {
                    if (killer.kill(this)) {
                        break;
                    }
                } catch (IOException var4) {
                    BkProcessTree.log("Failed to kill pid=" + this.getPid(), var4);
                }
            }

        }

        public abstract void killRecursively(boolean forceFlag) throws InterruptedException;

        public abstract List getArguments();

        public abstract EnvVars getEnvironmentVariables();

        public final boolean hasMatchingEnvVars(Map modelEnvVar) {
            if (!modelEnvVar.isEmpty()) {
                SortedMap envs = this.getEnvironmentVariables();
                Iterator> var3 = modelEnvVar.entrySet().iterator();

                Entry e;
                String v;
                do {
                    if (!var3.hasNext()) {
                        return true;
                    }

                    e = var3.next();
                    v = envs.get(e.getKey());
                } while (v != null && v.equals(e.getValue()));

            }
            return false;
        }

        Object writeReplace() {
            return BkProcessTree.this.new SerializedProcess(this.pid);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy