Read logcat programmatically within application - android

I want to read and react to logcat logs within my application.
I found the following code:
try {
Process process = Runtime.getRuntime().exec("logcat -d");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder log=new StringBuilder();
String line = "";
while ((line = bufferedReader.readLine()) != null) {
log.append(line);
}
TextView tv = (TextView)findViewById(R.id.textView1);
tv.setText(log.toString());
}
catch (IOException e) {}
This code indeed returns the logcat logs that made until the application was started -
But is it possible to continuously listen to even new logcat logs?

You can keep reading the logs, just by removing the "-d" flag in your code above.
The "-d" flag instruct to logcat to show log content and exit. If you remove the flag, logcat will not terminate and keeps sending any new line added to it.
Just have in mind that this may block your application if not correctly designed.
good luck.

With coroutines and the official lifecycle-livedata-ktx and lifecycle-viewmodel-ktx libraries it's simple like that:
class LogCatViewModel : ViewModel() {
fun logCatOutput() = liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
Runtime.getRuntime().exec("logcat -c")
Runtime.getRuntime().exec("logcat")
.inputStream
.bufferedReader()
.useLines { lines -> lines.forEach { line -> emit(line) }
}
}
}
Usage
val logCatViewModel by viewModels<LogCatViewModel>()
logCatViewModel.logCatOutput().observe(this, Observer{ logMessage ->
logMessageTextView.append("$logMessage\n")
})

You can clear your logcat with this method i'm using to clear after writing logcat to a file to avoid duplicated lines:
public void clearLog(){
try {
Process process = new ProcessBuilder()
.command("logcat", "-c")
.redirectErrorStream(true)
.start();
} catch (IOException e) {
}
}

Here is a quick put-together/drop-in that can be used for capturing all current, or all new (since a last request) log items.
You should modify/extend this, because you might want to return a continuous-stream rather than a LogCapture.
The Android LogCat "Manual": https://developer.android.com/studio/command-line/logcat.html
import android.util.Log;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Stack;
/**
* Created by triston on 6/30/17.
*/
public class Logger {
// http://www.java2s.com/Tutorial/Java/0040__Data-Type/SimpleDateFormat.htm
private static final String ANDROID_LOG_TIME_FORMAT = "MM-dd kk:mm:ss.SSS";
private static SimpleDateFormat logCatDate = new SimpleDateFormat(ANDROID_LOG_TIME_FORMAT);
public static String lineEnding = "\n";
private final String logKey;
private static List<String> logKeys = new ArrayList<String>();
Logger(String tag) {
logKey = tag;
if (! logKeys.contains(tag)) logKeys.add(logKey);
}
public static class LogCapture {
private String lastLogTime = null;
public final String buffer;
public final List<String> log, keys;
LogCapture(String oLogBuffer, List<String>oLogKeys) {
this.buffer = oLogBuffer;
this.keys = oLogKeys;
this.log = new ArrayList<>();
}
private void close() {
if (isEmpty()) return;
String[] out = log.get(log.size() - 1).split(" ");
lastLogTime = (out[0]+" "+out[1]);
}
private boolean isEmpty() {
return log.size() == 0;
}
public LogCapture getNextCapture() {
LogCapture capture = getLogCat(buffer, lastLogTime, keys);
if (capture == null || capture.isEmpty()) return null;
return capture;
}
public String toString() {
StringBuilder output = new StringBuilder();
for (String data : log) {
output.append(data+lineEnding);
}
return output.toString();
}
}
/**
* Get a list of the known log keys
* #return copy only
*/
public static List<String> getLogKeys() {
return logKeys.subList(0, logKeys.size() - 1);
}
/**
* Platform: Android
* Get the logcat output in time format from a buffer for this set of static logKeys.
* #param oLogBuffer logcat buffer ring
* #return A log capture which can be used to make further captures.
*/
public static LogCapture getLogCat(String oLogBuffer) { return getLogCat(oLogBuffer, null, getLogKeys()); }
/**
* Platform: Android
* Get the logcat output in time format from a buffer for a set of log-keys; since a specified time.
* #param oLogBuffer logcat buffer ring
* #param oLogTime time at which to start capturing log data, or null for all data
* #param oLogKeys logcat tags to capture
* #return A log capture; which can be used to make further captures.
*/
public static LogCapture getLogCat(String oLogBuffer, String oLogTime, List<String> oLogKeys) {
try {
List<String>sCommand = new ArrayList<String>();
sCommand.add("logcat");
sCommand.add("-bmain");
sCommand.add("-vtime");
sCommand.add("-s");
sCommand.add("-d");
sCommand.add("-T"+oLogTime);
for (String item : oLogKeys) sCommand.add(item+":V"); // log level: ALL
sCommand.add("*:S"); // ignore logs which are not selected
Process process = new ProcessBuilder().command(sCommand).start();
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
LogCapture mLogCapture = new LogCapture(oLogBuffer, oLogKeys);
String line = "";
long lLogTime = logCatDate.parse(oLogTime).getTime();
if (lLogTime > 0) {
// Synchronize with "NO YEAR CLOCK" # unix epoch-year: 1970
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(oLogTime));
calendar.set(Calendar.YEAR, 1970);
Date calDate = calendar.getTime();
lLogTime = calDate.getTime();
}
while ((line = bufferedReader.readLine()) != null) {
long when = logCatDate.parse(line).getTime();
if (when > lLogTime) {
mLogCapture.log.add(line);
break; // stop checking for date matching
}
}
// continue collecting
while ((line = bufferedReader.readLine()) != null) mLogCapture.log.add(line);
mLogCapture.close();
return mLogCapture;
} catch (Exception e) {
// since this is a log reader, there is nowhere to go and nothing useful to do
return null;
}
}
/**
* "Error"
* #param e
*/
public void failure(Exception e) {
Log.e(logKey, Log.getStackTraceString(e));
}
/**
* "Error"
* #param message
* #param e
*/
public void failure(String message, Exception e) {
Log.e(logKey, message, e);
}
public void warning(String message) {
Log.w(logKey, message);
}
public void warning(String message, Exception e) {
Log.w(logKey, message, e);
}
/**
* "Information"
* #param message
*/
public void message(String message) {
Log.i(logKey, message);
}
/**
* "Debug"
* #param message a Message
*/
public void examination(String message) {
Log.d(logKey, message);
}
/**
* "Debug"
* #param message a Message
* #param e An failure
*/
public void examination(String message, Exception e) {
Log.d(logKey, message, e);
}
}
In your project which performs activity logging:
Logger log = new Logger("SuperLog");
// perform logging methods
When you want to capture everything you logged through "Logger"
LogCapture capture = Logger.getLogCat("main");
When you get hungry and you want to snack on more logs
LogCapture nextCapture = capture.getNextCapture();
You can get the capture as a string with
String captureString = capture.toString();
Or you can get the log items of the capture with
String logItem = capture.log.get(itemNumber);
There is no exact static method to capture foreign log keys but there is a way none the less
LogCapture foreignCapture = Logger.getLogCat("main", null, foreignCaptureKeyList);
Using the above will also permit you to call Logger.this.nextCapture on the foreign capture.

