/* (C) 2012 Pragmatic Software
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/
*/
package com.googlecode.networklog;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Build;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipInputStream;
public class SysUtils {
public static String iptablesBinary;
public static String iptablesMd5;
public static int iptablesResource;
public static String grepBinary;
public static String grepMd5;
public static int grepResource;
public static String nflogBinary;
public static String nflogMd5;
public static int nflogResource;
public static String run_pieBinary;
public static String run_pieMd5;
public static int run_pieResource;
public static boolean getBinariesIdentifiers() {
String cpu_abi = Build.CPU_ABI.toLowerCase();
if(cpu_abi.contains("armeabi-v7") || cpu_abi.contains("arm64")) {
iptablesBinary = "iptables_armv7";
iptablesMd5 = "5515873b7ce1617f3d724a3332c2b947"; // iptables_armv7
iptablesResource = R.raw.iptables_armv7;
grepBinary = "grep_armv7";
grepMd5 = "6d5f2d3b8d50cb4db918e8530f975b08"; // grep_armv7
grepResource = R.raw.grep_armv7;
nflogBinary = "nflog_armv7";
nflogMd5 = "9d72441239afa8684e479d30d14feb75"; // nflog_armv7
nflogResource = R.raw.nflog_armv7;
run_pieBinary = "run_pie_armv7";
run_pieMd5 = "2a2d61479adb6182f13b5363c5a59895"; // run_pie_armv7
run_pieResource = R.raw.run_pie_armv7;
} else if(cpu_abi.contains("armeabi")) {
iptablesBinary = "iptables_armv5";
iptablesMd5 = "50e39f66369344b692084a9563c185d4"; // iptables_armv5
iptablesResource = R.raw.iptables_armv5;
grepBinary = "grep_armv5";
grepMd5 = "5200a181e0835a82e8c51790c2934353"; // grep_armv5
grepResource = R.raw.grep_armv5;
nflogBinary = "nflog_armv5";
nflogMd5 = "aa700f638adcfc09dc03ee8b23cad43d"; // nflog_armv5
nflogResource = R.raw.nflog_armv5;
run_pieBinary = "run_pie_armv5";
run_pieMd5 = "3aad21f6fb4933c6398ff92c008400c5"; // run_pie_armv5
run_pieResource = R.raw.run_pie_armv5;
} else if(cpu_abi.contains("x86")) {
iptablesBinary = "iptables_x86";
iptablesMd5 = "3e7090f93ae3964c98e16016b742acbc"; // iptables_x86
iptablesResource = R.raw.iptables_x86;
grepBinary = "grep_x86";
grepMd5 = "1ce10f593f5824daf3f91dae29c2e6d6"; // grep_x86
grepResource = R.raw.grep_x86;
nflogBinary = "nflog_x86";
nflogMd5 = "ce661bc02b64b6090d03807738020c98"; // nflog_x86
nflogResource = R.raw.nflog_x86;
run_pieBinary = "run_pie_x86";
run_pieMd5 = "dc4699e92868d0da1cb35af89033c5df"; // run_pie_x86
run_pieResource = R.raw.run_pie_x86;
} else if(cpu_abi.contains("mips")) {
iptablesBinary = "iptables_mips";
iptablesMd5 = "c208f8f9a6fa8d7b436c069b71299668"; // iptables_mips
iptablesResource = R.raw.iptables_mips;
grepBinary = "grep_mips";
grepMd5 = "8887e3bfb42ba335510d0adb739a0329"; // grep_mips
grepResource = R.raw.grep_mips;
nflogBinary = "nflog_mips";
nflogMd5 = "534ce71da7e383183697c4090c295624"; // nflog_mips
nflogResource = R.raw.nflog_mips;
run_pieBinary = "run_pie_mips";
run_pieMd5 = "ec8123a69e7527d243575d779a080b4a"; // run_pie_mips
run_pieResource = R.raw.run_pie_mips;
} else {
iptablesBinary = null;
grepBinary = null;
nflogBinary = null;
run_pieBinary = null;
return false;
}
return true;
}
public static String getIptablesBinary(Context context) {
if(Build.VERSION.SDK_INT >= 14) {
// use system built-in binaries on >= ICS due to SELinux
return "iptables";
} else {
if(iptablesBinary == null) {
getBinariesIdentifiers();
}
return context.getFilesDir().getAbsolutePath() + File.separator + iptablesBinary;
}
}
public static String getGrepBinary(Context context) {
if(Build.VERSION.SDK_INT >= 14) {
// use system built-in binaries on >= ICS due to SELinux
return "grep";
} else {
if(grepBinary == null) {
getBinariesIdentifiers();
}
if (Build.VERSION.SDK_INT < 16) {
return getRun_pieBinary(context) + " " + context.getFilesDir().getAbsolutePath() + File.separator + grepBinary;
} else {
return context.getFilesDir().getAbsolutePath() + File.separator + grepBinary;
}
}
}
public static String getNflogBinary(Context context) {
// FIXME: need some way to put nflog on system partition or
// some other workaround for SELinux on >= ICS
if(nflogBinary == null) {
getBinariesIdentifiers();
}
if (Build.VERSION.SDK_INT < 16) {
return getRun_pieBinary(context) + " " + context.getFilesDir().getAbsolutePath() + File.separator + nflogBinary;
} else {
return context.getFilesDir().getAbsolutePath() + File.separator + nflogBinary;
}
}
public static String getRun_pieBinary(Context context) {
// FIXME: need some way to put run_pie on system partition or
// some other workaround for SELinux on >= ICS
if(run_pieBinary == null) {
getBinariesIdentifiers();
}
return context.getFilesDir().getAbsolutePath() + File.separator + run_pieBinary;
}
public static boolean installBinary(Context context, String binary, String md5sum, int resource, String path) {
boolean needsInstall = false;
File file = new File(path);
MyLog.d("Checking for " + binary + " with md5sum " + md5sum);
if(file.isFile()) {
String hash = MD5Sum.digestFile(file);
if(!hash.equals(md5sum)) {
needsInstall = true;
}
MyLog.d(binary + " found with md5sum " + hash + "; needsInstall: " + needsInstall);
} else {
MyLog.d(binary + " does not exist.");
needsInstall = true;
}
if(needsInstall) {
try {
MyLog.d(binary + " not found: installing to " + path);
InputStream raw = context.getResources().openRawResource(resource);
ZipInputStream zip = new ZipInputStream(raw);
zip.getNextEntry();
InputStream in = zip;
FileOutputStream out = new FileOutputStream(path);
byte buf[] = new byte[8192];
int len;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
out.close();
in.close();
Runtime.getRuntime().exec("chmod 755 " + path).waitFor();
} catch (Exception e) {
Resources res = context.getResources();
showError(context, res.getString(R.string.error_default_title), String.format(res.getString(R.string.error_install_binary_text), binary) + e.getMessage());
return false;
}
}
return true;
}
public static boolean installBinaries(Context context) {
if(!getBinariesIdentifiers()) {
Resources res = context.getResources();
showError(context, res.getString(R.string.error_unsupported_system_title), String.format(res.getString(R.string.error_unsupported_system_text), Build.CPU_ABI));
return false;
}
String iptablesPath = context.getFilesDir().getAbsolutePath() + File.separator + iptablesBinary;
if(!installBinary(context, iptablesBinary, iptablesMd5, iptablesResource, iptablesPath)) {
return false;
}
String grepPath = context.getFilesDir().getAbsolutePath() + File.separator + grepBinary;
if(!installBinary(context, grepBinary, grepMd5, grepResource, grepPath)) {
return false;
}
String nflogPath = context.getFilesDir().getAbsolutePath() + File.separator + nflogBinary;
if(!installBinary(context, nflogBinary, nflogMd5, nflogResource, nflogPath)) {
return false;
}
String run_piePath = context.getFilesDir().getAbsolutePath() + File.separator + run_pieBinary;
if(!installBinary(context, run_pieBinary, run_pieMd5, run_pieResource, run_piePath)) {
return false;
}
return true;
}
public static boolean checkRoot(Context context) {
if(NetworkLog.shell == null || NetworkLog.shell.checkForExit()) {
NetworkLog.shell = createRootShell(context, "CheckRootShell", false);
if(NetworkLog.shell.hasError()) {
Log.e("NetworkLog", "[check-root] Check root failed: " + NetworkLog.shell.getError(true));
return false;
}
}
NetworkLog.shell.sendCommand("id");
List<String> output = new ArrayList<String>();
NetworkLog.shell.waitForCommandExit(output);
if(NetworkLog.shell.exitval == 0) {
for(String line : output) {
line.trim();
Log.d("NetworkLog", "[check-root] Got id output: [" + line + "]");
if(line.startsWith("uid=0")) {
Log.d("NetworkLog", "[check-root] Check root passed (uid=0)");
return true;
}
}
Log.e("NetworkLog", "[check-root] Check root failed (uid != 0)");
return false;
}
Log.d("NetworkLog", "[check-root] Check root tentatively passed (no id command, but su succeeded)");
return true;
}
public static InteractiveShell createRootShell(Context context, String tag, boolean showError) {
InteractiveShell shell = new InteractiveShell("su", tag);
shell.start();
if(shell.hasError()) {
if(showError) {
Resources res = context.getResources();
showError(context, res.getString(R.string.error_default_title), res.getString(R.string.error_noroot) + "\n\n" + shell.getError(false));
}
}
return shell;
}
public static void showError(final Context context, final String title, final String message) {
Log.d("NetworkLog", "Got error: [" + title + "] [" + message + "]");
context.startActivity(new Intent(context, ErrorDialogActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra("title", title)
.putExtra("message", message));
}
public static void applySamsungFix(final Context context) {
if(Build.BRAND.toLowerCase().contains("samsung") || Build.MANUFACTURER.toLowerCase().contains("samsung")) {
try {
FileInputStream fis = context.openFileInput("samsung_fixed");
// fix already applied
fis.close();
return;
} catch (Exception e) { /* ignored */ }
ShellCommand command = new ShellCommand(new String[] { "grep" }, "TestForGrep");
command.start(true);
Log.d("NetworkLog", "Test for grep exit val: " + command.exitval);
if(command.exitval < 0 || command.exitval > 2) {
// use cat if grep not found
NetworkLog.settings.setLogMethod(2);
} else {
// use grep
NetworkLog.settings.setLogMethod(1);
}
try {
FileOutputStream fos = context.openFileOutput("samsung_fixed", Context.MODE_PRIVATE);
fos.close();
return;
} catch (Exception e) {
Log.w("NetworkLog", "Exception saving record of applying Samsung fix", e);
}
}
}
}