1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.permissioncontroller 18 19 import android.util.Log 20 import com.android.permissioncontroller.Constants.LOGS_TO_DUMP_FILE 21 import java.io.File 22 23 /** 24 * Like {@link Log} but stores the logs in a file which can later be dumped via {@link #dump} 25 */ 26 object DumpableLog { 27 private const val MAX_FILE_SIZE = 64 * 1024 28 29 private val lock = Any() 30 private val file = File(PermissionControllerApplication.get().filesDir, LOGS_TO_DUMP_FILE) 31 32 init { 33 file.createNewFile() 34 } 35 36 /** 37 * Equivalent to {@link Log.v} 38 */ vnull39 fun v(tag: String, message: String, exception: Throwable? = null) { 40 Log.v(tag, message, exception) 41 addLogToDump("v", tag, message, exception) 42 } 43 44 /** 45 * Equivalent to {@link Log.d} 46 */ dnull47 fun d(tag: String, message: String, exception: Throwable? = null) { 48 Log.d(tag, message, exception) 49 addLogToDump("d", tag, message, exception) 50 } 51 52 /** 53 * Equivalent to {@link Log.i} 54 */ inull55 fun i(tag: String, message: String, exception: Throwable? = null) { 56 Log.i(tag, message, exception) 57 addLogToDump("i", tag, message, exception) 58 } 59 60 /** 61 * Equivalent to {@link Log.w} 62 */ wnull63 fun w(tag: String, message: String, exception: Throwable? = null) { 64 Log.w(tag, message, exception) 65 addLogToDump("w", tag, message, exception) 66 } 67 68 /** 69 * Equivalent to {@link Log.e} 70 */ enull71 fun e(tag: String, message: String, exception: Throwable? = null) { 72 Log.e(tag, message, exception) 73 addLogToDump("e", tag, message, exception) 74 } 75 addLogToDumpnull76 private fun addLogToDump(level: String, tag: String, message: String, exception: Throwable?) { 77 synchronized(lock) { 78 // TODO: Needs to be replaced by proper log rotation 79 if (file.length() > MAX_FILE_SIZE) { 80 val dump = file.readLines() 81 82 file.writeText("truncated at ${System.currentTimeMillis()}\n") 83 dump.subList(dump.size / 2, dump.size).forEach { file.appendText(it + "\n") } 84 } 85 86 file.appendText("${System.currentTimeMillis()} $tag:$level $message " + 87 "${exception?.let { it.message + Log.getStackTraceString(it) } ?: ""}\n") 88 } 89 } 90 91 /** 92 * @return the previously logged entries 93 */ getnull94 suspend fun get(): List<String> { 95 synchronized(lock) { 96 return file.readLines() 97 } 98 } 99 }