160ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad/*
260ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad * Copyright 2014, The Android Open Source Project
360ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad *
460ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad * Licensed under the Apache License, Version 2.0 (the "License");
560ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad * you may not use this file except in compliance with the License.
660ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad * You may obtain a copy of the License at
760ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad *
860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad *     http://www.apache.org/licenses/LICENSE-2.0
960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad *
1060ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad * Unless required by applicable law or agreed to in writing, software
1160ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad * distributed under the License is distributed on an "AS IS" BASIS,
1260ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1360ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad * See the License for the specific language governing permissions and
1460ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad * limitations under the License.
1560ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad */
1660ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
17ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunnpackage android.telecom;
1860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
194fb372fe169c6abd463a620b56dd6b05b5ff1e7aBrad Ebingerimport android.content.Context;
203c20d633731a3a2f6ea03012cb4b1d4903a31520Santos Cordonimport android.net.Uri;
21e362e501ee5d8f892d705c0762eff0a584cfb439Hall Liuimport android.os.AsyncTask;
22b3cd7b51d330caa1f54710741b73a63043515b82youhei.x.miyoshiimport android.os.Build;
2351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebingerimport android.telecom.Logging.EventManager;
2451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebingerimport android.telecom.Logging.Session;
2551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebingerimport android.telecom.Logging.SessionManager;
263c20d633731a3a2f6ea03012cb4b1d4903a31520Santos Cordonimport android.telephony.PhoneNumberUtils;
273c20d633731a3a2f6ea03012cb4b1d4903a31520Santos Cordonimport android.text.TextUtils;
28e362e501ee5d8f892d705c0762eff0a584cfb439Hall Liu
2951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebingerimport com.android.internal.annotations.VisibleForTesting;
3051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebingerimport com.android.internal.util.IndentingPrintWriter;
3151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
3260ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awadimport java.security.MessageDigest;
3360ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awadimport java.security.NoSuchAlgorithmException;
3460ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awadimport java.util.IllegalFormatException;
3560ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awadimport java.util.Locale;
3660ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
3760ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad/**
3860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad * Manages logging for the entire module.
3960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad *
4060ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad * @hide
4160ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad */
4251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebingerpublic class Log {
4351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
4451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    private static final long EXTENDED_LOGGING_DURATION_MILLIS = 60000 * 30; // 30 minutes
4551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
4651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    private static final int EVENTS_TO_CACHE = 10;
4751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    private static final int EVENTS_TO_CACHE_DEBUG = 20;
4860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
4951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    // Generic tag for all Telecom logging
5051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    @VisibleForTesting
5151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static String TAG = "TelecomFramework";
520c3541be65fa87519a879c053a7cf4b4526be5dbBrad Ebinger    public static boolean DEBUG = isLoggable(android.util.Log.DEBUG);
530c3541be65fa87519a879c053a7cf4b4526be5dbBrad Ebinger    public static boolean INFO = isLoggable(android.util.Log.INFO);
540c3541be65fa87519a879c053a7cf4b4526be5dbBrad Ebinger    public static boolean VERBOSE = isLoggable(android.util.Log.VERBOSE);
550c3541be65fa87519a879c053a7cf4b4526be5dbBrad Ebinger    public static boolean WARN = isLoggable(android.util.Log.WARN);
560c3541be65fa87519a879c053a7cf4b4526be5dbBrad Ebinger    public static boolean ERROR = isLoggable(android.util.Log.ERROR);
5760ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
5851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    private static final boolean FORCE_LOGGING = false; /* STOP SHIP if true */
595ab024333065c60620867e58eaa27f27dfa85752Jeff Sharkey    private static final boolean USER_BUILD = Build.IS_USER;
6060ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
6151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    // Used to synchronize singleton logging lazy initialization
6251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    private static final Object sSingletonSync = new Object();
6351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    private static EventManager sEventManager;
6451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    private static SessionManager sSessionManager;
65e362e501ee5d8f892d705c0762eff0a584cfb439Hall Liu
6651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    /**
6751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     * Tracks whether user-activated extended logging is enabled.
6851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     */
6951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    private static boolean sIsUserExtendedLoggingEnabled = false;
7060ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
7151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    /**
7251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     * The time when user-activated extended logging should be ended.  Used to determine when
7351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     * extended logging should automatically be disabled.
7451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     */
7551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    private static long sUserExtendedLoggingStopTime = 0;
76e362e501ee5d8f892d705c0762eff0a584cfb439Hall Liu
7751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    private Log() {
7860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
7960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
8060ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void d(String prefix, String format, Object... args) {
8151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        if (sIsUserExtendedLoggingEnabled) {
8251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            maybeDisableLogging();
8351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.i(TAG, buildMessage(prefix, format, args));
8451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        } else if (DEBUG) {
8551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.d(TAG, buildMessage(prefix, format, args));
8660ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        }
8760ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
8860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
8960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void d(Object objectPrefix, String format, Object... args) {
9051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        if (sIsUserExtendedLoggingEnabled) {
9151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            maybeDisableLogging();
9251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.i(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
9351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        } else if (DEBUG) {
9451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.d(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
9560ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        }
9660ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
9760ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
9860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void i(String prefix, String format, Object... args) {
9960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        if (INFO) {
10051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.i(TAG, buildMessage(prefix, format, args));
10160ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        }
10260ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
10360ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
10460ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void i(Object objectPrefix, String format, Object... args) {
10560ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        if (INFO) {
10651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.i(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
10760ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        }
10860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
10960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
11060ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void v(String prefix, String format, Object... args) {
11151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        if (sIsUserExtendedLoggingEnabled) {
11251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            maybeDisableLogging();
11351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.i(TAG, buildMessage(prefix, format, args));
11451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        } else if (VERBOSE) {
11551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.v(TAG, buildMessage(prefix, format, args));
11660ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        }
11760ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
11860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
11960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void v(Object objectPrefix, String format, Object... args) {
12051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        if (sIsUserExtendedLoggingEnabled) {
12151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            maybeDisableLogging();
12251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.i(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
12351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        } else if (VERBOSE) {
12451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.v(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
12560ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        }
12660ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
12760ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
12860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void w(String prefix, String format, Object... args) {
12960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        if (WARN) {
13051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.w(TAG, buildMessage(prefix, format, args));
13160ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        }
13260ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
13360ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
13460ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void w(Object objectPrefix, String format, Object... args) {
13560ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        if (WARN) {
13651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.w(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
13760ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        }
13860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
13960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
14060ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void e(String prefix, Throwable tr, String format, Object... args) {
14160ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        if (ERROR) {
14251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.e(TAG, buildMessage(prefix, format, args), tr);
14360ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        }
14460ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
14560ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
14660ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void e(Object objectPrefix, Throwable tr, String format, Object... args) {
14760ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        if (ERROR) {
14851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            android.util.Slog.e(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args),
14960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad                    tr);
15060ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        }
15160ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
15260ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
15360ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void wtf(String prefix, Throwable tr, String format, Object... args) {
15451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        android.util.Slog.wtf(TAG, buildMessage(prefix, format, args), tr);
15560ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
15660ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
15760ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void wtf(Object objectPrefix, Throwable tr, String format, Object... args) {
15851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        android.util.Slog.wtf(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args),
15960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad                tr);
16060ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
16160ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
16260ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void wtf(String prefix, String format, Object... args) {
16360ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        String msg = buildMessage(prefix, format, args);
16451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        android.util.Slog.wtf(TAG, msg, new IllegalStateException(msg));
16560ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
16660ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
16760ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    public static void wtf(Object objectPrefix, String format, Object... args) {
16860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        String msg = buildMessage(getPrefixFromObject(objectPrefix), format, args);
16951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        android.util.Slog.wtf(TAG, msg, new IllegalStateException(msg));
17060ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
17160ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
17260ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    /**
17351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     * The ease of use methods below only act mostly as proxies to the Session and Event Loggers.
17451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     * They also control the lazy loaders of the singleton instances, which will never be loaded if
17551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     * the proxy methods aren't used.
17651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     *
17751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     * Please see each method's documentation inside of their respective implementations in the
17851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     * loggers.
17960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad     */
18051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
1814fb372fe169c6abd463a620b56dd6b05b5ff1e7aBrad Ebinger    public static void setSessionContext(Context context) {
1824fb372fe169c6abd463a620b56dd6b05b5ff1e7aBrad Ebinger        getSessionManager().setContext(context);
1834fb372fe169c6abd463a620b56dd6b05b5ff1e7aBrad Ebinger    }
1844fb372fe169c6abd463a620b56dd6b05b5ff1e7aBrad Ebinger
18551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static void startSession(String shortMethodName) {
18651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        getSessionManager().startSession(shortMethodName, null);
18751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
18851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
1893445f829077cea72da77e31f0a2f6ccce3af295bBrad Ebinger    public static void startSession(Session.Info info, String shortMethodName) {
1903445f829077cea72da77e31f0a2f6ccce3af295bBrad Ebinger        getSessionManager().startSession(info, shortMethodName, null);
1913445f829077cea72da77e31f0a2f6ccce3af295bBrad Ebinger    }
1923445f829077cea72da77e31f0a2f6ccce3af295bBrad Ebinger
19351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static void startSession(String shortMethodName, String callerIdentification) {
19451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        getSessionManager().startSession(shortMethodName, callerIdentification);
19551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
19651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
197a0dc9765d339ee69da4a1adc3bd6863126267b08Brad Ebinger    public static void startSession(Session.Info info, String shortMethodName,
198a0dc9765d339ee69da4a1adc3bd6863126267b08Brad Ebinger            String callerIdentification) {
199a0dc9765d339ee69da4a1adc3bd6863126267b08Brad Ebinger        getSessionManager().startSession(info, shortMethodName, callerIdentification);
200a0dc9765d339ee69da4a1adc3bd6863126267b08Brad Ebinger    }
201a0dc9765d339ee69da4a1adc3bd6863126267b08Brad Ebinger
20251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static Session createSubsession() {
20351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        return getSessionManager().createSubsession();
20451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
20551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
2063445f829077cea72da77e31f0a2f6ccce3af295bBrad Ebinger    public static Session.Info getExternalSession() {
2073445f829077cea72da77e31f0a2f6ccce3af295bBrad Ebinger        return getSessionManager().getExternalSession();
2083445f829077cea72da77e31f0a2f6ccce3af295bBrad Ebinger    }
2093445f829077cea72da77e31f0a2f6ccce3af295bBrad Ebinger
21051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static void cancelSubsession(Session subsession) {
21151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        getSessionManager().cancelSubsession(subsession);
21251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
21351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
21451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static void continueSession(Session subsession, String shortMethodName) {
21551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        getSessionManager().continueSession(subsession, shortMethodName);
21651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
21751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
21851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static void endSession() {
21951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        getSessionManager().endSession();
22051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
22151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
222836efade0c24ec235fe3470198509f5040655642Brad Ebinger    public static void registerSessionListener(SessionManager.ISessionListener l) {
223836efade0c24ec235fe3470198509f5040655642Brad Ebinger        getSessionManager().registerSessionListener(l);
224836efade0c24ec235fe3470198509f5040655642Brad Ebinger    }
225836efade0c24ec235fe3470198509f5040655642Brad Ebinger
22651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static String getSessionId() {
22751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        // If the Session logger has not been initialized, then there have been no sessions logged.
22851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        // Don't load it now!
22951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        synchronized (sSingletonSync) {
23051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            if (sSessionManager != null) {
23151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                return getSessionManager().getSessionId();
23251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            } else {
23351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                return "";
23451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            }
23551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        }
23651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
23751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
23851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static void addEvent(EventManager.Loggable recordEntry, String event) {
23951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        getEventManager().event(recordEntry, event, null);
24051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
24151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
24251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static void addEvent(EventManager.Loggable recordEntry, String event, Object data) {
24351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        getEventManager().event(recordEntry, event, data);
24451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
24551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
24651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static void addEvent(EventManager.Loggable recordEntry, String event, String format,
24751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            Object... args) {
24851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        getEventManager().event(recordEntry, event, format, args);
24951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
25051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
25151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static void registerEventListener(EventManager.EventListener e) {
25251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        getEventManager().registerEventListener(e);
25351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
25451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
25551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static void addRequestResponsePair(EventManager.TimedEventPair p) {
25651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        getEventManager().addRequestResponsePair(p);
25751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
25851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
25951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static void dumpEvents(IndentingPrintWriter pw) {
26051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        // If the Events logger has not been initialized, then there have been no events logged.
26151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        // Don't load it now!
26251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        synchronized (sSingletonSync) {
26351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            if (sEventManager != null) {
26451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                getEventManager().dumpEvents(pw);
26551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            } else {
2662db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn                pw.println("No Historical Events Logged.");
2672db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn            }
2682db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn        }
2692db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn    }
2702db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn
2712db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn    /**
2722db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn     * Dumps the events in a timeline format.
2732db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn     * @param pw The {@link IndentingPrintWriter} to write to.
2742db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn     * @hide
2752db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn     */
2762db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn    public static void dumpEventsTimeline(IndentingPrintWriter pw) {
2772db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn        // If the Events logger has not been initialized, then there have been no events logged.
2782db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn        // Don't load it now!
2792db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn        synchronized (sSingletonSync) {
2802db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn            if (sEventManager != null) {
2812db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn                getEventManager().dumpEventsTimeline(pw);
2822db81b599b342de99fd80001ed1a131b9fc67f6aTyler Gunn            } else {
28351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                pw.println("No Historical Events Logged.");
28451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            }
28551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        }
28651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
28751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
28851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    /**
28951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     * Enable or disable extended telecom logging.
29051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     *
29151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     * @param isExtendedLoggingEnabled {@code true} if extended logging should be enabled,
29251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     *          {@code false} if it should be disabled.
29351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     */
29451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static void setIsExtendedLoggingEnabled(boolean isExtendedLoggingEnabled) {
29551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        // If the state hasn't changed, bail early.
29651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        if (sIsUserExtendedLoggingEnabled == isExtendedLoggingEnabled) {
29751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            return;
29851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        }
29951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
30051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        if (sEventManager != null) {
30151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            sEventManager.changeEventCacheSize(isExtendedLoggingEnabled ?
30251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                    EVENTS_TO_CACHE_DEBUG : EVENTS_TO_CACHE);
30351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        }
30451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
30551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        sIsUserExtendedLoggingEnabled = isExtendedLoggingEnabled;
30651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        if (sIsUserExtendedLoggingEnabled) {
30751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            sUserExtendedLoggingStopTime = System.currentTimeMillis()
30851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                    + EXTENDED_LOGGING_DURATION_MILLIS;
30951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        } else {
31051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            sUserExtendedLoggingStopTime = 0;
31151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        }
31251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
31351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
31451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    private static EventManager getEventManager() {
31551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        // Checking for null again outside of synchronization because we only need to synchronize
31651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        // during the lazy loading of the events logger. We don't need to synchronize elsewhere.
31751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        if (sEventManager == null) {
31851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            synchronized (sSingletonSync) {
31951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                if (sEventManager == null) {
32051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                    sEventManager = new EventManager(Log::getSessionId);
32151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                    return sEventManager;
32251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                }
32351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            }
32451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        }
32551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        return sEventManager;
32651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
32751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
3288adafe786cf548543d721602ea35969afcdc295fBrad Ebinger    @VisibleForTesting
3298adafe786cf548543d721602ea35969afcdc295fBrad Ebinger    public static SessionManager getSessionManager() {
33051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        // Checking for null again outside of synchronization because we only need to synchronize
33151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        // during the lazy loading of the session logger. We don't need to synchronize elsewhere.
33251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        if (sSessionManager == null) {
33351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            synchronized (sSingletonSync) {
33451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                if (sSessionManager == null) {
33551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                    sSessionManager = new SessionManager();
33651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                    return sSessionManager;
33751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                }
33851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            }
33951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        }
34051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        return sSessionManager;
34151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
34251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
34351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static void setTag(String tag) {
34451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        TAG = tag;
3450c3541be65fa87519a879c053a7cf4b4526be5dbBrad Ebinger        DEBUG = isLoggable(android.util.Log.DEBUG);
3460c3541be65fa87519a879c053a7cf4b4526be5dbBrad Ebinger        INFO = isLoggable(android.util.Log.INFO);
3470c3541be65fa87519a879c053a7cf4b4526be5dbBrad Ebinger        VERBOSE = isLoggable(android.util.Log.VERBOSE);
3480c3541be65fa87519a879c053a7cf4b4526be5dbBrad Ebinger        WARN = isLoggable(android.util.Log.WARN);
3490c3541be65fa87519a879c053a7cf4b4526be5dbBrad Ebinger        ERROR = isLoggable(android.util.Log.ERROR);
35051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
35151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
35251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    /**
35351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     * If user enabled extended logging is enabled and the time limit has passed, disables the
35451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     * extended logging.
35551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     */
35651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    private static void maybeDisableLogging() {
35751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        if (!sIsUserExtendedLoggingEnabled) {
35851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            return;
35951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        }
36051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
36151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        if (sUserExtendedLoggingStopTime < System.currentTimeMillis()) {
36251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            sUserExtendedLoggingStopTime = 0;
36351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            sIsUserExtendedLoggingEnabled = false;
36451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        }
36551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
36651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
36751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static boolean isLoggable(int level) {
36851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        return FORCE_LOGGING || android.util.Log.isLoggable(TAG, level);
36951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
37051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
37151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static String piiHandle(Object pii) {
37260ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        if (pii == null || VERBOSE) {
37360ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad            return String.valueOf(pii);
37460ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        }
37560ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
3763c20d633731a3a2f6ea03012cb4b1d4903a31520Santos Cordon        StringBuilder sb = new StringBuilder();
37751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        if (pii instanceof Uri) {
37851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            Uri uri = (Uri) pii;
37951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            String scheme = uri.getScheme();
38051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
38151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            if (!TextUtils.isEmpty(scheme)) {
38251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                sb.append(scheme).append(":");
38351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            }
38451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
38551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            String textToObfuscate = uri.getSchemeSpecificPart();
38651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            if (PhoneAccount.SCHEME_TEL.equals(scheme)) {
38751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                for (int i = 0; i < textToObfuscate.length(); i++) {
38851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                    char c = textToObfuscate.charAt(i);
38951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                    sb.append(PhoneNumberUtils.isDialable(c) ? "*" : c);
39051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                }
39151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            } else if (PhoneAccount.SCHEME_SIP.equals(scheme)) {
39251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                for (int i = 0; i < textToObfuscate.length(); i++) {
39351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                    char c = textToObfuscate.charAt(i);
39451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                    if (c != '@' && c != '.') {
39551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                        c = '*';
39651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                    }
3973c20d633731a3a2f6ea03012cb4b1d4903a31520Santos Cordon                    sb.append(c);
3983c20d633731a3a2f6ea03012cb4b1d4903a31520Santos Cordon                }
39951b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            } else {
40051b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger                sb.append(pii(pii));
4013c20d633731a3a2f6ea03012cb4b1d4903a31520Santos Cordon            }
4023c20d633731a3a2f6ea03012cb4b1d4903a31520Santos Cordon        }
40351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
4043c20d633731a3a2f6ea03012cb4b1d4903a31520Santos Cordon        return sb.toString();
40551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    }
4063c20d633731a3a2f6ea03012cb4b1d4903a31520Santos Cordon
40751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    /**
40851b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     * Redact personally identifiable information for production users.
409b3cd7b51d330caa1f54710741b73a63043515b82youhei.x.miyoshi     * If we are running in verbose mode, return the original string,
410f784b29c9dce6361dd2f1f45c92df30d4a6d3c7cBrad Ebinger     * and return "***" otherwise.
41151b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger     */
41251b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger    public static String pii(Object pii) {
41351b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        if (pii == null || VERBOSE) {
41451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger            return String.valueOf(pii);
41551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        }
416f784b29c9dce6361dd2f1f45c92df30d4a6d3c7cBrad Ebinger        return "***";
41760ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
41860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
41960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    private static String getPrefixFromObject(Object obj) {
42060ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        return obj == null ? "<null>" : obj.getClass().getSimpleName();
42160ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
42260ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad
42360ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    private static String buildMessage(String prefix, String format, Object... args) {
42451b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        // Incorporate thread ID and calling method into prefix
42551b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        String sessionName = getSessionId();
42651b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        String sessionPostfix = TextUtils.isEmpty(sessionName) ? "" : ": " + sessionName;
42751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger
42860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        String msg;
42960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        try {
43060ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad            msg = (args == null || args.length == 0) ? format
43160ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad                    : String.format(Locale.US, format, args);
43260ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        } catch (IllegalFormatException ife) {
4334fb372fe169c6abd463a620b56dd6b05b5ff1e7aBrad Ebinger            e(TAG, ife, "Log: IllegalFormatException: formatString='%s' numArgs=%d", format,
43460ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad                    args.length);
43560ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad            msg = format + " (An error occurred while formatting the message.)";
43660ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad        }
43751b9834180db6ecaf4edaf38fb12d5d408f2c1ceBrad Ebinger        return String.format(Locale.US, "%s: %s%s", prefix, msg, sessionPostfix);
43860ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad    }
43960ac30bb8a30fa7283d592c12ddf2da9447adf14Ihab Awad}
440