1 /* 2 * Copyright (C) 2022 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; 18 19 import android.annotation.NonNull; 20 import android.content.Context; 21 import android.content.pm.PackageManager; 22 import android.ondevicepersonalization.aidl.IExecuteCallback; 23 import android.ondevicepersonalization.aidl.IOnDevicePersonalizationManagingService; 24 import android.ondevicepersonalization.aidl.IRequestSurfacePackageCallback; 25 import android.os.Binder; 26 import android.os.IBinder; 27 import android.os.PersistableBundle; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.ondevicepersonalization.services.request.AppRequestFlow; 31 import com.android.ondevicepersonalization.services.request.RenderFlow; 32 33 import java.util.Objects; 34 35 /** Implementation of OnDevicePersonalizationManagingService */ 36 public class OnDevicePersonalizationManagingServiceDelegate 37 extends IOnDevicePersonalizationManagingService.Stub { 38 @NonNull private final Context mContext; 39 40 @VisibleForTesting 41 static class Injector { getAppRequestFlow( String callingPackageName, String servicePackageName, PersistableBundle params, IExecuteCallback callback, Context context)42 AppRequestFlow getAppRequestFlow( 43 String callingPackageName, 44 String servicePackageName, 45 PersistableBundle params, 46 IExecuteCallback callback, 47 Context context) { 48 return new AppRequestFlow( 49 callingPackageName, servicePackageName, params, callback, context); 50 } 51 getRenderFlow( String slotResultToken, IBinder hostToken, int displayId, int width, int height, IRequestSurfacePackageCallback callback, Context context)52 RenderFlow getRenderFlow( 53 String slotResultToken, 54 IBinder hostToken, 55 int displayId, 56 int width, 57 int height, 58 IRequestSurfacePackageCallback callback, 59 Context context) { 60 return new RenderFlow( 61 slotResultToken, hostToken, displayId, width, height, callback, context); 62 } 63 } 64 65 @NonNull private final Injector mInjector; 66 OnDevicePersonalizationManagingServiceDelegate(@onNull Context context)67 public OnDevicePersonalizationManagingServiceDelegate(@NonNull Context context) { 68 this(context, new Injector()); 69 } 70 71 @VisibleForTesting OnDevicePersonalizationManagingServiceDelegate( @onNull Context context, @NonNull Injector injector)72 public OnDevicePersonalizationManagingServiceDelegate( 73 @NonNull Context context, 74 @NonNull Injector injector) { 75 mContext = Objects.requireNonNull(context); 76 mInjector = Objects.requireNonNull(injector); 77 } 78 79 @Override getVersion()80 public String getVersion() { 81 return "1.0"; 82 } 83 84 @Override execute( @onNull String callingPackageName, @NonNull String servicePackageName, @NonNull PersistableBundle params, @NonNull IExecuteCallback callback)85 public void execute( 86 @NonNull String callingPackageName, 87 @NonNull String servicePackageName, 88 @NonNull PersistableBundle params, 89 @NonNull IExecuteCallback callback) { 90 Objects.requireNonNull(callingPackageName); 91 Objects.requireNonNull(servicePackageName); 92 Objects.requireNonNull(params); 93 Objects.requireNonNull(callback); 94 95 final int uid = Binder.getCallingUid(); 96 enforceCallingPackageBelongsToUid(callingPackageName, uid); 97 98 AppRequestFlow flow = mInjector.getAppRequestFlow( 99 callingPackageName, 100 servicePackageName, 101 params, 102 callback, 103 mContext); 104 flow.run(); 105 } 106 107 @Override requestSurfacePackage( @onNull String slotResultToken, @NonNull IBinder hostToken, int displayId, int width, int height, @NonNull IRequestSurfacePackageCallback callback)108 public void requestSurfacePackage( 109 @NonNull String slotResultToken, 110 @NonNull IBinder hostToken, 111 int displayId, 112 int width, 113 int height, 114 @NonNull IRequestSurfacePackageCallback callback) { 115 Objects.requireNonNull(slotResultToken); 116 Objects.requireNonNull(hostToken); 117 Objects.requireNonNull(callback); 118 if (width <= 0) { 119 throw new IllegalArgumentException("width must be > 0"); 120 } 121 122 if (height <= 0) { 123 throw new IllegalArgumentException("height must be > 0"); 124 } 125 126 if (displayId < 0) { 127 throw new IllegalArgumentException("displayId must be >= 0"); 128 } 129 130 RenderFlow flow = mInjector.getRenderFlow( 131 slotResultToken, 132 hostToken, 133 displayId, 134 width, 135 height, 136 callback, 137 mContext); 138 flow.run(); 139 } 140 enforceCallingPackageBelongsToUid(@onNull String packageName, int uid)141 private void enforceCallingPackageBelongsToUid(@NonNull String packageName, int uid) { 142 int packageUid; 143 PackageManager pm = mContext.getPackageManager(); 144 try { 145 packageUid = pm.getPackageUid(packageName, 0); 146 } catch (PackageManager.NameNotFoundException e) { 147 throw new SecurityException(packageName + " not found"); 148 } 149 if (packageUid != uid) { 150 throw new SecurityException(packageName + " does not belong to uid " + uid); 151 } 152 //TODO(b/242792629): Handle requests from the SDK sandbox. 153 } 154 } 155