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 static com.android.ondevicepersonalization.services.PhFlags.KEY_SHARED_ISOLATED_PROCESS_FEATURE_ENABLED; 20 21 import android.os.Bundle; 22 23 import com.android.ondevicepersonalization.internal.util.LoggerFactory; 24 import com.android.ondevicepersonalization.services.FlagsFactory; 25 import com.android.ondevicepersonalization.services.OnDevicePersonalizationExecutors; 26 import com.android.ondevicepersonalization.services.process.IsolatedServiceInfo; 27 import com.android.ondevicepersonalization.services.process.PluginProcessRunner; 28 import com.android.ondevicepersonalization.services.process.ProcessRunner; 29 import com.android.ondevicepersonalization.services.process.SharedIsolatedProcessRunner; 30 31 import com.google.common.util.concurrent.FluentFuture; 32 import com.google.common.util.concurrent.Futures; 33 import com.google.common.util.concurrent.ListenableFuture; 34 import com.google.common.util.concurrent.ListeningExecutorService; 35 36 /** 37 * Task object representing a service flow task. 38 */ 39 public class ServiceFlowTask { 40 41 private static final LoggerFactory.Logger sLogger = LoggerFactory.getLogger(); 42 private static final String TAG = ServiceFlowTask.class.getSimpleName(); 43 44 private final ServiceFlowType mServiceFlowType; 45 private final ServiceFlow mServiceFlow; 46 private final ProcessRunner mProcessRunner; 47 private volatile boolean mIsCompleted; 48 private volatile Exception mExecutionException; 49 50 private final ListeningExecutorService mExecutor = 51 OnDevicePersonalizationExecutors.getBackgroundExecutor(); 52 ServiceFlowTask(ServiceFlowType serviceFlowType, ServiceFlow serviceFlow)53 public ServiceFlowTask(ServiceFlowType serviceFlowType, ServiceFlow serviceFlow) { 54 mIsCompleted = false; 55 mServiceFlowType = serviceFlowType; 56 mServiceFlow = serviceFlow; 57 mProcessRunner = 58 (boolean) FlagsFactory.getFlags() 59 .getStableFlag(KEY_SHARED_ISOLATED_PROCESS_FEATURE_ENABLED) 60 ? SharedIsolatedProcessRunner.getInstance() 61 : PluginProcessRunner.getInstance(); 62 } 63 getServiceFlowType()64 public ServiceFlowType getServiceFlowType() { 65 return mServiceFlowType; 66 } 67 getServiceFlow()68 public ServiceFlow getServiceFlow() { 69 return mServiceFlow; 70 } 71 isCompleted()72 public boolean isCompleted() { 73 return mIsCompleted; 74 } 75 getExecutionException()76 public Exception getExecutionException() { 77 return mExecutionException; 78 } 79 80 /** Executes the given service flow. */ run()81 public void run() { 82 try { 83 if (mIsCompleted || !mServiceFlow.isServiceFlowReady()) { 84 sLogger.d(TAG + ": Unexpected service flow state for " + mServiceFlowType); 85 return; 86 } 87 88 ListenableFuture<IsolatedServiceInfo> loadServiceFuture = 89 mProcessRunner.loadIsolatedService( 90 mServiceFlowType.getTaskName(), mServiceFlow.getService()); 91 92 ListenableFuture<Bundle> runServiceFuture = FluentFuture.from(loadServiceFuture) 93 .transformAsync( 94 isolatedServiceInfo -> mProcessRunner 95 .runIsolatedService( 96 isolatedServiceInfo, 97 mServiceFlowType.getOperationCode(), 98 mServiceFlow.getServiceParams()), 99 mExecutor); 100 101 mServiceFlow.uploadServiceFlowMetrics(runServiceFuture); 102 103 ListenableFuture<?> serviceFlowResultFuture = 104 mServiceFlow.getServiceFlowResultFuture(runServiceFuture); 105 106 mServiceFlow.returnResultThroughCallback(serviceFlowResultFuture); 107 108 var unused = 109 Futures.whenAllComplete(loadServiceFuture, serviceFlowResultFuture) 110 .callAsync( 111 () -> { 112 mServiceFlow.cleanUpServiceParams(); 113 ListenableFuture<Void> unloadServiceFuture = 114 mProcessRunner.unloadIsolatedService( 115 loadServiceFuture.get()); 116 mIsCompleted = true; 117 return unloadServiceFuture; 118 }, mExecutor); 119 } catch (Exception e) { 120 sLogger.w(TAG + ": ServiceFlowTask " + mServiceFlowType + "failed. " + e); 121 mExecutionException = e; 122 } 123 } 124 } 125