public class

ServiceDispatcher

extends java.lang.Object

 java.lang.Object

↳androidx.car.app.activity.ServiceDispatcher

Gradle dependencies

compile group: 'androidx.car.app', name: 'app-automotive', version: '1.7.0-beta01'

  • groupId: androidx.car.app
  • artifactId: app-automotive
  • version: 1.7.0-beta01

Artifact androidx.car.app:app-automotive:1.7.0-beta01 it located at Google repository (https://maven.google.com/)

Overview

messages dispatcher, responsible for IPC error handling.

Summary

Constructors
publicServiceDispatcher(ErrorHandler errorHandler, ServiceDispatcher.OnBindingListener onBindingListener)

Methods
public voiddispatch(java.lang.String description, ServiceDispatcher.OneWayCall call)

Dispatches the given ServiceDispatcher.OneWayCall.

public voiddispatchNoFail(java.lang.String description, ServiceDispatcher.OneWayCall call)

Dispatches the given ServiceDispatcher.OneWayCall.

public java.lang.Objectfetch(java.lang.String description, java.lang.Object fallbackValue, ServiceDispatcher.ReturnCall<java.lang.Object> call)

Retrieves a value from the service handling any communication error and displaying the error to the user.

public java.lang.ObjectfetchNoFail(java.lang.String description, java.lang.Object fallbackValue, ServiceDispatcher.ReturnCall<java.lang.Object> call)

Retrieves a value from the service, ignoring any communication error and just returning the fallbackValue if an error is encountered in the communication.

public voidsetOnBindingListener(ServiceDispatcher.OnBindingListener onBindingListener)

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public ServiceDispatcher(ErrorHandler errorHandler, ServiceDispatcher.OnBindingListener onBindingListener)

Methods

public void setOnBindingListener(ServiceDispatcher.OnBindingListener onBindingListener)

public void dispatch(java.lang.String description, ServiceDispatcher.OneWayCall call)

Dispatches the given ServiceDispatcher.OneWayCall. This is a non-blocking call.

public void dispatchNoFail(java.lang.String description, ServiceDispatcher.OneWayCall call)

Dispatches the given ServiceDispatcher.OneWayCall. Ignores any errors. This is a non-blocking call.

public java.lang.Object fetch(java.lang.String description, java.lang.Object fallbackValue, ServiceDispatcher.ReturnCall<java.lang.Object> call)

Retrieves a value from the service handling any communication error and displaying the error to the user.

This is a blocking call

Parameters:

description: name for logging purposes
fallbackValue: value to return in case the call is unsuccessful
call: code to execute to retrieve the value

Returns:

the value retrieved or the fallbackValue if the call failed

public java.lang.Object fetchNoFail(java.lang.String description, java.lang.Object fallbackValue, ServiceDispatcher.ReturnCall<java.lang.Object> call)

Retrieves a value from the service, ignoring any communication error and just returning the fallbackValue if an error is encountered in the communication.

This is a blocking call

Parameters:

description: name for logging purposes
fallbackValue: value to return in case the call is unsuccessful
call: code to execute to retrieve the value

Returns:

the value retrieved or the fallbackValue if the call failed

Source

/*
 * Copyright 2021 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 androidx.car.app.activity;

import static androidx.annotation.RestrictTo.Scope.LIBRARY;

import android.os.DeadObjectException;
import android.os.RemoteException;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.car.app.activity.renderer.IRendererService;
import androidx.car.app.serialization.BundlerException;

/**
 * {@link IRendererService} messages dispatcher, responsible for IPC error handling.
 *
 */
@RestrictTo(LIBRARY)
public class ServiceDispatcher {

    /** An interface for monitoring the binding state of a service connection. */
    public interface OnBindingListener {
        /** Returns true if the service connection is bound. */
        boolean isBound();
    }

    private final ErrorHandler mErrorHandler;
    private OnBindingListener mOnBindingListener;

    /** A one way call to the service */
    public interface OneWayCall {
        /** Remote invocation to execute */
        void invoke() throws RemoteException, BundlerException;
    }

    /**
     * A call to fetch a value from the service. This call will block the thread until the value
     * is received
     *
     * @param <T> Type of value to be returned
     */
    // TODO(b/184697399): Remove blocking return callbacks.
    public interface ReturnCall<T> {
        /** Remote invocation to execute */
        @Nullable
        T invoke() throws RemoteException, BundlerException;
    }

    public ServiceDispatcher(@NonNull ErrorHandler errorHandler,
            @NonNull OnBindingListener onBindingListener) {
        mErrorHandler = errorHandler;
        mOnBindingListener = onBindingListener;
    }

    @VisibleForTesting
    public void setOnBindingListener(@NonNull OnBindingListener onBindingListener) {
        mOnBindingListener = onBindingListener;
    }

    /** Dispatches the given {@link OneWayCall}. This is a non-blocking call. */
    public void dispatch(@NonNull String description, @NonNull OneWayCall call) {
        fetch(description, null, (ReturnCall<Void>) () -> {
            call.invoke();
            return null;
        });
    }

    /** Dispatches the given {@link OneWayCall}. Ignores any errors. This is a non-blocking call. */
    public void dispatchNoFail(@NonNull String description, @NonNull OneWayCall call) {
        fetchNoFail(description, null, (ReturnCall<Void>) () -> {
            call.invoke();
            return null;
        });
    }

    /**
     * Retrieves a value from the service handling any communication error and displaying the
     * error to the user.
     *
     * <p>This is a blocking call
     *
     * @param description name for logging purposes
     * @param fallbackValue value to return in case the call is unsuccessful
     * @param call code to execute to retrieve the value
     * @return the value retrieved or the {@code fallbackValue} if the call failed
     */
    // TODO(b/184697399): Remove two-way calls as these are blocking.
    @Nullable
    public <T> T fetch(@NonNull String description, @Nullable T fallbackValue,
            @NonNull ReturnCall<T> call) {
        if (!mOnBindingListener.isBound()) {
            // Avoid dispatching messages if we are not bound to the service
            return fallbackValue;
        }
        try {
            // TODO(b/184697267): Implement ANR (application not responding) checks
            return call.invoke();
        } catch (DeadObjectException e) {
            Log.e(LogTags.TAG, "Connection lost", e);
            mErrorHandler.onError(ErrorHandler.ErrorType.HOST_CONNECTION_LOST);
        } catch (RemoteException e) {
            Log.e(LogTags.TAG, "Remote exception (host render service)", e);
            mErrorHandler.onError(ErrorHandler.ErrorType.HOST_ERROR);
        } catch (BundlerException e) {
            Log.e(LogTags.TAG, "Bundler exception (protocol)", e);
            mErrorHandler.onError(ErrorHandler.ErrorType.CLIENT_SIDE_ERROR);
        } catch (RuntimeException e) {
            Log.e(LogTags.TAG, "Runtime exception (unknown)", e);
            mErrorHandler.onError(ErrorHandler.ErrorType.UNKNOWN_ERROR);
        }
        return fallbackValue;
    }

    /**
     * Retrieves a value from the service, ignoring any communication error and just returning
     * the {@code fallbackValue} if an error is encountered in the communication.
     *
     * <p>This is a blocking call
     *
     * @param description name for logging purposes
     * @param fallbackValue value to return in case the call is unsuccessful
     * @param call code to execute to retrieve the value
     * @return the value retrieved or the {@code fallbackValue} if the call failed
     */
    @Nullable
    public <T> T fetchNoFail(@NonNull String description, @Nullable T fallbackValue,
            @NonNull ReturnCall<T> call) {
        if (!mOnBindingListener.isBound()) {
            // Avoid dispatching messages if we are not bound to the service
            return fallbackValue;
        }
        try {
            // TODO(b/184697267): Implement ANR (application not responding) checks
            return call.invoke();
        } catch (RemoteException e) {
            Log.e(LogTags.TAG, "Remote exception (host render service)", e);
        } catch (BundlerException e) {
            Log.e(LogTags.TAG, "Bundler exception (protocol)", e);
        } catch (RuntimeException e) {
            Log.e(LogTags.TAG, "Runtime exception (unknown)", e);
        }
        return fallbackValue;
    }
}