1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ondevicepersonalization.services.serviceflow; 18 19 import android.os.Bundle; 20 21 import com.android.ondevicepersonalization.internal.util.LoggerFactory; 22 import com.android.ondevicepersonalization.services.OnDevicePersonalizationExecutors; 23 import com.android.ondevicepersonalization.services.process.IsolatedServiceInfo; 24 import com.android.ondevicepersonalization.services.process.ProcessRunner; 25 import com.android.ondevicepersonalization.services.process.ProcessRunnerFactory; 26 27 import com.google.common.util.concurrent.FluentFuture; 28 import com.google.common.util.concurrent.Futures; 29 import com.google.common.util.concurrent.ListenableFuture; 30 import com.google.common.util.concurrent.ListeningExecutorService; 31 32 /** 33 * Task object representing a service flow task. 34 */ 35 public class ServiceFlowTask { 36 37 private static final LoggerFactory.Logger sLogger = LoggerFactory.getLogger(); 38 private static final String TAG = ServiceFlowTask.class.getSimpleName(); 39 40 private final ServiceFlowType mServiceFlowType; 41 private final ServiceFlow mServiceFlow; 42 private final ProcessRunner mProcessRunner; 43 private volatile boolean mIsCompleted; 44 private volatile Throwable mExecutionThrowable; 45 46 private final ListeningExecutorService mExecutor = 47 OnDevicePersonalizationExecutors.getBackgroundExecutor(); 48 ServiceFlowTask(ServiceFlowType serviceFlowType, ServiceFlow serviceFlow)49 public ServiceFlowTask(ServiceFlowType serviceFlowType, ServiceFlow serviceFlow) { 50 mIsCompleted = false; 51 mServiceFlowType = serviceFlowType; 52 mServiceFlow = serviceFlow; 53 mProcessRunner = ProcessRunnerFactory.getProcessRunner(); 54 } 55 getServiceFlowType()56 public ServiceFlowType getServiceFlowType() { 57 return mServiceFlowType; 58 } 59 getServiceFlow()60 public ServiceFlow getServiceFlow() { 61 return mServiceFlow; 62 } 63 isCompleted()64 public boolean isCompleted() { 65 return mIsCompleted; 66 } 67 getExeuctionThrowable()68 public Throwable getExeuctionThrowable() { 69 return mExecutionThrowable; 70 } 71 72 /** Executes the given service flow. */ run()73 public void run() { 74 try { 75 boolean isServiceFlowReady = mServiceFlow.isServiceFlowReady(); 76 if (mIsCompleted || !isServiceFlowReady) { 77 sLogger.d(TAG + " skipped running %s, isCompleted: %s, isServiceFlowReady: %s", 78 mServiceFlowType, mIsCompleted, isServiceFlowReady); 79 return; 80 } 81 82 ListenableFuture<IsolatedServiceInfo> loadServiceFuture = 83 mProcessRunner.loadIsolatedService( 84 mServiceFlowType.getTaskName(), mServiceFlow.getService()); 85 86 ListenableFuture<Bundle> runServiceFuture = FluentFuture.from(loadServiceFuture) 87 .transformAsync( 88 isolatedServiceInfo -> mProcessRunner 89 .runIsolatedService( 90 isolatedServiceInfo, 91 mServiceFlowType.getOperationCode(), 92 mServiceFlow.getServiceParams()), 93 mExecutor); 94 95 mServiceFlow.uploadServiceFlowMetrics(runServiceFuture); 96 97 ListenableFuture<?> serviceFlowResultFuture = 98 mServiceFlow.getServiceFlowResultFuture(runServiceFuture); 99 100 mServiceFlow.returnResultThroughCallback(serviceFlowResultFuture); 101 102 var unused = 103 Futures.whenAllComplete(loadServiceFuture, serviceFlowResultFuture) 104 .callAsync( 105 () -> { 106 mServiceFlow.cleanUpServiceParams(); 107 ListenableFuture<Void> unloadServiceFuture = 108 mProcessRunner.unloadIsolatedService( 109 loadServiceFuture.get()); 110 mIsCompleted = true; 111 return unloadServiceFuture; 112 }, mExecutor); 113 } catch (Throwable e) { 114 sLogger.e(e, TAG + ": ServiceFlowTask " + mServiceFlowType + " failed."); 115 mExecutionThrowable = e; 116 } 117 } 118 } 119