I have a rooted Android 7 phone and I would like to dump unix input event files. Using adb I could do it using the following command:
adb shell getevent -t /dev/input/event7 > recorded_touch_events.txt
This will dump the event7 file into recorded_touch_events.txt. But this only works when the phone is connected by usb cable with the PC. Using Android I can dump files with the following code:
th = new Thread(new Runnable(){
private Process exec;
#Override
public void run() {
try {
exec = Runtime.getRuntime().exec(new String[]{"su","-c","getevent -t /dev/input/event7"});
InputStreamReader is = new InputStreamReader(
exec.getInputStream());
String s;
BufferedReader br = new BufferedReader(is);
while(((s = br.readLine()) != null) && run){
// write line to text file
}
is.close();
exec.destroy();
} catch (IOException e) {
e.printStackTrace();
}
}
In this way, I could store every read line in a text file.
Are there other approaches (probably faster ones) for directly dumping the event file?
getevent is used to print input events out in human readable form. For example during interactive debug session. You do not need to use getevent for just dumping or any other computer processing task. Just open and read the input file. The event record format is very simple.
Certainly No, you are doing it right.
Related
I have been working on this small project in college about changing the default DNS of wifi network to a custom DNS like Google, OpenDNS, Metacert, etc.
I know I have to write a shellscript inside the app's code that would edit the hosts file in the filesystem.
The problem is I have no idea where to start from. I have researched on google for some time and I couldn't figure anything.
If anyone knows about it, please guide me. Please tell me the name of the file to be edited, its location, what commands are required and how to run those commands' combination as a shellscript on a click of a button on the UI of app.
EDIT : I'm stuck only at this. Any help will be greatly appreciated.
I'm not sure about which files you would have to edit but this should give you the tools you need to do that.
The first thing you need to do is root the phone if you haven't already. If it's not rooted, you'll run into an issue like: Working Directory : null environment when running Process.Builder on android
There are a lot of guides available for that online. Install SuperSU as well. In order to run shell commands or scripts you should look at the ProcessBuilder class in Android:
http://developer.android.com/reference/java/lang/ProcessBuilder.html
I've given some sample code below to help you along the way. You could execute this in an OnClick() for a button.
/**
* Runs the shell command.
*
* #param command an array of Strings. command[0] contains the name of the
* shell command. command[1]... contains parameters.
*
* #return the text outputted by the command to stderr or stdout
*/
String runCmd(String[] command, boolean readOutput,
boolean waitForExit) {
ProcessBuilder probuilder = new ProcessBuilder()
.command(command)
.redirectErrorStream(true);
String output = "";
Process process;
// Log.d("MyShellCommand", "Executing " + command[0]);
try {
process = probuilder.start();
} catch(IOException e) {
return e.getMessage();
}
if (readOutput) {
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
try {
while ((line = br.readLine()) != null) {
// Log.d("MyShellCommand", "Read a line: " + line);
output += line + "\n";
}
} catch(IOException e) {
output = e.getMessage();
}
}
I need to capture all the logs written through my application. I know from Jetllybean OS we can read need only our application log. But when I tried by using command "logcat -d" using exec method by application and I did not get any data.
Please help me on this.
Thanks,
Saravanakumar
This is the example that I was playing around with before that will generate a log text file in local storage:
private static String generateLogcatLogCommond = "logcat -d > /sdcard/IssueReport/log.txt";
public static String generateLogcatLog() throws InterruptedException {
try {
File issueReport = new File(Environment.getExternalStorageDirectory(), "IssueReport");
if (!issueReport.exists())
issueReport.mkdir();
File logFile = new File(issueReport,"log.txt");
logFile.createNewFile();
Process process = Runtime.getRuntime().exec("/system/bin/sh -");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes(generateLogcatLogCommond);
logLocation = "/sdcard/IssueReport/log.txt";
Log.d("Client", logLocation);
} catch (IOException e) {
e.printStackTrace();
}
return logLocation;
}
What the above code is doing is using 'sh' to run 'logcat -d' command and save it as a file locally. This will get ALL the logcat log. For you, you can change that to 'logcat -s ""' and it will save all logcat log of your application to a file.
I'm writing an android app, and i need to read 7 SYSTEM files at start up. What would be the most efficient way to do this?
This is my code right now and it's pretty slow
read(file1);
read(file2);
...
read(file7);
...
public static String read(String file) {
String fileContents = "";
try {
String[] args = {"/system/bin/cat", file };
ProcessBuilder cmd = new ProcessBuilder(args);
Process p = cmd.start();
InputStream stream = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
fileContents = reader.readLine();
reader.close();
stream.close();
}
catch (IOException e) {
e.printStackTrace();
}
return fileContents;
}
There has to be some way to cat each file without closing the stream which should significantly speed things up. I tried making a shell script with the 7 cat cmds and reading the output but everything is all mashed together and i can't split the results.
I tried splitting the cat cmds with echo cmds to form a deliminator in the output:
cat file1
echo !
cat file2
echo !
But the deliminators "!" don't show up in the output and i can't figure out why.
Any suggestions?
I guess you could try multiple threads. Probably 7 would do just fine, but you have to check if 7 is not too much for the slowest device you are targeting. You need to leave some CPU for UI thread.
I've implemented a service that listens to commands issued through ADB. An example of a command sent through ADB could look like this:
adb shell am startservice -a com.testandroid.SEND_SMS -e number 123123123 -e message "åäö"
Now, the problem here is that the encoding of the string "åäö" seems to mess up. If I take that string extras and immediately output it to the log, I get a square "[]", unknown character. If I send this message I get chinese characters in the messages app. As long as I stick to non-umlaut characters (ASCII I guess), everything works fine.
I'm using Windows 7 and the command line for this. I have not touched the encoding of the command line and I've tried to process the extras string by getting the byte characters, passing in UTF-8 as an encoding argument, then creating a new String passing in UTF-8 as an encoding argument there as well. No dice, though.
The values of the bytes, when using getBytes() are å: -27, ä: -92, ö: -74
How do I get this to play nice so I can make use of at least the umlauts?
All of this works perfectly fine in Linux.
i ran into the same issue, but finally i got it work!
if you use for example C#, you have to do it like the following example:
02.12.2019
According to the protocol.txt, the ADB-Protocol supports "smart-sockets". Those sockets can be used to do all the stuff, the ADB-Client inside the adb.exe does. For example if you want upload an file, you have to request such an "smart-socket". After that, you have to follow the protocol assigned to the service (for an service overview see SERVICE.txt) as described, for example, in the SYNC.txt.
13.10.2014
public static List<string> ExecuteBG(string exe, string args, int timeOut = -1)
{
if (File.Exists(exe) || exe == "cmd.exe")
{
ProcessStartInfo StartInfo = new ProcessStartInfo();
StartInfo.FileName = exe;
StartInfo.Arguments = Encoding.Default.GetString(Encoding.UTF8.GetBytes(args));
StartInfo.CreateNoWindow = true;
StartInfo.UseShellExecute = false;
StartInfo.RedirectStandardError = true;
StartInfo.RedirectStandardOutput = true;
StartInfo.StandardErrorEncoding = Encoding.UTF8;
StartInfo.StandardOutputEncoding = Encoding.UTF8;
AutoResetEvent errorWaitHandle = new AutoResetEvent(false);
AutoResetEvent outputWaitHandle = new AutoResetEvent(false);
List<string> response = new List<string>();
Process proc = new Process();
proc.StartInfo = StartInfo;
proc.ErrorDataReceived += (s, e) =>
{
if (String.IsNullOrEmpty(e.Data))
{
errorWaitHandle.Set();
}
else
{
response.Add(e.Data);
}
};
proc.OutputDataReceived += (s, e) =>
{
if (String.IsNullOrEmpty(e.Data))
{
outputWaitHandle.Set();
}
else
{
response.Add(e.Data);
}
};
proc.Start();
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit(timeOut);
errorWaitHandle.WaitOne(timeOut);
outputWaitHandle.WaitOne(timeOut);
return response;
}
return new List<string>();
}
Really important is this part "StartInfo.Arguments = Encoding.Default.GetString(Encoding.UTF8.GetBytes(args));", here we convert the UTF8 string into the Windows "default" charset which is known by cmd. So we send a "destroyed" "default" encoded string to cmd and the Android shell will convert it back to UTF8. So we have the "umlauts" like "üöäÜÖÄàè etc.".
Hope this helps someone.
PS: If u need a working "Framework" which supports UTF8 push/pull for files/folders also have a look at my AndroidCtrl.dll it's C# .NET4 written.
Regards,
Sebastian
Concluding, either the problem is situated in cmd.exe or adb.exe. Until either one or both are updated to be more compliant with eachother I will sadly not be able to make use of this for the time being.
I've been trying to build a Terminal Emulator for Android. Being pretty new to this, my idea was to execute each command and store the output in a file, whose contents would be displayed after each execution.
Pseudo Code :
public Boolean execCommands(String command) {
try {
rt = Runtime.getRuntime();
process = rt.exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("echo $ \""+command+ "\" >> /sdcard/Android/data/terminalemulatorlog.txt\n\n\n");
/**** Note : String command = (EditText)findViewById(R.id.command).getText().toString(); ****/
os.flush();
os.writeBytes("exit\n");
os.flush();
process.waitFor();
}
// Error Handling
displayOutput(); //Loads and displays the Text File (/sdcard/Android/data/terminalemulatorlog.txt)
return true;
}
This piece of code works except for a few special commands (Eg. 'clear').
But what I'm more concerned about are the following problems :
Each time a command is to be executed, I end up seeking SuperUser permissions (second line of code). And I'd like to do away with this.
In cases when the user enters one command followed by another,
Such as :
cd /sdcard
touch File.txt
The File.txt is created in '/' and not in '/sdcard'. As of now to avoid this, I'm keeping a track of all the 'cd' commands to figure out what the present working directory is. And I'm hoping that there is a better way around this.
I'd be grateful if someone could help me out here.
Not sure if you are still needing this or not, but here is how I am issuing multiple commands at one time and not using "su" to have them run.
try {
String[] commands = {
"dumpstate > /sdcard/LogFiles/dumpstate.txt",
"dumpsys > /sdcard/LogFiles/dumpsys.txt",
"logcat -d > /sdcard/LogFiles/log.txt",
"cat /sdcard/LogFiles/dumpstate.txt /sdcard/LogFiles/dumpsys.txt /sdcard/LogFiles/log.txt > /sdcard/LogFiles/bugreport.rtf" };
Process p = Runtime.getRuntime().exec("/system/bin/sh -");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
for (String tmpCmd : commands) {
os.writeBytes(tmpCmd + "\n");
}
} catch (IOException e) {
e.printStackTrace();
}
This a bit late but here a few ways of doing this.
1)
Instead of using su as a starting point use /system/bin/sh.
and after calling
rt.exec("/system/bin/sh");
You should hold onto the Output Stream and Input Stream to give further commands.
After you issued a command you should echo a magic line like "---EOF---" and stop reading input after reading that line. If you don't have this you'll end up with the read function from the InputStream blocking.
2) Pipe the data to a native process you've written that simply moves the data on to your Android Application with a terminating character or string attached to the end.
I am not entirely sure how to do this, but it is essentially the same as the previous method just relies on you native application as a middle man.
This will get you close to a functioning "Terminal Emulator".
3)If you wan't a true Ternimal Emulator then there's no other way to do it than : using a native application that opens a connection to a psuedoterminal.
Here's some basic information of how to open a pty : link
Terminal Emulator is a open source project that uses this technique.
Have a look here
Regarding problem 1:
Each time a command is to be executed, I end up seeking SuperUser permissions (second line of code). And I'd like to do away with this.
Thanks to Xonar's suggestion from another answer:
After you issued a command you should echo a magic line like "---EOF---" and stop reading input after reading that line.
Solution in Kotlin:
private lateinit var suProcess: Process
private lateinit var outputStream: DataOutputStream
private fun getSu(): Boolean {
return try {
suProcess = Runtime.getRuntime().exec("su")
outputStream = DataOutputStream(suProcess.outputStream)
true
} catch (e: Exception) {
e.printStackTrace()
false
}
}
private fun sudo(command: String): List<String>? {
return try {
outputStream.writeBytes("$command\n")
outputStream.flush()
outputStream.writeBytes("echo ---EOF---\n")
outputStream.flush()
val reader = suProcess.inputStream.bufferedReader()
val result = mutableListOf<String>()
while (true) {
val line = reader.readLine()
if (line == "---EOF---") break
result += line
}
result
} catch (e: Exception) {
e.printStackTrace()
null
}
}
private fun exitTerminal() {
try {
outputStream.writeBytes("exit\n")
outputStream.flush()
suProcess.waitFor()
} catch (e: Exception) {
e.printStackTrace()
} finally {
outputStream.close()
}
}
//Activity method
override fun onDestroy() {
super.onDestroy()
exitTerminal()
}