@Override public void run() { try { Log.i(TAG, "Starting openvpn"); startOpenVPNThreadArgs(mArgv, mProcessEnv); Log.i(TAG, "Giving up"); } catch (Exception e) { VpnStatus.logException("Starting OpenVPN Thread", e); Log.e(TAG, "OpenVPNThread Got " + e.toString()); } finally { int exitvalue = 0; try { if (mProcess != null) exitvalue = mProcess.waitFor(); } catch (IllegalThreadStateException ite) { VpnStatus.logError("Illegal Thread state: " + ite.getLocalizedMessage()); } catch (InterruptedException ie) { VpnStatus.logError("InterruptedException: " + ie.getLocalizedMessage()); } if (exitvalue != 0) { VpnStatus.logError("Process exited with exit value " + exitvalue); if (mBrokenPie) { /* This will probably fail since the NoPIE binary is probably not written */ String[] noPieArgv = VPNLaunchHelper.replacePieWithNoPie(mArgv); // We are already noPIE, nothing to gain if (!noPieArgv.equals(mArgv)) { mArgv = noPieArgv; VpnStatus.logInfo("PIE Version could not be executed. Trying no PIE version"); run(); return; } } } VpnStatus.updateStateString( "NOPROCESS", "No process running.", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED); if (mDumpPath != null) { try { BufferedWriter logout = new BufferedWriter(new FileWriter(mDumpPath + ".log")); SimpleDateFormat timeformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.GERMAN); for (LogItem li : VpnStatus.getlogbuffer()) { String time = timeformat.format(new Date(li.getLogtime())); logout.write(time + " " + li.getString(mService) + "\n"); } logout.close(); VpnStatus.logError(R.string.minidump_generated); } catch (IOException e) { VpnStatus.logError("Writing minidump log: " + e.getLocalizedMessage()); } } mService.processDied(); Log.i(TAG, "Exiting"); } }
private void startOpenVPNThreadArgs(String[] argv, Map<String, String> env) { LinkedList<String> argvlist = new LinkedList<String>(); Collections.addAll(argvlist, argv); ProcessBuilder pb = new ProcessBuilder(argvlist); // Hack O rama String lbpath = genLibraryPath(argv, pb); pb.environment().put("LD_LIBRARY_PATH", lbpath); // Add extra variables for (Entry<String, String> e : env.entrySet()) { pb.environment().put(e.getKey(), e.getValue()); } pb.redirectErrorStream(true); try { mProcess = pb.start(); // openvpn被配置为从stdin接受配置文件 // 写入配置文件 Writer writer = new OutputStreamWriter(mProcess.getOutputStream(), "UTF-8"); VpnProfile startProfile = VPNLaunchHelper.getStartProfile(); String configString = startProfile.getConfigFile(VPNLaunchHelper.getStartContext(), false); writer.write(configString); writer.close(); InputStream in = mProcess.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(in)); while (true) { String logline = br.readLine(); if (logline == null) return; if (logline.startsWith(DUMP_PATH_STRING)) mDumpPath = logline.substring(DUMP_PATH_STRING.length()); if (logline.startsWith(BROKEN_PIE_SUPPORT) || logline.contains(BROKEN_PIE_SUPPORT2)) mBrokenPie = true; // 1380308330.240114 18000002 Send to HTTP proxy: 'X-Online-Host: bla.blabla.com' Pattern p = Pattern.compile("(\\d+).(\\d+) ([0-9a-f])+ (.*)"); Matcher m = p.matcher(logline); if (m.matches()) { int flags = Integer.parseInt(m.group(3), 16); String msg = m.group(4); int logLevel = flags & 0x0F; VpnStatus.LogLevel logStatus = VpnStatus.LogLevel.INFO; if ((flags & M_FATAL) != 0) logStatus = VpnStatus.LogLevel.ERROR; else if ((flags & M_NONFATAL) != 0) logStatus = VpnStatus.LogLevel.WARNING; else if ((flags & M_WARN) != 0) logStatus = VpnStatus.LogLevel.WARNING; else if ((flags & M_DEBUG) != 0) logStatus = VpnStatus.LogLevel.VERBOSE; if (msg.startsWith("MANAGEMENT: CMD")) logLevel = Math.max(4, logLevel); VpnStatus.logMessageOpenVPN(logStatus, logLevel, msg); } else { VpnStatus.logInfo("P:" + logline); } } } catch (IOException e) { VpnStatus.logException("Error reading from output of OpenVPN process", e); stopProcess(); } }