• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.google.android.mobly.snippet.util;
18 
19 import android.content.Context;
20 import android.content.pm.ApplicationInfo;
21 import android.content.pm.PackageManager;
22 import android.content.pm.PackageManager.NameNotFoundException;
23 import android.os.Bundle;
24 
25 public final class Log {
26     public static volatile String apkLogTag = null;
27 
28     private static final String MY_CLASS_NAME = Log.class.getName();
29     private static final String ANDROID_LOG_CLASS_NAME = android.util.Log.class.getName();
30 
31     // Skip the first two entries in stack trace when trying to infer the caller.
32     // The first two entries are:
33     // - dalvik.system.VMStack.getThreadStackTrace(Native Method)
34     // - java.lang.Thread.getStackTrace(Thread.java:580)
35     // The {@code getStackTrace()} function returns the stack trace at where the trace is collected
36     // (inisde the JNI function {@code getThreadStackTrace()} instead of at where the {@code
37     // getStackTrace()} is called (althrought this is the natual expectation).
38     private static final int STACK_TRACE_WALK_START_INDEX = 2;
39 
Log()40     private Log() {}
41 
initLogTag(Context context)42     public static synchronized void initLogTag(Context context) {
43         if (apkLogTag != null) {
44             throw new IllegalStateException("Logger should not be re-initialized");
45         }
46         String packageName = context.getPackageName();
47         PackageManager packageManager = context.getPackageManager();
48         ApplicationInfo appInfo;
49         try {
50             appInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
51         } catch (NameNotFoundException e) {
52             throw new IllegalStateException(
53                     "Failed to find ApplicationInfo with package name: " + packageName);
54         }
55         Bundle bundle = appInfo.metaData;
56         apkLogTag = bundle.getString("mobly-log-tag");
57         if (apkLogTag == null) {
58             apkLogTag = packageName;
59             w(
60                     "AndroidManifest.xml does not contain metadata field named \"mobly-log-tag\". "
61                             + "Using package name for logging instead.");
62         }
63     }
64 
getTag()65     private static String getTag() {
66         String logTag = apkLogTag;
67         if (logTag == null) {
68             throw new IllegalStateException("Logging called before initLogTag()");
69         }
70         StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
71 
72         boolean isCallerClassNameFound = false;
73         String fullClassName = null;
74         int lineNumber = 0;
75         // Walk up the stack and look for the first class name that is neither us nor
76         // android.util.Log: that's the caller.
77         // Do not used hard-coded stack depth: that does not work all the time because of proguard
78         // inline optimization.
79         for (int i = STACK_TRACE_WALK_START_INDEX; i < stackTraceElements.length; i++) {
80             StackTraceElement element = stackTraceElements[i];
81             fullClassName = element.getClassName();
82             if (!fullClassName.equals(MY_CLASS_NAME)
83                     && !fullClassName.equals(ANDROID_LOG_CLASS_NAME)) {
84                 lineNumber = element.getLineNumber();
85                 isCallerClassNameFound = true;
86                 break;
87             }
88         }
89 
90         if (!isCallerClassNameFound) {
91             // Failed to determine caller's class name, fall back the the minimal one.
92             return logTag;
93         } else {
94             String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
95             return logTag + "." + className + ":" + lineNumber;
96         }
97     }
98 
v(String message)99     public static void v(String message) {
100         android.util.Log.v(getTag(), message);
101     }
102 
v(String message, Throwable e)103     public static void v(String message, Throwable e) {
104         android.util.Log.v(getTag(), message, e);
105     }
106 
e(Throwable e)107     public static void e(Throwable e) {
108         android.util.Log.e(getTag(), "Error", e);
109     }
110 
e(String message)111     public static void e(String message) {
112         android.util.Log.e(getTag(), message);
113     }
114 
e(String message, Throwable e)115     public static void e(String message, Throwable e) {
116         android.util.Log.e(getTag(), message, e);
117     }
118 
w(Throwable e)119     public static void w(Throwable e) {
120         android.util.Log.w(getTag(), "Warning", e);
121     }
122 
w(String message)123     public static void w(String message) {
124         android.util.Log.w(getTag(), message);
125     }
126 
w(String message, Throwable e)127     public static void w(String message, Throwable e) {
128         android.util.Log.w(getTag(), message, e);
129     }
130 
d(String message)131     public static void d(String message) {
132         android.util.Log.d(getTag(), message);
133     }
134 
d(String message, Throwable e)135     public static void d(String message, Throwable e) {
136         android.util.Log.d(getTag(), message, e);
137     }
138 
i(String message)139     public static void i(String message) {
140         android.util.Log.i(getTag(), message);
141     }
142 
i(String message, Throwable e)143     public static void i(String message, Throwable e) {
144         android.util.Log.i(getTag(), message, e);
145     }
146 }
147