Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cb209010 authored by Chinmay Dhodapkar's avatar Chinmay Dhodapkar
Browse files

Telecom Emergency call diagnostics logger

Core logic to trigger diagnostics on (potential) errors
Decides type of data to be collected

The actual data is collected from telephony service since
Telecom runs as part of system_service (b/28035297)

Bug: 271900116
Test: atest EmergencyCallDiagnosticLogger
Change-Id: Ia40a74fd5acb509c3ebda53b6e6e04bbd12be436
parent 655d1897
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -3914,6 +3914,10 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        return mCallDirection == CALL_DIRECTION_UNKNOWN;
    }

    public boolean isOutgoing() {
        return mCallDirection == CALL_DIRECTION_OUTGOING;
    }

    /**
     * Determines if this call is in a disconnecting state.
     *
+6 −1
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@ import java.util.stream.Collectors;
 * Watchdog class responsible for detecting potential anomalous conditions for {@link Call}s.
 */
public class CallAnomalyWatchdog extends CallsManagerListenerBase implements Call.Listener {
    private final EmergencyCallDiagnosticLogger mEmergencyCallDiagnosticLogger;

    /**
     * Class used to track the call state as it pertains to the watchdog. The watchdog cares about
     * both the call state and whether a {@link ConnectionService} has finished creating the
@@ -146,11 +148,13 @@ public class CallAnomalyWatchdog extends CallsManagerListenerBase implements Cal

    public CallAnomalyWatchdog(ScheduledExecutorService executorService,
            TelecomSystem.SyncRoot lock,
            Timeouts.Adapter timeoutAdapter, ClockProxy clockProxy) {
            Timeouts.Adapter timeoutAdapter, ClockProxy clockProxy,
            EmergencyCallDiagnosticLogger emergencyCallDiagnosticLogger) {
        mScheduledExecutorService = executorService;
        mLock = lock;
        mTimeoutAdapter = timeoutAdapter;
        mClockProxy = clockProxy;
        mEmergencyCallDiagnosticLogger = emergencyCallDiagnosticLogger;
    }

    /**
@@ -357,6 +361,7 @@ public class CallAnomalyWatchdog extends CallsManagerListenerBase implements Cal
                        mAnomalyReporter.reportAnomaly(
                                WATCHDOG_DISCONNECTED_STUCK_EMERGENCY_CALL_UUID,
                                WATCHDOG_DISCONNECTED_STUCK_EMERGENCY_CALL_MSG);
                        mEmergencyCallDiagnosticLogger.reportStuckCall(call);
                    } else {
                        mAnomalyReporter.reportAnomaly(
                                WATCHDOG_DISCONNECTED_STUCK_CALL_UUID,
+21 −4
Original line number Diff line number Diff line
@@ -117,6 +117,7 @@ import com.android.server.telecom.bluetooth.BluetoothRouteManager;
import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
import com.android.server.telecom.callfiltering.BlockCheckerAdapter;
import com.android.server.telecom.callfiltering.BlockCheckerFilter;
import com.android.server.telecom.callfiltering.BlockedNumbersAdapter;
import com.android.server.telecom.callfiltering.CallFilterResultCallback;
import com.android.server.telecom.callfiltering.CallFilteringResult;
import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
@@ -124,11 +125,9 @@ import com.android.server.telecom.callfiltering.CallScreeningServiceFilter;
import com.android.server.telecom.callfiltering.DirectToVoicemailFilter;
import com.android.server.telecom.callfiltering.DndCallFilter;
import com.android.server.telecom.callfiltering.IncomingCallFilterGraph;
import com.android.server.telecom.callfiltering.BlockedNumbersAdapter;
import com.android.server.telecom.callredirection.CallRedirectionProcessor;
import com.android.server.telecom.components.ErrorDialogActivity;
import com.android.server.telecom.components.TelecomBroadcastReceiver;
import com.android.server.telecom.settings.BlockedNumbersUtil;
import com.android.server.telecom.stats.CallFailureCause;
import com.android.server.telecom.ui.AudioProcessingNotification;
import com.android.server.telecom.ui.CallRedirectionTimeoutDialogActivity;
@@ -440,6 +439,8 @@ public class CallsManager extends Call.ListenerBase
    private final RoleManagerAdapter mRoleManagerAdapter;
    private final CallEndpointController mCallEndpointController;
    private final CallAnomalyWatchdog mCallAnomalyWatchdog;

    private final EmergencyCallDiagnosticLogger mEmergencyCallDiagnosticLogger;
    private final CallStreamingController mCallStreamingController;
    private final BlockedNumbersAdapter mBlockedNumbersAdapter;
    private final TransactionManager mTransactionManager;
@@ -552,7 +553,9 @@ public class CallsManager extends Call.ListenerBase
            Ringer.AccessibilityManagerAdapter accessibilityManagerAdapter,
            Executor asyncTaskExecutor,
            BlockedNumbersAdapter blockedNumbersAdapter,
            TransactionManager transactionManager) {
            TransactionManager transactionManager,
            EmergencyCallDiagnosticLogger emergencyCallDiagnosticLogger) {

        mContext = context;
        mLock = lock;
        mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter;
@@ -569,6 +572,7 @@ public class CallsManager extends Call.ListenerBase
        mTimeoutsAdapter = timeoutsAdapter;
        mEmergencyCallHelper = emergencyCallHelper;
        mCallerInfoLookupHelper = callerInfoLookupHelper;
        mEmergencyCallDiagnosticLogger = emergencyCallDiagnosticLogger;

        mDtmfLocalTonePlayer =
                new DtmfLocalTonePlayer(new DtmfLocalTonePlayer.ToneGeneratorProxy());
@@ -653,6 +657,7 @@ public class CallsManager extends Call.ListenerBase
        mListeners.add(mProximitySensorManager);
        mListeners.add(audioProcessingNotification);
        mListeners.add(callAnomalyWatchdog);
        mListeners.add(mEmergencyCallDiagnosticLogger);
        mListeners.add(mCallStreamingController);

        // this needs to be after the mCallAudioManager
@@ -1277,6 +1282,10 @@ public class CallsManager extends Call.ListenerBase
        return mEmergencyCallHelper;
    }

    EmergencyCallDiagnosticLogger getEmergencyCallDiagnosticLogger() {
        return mEmergencyCallDiagnosticLogger;
    }

    public DefaultDialerCache getDefaultDialerCache() {
        return mDefaultDialerCache;
    }
@@ -5378,7 +5387,7 @@ public class CallsManager extends Call.ListenerBase
     *
     * @param pw The {@code IndentingPrintWriter} to write the state to.
     */
    public void dump(IndentingPrintWriter pw) {
    public void dump(IndentingPrintWriter pw, String[] args) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
        if (mCalls != null) {
            pw.println("mCalls: ");
@@ -5440,6 +5449,14 @@ public class CallsManager extends Call.ListenerBase
            mCallAnomalyWatchdog.dump(pw);
            pw.decreaseIndent();
        }

        if (mEmergencyCallDiagnosticLogger != null) {
            pw.println("mEmergencyCallDiagnosticLogger:");
            pw.increaseIndent();
            mEmergencyCallDiagnosticLogger.dump(pw, args);
            pw.decreaseIndent();
        }

        if (mDefaultDialerCache != null) {
            pw.println("mDefaultDialerCache:");
            pw.increaseIndent();
+438 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.telecom;

import static android.telephony.TelephonyManager.EmergencyCallDiagnosticParams;

import android.os.BugreportManager;
import android.os.DropBoxManager;
import android.provider.DeviceConfig;
import android.telecom.DisconnectCause;
import android.telecom.Log;
import android.telephony.TelephonyManager;
import android.util.LocalLog;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;

/**
 * The EmergencyCallDiagnosticsLogger monitors information required to diagnose potential outgoing
 * ecall failures on the device. When a potential failure is detected, it calls a Telephony API to
 * persist relevant information (dumpsys, logcat etc.) to the dropbox. This acts as a central place
 * to determine when and what to collect.
 *
 * <p>When a bugreport is triggered, this module will read the dropbox entries and add them to the
 * telecom dump.
 */
public class EmergencyCallDiagnosticLogger extends CallsManagerListenerBase
        implements Call.Listener {

    public static final int REPORT_REASON_RANGE_START = -1; //!!DO NOT CHANGE
    public static final int REPORT_REASON_RANGE_END = 5; //increment this and add new reason above
    public static final int COLLECTION_TYPE_BUGREPORT = 10;
    public static final int COLLECTION_TYPE_TELECOM_STATE = 11;
    public static final int COLLECTION_TYPE_TELEPHONY_STATE = 12;
    public static final int COLLECTION_TYPE_LOGCAT_BUFFERS = 13;
    private static final int REPORT_REASON_STUCK_CALL_DETECTED = 0;
    private static final int REPORT_REASON_INACTIVE_CALL_TERMINATED_BY_USER_AFTER_DELAY = 1;
    private static final int REPORT_REASON_CALL_FAILED = 2;
    private static final int REPORT_REASON_CALL_CREATED_BUT_NEVER_ADDED = 3;
    private static final int REPORT_REASON_SHORT_DURATION_AFTER_GOING_ACTIVE = 4;
    private static final String DROPBOX_TAG = "ecall_diagnostic_data";
    private static final String ENABLE_BUGREPORT_COLLECTION_FOR_EMERGENCY_CALL_DIAGNOSTICS =
            "enable_bugreport_collection_for_emergency_call_diagnostics";
    private static final String ENABLE_TELECOM_DUMP_COLLECTION_FOR_EMERGENCY_CALL_DIAGNOSTICS =
            "enable_telecom_dump_collection_for_emergency_call_diagnostics";

    private static final String ENABLE_LOGCAT_COLLECTION_FOR_EMERGENCY_CALL_DIAGNOSTICS =
            "enable_logcat_collection_for_emergency_call_diagnostics";
    private static final String ENABLE_TELEPHONY_DUMP_COLLECTION_FOR_EMERGENCY_CALL_DIAGNOSTICS =
            "enable_telephony_dump_collection_for_emergency_call_diagnostics";

    private static final String DUMPSYS_ARG_FOR_DIAGNOSTICS = "EmergencyDiagnostics";

    // max text size to read from dropbox entry
    private static final int DEFAULT_MAX_READ_BYTES_PER_DROP_BOX_ENTRY = 500000;
    private static final String MAX_BYTES_PER_DROP_BOX_ENTRY = "max_bytes_per_dropbox_entry";
    private static final int MAX_DROPBOX_ENTRIES_TO_DUMP = 6;

    private final Timeouts.Adapter mTimeoutAdapter;
    // This map holds all calls, but keeps pruning non-emergency calls when we can determine it
    private final Map<Call, CallEventTimestamps> mEmergencyCallsMap = new ConcurrentHashMap<>(2);
    private final DropBoxManager mDropBoxManager;
    private final LocalLog mLocalLog = new LocalLog(10);
    private final TelephonyManager mTelephonyManager;
    private final BugreportManager mBugreportManager;
    private final Executor mAsyncTaskExecutor;
    private final ClockProxy mClockProxy;

    public EmergencyCallDiagnosticLogger(
            TelephonyManager tm,
            BugreportManager brm,
            Timeouts.Adapter timeoutAdapter, DropBoxManager dropBoxManager,
            Executor asyncTaskExecutor, ClockProxy clockProxy) {
        mTimeoutAdapter = timeoutAdapter;
        mDropBoxManager = dropBoxManager;
        mTelephonyManager = tm;
        mBugreportManager = brm;
        mAsyncTaskExecutor = asyncTaskExecutor;
        mClockProxy = clockProxy;
    }

    // this calculates time from ACTIVE --> removed
    private static long getCallTimeInActiveStateSec(CallEventTimestamps ts) {
        if (ts.getCallActiveTime() == 0 || ts.getCallRemovedTime() == 0) {
            return 0;
        } else {
            return (ts.getCallRemovedTime() - ts.getCallActiveTime()) / 1000;
        }
    }

    // this calculates time from call created --> removed
    private static long getTotalCallTimeSec(CallEventTimestamps ts) {
        if (ts.getCallRemovedTime() == 0 || ts.getCallCreatedTime() == 0) {
            return 0;
        } else {
            return (ts.getCallRemovedTime() - ts.getCallCreatedTime()) / 1000;
        }
    }

    //determines what to collect based on fail reason
    //if COLLECTION_TYPE_BUGREPORT is present in the returned list, then that
    //should be the only collection type in the list
    @VisibleForTesting
    public static List<Integer> getDataCollectionTypes(int reason) {
        switch (reason) {
            case REPORT_REASON_SHORT_DURATION_AFTER_GOING_ACTIVE:
                return Arrays.asList(COLLECTION_TYPE_TELECOM_STATE);
            case REPORT_REASON_CALL_CREATED_BUT_NEVER_ADDED:
                return Arrays.asList(
                        COLLECTION_TYPE_TELECOM_STATE, COLLECTION_TYPE_TELEPHONY_STATE);
            case REPORT_REASON_CALL_FAILED:
            case REPORT_REASON_INACTIVE_CALL_TERMINATED_BY_USER_AFTER_DELAY:
            case REPORT_REASON_STUCK_CALL_DETECTED:
                return Arrays.asList(
                        COLLECTION_TYPE_TELECOM_STATE,
                        COLLECTION_TYPE_TELEPHONY_STATE,
                        COLLECTION_TYPE_LOGCAT_BUFFERS);
            default:
        }
        return new ArrayList<>();
    }

    private int getMaxBytesPerDropboxEntry() {
        return DeviceConfig.getInt(DeviceConfig.NAMESPACE_TELEPHONY,
                MAX_BYTES_PER_DROP_BOX_ENTRY, DEFAULT_MAX_READ_BYTES_PER_DROP_BOX_ENTRY);
    }

    @VisibleForTesting
    public Map<Call, CallEventTimestamps> getEmergencyCallsMap() {
        return mEmergencyCallsMap;
    }

    private void triggerDiagnosticsCollection(Call call, int reason) {
        Log.i(this, "Triggering diagnostics for call %s reason: %d", call.getId(), reason);
        List<Integer> dataCollectionTypes = getDataCollectionTypes(reason);
        boolean invokeTelephonyPersistApi = false;
        CallEventTimestamps ts = mEmergencyCallsMap.get(call);
        EmergencyCallDiagnosticParams dp =
                new EmergencyCallDiagnosticParams();
        for (Integer dataCollectionType : dataCollectionTypes) {
            switch (dataCollectionType) {
                case COLLECTION_TYPE_TELECOM_STATE:
                    if (isTelecomDumpCollectionEnabled()) {
                        dp.setTelecomDumpSysCollection(true);
                        invokeTelephonyPersistApi = true;
                    }
                    break;
                case COLLECTION_TYPE_TELEPHONY_STATE:
                    if (isTelephonyDumpCollectionEnabled()) {
                        dp.setTelephonyDumpSysCollection(true);
                        invokeTelephonyPersistApi = true;
                    }
                    break;
                case COLLECTION_TYPE_LOGCAT_BUFFERS:
                    if (isLogcatCollectionEnabled()) {
                        dp.setLogcatCollection(true, ts.getCallCreatedTime());
                        invokeTelephonyPersistApi = true;
                    }
                    break;
                case COLLECTION_TYPE_BUGREPORT:
                    if (isBugreportCollectionEnabled()) {
                        mAsyncTaskExecutor.execute(new Runnable() {
                            @Override
                            public void run() {
                                persistBugreport();
                            }
                        });
                    }
                    break;
                default:
            }
        }
        if (invokeTelephonyPersistApi) {
            mAsyncTaskExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    Log.i(this, "Requesting Telephony to persist data %s", dp.toString());
                    try {
                        mTelephonyManager.persistEmergencyCallDiagnosticData(DROPBOX_TAG, dp);
                    } catch (Exception e) {
                        Log.w(this,
                                "Exception while invoking "
                                        + "Telephony#persistEmergencyCallDiagnosticData  %s",
                                e.toString());
                    }
                }
            });
        }
    }

