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 /** Like {@link Log} but stores the logs in a file which can later be dumped via {@link #dump} */ 24 object DumpableLog { 25 private const val MAX_FILE_SIZE = 64 * 1024 26 27 private val lock = Any() 28 private val file = File(PermissionControllerApplication.get().filesDir, LOGS_TO_DUMP_FILE) 29 30 init { 31 file.createNewFile() 32 } 33 34 /** Equivalent to {@link Log.v} */ vnull35 fun v(tag: String, message: String, exception: Throwable? = null) { 36 Log.v(tag, message, exception) 37 addLogToDump("v", tag, message, exception) 38 } 39 40 /** Equivalent to {@link Log.d} */ dnull41 fun d(tag: String, message: String, exception: Throwable? = null) { 42 Log.d(tag, message, exception) 43 addLogToDump("d", tag, message, exception) 44 } 45 46 /** Equivalent to {@link Log.i} */ inull47 fun i(tag: String, message: String, exception: Throwable? = null) { 48 Log.i(tag, message, exception) 49 addLogToDump("i", tag, message, exception) 50 } 51 52 /** Equivalent to {@link Log.w} */ wnull53 fun w(tag: String, message: String, exception: Throwable? = null) { 54 Log.w(tag, message, exception) 55 addLogToDump("w", tag, message, exception) 56 } 57 58 /** Equivalent to {@link Log.e} */ enull59 fun e(tag: String, message: String, exception: Throwable? = null) { 60 Log.e(tag, message, exception) 61 addLogToDump("e", tag, message, exception) 62 } 63 addLogToDumpnull64 private fun addLogToDump(level: String, tag: String, message: String, exception: Throwable?) { 65 synchronized(lock) { 66 // TODO: Needs to be replaced by proper log rotation 67 if (file.length() > MAX_FILE_SIZE) { 68 val dump = file.readLines() 69 70 file.writeText("truncated at ${System.currentTimeMillis()}\n") 71 dump.subList(dump.size / 2, dump.size).forEach { file.appendText(it + "\n") } 72 } 73 74 file.appendText( 75 "${System.currentTimeMillis()} $tag:$level $message " + 76 "${exception?.let { it.message + Log.getStackTraceString(it) } ?: ""}\n" 77 ) 78 } 79 } 80 81 /** @return the previously logged entries */ getnull82 suspend fun get(): List<String> { 83 synchronized(lock) { 84 return file.readLines() 85 } 86 } 87 } 88