私はAndroidプログラミングの初心者であり、最終的なプロジェクトを行っており、パケットスニッフィングアプリケーションを開発する必要があります。インターネットでいくつかのコードを見つけ、それを自分のプロジェクトに拡張しようとしています。しかし、致命的な例外が発生する:主なエラーとそれに続くエラー。
コードは次のとおりです。
public class Main extends Activity {
// Variable declarations for handling the view items in the layout.
private Button start_button;
private Button stop_button;
private Button read_button;
private EditText parameters;
// Variable declarations for handling the TCPdump process.
private TCPdump tcpdump = null;
private TCPdumpHandler tcpDumpHandler = null;
private SharedPreferences settings = null;
// Variable declarations for handling the options and reader activities.
private Intent optionsIntent = null;
private Intent readerIntent = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Associating the items in the view to the variables.
start_button = (Button) findViewById(R.id.start_button);
stop_button = (Button) findViewById(R.id.stop_button);
read_button = (Button) findViewById(R.id.read_button);
parameters = (EditText) findViewById(R.id.params_text);
// Accessing the app's preferences.
settings = getSharedPreferences(GlobalConstants.prefsName, 0);
// Extracting the TCPdump binary to the app folder.
if (RootTools.installBinary(Main.this, R.raw.tcpdump, "tcpdump") == false) {
new AlertDialog.Builder(Main.this)
.setTitle(R.string.extraction_error)
.setMessage(R.string.extraction_error_msg)
.setNeutralButton(R.string.ok, null).show();
}
// Creating a new TCPdump object.
tcpdump = new TCPdump();
// Creating a TCPdump handler for the TCPdump object created after.
tcpDumpHandler = new TCPdumpHandler(tcpdump, this, this, true);
// Obtaining the command from the options that were saved last time
// Shark was running.
tcpDumpHandler.generateCommand();
start_button.setOnClickListener(new OnClickListener() {
// Setting the action to perform when the start button is pressed.
public void onClick(View v) {
startTCPdump();
}
});
stop_button.setOnClickListener(new OnClickListener() {
// Setting the action to perform when the stop button is pressed.
public void onClick(View v) {
stopTCPdump();
}
});
read_button.setOnClickListener(new OnClickListener() {
// Setting the action to perform when the open in reader button is
// pressed.
public void onClick(View v) {
launchReader();
}
});
BroadcastReceiver connectionReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Setting the action to be performed when the network status
// changes.
if ((tcpDumpHandler.checkNetworkStatus() == false)
&& (tcpdump.getProcessStatus())) {
stopTCPdump();
new AlertDialog.Builder(Main.this)
.setTitle(
getString(R.string.network_connection_down))
.setMessage(
getString(R.string.network_connection_down_msg))
.setNeutralButton(getString(R.string.ok), null)
.show();
}
}
};
// Registering the BroadcastReceiver and associating it with the
// connectivity change event.
registerReceiver(connectionReceiver, new IntentFilter(
"android.net.conn.CONNECTIVITY_CHANGE"));
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Setting the action to perform when returning to this activity from
// another activity which had been called.
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == 1) {
if (tcpdump.getProcessStatus()) {
new AlertDialog.Builder(Main.this)
.setTitle(getString(R.string.settings_changed))
.setMessage(getString(R.string.settings_changed_msg))
.setNeutralButton(getString(R.string.ok), null).show();
}
tcpDumpHandler.generateCommand();
}
}
@Override
public void onDestroy() {
// Setting the action to perform when the Android O.S. kills this
// activity.
if (tcpdump.getProcessStatus()) {
stopTCPdump();
}
}
public boolean onCreateOptionsMenu(Menu menu) {
// This code makes the activity to show a menu when the device's menu
// key is pressed.
menu.add(0, 0, 0, getString(R.string.options_text));
menu.add(0, 1, 0, getString(R.string.about_text));
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
// Setting the action to perform when an option from the menu is
// selected.
switch (item.getItemId()) {
case 0:
optionsIntent = new Intent(Main.this, Options.class);
startActivityForResult(optionsIntent, 1);
return true;
case 1:
new AlertDialog.Builder(Main.this).setTitle(R.string.about_text)
.setMessage(getString(R.string.about_shark))
.setNeutralButton(getString(R.string.ok), null).show();
return true;
}
return false;
}
/**
* Calls TCPdumpHandler to try start the packet capture.
*/
private void startTCPdump() {
if (tcpDumpHandler.checkNetworkStatus()) {
switch (tcpDumpHandler.start(parameters.getText().toString())) {
case 0:
Toast.makeText(Main.this, getString(R.string.tcpdump_started),
Toast.LENGTH_SHORT).show();
break;
case -1:
Toast.makeText(Main.this,
getString(R.string.tcpdump_already_started),
Toast.LENGTH_SHORT).show();
break;
case -2:
new AlertDialog.Builder(Main.this)
.setTitle(getString(R.string.device_not_rooted_error))
.setMessage(
getString(R.string.device_not_rooted_error_msg))
.setNeutralButton(getString(R.string.ok), null).show();
break;
case -4:
new AlertDialog.Builder(Main.this).setTitle("Error")
.setMessage(getString(R.string.command_error))
.setNeutralButton(getString(R.string.ok), null).show();
break;
case -5:
new AlertDialog.Builder(Main.this).setTitle("Error")
.setMessage(getString(R.string.outputstream_error))
.setNeutralButton(getString(R.string.ok), null).show();
break;
default:
new AlertDialog.Builder(Main.this).setTitle("Error")
.setMessage(getString(R.string.unknown_error))
.setNeutralButton(getString(R.string.ok), null).show();
}
} else {
new AlertDialog.Builder(Main.this)
.setTitle(getString(R.string.network_connection_error))
.setMessage(
getString(R.string.network_connection_error_msg))
.setPositiveButton(getString(R.string.yes),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
startActivity(new Intent(
Settings.ACTION_WIRELESS_SETTINGS));
}
}).setNegativeButton(getString(R.string.no), null)
.show();
}
}
/**
* Calls TCPdumpHandler to try to stop the packet capture.
*/
private void stopTCPdump() {
switch (tcpDumpHandler.stop()) {
case 0:
Toast.makeText(Main.this, getString(R.string.tcpdump_stoped),
Toast.LENGTH_SHORT).show();
break;
case -1:
Toast.makeText(Main.this,
getString(R.string.tcpdump_already_stoped),
Toast.LENGTH_SHORT).show();
break;
case -2:
new AlertDialog.Builder(Main.this)
.setTitle(getString(R.string.device_not_rooted_error))
.setMessage(getString(R.string.device_not_rooted_error_msg))
.setNeutralButton(getString(R.string.ok), null).show();
break;
case -4:
new AlertDialog.Builder(Main.this).setTitle("Error")
.setMessage(getString(R.string.command_error))
.setNeutralButton(getString(R.string.ok), null).show();
break;
case -5:
new AlertDialog.Builder(Main.this).setTitle("Error")
.setMessage(getString(R.string.outputstream_error))
.setNeutralButton(getString(R.string.ok), null).show();
break;
case -6:
new AlertDialog.Builder(Main.this).setTitle("Error")
.setMessage(getString(R.string.close_shell_error))
.setNeutralButton(getString(R.string.ok), null).show();
break;
case -7:
new AlertDialog.Builder(Main.this).setTitle("Error")
.setMessage(getString(R.string.process_finish_error))
.setNeutralButton(getString(R.string.ok), null).show();
default:
new AlertDialog.Builder(Main.this).setTitle("Error")
.setMessage(getString(R.string.unknown_error))
.setNeutralButton(getString(R.string.ok), null).show();
}
}
/**
* Tries to launch the reader activity.
*/
private void launchReader() {
readerIntent = new Intent(Main.this, Reader.class);
if (FileManager.checkFile(GlobalConstants.dirName,
settings.getString("fileText", "shark_capture.pcap"))) {
if (tcpdump.getProcessStatus() == false) {
startActivity(readerIntent);
} else {
new AlertDialog.Builder(Main.this)
.setTitle(getString(R.string.capture_in_progress_error))
.setMessage(
getString(R.string.capture_in_progress_error_msg))
.setPositiveButton(getString(R.string.yes),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0,
int arg1) {
stopTCPdump();
startActivity(readerIntent);
}
})
.setNegativeButton(getString(R.string.no), null).show();
}
} else {
new AlertDialog.Builder(Main.this)
.setTitle(getString(R.string.file_error))
.setMessage(getString(R.string.file_error_msg))
.setNeutralButton(getString(R.string.ok), null).show();
}
}
}
このEclipseを実行すると、ログに次のエラーが表示されます。私は提案された多くの解決策を試しましたが、それでも解決策を得ることができませんでした。
08-21 15:38:01.483: D/AndroidRuntime(499): Shutting down VM
08-21 15:38:01.483: W/dalvikvm(499): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
08-21 15:38:01.504: E/AndroidRuntime(499): FATAL EXCEPTION: main
08-21 15:38:01.504: E/AndroidRuntime(499): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.shark/com.shark.Main}: java.lang.NullPointerException
08-21 15:38:01.504: E/AndroidRuntime(499): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
08-21 15:38:01.504: E/AndroidRuntime(499): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
08-21 15:38:01.504: E/AndroidRuntime(499): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
08-21 15:38:01.504: E/AndroidRuntime(499): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
08-21 15:38:01.504: E/AndroidRuntime(499): at android.os.Handler.dispatchMessage(Handler.java:99)
08-21 15:38:01.504: E/AndroidRuntime(499): at android.os.Looper.loop(Looper.java:123)
08-21 15:38:01.504: E/AndroidRuntime(499): at android.app.ActivityThread.main(ActivityThread.java:4627)
08-21 15:38:01.504: E/AndroidRuntime(499): at java.lang.reflect.Method.invokeNative(Native Method)
08-21 15:38:01.504: E/AndroidRuntime(499): at java.lang.reflect.Method.invoke(Method.java:521)
08-21 15:38:01.504: E/AndroidRuntime(499): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
08-21 15:38:01.504: E/AndroidRuntime(499): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
08-21 15:38:01.504: E/AndroidRuntime(499): at dalvik.system.NativeStart.main(Native Method)
08-21 15:38:01.504: E/AndroidRuntime(499): Caused by: java.lang.NullPointerException
08-21 15:38:01.504: E/AndroidRuntime(499): at com.shark.TCPdumpHandler.generateCommand(TCPdumpHandler.java:322)
08-21 15:38:01.504: E/AndroidRuntime(499): at com.shark.Main.onCreate(Main.java:93)
08-21 15:38:01.504: E/AndroidRuntime(499): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
08-21 15:38:01.504: E/AndroidRuntime(499): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
08-21 15:38:01.504: E/AndroidRuntime(499): ... 11 more
正確にエラーが発生している場所を見つけました。それによると、「closeShell」は次のコードでnullを返しています。さらに3つのクラスにループバックします。
public class RootShell {
protected Process process = null;
protected DataOutputStream os = null;
protected DataInputStream is = null;
private boolean deviceRooted = false;
/**
* RootShell class constructor. Checks if the device is rooted.
*/
public RootShell() {
deviceRooted = checkRootStatus();
}
/**
* RootShell class destructor. Closes the shell if its not already closed.
*/
protected void finalize() {
if (process != null)
closeShell();
}
/**
* Opens a root shell and waits for commands.
*
* @return 0 Everything went OK.<br>
* -1 The shell has already been opened.<br>
* -2 The device isn't rooted.<br>
* -3 IOException when running the su command.
*/
public int openShell() {
if (process == null) {
if (deviceRooted) {
// Trying to get root access.
try {
process = Runtime.getRuntime().exec("su");
} catch (IOException e) {
return -3;
}
// Getting an output stream to the root shell for introducing
// commands.
os = new DataOutputStream(process.getOutputStream());
// Getting an input stream to the root shell for displaying
// results.
is = new DataInputStream(process.getInputStream());
return 0;
} else
return -2;
} else
return -1;
}
/**
* Runs the command in the root shell.
*
* @param command
* The command which will be executed in the root shell.
* @return 0 Everything went OK.<br>
* -1 The shell wasn't opened.<br>
* -2 The device isn't rooted.<br>
* -4 IOException when running the user command.<br>
* -5 IOException when flushing the DataOutputStream.
*/
public int runCommand(String command) {
if (process != null) {
if (deviceRooted) {
try {
os.writeBytes(command + "\n");
} catch (IOException e) {
return -4;
}
try {
os.flush();
} catch (IOException e) {
return -5;
}
return 0;
} else
return -2;
} else
return -1;
}
/**
* Closes a shell which is already open.
*
* @return -1 The shell wasn't opened.<br>
* -2 The device isn't rooted.<br>
* -6 IOException when running the exit command.<br>
* -7 InterruptedException when waiting for the process to stop.
*/
public int closeShell() {
if (process != null) {
if (deviceRooted) {
try {
os.writeBytes("exit\n");
} catch (IOException e1) {
return -6;
}
try {
process.waitFor();
} catch (InterruptedException e) {
return -7;
}
process.destroy();
process = null;
os = null;
is = null;
return 0;
} else
return -2;
} else
return -1;
}
/**
* Checks if an Android device is rooted or not.<br>
* Code borrowed from: http://www
* .stealthcopter.com/blog/2010/01/android-requesting-root-access-in
* -your-app/
*
* @return true: The device is rooted.<br>
* false: The device isn't rooted.
*/
private static boolean checkRootStatus() {
Process p;
try {
// Preform su to get root privileges
p = Runtime.getRuntime().exec("su");
// Attempt to write a file to a root-only
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("echo \"Do I have root?\" >/system/sd/temporary.txt\n");
// Close the terminal
os.writeBytes("exit\n");
os.flush();
try {
p.waitFor();
if (p.exitValue() != 255) {
return true;
} else {
return false;
}
} catch (InterruptedException e) {
return false;
}
} catch (IOException e) {
return false;
}
}
/**
* @return A DataInputStream to the root shell.
*/
public DataInputStream getInputStream() {
return is;
}
/**
* @return A DataOutputStream to the root shell.
*/
public DataOutputStream getOutputStream() {
return os;
}
/**
* @return true if the shell is opened.<br>
* false if the shell isn't opened.
*/
public boolean getProcessStatus() {
if (process != null)
return true;
else
return false;
}
}
また、「08-22 19:05:19.701:I / System.out(275):e1java.io.IOException:壊れたパイプ」を表示していることもわかりました。「closeshell」でtrycatchに入ります。