1 /* 2 * Copyright (C) 2018 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.server.appbinding; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.Intent; 22 import android.content.pm.IPackageManager; 23 import android.content.pm.ParceledListSlice; 24 import android.content.pm.ResolveInfo; 25 import android.content.pm.ServiceInfo; 26 import android.os.RemoteException; 27 import android.util.Log; 28 29 import java.util.List; 30 31 /** 32 * Utility class to find a persistent bound service within an app. 33 */ 34 public class AppBindingUtils { 35 private static final String TAG = "AppBindingUtils"; AppBindingUtils()36 private AppBindingUtils() { 37 } 38 39 /** 40 * Find a service with the action {@code serviceAction} in the package {@code packageName}. 41 * Returns null in any of the following cases. 42 * - No service with the action is found. 43 * - More than 1 service with the action is found. 44 * - Found service is not protected with the permission {@code servicePermission}. 45 */ 46 @Nullable findService(@onNull String packageName, int userId, String serviceAction, String servicePermission, Class<?> serviceClassForLogging, IPackageManager ipm, StringBuilder errorMessage)47 public static ServiceInfo findService(@NonNull String packageName, int userId, 48 String serviceAction, String servicePermission, 49 Class<?> serviceClassForLogging, 50 IPackageManager ipm, 51 StringBuilder errorMessage) { 52 final String simpleClassName = serviceClassForLogging.getSimpleName(); 53 final Intent intent = new Intent(serviceAction); 54 intent.setPackage(packageName); 55 56 errorMessage.setLength(0); // Clear it. 57 try { 58 final ParceledListSlice<ResolveInfo> pls = ipm 59 .queryIntentServices(intent, null, /* flags=*/ 0, userId); 60 if (pls == null || pls.getList().size() == 0) { 61 errorMessage.append("Service with " + serviceAction + " not found."); 62 return null; 63 } 64 final List<ResolveInfo> list = pls.getList(); 65 // Note if multiple services are found, that's an error, even if only one of them 66 // is exported. 67 if (list.size() > 1) { 68 errorMessage.append("More than one " + simpleClassName + "'s found in package " 69 + packageName + ". They'll all be ignored."); 70 Log.e(TAG, errorMessage.toString()); 71 return null; 72 } 73 final ServiceInfo si = list.get(0).serviceInfo; 74 75 if (!servicePermission.equals(si.permission)) { 76 errorMessage.append(simpleClassName + " " 77 + si.getComponentName().flattenToShortString() 78 + " must be protected with " + servicePermission 79 + "."); 80 Log.e(TAG, errorMessage.toString()); 81 return null; 82 } 83 return si; 84 } catch (RemoteException e) { 85 // Shouldn't happen 86 } 87 return null; 88 } 89 } 90