Loading proto/telecom.proto +7 −0 Original line number Diff line number Diff line Loading @@ -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. Loading res/values/strings.xml +11 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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". --> Loading src/com/android/server/telecom/Analytics.java +11 −3 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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 Loading Loading @@ -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("]"); Loading src/com/android/server/telecom/InCallController.java +97 −11 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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 { /** Loading @@ -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; Loading @@ -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 { Loading @@ -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, Loading Loading @@ -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) { Loading Loading @@ -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 Loading Loading @@ -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, Loading @@ -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; } Loading @@ -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); Loading Loading @@ -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); } } } Loading @@ -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 Loading @@ -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); } } } Loading Loading @@ -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. Loading @@ -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; Loading @@ -819,6 +904,7 @@ public class InCallController extends CallsManagerListenerBase { mEmergencyCallHelper = emergencyCallHelper; mCarModeTracker = carModeTracker; mSystemStateHelper.addListener(mSystemStateListener); mClockProxy = clockProxy; } @Override Loading src/com/android/server/telecom/TelecomSystem.java +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
proto/telecom.proto +7 −0 Original line number Diff line number Diff line Loading @@ -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. Loading
res/values/strings.xml +11 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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". --> Loading
src/com/android/server/telecom/Analytics.java +11 −3 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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 Loading Loading @@ -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("]"); Loading
src/com/android/server/telecom/InCallController.java +97 −11 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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 { /** Loading @@ -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; Loading @@ -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 { Loading @@ -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, Loading Loading @@ -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) { Loading Loading @@ -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 Loading Loading @@ -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, Loading @@ -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; } Loading @@ -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); Loading Loading @@ -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); } } } Loading @@ -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 Loading @@ -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); } } } Loading Loading @@ -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. Loading @@ -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; Loading @@ -819,6 +904,7 @@ public class InCallController extends CallsManagerListenerBase { mEmergencyCallHelper = emergencyCallHelper; mCarModeTracker = carModeTracker; mSystemStateHelper.addListener(mSystemStateListener); mClockProxy = clockProxy; } @Override Loading
src/com/android/server/telecom/TelecomSystem.java +1 −1 Original line number Diff line number Diff line Loading @@ -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