    private boolean isBugreportCollectionEnabled() {
        return DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_TELEPHONY,
                ENABLE_BUGREPORT_COLLECTION_FOR_EMERGENCY_CALL_DIAGNOSTICS,
                false);
    }

    private boolean isTelecomDumpCollectionEnabled() {
        return DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_TELEPHONY,
                ENABLE_TELECOM_DUMP_COLLECTION_FOR_EMERGENCY_CALL_DIAGNOSTICS,
                true);
    }

    private boolean isLogcatCollectionEnabled() {
        return DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_TELEPHONY,
                ENABLE_LOGCAT_COLLECTION_FOR_EMERGENCY_CALL_DIAGNOSTICS,
                true);
    }

    private boolean isTelephonyDumpCollectionEnabled() {
        return DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_TELEPHONY,
                ENABLE_TELEPHONY_DUMP_COLLECTION_FOR_EMERGENCY_CALL_DIAGNOSTICS,
                true);
    }

    private void persistBugreport() {
        if (isBugreportCollectionEnabled()) {
            // TODO:
        }
    }

    private boolean shouldTrackCall(Call call) {
        return (call != null && call.isEmergencyCall() && call.isOutgoing());
    }

    public void reportStuckCall(Call call) {
        if (shouldTrackCall(call)) {
            Log.i(this, "Triggering diagnostics for stuck call %s", call.getId());
            triggerDiagnosticsCollection(call, REPORT_REASON_STUCK_CALL_DETECTED);
            call.removeListener(this);
            mEmergencyCallsMap.remove(call);
        }
    }

    @Override
    public void onStartCreateConnection(Call call) {
        if (shouldTrackCall(call)) {
            long currentTime = mClockProxy.currentTimeMillis();
            call.addListener(this);
            Log.i(this, "Tracking call %s timestamp: %d", call.getId(), currentTime);
            mEmergencyCallsMap.put(call, new CallEventTimestamps(currentTime));
        }
    }

    @Override
    public void onCreateConnectionFailed(Call call) {
        if (shouldTrackCall(call)) {
            Log.i(this, "Triggering diagnostics for  call %s that was never added", call.getId());
            triggerDiagnosticsCollection(call, REPORT_REASON_CALL_CREATED_BUT_NEVER_ADDED);
            call.removeListener(this);
            mEmergencyCallsMap.remove(call);
        }
    }

    /**
     * Override of {@link CallsManagerListenerBase} to track when calls are removed
     *
     * @param call the call
     */
    @Override
    public void onCallRemoved(Call call) {
        if (call != null && (mEmergencyCallsMap.get(call) != null)) {
            call.removeListener(this);

            CallEventTimestamps ts = mEmergencyCallsMap.get(call);
            long currentTime = mClockProxy.currentTimeMillis();
            ts.setCallRemovedTime(currentTime);

            maybeTriggerDiagnosticsCollection(call, ts);
            mEmergencyCallsMap.remove(call);
        }
    }

    // !NOTE!: this method should only be called after we get onCallRemoved
    private void maybeTriggerDiagnosticsCollection(Call removedCall, CallEventTimestamps ts) {
        Log.i(this, "Evaluating emergency call for diagnostic logging: %s", removedCall.getId());
        boolean wentActive = (ts.getCallActiveTime() != 0);
        long callActiveTimeSec = (wentActive ? getCallTimeInActiveStateSec(ts) : 0);
        long timeSinceCallCreatedSec = getTotalCallTimeSec(ts);
        int dc = removedCall.getDisconnectCause().getCode();

        if (wentActive) {
            if (callActiveTimeSec
                    < mTimeoutAdapter.getEmergencyCallActiveTimeThresholdMillis() / 1000) {
                // call connected but did not go on for long
                triggerDiagnosticsCollection(
                        removedCall, REPORT_REASON_SHORT_DURATION_AFTER_GOING_ACTIVE);
            }
        } else {

            if (dc == DisconnectCause.LOCAL
                    && timeSinceCallCreatedSec
                    > mTimeoutAdapter.getEmergencyCallTimeBeforeUserDisconnectThresholdMillis()
                    / 1000) {
                // call was disconnected by the user (but not immediately)
                triggerDiagnosticsCollection(
                        removedCall, REPORT_REASON_INACTIVE_CALL_TERMINATED_BY_USER_AFTER_DELAY);
            } else if (dc != DisconnectCause.LOCAL) {
                // this can be a case for a full bugreport
                triggerDiagnosticsCollection(removedCall, REPORT_REASON_CALL_FAILED);
            }
        }
    }

    /**
     * Override of {@link com.android.server.telecom.CallsManager.CallsManagerListener} to track
     * call state changes.
     *
     * @param call     the call
     * @param oldState its old state
     * @param newState the new state
     */
    @Override
    public void onCallStateChanged(Call call, int oldState, int newState) {

        if (call != null && mEmergencyCallsMap.get(call) != null && newState == CallState.ACTIVE) {
            CallEventTimestamps ts = mEmergencyCallsMap.get(call);
            if (ts != null) {
                long currentTime = mClockProxy.currentTimeMillis();
                ts.setCallActiveTime(currentTime);
            }
        }
    }

    private void dumpDiagnosticDataFromDropbox(IndentingPrintWriter pw) {
        pw.increaseIndent();
        pw.println("PERSISTED DIAGNOSTIC DATA FROM DROP BOX");
        int totalEntriesDumped = 0;
        long currentTime = mClockProxy.currentTimeMillis();
        long entriesAfterTime =
                currentTime - (mTimeoutAdapter.getDaysBackToSearchEmergencyDiagnosticEntries() * 24
                        * 60L * 60L * 1000L);
        Log.i(this, "current time: %d entriesafter: %d", currentTime, entriesAfterTime);
        DropBoxManager.Entry entry;
        entry = mDropBoxManager.getNextEntry(DROPBOX_TAG, entriesAfterTime);
        while (entry != null) {
            Log.i(this, "found entry with ts: %d", entry.getTimeMillis());
            String content[] = entry.getText(getMaxBytesPerDropboxEntry()).split(
                    System.lineSeparator());
            long entryTime = entry.getTimeMillis();
            if (content != null) {
                pw.increaseIndent();
                pw.println("------------BEGIN ENTRY (" + entryTime + ")--------");
                for (String line : content) {
                    pw.println(line);
                }
                pw.println("--------END ENTRY--------");
                pw.decreaseIndent();
                totalEntriesDumped++;
            }
            entry = mDropBoxManager.getNextEntry(DROPBOX_TAG, entryTime);
            if (totalEntriesDumped > MAX_DROPBOX_ENTRIES_TO_DUMP) {
                /*
                Since Emergency calls are a rare/once in a lifetime time occurrence for most users,
                we should not be seeing too many entries. This code just guards against edge case
                like load testing, b2b failures etc. We may accumulate a lot of dropbox entries in
                such cases, but we limit to dumping only MAX_DROPBOX_ENTRIES_TO_DUMP in the
                bugreport

                The Dropbox API in its current state does not allow to query Entries in reverse
                chronological order efficiently.
                 */

                Log.i(this, "Skipping dump for remaining entries. dumped :%d", totalEntriesDumped);
                break;
            }
        }
        pw.println("END OF PERSISTED DIAGNOSTIC DATA FROM DROP BOX");
        pw.decreaseIndent();
    }

    public void dump(IndentingPrintWriter pw, String[] args) {
        pw.increaseIndent();
        mLocalLog.dump(pw);
        pw.decreaseIndent();
        if (args != null && args.length > 0 && args[0].equals(DUMPSYS_ARG_FOR_DIAGNOSTICS)) {
            //dont read dropbox entries since this dump is triggered by telephony for diagnostics
            Log.i(this, "skipped dumping diagnostic data");
            return;
        }
        dumpDiagnosticDataFromDropbox(pw);
    }

    private static class CallEventTimestamps {

        private final long mCallCreatedTime;
        private long mCallActiveTime;
        private long mCallRemovedTime;

        public CallEventTimestamps(long createdTime) {
            mCallCreatedTime = createdTime;
        }

        public long getCallActiveTime() {
            return mCallActiveTime;
        }

        public void setCallActiveTime(long callActiveTime) {
            this.mCallActiveTime = callActiveTime;
        }

        public long getCallCreatedTime() {
            return mCallCreatedTime;
        }

        public long getCallRemovedTime() {
            return mCallRemovedTime;
        }

        public void setCallRemovedTime(long callRemovedTime) {
            this.mCallRemovedTime = callRemovedTime;
        }
    }
}
+7 −6

File changed.

Preview size limit exceeded, changes collapsed.

Loading