Based on #user1185087's answer, a simple solution without ViewModel could be:
Start the job on an IO thread:
// Custom scope for collecting logs on IO threads.
val scope = CoroutineScope(Job() + Dispatchers.IO)
val job = scope.launch {
Runtime.getRuntime().exec("logcat -c") // Clear logs
Runtime.getRuntime().exec("logcat") // Start to capture new logs
.inputStream
.bufferedReader()
.useLines { lines ->
// Note that this forEach loop is an infinite loop until this job is cancelled.
lines.forEach { newLine ->
// Check whether this job is cancelled, since a coroutine must
// cooperate to be cancellable.
ensureActive()
// TODO: Write newLine into a file or buffer or anywhere appropriate
}
}
}
Cancel the job from the main thread:
MainScope().launch {
// Cancel the job and wait for its completion on main thread.
job.cancelAndJoin()
job = null // May be necessary
// TODO: Anything else you may want to clean up
}
This solution should suffice if you want to collect your app's new logs continuously on a background thread.

The "-c" flag clears the buffer.
-c Clears (flushes) the entire log and exits.

//CLEAR LOGS
Runtime.getRuntime().exec("logcat -c");
//LISTEN TO NEW LOGS
Process pq=Runtime.getRuntime().exec("logcat v main");
BufferedReader brq = new BufferedReader(new InputStreamReader(pq.getInputStream()));
String sq="";
while ((sq = brq.readLine()) != null)
{
//CHECK YOUR MSG HERE
if(sq.contains("send MMS with param"))
{
}
}
I am using this in my app and it works .
And you can use above code in Timer Task so that it wont stop your main thread
Timer t;
this.t.schedule(new TimerTask()
{
public void run()
{
try
{
ReadMessageResponse.this.startRecord();//ABOVE METHOD HERE
}
catch (IOException ex)
{
//NEED TO CHECK SOME VARIABLE TO STOP MONITORING LOGS
System.err.println("Record Stopped");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
ReadMessageResponse.this.t.cancel();
}
}
}, 0L);
}

