content: /*
   * Copyright (C) 2018 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.android.server.appbinding;
  
  import android.annotation.NonNull;
  import android.annotation.Nullable;
  import android.content.Intent;
  import android.content.pm.IPackageManager;
  import android.content.pm.ParceledListSlice;
  import android.content.pm.ResolveInfo;
  import android.content.pm.ServiceInfo;
  import android.os.RemoteException;
  import android.util.Log;
  
  import java.util.List;
  
  /**
   * Utility class to find a persistent bound service within an app.
   */
  public class AppBindingUtils {
      private static final String TAG = "AppBindingUtils";
      private AppBindingUtils() {
      }
  
      /**
       * Find a service with the action {@code serviceAction} in the package {@code packageName}.
       * Returns null in any of the following cases.
       * - No service with the action is found.
       * - More than 1 service with the action is found.
       * - Found service is not protected with the permission {@code servicePermission}.
       */
      @Nullable
      public static ServiceInfo findService(@NonNull String packageName, int userId,
              String serviceAction, String servicePermission,
              Class<?> serviceClassForLogging,
              IPackageManager ipm,
              StringBuilder errorMessage) {
          final String simpleClassName = serviceClassForLogging.getSimpleName();
          final Intent intent = new Intent(serviceAction);
          intent.setPackage(packageName);
  
          errorMessage.setLength(0); // Clear it.
          try {
              final ParceledListSlice<ResolveInfo> pls = ipm
                      .queryIntentServices(intent, null, /* flags=*/ 0, userId);
              if (pls == null || pls.getList().size() == 0) {
                  errorMessage.append("Service with " + serviceAction + " not found.");
                  return null;
              }
              final List<ResolveInfo> list = pls.getList();
              // Note if multiple services are found, that's an error, even if only one of them
              // is exported.
              if (list.size() > 1) {
                  errorMessage.append("More than one " + simpleClassName + "'s found in package "
                                  + packageName + ".  They'll all be ignored.");
                  Log.e(TAG, errorMessage.toString());
                  return null;
              }
              final ServiceInfo si = list.get(0).serviceInfo;
  
              if (!servicePermission.equals(si.permission)) {
                  errorMessage.append(simpleClassName + " "
                          + si.getComponentName().flattenToShortString()
                          + " must be protected with " + servicePermission
                          + ".");
                  Log.e(TAG, errorMessage.toString());
                  return null;
              }
              return si;
          } catch (RemoteException e) {
              // Shouldn't happen
          }
          return null;
      }
  }
  