UWP In-Process AppService connection only when Host app is running

83 Views Asked by At

My UWP app hosts an AppService that runs in the same process as the app does. To do this I have followed this documentation.

The goal of this AppService is to communicate two running Apps.

This is the code I use to allow incoming AppService connections:

        private AppServiceConnection AppServiceConnection;
        private BackgroundTaskDeferral AppServiceDeferral;

        protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
        {
            base.OnBackgroundActivated(args);

            IBackgroundTaskInstance taskInstance = args.TaskInstance;
            AppServiceTriggerDetails appService = taskInstance.TriggerDetails as AppServiceTriggerDetails;
            AppServiceDeferral = taskInstance.GetDeferral();
            taskInstance.Canceled += OnAppServicesCanceled;
            AppServiceConnection = appService.AppServiceConnection;
            AppServiceConnection.RequestReceived += OnAppServiceRequestReceived;
            AppServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed;
        }
        private async void OnAppServiceRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
        {
            AppServiceDeferral messageDeferral = args.GetDeferral();
            ValueSet response = (await IPC.Controller.ProcessIncomeRequests(args.Request.Message.ToDictionary())).ToValueSet();
            await args.Request.SendResponseAsync(response);
            messageDeferral.Complete();
        }

        private void OnAppServicesCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
        {
            AppServiceDeferral.Complete();
        }
        private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
        {
            AppServiceDeferral.Complete();
        }

As mentioned in the following Stackoverflow question, a communication from a 'client' app can be established to the 'host' app even if the 'host' app isn't running. For my purposes, I would like to deny incoming AppServices connections unless the 'host' app is currently running.

Is there a way I can do this? What property could I check within the OnBackgroundActivated method to decide whether to accept the taskInstance or not?

UPDATE:

Is it right to say that the method OnLaunched(LaunchActivatedEventArgs e) is only fired after a "conventional" start up of the app (user launching the app manually)?

If that's the case, then one solution could be to keep track of a boolean variable AppIsRunning:

private static bool AppIsRunning = false;

protected override async void OnLaunched(LaunchActivatedEventArgs e)
{
    ...    
    AppIsRunning = true;
    ...
}

private AppServiceConnection AppServiceConnection;
private BackgroundTaskDeferral AppServiceDeferral;

protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
    base.OnBackgroundActivated(args);

    IBackgroundTaskInstance taskInstance = args.TaskInstance;
    AppServiceTriggerDetails appService = taskInstance.TriggerDetails as AppServiceTriggerDetails;
    AppServiceDeferral = taskInstance.GetDeferral();
    taskInstance.Canceled += OnAppServicesCanceled;
    AppServiceConnection = appService.AppServiceConnection;
    AppServiceConnection.RequestReceived += OnAppServiceRequestReceived;
    AppServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed;
}
private async void OnAppServiceRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
    if (AppIsRunning)
    {
        AppServiceDeferral messageDeferral = args.GetDeferral();
        ValueSet response = (await IPC.Controller.ProcessIncomeRequests(args.Request.Message.ToDictionary())).ToValueSet();
        await args.Request.SendResponseAsync(response);
        messageDeferral.Complete();
    }
}

private void OnAppServicesCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
    AppServiceDeferral.Complete();
}
private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
{
    AppServiceDeferral.Complete();
}

This way the incoming AppService requests wouldn't be handled when the app is not currently running.

2

There are 2 best solutions below

1
On BEST ANSWER

As I have mentioned in my Update to the question, tracking a boolean variable that changes it's default value when the OnLaunched(LaunchActivatedEventArgs e) method is called could be used as a workaround for the required purposes. The value of this variable should be checked before accepting an AppService Request, to decide whether it is accepted or not.

2
On

I would like to deny incoming AppServices connections unless the 'host' app is currently running.

According to the current design, In-Process AppService uses OnBackgroundActivated as EntryPoint. When BackgroundActivated is triggered, the AppService is awakened by the client app. Currently, there is no document API that can determine whether the host app is running.

What property could I check within the OnBackgroundActivated method to decide whether to accept the taskInstance or not?

In OnBackgroundActivated and AppServiceRequestReceivedEvent, there is also no property that can be used to determine whether the host app is running.