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

Commit 6306f47d authored by Grace Jia's avatar Grace Jia
Browse files

Capture metrics on InCallService failures and inform user of failures

Test: Manual test on telecom testapps, atest TelecomUnitTest
Bug: 147883088
Change-Id: Id0e11558c16d770156fd01e470969c99e956be45
parent 73ae8d85
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -177,6 +177,13 @@ message InCallServiceInfo {

  // The type of the in-call service
  optional InCallServiceType in_call_service_type = 2;

  // The number of milliseconds that the in call service remained bound between binding and
  // disconnection.
  optional int64 bound_duration_millis = 3;

  // True if the in call service has ever crashed during a call.
  optional bool is_null_binding = 4;
}

// Information about each call.
+11 −0
Original line number Diff line number Diff line
@@ -68,6 +68,15 @@
        background. This app may be accessing and playing audio over the call.
    </string>

    <!-- Crashed in call service notification label, used when the in call service has cranshed and
         the system fall back to use system dialer. [CHAR LIMIT=NONE] -->
    <string name="notification_crashedInCallService_title">Crashed phone app</string>
    <!-- Body of the notification presented when an in call service crashed. [CHAR LIMIT=NONE] -->
    <string name="notification_crashedInCallService_body">
        Your Phone app <xliff:g id="in_call_service_app_name">%s</xliff:g> has crashed.
        You call was continued using the Phone app that came with your device.
    </string>

    <!-- Content description of the call muted notification icon for
         accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
    <string name="accessibility_call_muted">Call muted.</string>
@@ -300,6 +309,8 @@
    <string name="notification_channel_background_calls">Background calls</string>
    <!-- Notification channel name for a channel containing disconnected call notifications. -->
    <string name="notification_channel_disconnected_calls">Disconnected calls</string>
    <!-- Notification channel name for a channel containing crashed phone apps service notifications. -->
    <string name="notification_channel_in_call_service_crash">Crashed phone apps</string>

    <!-- Alert dialog content used to inform the user that placing a new outgoing call will end the
         ongoing call in the app "other_app". -->
