Catalogue introduction
- 1. Business requirements
- 2. What are the current practices and problems?
- 3. Customize log Tool Class, Print log and Write Files
- 4. Open thread pool in application for log printing
- 5. Write a service to write system logs to files
About links
- 1.Technology Blog Summary
- 2.Summary of Open Source Projects
- 3.Summary of Life Blog
- 4.Himalayan Audio Summary
- 5.Summary of programmer chat notes
- 5.Other summary
1. Business requirements
- Requires that app system logs be written to files in the specified file directory
- Automatically switch to the next folder after writing files to a certain size
- Require app to continuously write logs to files at runtime
- Requirements can clear log files 7 or n days ago
- Require sd card, write log to sd card file; no write to memory card; if no sd card to sd card, then you can switch paths
- For code addresses, you can refer to: https://github.com/yangchong211/YCAudioPlayer
2. What are the current practices and problems?
- 1. Customize the log tool class to write the output log to the folder when the log is output. However, only the status log in priority5 can be recorded
- 2. Open the thread pool in application, and then call the setPrint method in the PrintToFileUtil class (tool class written by myself). Problem: app is always on, it can't print continuously, and it hasn't found the reason yet.
- 3. When opening app, open service service service. When app process is not killed or service is not destroyed, it will always run in the background, so it can also handle printing log logic. And by broadcasting, the sd state can be monitored to achieve the goal of switching log paths.
3. Customize log Tool Class, Print log and Write Files
- 3.1 The direct invocation code is as follows:
public static void e(String msg) { if (isDebug){ Log.e(TAG, msg); PrintToFileUtil.input2File(msg,"path"); } }
- 3.2 Tool classes are as follows
/** * Write the content directly in the file and set the path by yourself. * This is to print the log and write it to the file at the same time. * It is not recommended to write directly to a new sub-thread. It is recommended to open the thread pool to avoid thread wastage everywhere. * @param input Write contents * @param filePath Route * @return */ static boolean input2File(final String input, final String filePath) { if (sExecutor == null) { sExecutor = Executors.newScheduledThreadPool(5); } Future<Boolean> submit = sExecutor.submit(new Callable<Boolean>() { @Override public Boolean call() throws Exception { BufferedWriter bw = null; try { // Construct a FileWriter object with a given file name and use Boolean values to indicate whether additional data is written. FileWriter fileWriter = new FileWriter(filePath, true); bw = new BufferedWriter(fileWriter); bw.write(input); return true; } catch (IOException e) { e.printStackTrace(); return false; } finally { try { if (bw != null) { bw.close(); } } catch (IOException e) { e.printStackTrace(); } } } }); try { return submit.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } return false; }
4. Open thread pool in application for log printing
/** * Problems encountered: * 1.When will this method be called? * 2.Why does calling this method cause the program to be unresponsive and where is the card? * 3.How to Avoid Thread Blockage * 4.How to switch to the next. txt file after printing to a certain log? * @param logPath */ public static void setPrint(String logPath){ if (sExecutor == null) { sExecutor = Executors.newScheduledThreadPool(5); } //Name the file as xx month and xx day, so that every day's file is different Date now = new Date(System.currentTimeMillis()); String format = FORMAT.format(now); String date = format.substring(0, 5); final String newLogPath = logPath +date; Future<Boolean> submit = sExecutor.submit(new Callable<Boolean>() { @Override public Boolean call() throws Exception { /*Core code*/ while(captureLogThreadOpen){ /*Order preparation*/ ArrayList<String> getLog = new ArrayList<>(); getLog.add("logcat"); getLog.add("-d"); getLog.add("-v"); getLog.add("time"); ArrayList<String> clearLog = new ArrayList<>(); clearLog.add("logcat"); clearLog.add("-c"); try{ //Crawl the current cache log Process process = Runtime.getRuntime().exec(getLog.toArray(new String[getLog.size()])); //Get the input stream BufferedReader buffRead = new BufferedReader(new InputStreamReader(process.getInputStream())); //Clearance is for the purpose that the next crawl will not be scratched from scratch. Runtime.getRuntime().exec(clearLog.toArray(new String[clearLog.size()])); String str = null; //Open file File logFile = new File(newLogPath + "log.txt"); //true means appending at the end of a document when it is written FileOutputStream fos = new FileOutputStream(logFile, true); //Line-wrapping strings String newline = System.getProperty("line.separator"); //Date date = new Date(System.currentTimeMillis()); //String time = format.format(date); //Log.i(TAG, "thread"); //Printing device information fos.write(printDeviceInfo().getBytes()); while((str=buffRead.readLine())!=null){ //Loop read each line //Runtime.getRuntime().exec(clearLog.toArray(new String[clearLog.size()])); //Log.i(TAG, str); @SuppressLint("SimpleDateFormat") Date date = new Date(System.currentTimeMillis()); String time = FORMAT.format(date); //Plus last year fos.write((time + str).getBytes()); //Line feed fos.write(newline.getBytes()); logCount++; //Exit more than 100,000 lines if(logCount>100000){ captureLogThreadOpen = false; fos.close(); break; } } fos.close(); String[] strings = clearLog.toArray(new String[clearLog.size()]); Runtime.getRuntime().exec(strings); return true; }catch(Exception e){ e.printStackTrace(); return false; } } return true; } }); try { submit.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }
5. Write a service to write system logs to files
-
5.1 Document Points
- 1. Support customizing the path and file name of log writing;
- 2. If there is an sd card, it will be recorded in the sd card; otherwise, it will be recorded in the memory card.
- 3. If the previous log is recorded in the memory card and the sd card is later, the files in the previous memory will be copied into the SDCard.
- 4. sd card loading and unloading broadcasting can be monitored to switch the save path of the log.
- 5. The longest period of log storage can be set in SD card, which is currently set to 7 days.
- 6. When the file written to the log is larger than the custom maximum (currently 10M), it can be automatically switched to the next folder.
- 7. Supports clearing log caches. Clear the log caches before recording each log, otherwise duplicate logs will be recorded in two log files.
- 8. Logs collected include: d, v, e, w, c
- 9. Supports automatic deletion of files after exceeding the maximum save date. The deletion logic is to compare the name of the file named by the date with the current time.
- 10. Open the service when the app opens, and the service keeps a log and writes to a file at run time unless the service is killed.
- 11. It is recommended that log names be named by date to facilitate deletion logic.
-
5.2 Specific Implementation Code
- 5.2.1 Register in List File
<service android:name=".service.LogService" /> <!--System log permissions--> <uses-permission android:name="android.permission.READ_LOGS" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
-
- 5.2.2 The logService code is as follows
public class LogService extends Service { //Journal private static final String TAG = "LogService"; //Maximum in-memory log file, 10M private static final int MEMORY_LOG_FILE_MAX_SIZE = 10 * 1024 * 1024; //In-memory log file size monitoring interval, 10 minutes private static final int MEMORY_LOG_FILE_MONITOR_INTERVAL = 10 * 60 * 1000; //The maximum number of days to save log files in sd card private static final int SDCARD_LOG_FILE_SAVE_DAYS = 7; //The path of the log file in memory (the path of the log file in the installation directory) private String LOG_PATH_MEMORY_DIR; //The path of log files in sdcard private String LOG_PATH_SDCARD_DIR; //The current logging type is stored under the SD card private final int SDCARD_TYPE = 0; //The current logging type is stored in memory private final int MEMORY_TYPE = 1; //Current log record type, default SD card private int CURR_LOG_TYPE = SDCARD_TYPE; //If the current log is written in memory, record the current log file name private String CURR_INSTALL_LOG_NAME; //The name of the log file output by this service can also be in txt format, or the suffix name is. log. private String logServiceLogName = "Log.log"; @SuppressLint("SimpleDateFormat") private SimpleDateFormat myLogSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //Log Name Format @SuppressLint("SimpleDateFormat") private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH time mm branch ss second"); private OutputStreamWriter writer ; private Process process; //awaken private PowerManager.WakeLock wakeLock; //SDCard status monitoring, broadcast monitoring sd card dynamics, such as users unplug sd card private SDStateMonitorReceiver sdStateReceiver; private LogTaskReceiver logTaskReceiver; /* Is the log file size being monitored? * If the current log record is false in SDAD * true if the current log record is in memory*/ private boolean logSizeMoniting = false; //Log file monitoring action private static String MONITOR_LOG_SIZE_ACTION = "MONITOR_LOG_SIZE"; //Switching log file action private static String SWITCH_LOG_FILE_ACTION = "SWITCH_LOG_FILE_ACTION"; /** * No binding required * @param intent intent * @return IBinder object */ @Override public IBinder onBind(Intent intent) { return null; } /** * Call this method when destroyed */ @Override public void onDestroy() { super.onDestroy(); recordLogServiceLog("LogService onDestroy"); if (writer != null) { try { writer.close(); writer = null; } catch (IOException e) { e.printStackTrace(); } } if (process != null) { process.destroy(); } //Note the need to cancel broadcasting if(sdStateReceiver!=null){ unregisterReceiver(sdStateReceiver); } if(logTaskReceiver!=null){ unregisterReceiver(logTaskReceiver); } } /** * This method is called once every time a service is opened for initialization. */ @Override public void onCreate() { super.onCreate(); init(); register(); deploySwitchLogFileTask(); new LogCollectorThread().start(); } private void init(){ //The path of the log file in memory (the path of the log file in the installation directory) LOG_PATH_MEMORY_DIR = getFilesDir().getAbsolutePath() + File.separator + "log"; //Log generated by this service to record the failure information of log service opening String LOG_SERVICE_LOG_PATH = LOG_PATH_MEMORY_DIR + File.separator + logServiceLogName; //The path of log files in sdcard LOG_PATH_SDCARD_DIR = FileUtils.getLocalRootSavePathDir("logger")+ File.separator + "log"; //Create a log folder createLogDir(); try { //true means that it can be written FileOutputStream fos = new FileOutputStream(LOG_SERVICE_LOG_PATH, true); writer = new OutputStreamWriter(fos); } catch (FileNotFoundException e) { Log.e(TAG, e.getMessage(), e); } //Get PowerManager Manager Manager PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE); if (pm != null) { wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); } //Current logging types CURR_LOG_TYPE = getCurrLogType(); Log.i(TAG, "LogService onCreate"); } private void register(){ IntentFilter sdCarMonitorFilter = new IntentFilter(); sdCarMonitorFilter.addAction(Intent.ACTION_MEDIA_MOUNTED); sdCarMonitorFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); sdCarMonitorFilter.addDataScheme("file"); sdStateReceiver = new SDStateMonitorReceiver(); registerReceiver(sdStateReceiver, sdCarMonitorFilter); IntentFilter logTaskFilter = new IntentFilter(); logTaskFilter.addAction(MONITOR_LOG_SIZE_ACTION); logTaskFilter.addAction(SWITCH_LOG_FILE_ACTION); logTaskReceiver = new LogTaskReceiver(); registerReceiver(logTaskReceiver,logTaskFilter); } /** * Get whether the current storage should be in memory or SDCard * @return If there is an sd card, put it in the sd card; if not, put it in the memory card. */ public int getCurrLogType(){ if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { return MEMORY_TYPE; }else{ return SDCARD_TYPE; } } /** * Deploy log switching tasks and switch log files every morning */ private void deploySwitchLogFileTask() { Intent intent = new Intent(SWITCH_LOG_FILE_ACTION); PendingIntent sender = PendingIntent.getBroadcast(this, 0, intent, 0); Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DAY_OF_MONTH, 1); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); // Deployment task AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); if (am != null) { am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, sender); } recordLogServiceLog("deployNextTask success,next task time is:"+myLogSdf.format(calendar.getTime())); } /** * Log collection * 1.Clear Log Cache * 2.Kill the Logcat process that the application has opened to prevent multiple processes from writing to a log file * 3.Open the log collection process * 4.Processing log files, mobile OR deletion */ class LogCollectorThread extends Thread { LogCollectorThread(){ super("LogCollectorThread"); Log.d(TAG, "LogCollectorThread is create"); } @SuppressLint("WakelockTimeout") @Override public void run() { try { //Wake-up call wakeLock.acquire(); //Clear the log cache before recording each log, otherwise duplicate logs will be recorded in two log files clearLogCache(); //Running PS command to get process information List<String> orgProcessList = getAllProcess(); //Get information such as PID, User, name according to the content of ps command List<ProcessInfo> processInfoList = getProcessInfoList(orgProcessList); //Close the logcat process opened by this program killLogcatPro(processInfoList); //Start collecting log information createLogCollector(); //Hibernate, create a file, and then process the file. Otherwise, the file has not been created, which will affect file deletion. Thread.sleep(1000); //Processing log files, which mainly deal with sd card and memory card switching storage log logic handleLog(); //release wakeLock.release(); } catch (Exception e) { e.printStackTrace(); recordLogServiceLog(Log.getStackTraceString(e)); } } } /** * Clear the log cache before recording each log, otherwise duplicate logs will be recorded in two log files */ private void clearLogCache() { Process pro = null; List<String> commandList = new ArrayList<>(); commandList.add("logcat"); commandList.add("-c"); try { pro = Runtime.getRuntime().exec(commandList.toArray(new String[commandList.size()])); StreamConsumer errorGobbler = new StreamConsumer(pro.getErrorStream()); StreamConsumer outputGobbler = new StreamConsumer(pro.getInputStream()); errorGobbler.start(); outputGobbler.start(); if (pro.waitFor() != 0) { Log.e(TAG, " clearLogCache proc.waitFor() != 0"); recordLogServiceLog("clearLogCache clearLogCache proc.waitFor() != 0"); } } catch (Exception e) { Log.e(TAG, "clearLogCache failed", e); recordLogServiceLog("clearLogCache failed"); } finally { try { if (pro != null) { pro.destroy(); } } catch (Exception e) { Log.e(TAG, "clearLogCache failed", e); recordLogServiceLog("clearLogCache failed"); } } } /** * Close the logcat process opened by this program: * Kill the process according to the user name (if the Logcat collection process is opened by the process of this program, then the USER of both processes is the same) * If you do not close, there will be multiple processes reading logcat log caching information to write to the log file * @param allPro allPro */ private void killLogcatPro(List<ProcessInfo> allPro) { if(process != null){ process.destroy(); } String packName = this.getPackageName(); //Get the user name of the program String myUser = getAppUser(packName, allPro); for (ProcessInfo processInfo : allPro) { if (processInfo.name.toLowerCase().equals("logcat") && processInfo.user.equals(myUser)) { android.os.Process.killProcess(Integer.parseInt(processInfo.pid)); //recordLogServiceLog("kill another logcat process success,the process info is:" // + processInfo); } } } /** * Get the user name of the program * @param packName packName * @param allProList allProList * @return Program name */ private String getAppUser(String packName, List<ProcessInfo> allProList) { for (ProcessInfo processInfo : allProList) { if (processInfo.name.equals(packName)) { return processInfo.user; } } return null; } /** * Get information such as PID, User, name according to the content of ps command * @param orgProcessList orgProcessList * @return aggregate */ private List<ProcessInfo> getProcessInfoList(List<String> orgProcessList) { List<ProcessInfo> proInfoList = new ArrayList<>(); for (int i = 1; i < orgProcessList.size(); i++) { String processInfo = orgProcessList.get(i); String[] proStr = processInfo.split(" "); // USER PID PPID VSIZE RSS WCHAN PC NAME // root 1 0 416 300 c00d4b28 0000cd5c S /init List<String> orgInfo = new ArrayList<>(); for (String str : proStr) { if (!"".equals(str)) { orgInfo.add(str); } } if (orgInfo.size() == 9) { ProcessInfo pInfo = new ProcessInfo(); pInfo.user = orgInfo.get(0); pInfo.pid = orgInfo.get(1); pInfo.ppid = orgInfo.get(2); pInfo.name = orgInfo.get(8); proInfoList.add(pInfo); } } return proInfoList; } /** * Running PS command to get process information * @return * USER PID PPID VSIZE RSS WCHAN PC NAME * root 1 0 416 300 c00d4b28 0000cd5c S /init */ private List<String> getAllProcess() { List<String> orgProList = new ArrayList<>(); Process pro = null; try { pro = Runtime.getRuntime().exec("ps"); StreamConsumer errorConsumer = new StreamConsumer(pro.getErrorStream()); StreamConsumer outputConsumer = new StreamConsumer(pro.getInputStream(), orgProList); errorConsumer.start(); outputConsumer.start(); if (pro.waitFor() != 0) { Log.e(TAG, "getAllProcess pro.waitFor() != 0"); recordLogServiceLog("getAllProcess pro.waitFor() != 0"); } } catch (Exception e) { Log.e(TAG, "getAllProcess failed", e); recordLogServiceLog("getAllProcess failed"); } finally { try { if (pro != null) { pro.destroy(); } } catch (Exception e) { Log.e(TAG, "getAllProcess failed", e); recordLogServiceLog("getAllProcess failed"); } } return orgProList; } /** * Start collecting log information * Logs include, f, d, v, time, */ public void createLogCollector() { // Log file name String logFileName = sdf.format(new Date()) + ".log"; List<String> commandList = new ArrayList<>(); commandList.add("logcat"); commandList.add("-f"); commandList.add("-d"); //commandList.add(LOG_PATH_INSTALL_DIR + File.separator + logFileName); commandList.add(getLogPath()); commandList.add("-v"); commandList.add("time"); // Filter all i information commandList.add("*:I"); // Filter all error messages //commandList.add("*:E"); // Filtering information for specified TAG // commandList.add("MyAPP:V"); // commandList.add("*:S"); try { process = Runtime.getRuntime().exec(commandList.toArray(new String[commandList.size()])); recordLogServiceLog("start collecting the log,and log name is:"+logFileName); // process.waitFor(); } catch (Exception e) { Log.e(TAG, "CollectorThread == >" + e.getMessage(), e); recordLogServiceLog("CollectorThread == >" + e.getMessage()); } } /** * Obtain the absolute storage path of the log based on the current storage location * @return Route */ public String getLogPath(){ createLogDir(); // Log file name String logFileName = sdf.format(new Date()) + ".log"; if(CURR_LOG_TYPE == MEMORY_TYPE){ CURR_INSTALL_LOG_NAME = logFileName; Log.d(TAG, "Log stored in memory, the path is:"+LOG_PATH_MEMORY_DIR + File.separator + logFileName); return LOG_PATH_MEMORY_DIR + File.separator + logFileName; }else{ CURR_INSTALL_LOG_NAME = null; Log.d(TAG, "Log stored in SDcard, the path is:"+LOG_PATH_SDCARD_DIR + File.separator + logFileName); return LOG_PATH_SDCARD_DIR + File.separator + logFileName; } } /** * Processing log files * 1.If the log file storage location is switched to memory, delete the log file except the one being written * And deploy log size monitoring tasks to control log size not exceeding specified values * 2.If the location of the log file is switched to SDCard, delete the log 7 days ago and move it. * Move all logs stored in memory to SDCard and size the previously deployed logs * Monitoring cancellation */ public void handleLog(){ //The current logging type is stored in memory if(CURR_LOG_TYPE == MEMORY_TYPE){ //Deploy log size monitoring tasks deployLogSizeMonitorTask(); //Delete out-of-date logs in memory, delete rules: all but the current log and the most recent log saved are deleted deleteMemoryExpiredLog(); }else{ //Transfer log files to the SD card moveLogfile(); //Cancel Deployment Log Size Monitoring Task cancelLogSizeMonitorTask(); //Delete out-of-memory logs deleteSDCardExpiredLog(); } } /** * Deploy log size monitoring tasks */ private void deployLogSizeMonitorTask() { //If you are currently monitoring, you do not need to continue deploying if(logSizeMoniting){ return; } logSizeMoniting = true; Intent intent = new Intent(MONITOR_LOG_SIZE_ACTION); PendingIntent sender = PendingIntent.getBroadcast(this, 0, intent, 0); AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); if (am != null) { am.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(), MEMORY_LOG_FILE_MONITOR_INTERVAL, sender); } Log.d(TAG, "deployLogSizeMonitorTask() suc !"); //recordLogServiceLog("deployLogSizeMonitorTask() succ ,start time is " + calendar.getTime().toLocaleString()); } /** * Cancel Deployment Log Size Monitoring Task */ private void cancelLogSizeMonitorTask() { logSizeMoniting = false; AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); Intent intent = new Intent(MONITOR_LOG_SIZE_ACTION); PendingIntent sender = PendingIntent.getBroadcast(this, 0, intent, 0); if (am != null) { am.cancel(sender); } Log.d(TAG, "canelLogSizeMonitorTask() suc"); } /** * Check whether the log file size exceeds the specified size * If a log collection process has exceeded reopening */ private void checkLogSize(){ //When the file is not empty if(CURR_INSTALL_LOG_NAME != null && CURR_INSTALL_LOG_NAME.length()>0){ //The path of the log file in memory + If the current log is written in memory, record the name of the current log file String path = LOG_PATH_MEMORY_DIR + File.separator + CURR_INSTALL_LOG_NAME; File file = new File(path); if(!file.exists()){ return; } Log.d(TAG, "checkLog() ==> The size of the log is too big?"); //When the file length >= 10M, create a new folder if(file.length() >= MEMORY_LOG_FILE_MAX_SIZE){ Log.d(TAG, "The log's size is too big!"); new LogCollectorThread().start(); } } } /** * Create a log directory */ private void createLogDir() { //A folder for the path of a log file in memory File file = new File(LOG_PATH_MEMORY_DIR); boolean mkOk; if (!file.isDirectory() && file.exists()) { mkOk = file.mkdirs(); if (!mkOk) { //noinspection ResultOfMethodCallIgnored file.mkdirs(); } } //Determine whether SD card exists and whether it has read and write permission //Create folders under SD card path if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { file = new File(LOG_PATH_SDCARD_DIR); if (!file.isDirectory()) { mkOk = file.mkdirs(); if (!mkOk) { recordLogServiceLog("move file failed,dir is not created succ"); } } } } /** * Transfer log files to the SD card */ private void moveLogfile() { //First, the state of sd card is judged if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { //recordLogServiceLog("move file failed, sd card does not mount"); return; } File file = new File(LOG_PATH_SDCARD_DIR); if (!file.isDirectory()) { boolean mkOk = file.mkdirs(); if (!mkOk) { //recordLogServiceLog("move file failed,dir is not created succ"); return; } } file = new File(LOG_PATH_MEMORY_DIR); if (file.isDirectory()) { File[] allFiles = file.listFiles(); for (File logFile : allFiles) { String fileName = logFile.getName(); if (logServiceLogName.equals(fileName)) { continue; } //String createDateInfo = getFileNameWithoutExtension(fileName); File beforeFile = new File(LOG_PATH_SDCARD_DIR + File.separator + fileName); boolean isSuccess = copy(logFile,beforeFile); if (isSuccess) { //noinspection ResultOfMethodCallIgnored logFile.delete(); //recordLogServiceLog("move file success,log name is:"+fileName); } } } } /** * Delete out-of-memory logs */ private void deleteSDCardExpiredLog() { File file = new File(LOG_PATH_SDCARD_DIR); if (file.isDirectory()) { File[] allFiles = file.listFiles(); for (File logFile : allFiles) { String fileName = logFile.getName(); if (logServiceLogName.equals(fileName)) { continue; } //Remove file extension types String createDateInfo = getFileNameWithoutExtension(fileName); //Determine whether log files on sdcard can be deleted if (canDeleteSDLog(createDateInfo)) { //noinspection ResultOfMethodCallIgnored logFile.delete(); Log.d(TAG, "delete expired log success,the log path is:" + logFile.getAbsolutePath()); } } } } /** * Determine whether log files on sdcard can be deleted * @param createDateStr createDateStr * @return Can I delete it? */ public boolean canDeleteSDLog(String createDateStr) { boolean canDel ; //Get the current time Calendar calendar = Calendar.getInstance(); //Delete logs 7 days ago calendar.add(Calendar.DAY_OF_MONTH, -1 * SDCARD_LOG_FILE_SAVE_DAYS); Date expiredDate = calendar.getTime(); try { Date createDate = sdf.parse(createDateStr); canDel = createDate.before(expiredDate); } catch (ParseException e) { Log.e(TAG, e.getMessage(), e); canDel = false; } return canDel; } /** * Delete expired logs in memory and delete rules: * All but the current log and the most recent log saved are deleted. */ private void deleteMemoryExpiredLog(){ File file = new File(LOG_PATH_MEMORY_DIR); if (file.isDirectory()) { File[] allFiles = file.listFiles(); Arrays.sort(allFiles, new FileComparator()); for (int i=0;i<allFiles.length-2;i++) { //"-2" saves the last two log files File _file = allFiles[i]; if (logServiceLogName.equals(_file.getName()) || _file.getName().equals(CURR_INSTALL_LOG_NAME)) { continue; } //noinspection ResultOfMethodCallIgnored _file.delete(); Log.d(TAG, "delete expired log success,the log path is:"+_file.getAbsolutePath()); } } } /** * Copy file * @param source file * @param target file * @return Is the copy successful? */ private boolean copy(File source, File target) { FileInputStream in = null; FileOutputStream out = null; try { if(!target.exists()){ boolean createSuccess = target.createNewFile(); if(!createSuccess){ return false; } } in = new FileInputStream(source); out = new FileOutputStream(target); byte[] buffer = new byte[8*1024]; int count; while ((count = in.read(buffer)) != -1) { out.write(buffer, 0, count); } return true; } catch (Exception e) { e.printStackTrace(); Log.e(TAG, e.getMessage(), e); recordLogServiceLog("copy file fail"); return false; } finally{ try { if(in != null){ in.close(); } if(out != null){ out.close(); } } catch (IOException e) { e.printStackTrace(); Log.e(TAG, e.getMessage(), e); recordLogServiceLog("copy file fail"); } } } /** * This note is a log of errors. * Recording the basic information of the log service prevents errors in the log service and cannot be found in the LogCat log * The log name is Log.log * @param msg msg */ private void recordLogServiceLog(String msg) { if (writer != null) { try { Date time = new Date(); writer.write(myLogSdf.format(time) + " : " + msg); writer.write("\n"); writer.flush(); } catch (IOException e) { e.printStackTrace(); Log.e(TAG, e.getMessage(), e); } } } /** * Remove file extension type (. log) * @param fileName fileName * @return Character string */ private String getFileNameWithoutExtension(String fileName){ return fileName.substring(0, fileName.indexOf(".")); } class ProcessInfo { public String user; private String pid; private String ppid; public String name; @Override public String toString() { return "ProcessInfo{" + "user='" + user + '\'' + ", pid='" + pid + '\'' + ", ppid='" + ppid + '\'' + ", name='" + name + '\'' + '}'; } } class StreamConsumer extends Thread { InputStream is; List<String> list; StreamConsumer(InputStream is) { this.is = is; } StreamConsumer(InputStream is, List<String> list) { this.is = is; this.list = list; } public void run() { try { InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line ; while ((line = br.readLine()) != null) { if (list != null) { list.add(line); } } } catch (IOException ioe) { ioe.printStackTrace(); } } } /** * Monitoring SD Card Status * @author Administrator * */ private class SDStateMonitorReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { //Storage Card Unloaded if(Intent.ACTION_MEDIA_UNMOUNTED.equals(intent.getAction())){ if(CURR_LOG_TYPE == SDCARD_TYPE){ Log.d(TAG, "SDCard is UNMOUNTED"); CURR_LOG_TYPE = MEMORY_TYPE; new LogCollectorThread().start(); } }else{ //Storage card mounted if(CURR_LOG_TYPE == MEMORY_TYPE){ Log.d(TAG, "SDCard is MOUNTED"); CURR_LOG_TYPE = SDCARD_TYPE; new LogCollectorThread().start(); } } } } /** * Log Task Receiving Broadcast * Switch logs to monitor log size * @author Administrator * */ class LogTaskReceiver extends BroadcastReceiver{ public void onReceive(Context context, Intent intent) { String action = intent.getAction(); //Switching log file action if(SWITCH_LOG_FILE_ACTION.equals(action)){ new LogCollectorThread().start(); }else if(MONITOR_LOG_SIZE_ACTION.equals(action)){ //Log file monitoring action checkLogSize(); } } } class FileComparator implements Comparator<File> { public int compare(File file1, File file2) { if(logServiceLogName.equals(file1.getName())){ return -1; }else if(logServiceLogName.equals(file2.getName())){ return 1; } String createInfo1 = getFileNameWithoutExtension(file1.getName()); String createInfo2 = getFileNameWithoutExtension(file2.getName()); try { Date create1 = sdf.parse(createInfo1); Date create2 = sdf.parse(createInfo2); if(create1.before(create2)){ return -1; }else{ return 1; } } catch (ParseException e) { return 0; } } } }