Try to add this permission into the mainfest:
<uses-permission android:name="android.permission.READ_LOGS"/>

Related

logcat Android to text file

Please tell me that how can I write my own created logs to text file in device ?
I found this code in stackoverflow itself but this code it prints whole logcat, How can I filter the same?
public static void write() {
try {
Process process = Runtime.getRuntime().exec("logcat -d");
// Log.e("","******************---1");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
log = new StringBuilder();
String line;
// Log.e("","******************---2");
while ((line = bufferedReader.readLine()) != null) {
log.append(line);
}
} catch (IOException exception) {
}
//convert log to string
final String logString = new String(log.toString());
//create text file in SDCard
File sdCard = Environment.getExternalStorageDirectory();
// Log.e("","******************---3");
File dir = new File(sdCard.getAbsolutePath() + "/myLogcat");
dir.mkdirs();
File file = new File(dir, "logcat.txt");
try {
//to write logcat in text file
FileOutputStream fOut = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fOut);
// Write the string to the file
osw.write(logString);
// Log.e("", "******************---4");
osw.flush();
osw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Try this :
try {
Process process = Runtime.getRuntime().exec("logcat -d");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder log=new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
log.append(line);
}
appendLog(log.toString());
} catch (IOException e) {
}
Method to write log to file:
public void appendLog(String text) {
File logFile = new File("sdcard/Log.txt");
if (!logFile.exists()) {
try {
logFile.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
// BufferedWriter for performance, true to set append to file flag
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile,
true));
buf.append(text);
buf.newLine();
buf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Add the following permission in manifest file also :
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
First check out the log locations here: https://android.stackexchange.com/questions/14430/how-can-i-view-and-examine-the-android-log
If that's not good enough, you can always make your own Log.java class which would log directly to the file you want (though you should really reconsider using LogCat as it is working as expected).
As a alternate way you can create your custom logger.
Here is one sample util class that I have created for my project.
import android.os.Environment;
import android.util.Log;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
/**
* TODO: Add a class header comment!
*
* #author Dhaval Patel
* #version 1.0, May 24, 2015
* #since 1.0
*/
public final class Logger {
public static final int MAX_FILE_SIZE = 1024*1024*5;// max file size 5MB, if file size increase, Logger will create new file.
private static final String LOG_PREFIX = "prefix_";
private static final int LOG_PREFIX_LENGTH = LOG_PREFIX.length();
private static final int MAX_LOG_TAG_LENGTH = 23;
private static final Boolean ENABLE_CONSOLE_LOG = true; //Flag to enable or disable console log
private static final Boolean ENABLE_FILE_LOG = true; //Flag to enable or disable file log
private static final LogLevel GLOBAL_LOG_LEVEL = LogLevel.VERBOSE; //Flag indicate log level
private static final String LOG_DIRECTORY = Environment.getExternalStorageDirectory()+"log"+File.separator; //Log directory
public static String makeLogTag(String str) {
if (str.length() > MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH) {
return LOG_PREFIX + str.substring(0, MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH - 1);
}
return LOG_PREFIX + str;
}
private enum LogLevel{
VERBOSE(Log.VERBOSE),
DEBUG(Log.DEBUG),
INFO(Log.INFO),
WARNING(Log.WARN),
ERROR(Log.ERROR),
ASSERT(Log.ASSERT);
private final int logLevel;
LogLevel(int logLevel) {
this.logLevel = logLevel;
}
public int getLogLevel() {
return logLevel;
}
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
*
*/
public static void v(String tag, String msg) {
write(LogLevel.VERBOSE, tag, msg);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
* #param tr An exception to log
*
*/
public static void v(String tag, String msg, Throwable tr) {
write(LogLevel.VERBOSE, tag, msg, tr);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
*
*/
public static void d(String tag, String msg) {
write(LogLevel.DEBUG, tag, msg);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
* #param tr An exception to log
*
*/
public static void d(String tag, String msg, Throwable tr) {
write(LogLevel.DEBUG, tag, msg, tr);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
*
*/
public static void i(String tag, String msg) {
write(LogLevel.INFO, tag, msg);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
* #param tr An exception to log
*
*/
public static void i(String tag, String msg, Throwable tr) {
write(LogLevel.INFO, tag, msg, tr);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
*
*/
public static void w(String tag, String msg) {
write(LogLevel.WARNING, tag, msg);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
* #param tr An exception to log
*
*/
public static void w(String tag, String msg, Throwable tr) {
write(LogLevel.WARNING, tag, msg, tr);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
*
*/
public static void e(String tag, String msg) {
write(LogLevel.ERROR, tag, msg);
}
/**
*
* #param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* #param msg The message you would like logged.
* #param tr An exception to log
*
*/
public static void e(String tag, String msg, Throwable tr) {
write(LogLevel.ERROR, tag, msg, tr);
}
private static boolean isLogEnable(LogLevel logLevel){
return GLOBAL_LOG_LEVEL.getLogLevel() <= logLevel.getLogLevel();
}
private static void write(LogLevel logLevel, String tag, String log) {
if (isLogEnable(logLevel) && ENABLE_FILE_LOG){
StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[4];
String logPoint = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
String msg = "["+getCurrentDateTime()+"] "+ logLevel.name() +" "+ logPoint +" "+tag+"//:"+log;
write(msg);
}
if (isLogEnable(logLevel) && ENABLE_CONSOLE_LOG){
Log.println(logLevel.getLogLevel(), makeLogTag(tag), log);
}
}
private static void write(LogLevel logLevel, String tag, String log, Throwable tr){
if (isLogEnable(logLevel) && ENABLE_FILE_LOG){
StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[4];
String logPoint = stackTraceElement.getClassName() + "::" + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
String msg = "["+getCurrentDateTime()+"] "+ logLevel.name() +" "+ logPoint+" "+tag+"//:"+log+"\n"+Log.getStackTraceString(tr);
write(msg);
}
if (isLogEnable(logLevel) && ENABLE_CONSOLE_LOG){
Log.println(logLevel.getLogLevel(), makeLogTag(tag), log + "\n" + Log.getStackTraceString(tr));
}
}
private static void write(String text){
BufferedWriter out = null;
String filePath=LOG_DIRECTORY;
try {
SimpleDateFormat df = new SimpleDateFormat("dd_MMM_yyyy", Locale.ENGLISH);
String formattedDate = df.format(System.currentTimeMillis());
if(!new File(LOG_DIRECTORY).exists()) {
new File(LOG_DIRECTORY).mkdirs();
}
filePath = LOG_DIRECTORY +formattedDate+".log";
while (new File(filePath).exists() && new File(filePath).length() > MAX_FILE_SIZE) {
String[] txt1 = filePath.split("\\.log");
int fileNum = 1;
if (txt1.length == 2) {
fileNum = Integer.parseInt(txt1[1].substring(1));
fileNum++;
}
filePath = LOG_DIRECTORY + formattedDate + ".log" + "." + fileNum;
}
if(!new File(filePath).exists()){
new File(filePath).createNewFile();
}
if(new File(filePath).exists()){
FileWriter fStream = new FileWriter(filePath, true);
out = new BufferedWriter(fStream);
out.write(text + "\n" + new File(filePath).length());
out.flush();
}
} catch (IOException e) {
Log.e("Log", "Path:"+filePath);
e.printStackTrace();
} catch (Exception e) {
Log.e("Log", e.getMessage());
e.printStackTrace();
} finally {
try {
if(out!=null)
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static String getCurrentDateTime(){
return new SimpleDateFormat("dd MMM yyyy HH:mm:ss:SSS" , Locale.getDefault()).format(Calendar.getInstance().getTime());
}
}
Use it same like your android Log.
Logger.i("Info", "my sample log");
Here log store in file date-wise, you can modify write method as per your needs.

Cloudant replicate all data in android

I'm trying to have user registration for my android application. I'm able to successfully make user register and store their details in Cloudant. They can also login using the phone they had used to register.
However, when I try using another phone to login the account, it doesn't work. Is possible to replicate all data from Cloudant so that users can also login to other phones too? Here is my code:
public class CloudantConnect {
private static final String TAG = CloudantConnect.class.getSimpleName();
private static final String DATASTORE_DIRECTORY = "data";
private Datastore datastore;
private IndexManager indexManager;
private Replicator push_replicator;
private Replicator pull_replicator;
private Context context;
private final Handler handler;
private RegisterActivity register_listener;
public CloudantConnect(Context context, String datastore_name) {
this.context = context;
// Set up information within its own folder in the application
File path = this.context.getApplicationContext().getDir(DATASTORE_DIRECTORY, Context.MODE_PRIVATE);
DatastoreManager manager = new DatastoreManager(path.getAbsolutePath());
try {
this.datastore = manager.openDatastore(datastore_name);
} catch (DatastoreNotCreatedException e) {
Log.e(TAG, "Unable to open Datastore", e);
}
// Reach here if datastore successfully created
Log.d(TAG, "Successfully set up database at" + path.getAbsolutePath());
// Set up replicator objects
try {
this.reloadReplicationSettings();
} catch (URISyntaxException e) {
Log.e(TAG, "Unable to construct remote URI from configuration", e);
}
this.handler = new Handler(Looper.getMainLooper());
Log.d(TAG, "CloudantConnect set up " + path.getAbsolutePath());
}
/**
* Creates new document for user details database storage
* #param user to store user details into database
* #return document of user details stored
*/
public User createNewUserDocument(User user) {
MutableDocumentRevision revision = new MutableDocumentRevision();
revision.body = DocumentBodyFactory.create(user.asMap());
try {
BasicDocumentRevision created = this.datastore.createDocumentFromRevision(revision);
return User.fromRevision(created);
} catch (DocumentException e) {
return null;
}
}
/**
* Sets replication listener
*/
public void setReplicationListener(RegisterActivity listener) {
this.register_listener = listener;
}
/**
* Start push replication
*/
public void startPushReplication() {
if(this.push_replicator != null) {
this.push_replicator.start();
} else {
throw new RuntimeException("Push replication not set up correctly");
}
}
/**
* Start pull replication
*/
public void startPullReplication() {
if(this.pull_replicator != null) {
this.pull_replicator.start();
} else {
throw new RuntimeException("Pull replication not set up correctly");
}
}
/**
* Stop running replication
*/
public void stopAllReplication() {
if(this.push_replicator != null) {
this.push_replicator.stop();
}
if(this.pull_replicator != null) {
this.pull_replicator.stop();
}
}
/**
* Stop running replication and reloads replication settings
* from the app's preferences.
*/
public void reloadReplicationSettings() throws URISyntaxException {
this.stopAllReplication();
// Set up new replicator objects
URI uri = this.createServerURI();
// Push replication
PushReplication push = new PushReplication();
push.source = datastore;
push.target = uri;
push_replicator = ReplicatorFactory.oneway(push);
push_replicator.getEventBus().register(this);
// Pull replication
PullReplication pull = new PullReplication();
pull.source = uri;
pull.target = datastore;
pull_replicator = ReplicatorFactory.oneway(pull);
pull_replicator.getEventBus().register(this);
Log.d(TAG, "Set up replicators for URI:" + uri.toString());
}
/**
* Calls when replication is completed
*/
public void complete(ReplicationCompleted rc) {
handler.post(new Runnable() {
#Override
public void run() {
if(register_listener != null) {
register_listener.replicationComplete();
}
}
});
}
/**
* Calls when replication has error
*/
public void error(ReplicationErrored re) {
Log.e(TAG, "Replication error:", re.errorInfo.getException());
handler.post(new Runnable() {
#Override
public void run() {
if(register_listener != null) {
register_listener.replicationError();
}
}
});
}
}
It looks like you've got all the code there to do replication. Do you actually call startPullReplication() from somewhere?
If you want your complete and error callbacks to run when replication completes/fails, you will need to add the #Subscribe annotation on them both so they're triggered when the events are put on the EventBus.

Determine by which process Application.onCreate() is called

In my application I have local service, which needs to be run in separate process. It is specified as
<service android:name=".MyService" android:process=":myservice"></service>
in AndroidManifest.xml. I also subclass Application object and want to detect in it's onCreate method when it is called by ordinary launch and when by myservice launch. The only working solution that I have found is described by
https://stackoverflow.com/a/28907058/2289482
But I don't want to get all running processes on device and iterate over them. I try to use getApplicationInfo().processName from Context, but unfortunately it always return the same String, while the solution in the link above return: myPackage, myPackage:myservice. I don't need processName at the first place, but some good solution to determine when onCreate method is called by ordinary launch and when by myservice launch. May be it can be done by applying some kind of tag or label somewhere, but i didn't find how to do it.
You can use this code to get your process name:
int myPid = android.os.Process.myPid(); // Get my Process ID
InputStreamReader reader = null;
try {
reader = new InputStreamReader(
new FileInputStream("/proc/" + myPid + "/cmdline"));
StringBuilder processName = new StringBuilder();
int c;
while ((c = reader.read()) > 0) {
processName.append((char) c);
}
// processName.toString() is my process name!
Log.v("XXX", "My process name is: " + processName.toString());
} catch (Exception e) {
// ignore
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
// Ignore
}
}
}
From Acra sources. The same way as above answer but presents useful methods
private static final String ACRA_PRIVATE_PROCESS_NAME= ":acra";
/**
* #return true if the current process is the process running the SenderService.
* NB this assumes that your SenderService is configured to used the default ':acra' process.
*/
public static boolean isACRASenderServiceProcess() {
final String processName = getCurrentProcessName();
if (ACRA.DEV_LOGGING) log.d(LOG_TAG, "ACRA processName='" + processName + '\'');
//processName sometimes (or always?) starts with the package name, so we use endsWith instead of equals
return processName != null && processName.endsWith(ACRA_PRIVATE_PROCESS_NAME);
}
#Nullable
private static String getCurrentProcessName() {
try {
return IOUtils.streamToString(new FileInputStream("/proc/self/cmdline")).trim();
} catch (IOException e) {
return null;
}
}
private static final Predicate<String> DEFAULT_FILTER = new Predicate<String>() {
#Override
public boolean apply(String s) {
return true;
}
};
private static final int NO_LIMIT = -1;
public static final int DEFAULT_BUFFER_SIZE_IN_BYTES = 8192;
/**
* Reads an InputStream into a string
*
* #param input InputStream to read.
* #return the String that was read.
* #throws IOException if the InputStream could not be read.
*/
#NonNull
public static String streamToString(#NonNull InputStream input) throws IOException {
return streamToString(input, DEFAULT_FILTER, NO_LIMIT);
}
/**
* Reads an InputStream into a string
*
* #param input InputStream to read.
* #param filter Predicate that should return false for lines which should be excluded.
* #param limit the maximum number of lines to read (the last x lines are kept)
* #return the String that was read.
* #throws IOException if the InputStream could not be read.
*/
#NonNull
public static String streamToString(#NonNull InputStream input, Predicate<String> filter, int limit) throws IOException {
final BufferedReader reader = new BufferedReader(new InputStreamReader(input), ACRAConstants.DEFAULT_BUFFER_SIZE_IN_BYTES);
try {
String line;
final List<String> buffer = limit == NO_LIMIT ? new LinkedList<String>() : new BoundedLinkedList<String>(limit);
while ((line = reader.readLine()) != null) {
if (filter.apply(line)) {
buffer.add(line);
}
}
return TextUtils.join("\n", buffer);
} finally {
safeClose(reader);
}
}
/**
* Closes a Closeable.
*
* #param closeable Closeable to close. If closeable is null then method just returns.
*/
public static void safeClose(#Nullable Closeable closeable) {
if (closeable == null) return;
try {
closeable.close();
} catch (IOException ignored) {
// We made out best effort to release this resource. Nothing more we can do.
}
}
You can use the next method
#Nullable
public static String getProcessName(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo processInfo : activityManager.getRunningAppProcesses()) {
if (processInfo.pid == android.os.Process.myPid()) {
return processInfo.processName;
}
}
return null;
}

AsyncTask in an android socket application

i am making an android socket app to communicate with the server for creating accounts, and i noticed i have to do this in AsyncTask sub class, even when i seperate it to another class without UI,but i am terribly confused how can i use AsyncTask on this, is there any one expert here who can help me please?
this is the code:
public class AccountCreator extends Activity {
public AccountCreator(){
super();
}
// for I/O
ObjectInputStream sInput; // to read from the socket
ObjectOutputStream sOutput; // to write on the socket
Socket socket;
public static String LOGTAG="Lifemate";
public String server = "localhost";
public String username = "user";
public String password = "rezapassword" ;
public int port = 1400;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(LOGTAG,"oncreate called");
this.start();
}
AccountCreator(String server, int port, String username,String password) {
this.server = "localhost";
this.port = 1400;
this.username = username;
Log.i(LOGTAG,"first accountcreator called");
}
public boolean start() {
// try to connect to the server
//this method returns a value of true or false when called
try {
socket = new Socket(server, port);
}
// if it failed not much I can so
catch(Exception ec) {
// display("Error connectiong to server:" + ec);
Log.i(LOGTAG,"Error connectiong to server:" + ec);
return false;
}
String msg = "Connection accepted " + socket.getInetAddress() + ":" +
socket.getPort();
// display(msg);
Log.i(LOGTAG, msg);
/* Creating both Data Stream */
try
{
sInput = new ObjectInputStream(socket.getInputStream());
sOutput = new ObjectOutputStream(socket.getOutputStream());
}
catch (IOException eIO) {
// display("Exception creating new Input/output Streams: " + eIO);
Log.i(LOGTAG,"Exception creating new Input/output Streams: " +
eIO);
return false;
}
// creates the Thread to listen from the server
// Send our username to the server this is the only message that we
// will send as a String. All other messages will be ChatMessage objects
try
{
sOutput.writeObject(username);
sOutput.writeObject(password);
}
catch (IOException eIO) {
// display("Exception doing login : " + eIO);
Log.i(LOGTAG,"Exception doing login : " + eIO);
disconnect();
return false;
}
// success we inform the caller that it worked
return true;
}
// private void display(String msg) {
// TextView screenprint = (TextView)findViewById(R.id.systemmessages);
// screenprint.setText(msg);
// }
private void disconnect() {
Log.i(LOGTAG,"reached disconnect");
try {
if(sInput != null) sInput.close();
}
catch(Exception e) {} // not much else I can do
try {
if(sOutput != null) sOutput.close();
}
catch(Exception e) {} // not much else I can do
try{
if(socket != null) socket.close();
}
catch(Exception e) {} // not much else I can do
}
public void Begin() {
Log.i(LOGTAG,"it begun");
int portNumber = 1400;
String serverAddress = server;
String userName = username;
String newpassword = password;
AccountCreator accountcreator = new AccountCreator(serverAddress, portNumber,
userName,password);
if(!accountcreator.start())
return;
}
}
i was trying to put whole code in Async, i dont know if was i right, do i need to do that also or just some parts of it?
In brief, AsyncTask contains a few methods which may be helpful:
onPreExecute:
This method is the first block of code executed when calling asyncTask.execute(); (runs on mainUIThread).
doInBackground:
Here you put all the code which may suspend you main UI (causes hang for your application) like internet requests, or any processing which may take a lot of memory and processing. (runs on background thread), contains one parameter taken from the asyncTask.execute(ParameterType parameter);
onPostExecute
Runs after doInBackground(). Its parameter is the return value of the doInBackground function, and mainly you put the changes in UI need to be done after the connection is finished (runs on mainUIThread)
You have to declare another class within the class you have already created.
class SomeName extends Async<Void, String, Void>{
protected void OnPreExecute(){
// starts the task runs on main UI thread
// Can be used to start a progress dialog to show the user progress
}
#Override
protected Void doInBackground(Void... params){
// does what you want it to do in the background
// Connected to the server to check a log-in
return result;
}
protected void OnPostExecute(Void result){
// finishes the task and can provide information back on the main UI thread
// this would be were you would dismiss the progress dialog
}
}

Periodic LogCat polling for updates and saving to SDcard

Goal
Collect periodic updates of the LogCat and save (append) those chunks of text to a file on the SDcard
Problem
The Log class doesn't provide updates since a specific time-stamp
Possible solution
My plan is to periodically run code that is similar to: http://www.helloandroid.com/tutorials/reading-logs-programatically
or https://stackoverflow.com/a/9039352/550471
However, with one notable difference: use the -v time parameter to ensure that each line is time-stamped.
After each time the LogCat data is collected, the app will store the time-stamp of the last Log entry. The next time the LogCat data is collected the app will search through the text to find the time-stamp and then save the chunk of data to sdcard that was added to the Log since the specified time-stamp.
Possible problem
If the LogCat data is collected at too short periods then the CPU is busy processing a lot of 'old' data.
If the Logcat data is collected at too long periods then some data could be missed.
Is there a better way ?
This is what I came up with - it works very well when it doesn't freeze up.
As you might know, Runtime.getRuntime().exec("") has a pretty good chance of causing an ANR in Android earlier than Jelly Bean. If someone has a solution to overcome the ANR, then please share.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import android.os.Environment;
import android.util.Log;
/*
* For (compressed) buffer sizes, see: http://elinux.org/Android_Logging_System
* buffer:main = 64KB
* buffer:radio = 64KB
* buffer:system = 64KB
* buffer:event = 256KB
*
* NOTE: the 'command' must include "-d -v time" !!
* to switch buffers, use "-b <buffer>"
*/
public class LogCatReader {
// constants
private static final String CR = "\r\n";
private static final String END_OF_DATE_TIME = "): ";
private static final int DEFAULT_SEARCH_START_INDEX = 0;
// member variables
private StringBuilder mLog;
private LogThread mLogThread = null;
private String mLastLogReadToken = "";
private String mLogCommand = "";
private int mStringCapacity;
private File mFileTarget = null;
// constructor
public LogCatReader(String command, int capacity) {
mLogCommand = command;
mStringCapacity = capacity;
}
// returns complete logcat buffer
// note: takes about 1.5sec to finish
synchronized public StringBuilder getLogComplete() {
try {
// capacity should be about 25% bigger than buffer size since the
// buffer is compressed
mLog = new StringBuilder(mStringCapacity);
// command to capture log
Process process = Runtime.getRuntime().exec(mLogCommand);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
// append() is costly if capacity needs to be increased, be sure
// to reserve enough in the first place
mLog.append(line + CR);
}
} catch (IOException e) {
}
return mLog;
}
public String getLogUpdatesOnly() {
String strReturn = "";
StringBuilder sbLog = getLogComplete();
try {
int iStartindex = DEFAULT_SEARCH_START_INDEX;
// if there exists a token from a previous search then use that
if (mLastLogReadToken.length() > 0) {
iStartindex = sbLog.indexOf(mLastLogReadToken);
// if string not found then start at beginning
if (iStartindex == -1) {
// start search at beginning of log
iStartindex = DEFAULT_SEARCH_START_INDEX;
}
}
int iEndindex = sbLog.length();
// if token is found then move index to the next line
if (iStartindex > DEFAULT_SEARCH_START_INDEX) {
iStartindex = sbLog.indexOf(CR, iStartindex);
if (iStartindex != -1) {
iStartindex += CR.length();
} else {
// return an empty string
iStartindex = iEndindex;
}
}
// grab the data between the start and end indices
strReturn = sbLog.substring(iStartindex, iEndindex);
// grab date/time token for next search
iStartindex = sbLog.lastIndexOf(END_OF_DATE_TIME);
if (iStartindex != -1) {
iEndindex = iStartindex;
iStartindex = sbLog.lastIndexOf(CR, iEndindex);
iStartindex += CR.length();
if (iStartindex == -1) {
// read from beginning
iStartindex = 0;
}
mLastLogReadToken = sbLog.substring(iStartindex, iEndindex);
}
} catch (Exception e) {
strReturn = "";
}
return strReturn;
}
public void startPeriodicLogCatReader(int timePeriod, String logfilename) {
if (mLogThread == null) {
mLogThread = new LogThread(timePeriod, logfilename);
mLogThread.start();
}
}
public void stopPeriodicLogCatReader() {
if (mLogThread != null) {
mLogThread.interrupt();
mLogThread = null;
}
}
private class LogThread extends Thread {
private boolean mInterrupted;
private int mTimePeriod;// in seconds
private String mLogref;
private BufferedWriter mBuffWriter = null;
public boolean mPauseLogCollection = false;
// constructor: logfilename is optional - pass null to not use
public LogThread(int timePeriod, String logfilename) {
mTimePeriod = timePeriod;
if (logfilename != null) {
File fLogFolder = new File(
Environment.getExternalStorageDirectory() + "/logfiles");
if (fLogFolder.exists() == false) {
if (fLogFolder.mkdirs() == false) {
Log.e("LogCatReader",
"Could not create "
+ fLogFolder.getAbsolutePath());
}
}
mFileTarget = new File(
Environment.getExternalStorageDirectory() + "/logfiles",
logfilename);
if (mFileTarget.exists() == false) {
try {
// file doesn't yet exist - create a fresh one !
mFileTarget.createNewFile();
} catch (IOException e) {
e.printStackTrace();
mFileTarget = null;
}
}
}
}
#Override
public void interrupt() {
mInterrupted = true;
super.interrupt();
}
#Override
public void run() {
super.run();
// initialization
mInterrupted = false;
// set up storage
if (mFileTarget != null) {
try {
mBuffWriter = new BufferedWriter(new FileWriter(
mFileTarget, true), 10240);
} catch (IOException e) {
e.printStackTrace();
}
}
while ((mInterrupted == false) && (mBuffWriter != null)) {
if (mPauseLogCollection == false) {
// read log updates
mLogref = getLogUpdatesOnly();
// save log updates to file
try {
mBuffWriter.append(mLogref);
mBuffWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
if (!mInterrupted) {
try {
sleep(mTimePeriod * 1000);
} catch (InterruptedException e) {
}
}
}
if (mBuffWriter != null) {
try {
mBuffWriter.close();
mBuffWriter = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}// end of inner class
}// end of outer class
The procedure I used to find only the updates is to capture the date and time of the very last line of a logcat and use that as the search token next time around.
To use this class, the following is an example:
LogCatReader logcatPeriodicReader = new LogCatReader("logcat -b main -d -v time", 80 * 1024);//collect "main" buffer, exit after reading logcat
logcatPeriodicReader.startPeriodicLogReader(90, "log.txt");//read logcat every 90 secs

Categories

Resources