+11 −3
Original line number Diff line number Diff line
@@ -201,7 +201,8 @@ public class Analytics {
        public void addVideoEvent(int eventId, int videoState) {
        }

        public void addInCallService(String serviceName, int type) {
        public void addInCallService(String serviceName, int type, long boundDuration,
                boolean isNullBinding) {
        }

        public void addCallProperties(int properties) {
@@ -370,10 +371,13 @@ public class Analytics {
        }

        @Override
        public void addInCallService(String serviceName, int type) {
        public void addInCallService(String serviceName, int type, long boundDuration,
                boolean isNullBinding) {
            inCallServiceInfos.add(new TelecomLogClass.InCallServiceInfo()
                    .setInCallServiceName(serviceName)
                    .setInCallServiceType(type));
                    .setInCallServiceType(type)
                    .setBoundDurationMillis(boundDuration)
                    .setIsNullBinding(isNullBinding));
        }

        @Override
@@ -533,6 +537,10 @@ public class Analytics {
                s.append(service.getInCallServiceName());
                s.append(" type: ");
                s.append(service.getInCallServiceType());
                s.append(" is crashed: ");
                s.append(service.getIsNullBinding());
                s.append(" service last time in ms: ");
                s.append(service.getBoundDurationMillis());
                s.append("\n");
            }
            s.append("]");
+97 −11
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.server.telecom;

import android.Manifest;
import android.annotation.NonNull;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -47,6 +49,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telecom.IInCallService;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.telecom.SystemStateHelper.SystemStateListener;
import com.android.server.telecom.ui.NotificationChannelManager;

import java.util.ArrayList;
import java.util.Arrays;
@@ -65,6 +68,8 @@ import java.util.stream.Collectors;
 * a binding to the {@link IInCallService} (implemented by the in-call app).
 */
public class InCallController extends CallsManagerListenerBase {
    public static final int IN_CALL_SERVICE_NOTIFICATION_ID = 3;
    public static final String NOTIFICATION_TAG = InCallController.class.getSimpleName();

    public class InCallServiceConnection {
        /**
@@ -83,7 +88,7 @@ public class InCallController extends CallsManagerListenerBase {
        public static final int CONNECTION_NOT_SUPPORTED = 3;

        public class Listener {
            public void onDisconnect(InCallServiceConnection conn) {}
            public void onDisconnect(InCallServiceConnection conn, Call call) {}
        }

        protected Listener mListener;
@@ -97,6 +102,7 @@ public class InCallController extends CallsManagerListenerBase {
        }
        public InCallServiceInfo getInfo() { return null; }
        public void dump(IndentingPrintWriter pw) {}
        public Call mCall;
    }

    private class InCallServiceInfo {
@@ -104,6 +110,8 @@ public class InCallController extends CallsManagerListenerBase {
        private boolean mIsExternalCallsSupported;
        private boolean mIsSelfManagedCallsSupported;
        private final int mType;
        private long mBindingStartTime;
        private long mDisconnectTime;

        public InCallServiceInfo(ComponentName componentName,
                boolean isExternalCallsSupported,
@@ -131,6 +139,22 @@ public class InCallController extends CallsManagerListenerBase {
            return mType;
        }

        public long getBindingStartTime() {
            return mBindingStartTime;
        }

        public long getDisconnectTime() {
            return mDisconnectTime;
        }

        public void setBindingStartTime(long bindingStartTime) {
            mBindingStartTime = bindingStartTime;
        }

        public void setDisconnectTime(long disconnectTime) {
            mDisconnectTime = disconnectTime;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
@@ -198,14 +222,47 @@ public class InCallController extends CallsManagerListenerBase {
                    }
                }
            }

            @Override
            public void onNullBinding(ComponentName name) {
                Log.startSession("ICSBC.oNB");
                synchronized (mLock) {
                    try {
                        Log.d(this, "onNullBinding: %s", name);
                        mIsNullBinding = true;
                        mIsBound = false;
                        onDisconnected();
                    } finally {
                        Log.endSession();
                    }
                }
            }

            @Override
            public void onBindingDied(ComponentName name) {
                Log.startSession("ICSBC.oBD");
                synchronized (mLock) {
                    try {
                        Log.d(this, "onBindingDied: %s", name);
                        mIsBound = false;
                        onDisconnected();
                    } finally {
                        Log.endSession();
                    }
                }
            }
        };

        private final InCallServiceInfo mInCallServiceInfo;
        private boolean mIsConnected = false;
        private boolean mIsBound = false;
        private boolean mIsNullBinding = false;
        private NotificationManager mNotificationManager;

        public InCallServiceBindingConnection(InCallServiceInfo info) {
            mInCallServiceInfo = info;
            mNotificationManager =
                    (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
        }

        @Override
@@ -234,6 +291,7 @@ public class InCallController extends CallsManagerListenerBase {

            Log.i(this, "Attempting to bind to InCall %s, with %s", mInCallServiceInfo, intent);
            mIsConnected = true;
            mInCallServiceInfo.setBindingStartTime(mClockProxy.elapsedRealtime());
            if (!mContext.bindServiceAsUser(intent, mServiceConnection,
                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
                        | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS,
@@ -242,11 +300,10 @@ public class InCallController extends CallsManagerListenerBase {
                mIsConnected = false;
            }

            if (call != null && mIsConnected) {
                call.getAnalytics().addInCallService(
                        mInCallServiceInfo.getComponentName().flattenToShortString(),
                        mInCallServiceInfo.getType());
            if (mIsConnected && call != null) {
                mCall = call;
            }
            Log.i(this, "mCall: %s, mIsConnected: %s", mCall, mIsConnected);

            return mIsConnected ? CONNECTION_SUCCEEDED : CONNECTION_FAILED;
        }
@@ -259,10 +316,36 @@ public class InCallController extends CallsManagerListenerBase {
        @Override
        public void disconnect() {
            if (mIsConnected) {
                Log.i(InCallController.this, "ICSBC#disconnect: unbinding; %s",
                        mInCallServiceInfo);
                mInCallServiceInfo.setDisconnectTime(mClockProxy.elapsedRealtime());
                Log.i(InCallController.this, "ICSBC#disconnect: unbinding after %s ms;"
                                + "%s. isCrashed: %s", mInCallServiceInfo.mDisconnectTime
                                - mInCallServiceInfo.mBindingStartTime,
                        mInCallServiceInfo, mIsNullBinding);
                String packageName = mInCallServiceInfo.getComponentName().getPackageName();
                mContext.unbindService(mServiceConnection);
                mIsConnected = false;
                if (mIsNullBinding) {
                    Notification.Builder builder = new Notification.Builder(mContext,
                            NotificationChannelManager.CHANNEL_ID_IN_CALL_SERVICE_CRASH);
                    builder.setSmallIcon(R.drawable.ic_phone)
                            .setColor(mContext.getResources().getColor(R.color.theme_color))
                            .setContentTitle(
                                    mContext.getText(
                                            R.string.notification_crashedInCallService_title))
                            .setStyle(new Notification.BigTextStyle()
                                    .bigText(mContext.getString(
                                            R.string.notification_crashedInCallService_body,
                                            packageName)));
                    mNotificationManager.notify(NOTIFICATION_TAG, IN_CALL_SERVICE_NOTIFICATION_ID,
                            builder.build());
                }
                if (mCall != null) {
                    mCall.getAnalytics().addInCallService(
                            mInCallServiceInfo.getComponentName().flattenToShortString(),
                            mInCallServiceInfo.getType(),
                            mInCallServiceInfo.getDisconnectTime()
                                    - mInCallServiceInfo.getBindingStartTime(), mIsNullBinding);
                }
            } else {
                Log.i(InCallController.this, "ICSBC#disconnect: already disconnected; %s",
                        mInCallServiceInfo);
@@ -302,7 +385,7 @@ public class InCallController extends CallsManagerListenerBase {
            InCallController.this.onDisconnected(mInCallServiceInfo);
            disconnect();  // Unbind explicitly if we get disconnected.
            if (mListener != null) {
                mListener.onDisconnect(InCallServiceBindingConnection.this);
                mListener.onDisconnect(InCallServiceBindingConnection.this, mCall);
            }
        }
    }
@@ -319,7 +402,7 @@ public class InCallController extends CallsManagerListenerBase {

        private Listener mSubListener = new Listener() {
            @Override
            public void onDisconnect(InCallServiceConnection subConnection) {
            public void onDisconnect(InCallServiceConnection subConnection, Call call) {
                if (subConnection == mSubConnection) {
                    if (mIsConnected && mIsProxying) {
                        // At this point we know that we need to be connected to the InCallService
@@ -327,7 +410,7 @@ public class InCallController extends CallsManagerListenerBase {
                        // just died so we need to stop proxying and connect to the system in-call
                        // service instead.
                        mIsProxying = false;
                        connect(null);
                        connect(call);
                    }
                }
            }
@@ -799,6 +882,7 @@ public class InCallController extends CallsManagerListenerBase {
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private CarSwappingInCallServiceConnection mInCallServiceConnection;
    private NonUIInCallServiceConnectionCollection mNonUIInCallServiceConnections;
    private final ClockProxy mClockProxy;

    // Future that's in a completed state unless we're in the middle of binding to a service.
    // The future will complete with true if binding succeeds, false if it timed out.
@@ -809,7 +893,8 @@ public class InCallController extends CallsManagerListenerBase {
    public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager,
            SystemStateHelper systemStateHelper,
            DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter,
            EmergencyCallHelper emergencyCallHelper, CarModeTracker carModeTracker) {
            EmergencyCallHelper emergencyCallHelper, CarModeTracker carModeTracker,
            ClockProxy clockProxy) {
        mContext = context;
        mLock = lock;
        mCallsManager = callsManager;
@@ -819,6 +904,7 @@ public class InCallController extends CallsManagerListenerBase {
        mEmergencyCallHelper = emergencyCallHelper;
        mCarModeTracker = carModeTracker;
        mSystemStateHelper.addListener(mSystemStateListener);
        mClockProxy = clockProxy;
    }

    @Override
+1 −1
Original line number Diff line number Diff line
@@ -270,7 +270,7 @@ public class TelecomSystem {
                    EmergencyCallHelper emergencyCallHelper) {
                return new InCallController(context, lock, callsManager, systemStateProvider,
                        defaultDialerCache, timeoutsAdapter, emergencyCallHelper,
                        new CarModeTracker());
                        new CarModeTracker(), clockProxy);
            }
        };

Loading