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.server.credentials; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.ComponentName; 22 import android.content.pm.PackageManager; 23 import android.content.pm.ServiceInfo; 24 import android.credentials.CredentialProviderInfo; 25 import android.service.credentials.CredentialProviderInfoFactory; 26 import android.util.Slog; 27 28 import com.android.internal.annotations.GuardedBy; 29 import com.android.server.infra.AbstractPerUserSystemService; 30 31 import java.util.List; 32 33 34 /** 35 * Per-user, per remote service implementation of {@link CredentialManagerService} 36 */ 37 public final class CredentialManagerServiceImpl extends 38 AbstractPerUserSystemService<CredentialManagerServiceImpl, CredentialManagerService> { 39 private static final String TAG = "CredManSysServiceImpl"; 40 41 @GuardedBy("mLock") 42 @NonNull 43 private CredentialProviderInfo mInfo; 44 CredentialManagerServiceImpl( @onNull CredentialManagerService master, @NonNull Object lock, int userId, String serviceName)45 CredentialManagerServiceImpl( 46 @NonNull CredentialManagerService master, 47 @NonNull Object lock, int userId, String serviceName) 48 throws PackageManager.NameNotFoundException { 49 super(master, lock, userId); 50 Slog.i(TAG, "CredentialManagerServiceImpl constructed for: " + serviceName); 51 synchronized (mLock) { 52 newServiceInfoLocked(ComponentName.unflattenFromString(serviceName)); 53 } 54 } 55 56 @GuardedBy("mLock") getComponentName()57 public ComponentName getComponentName() { 58 return mInfo.getServiceInfo().getComponentName(); 59 } 60 CredentialManagerServiceImpl( @onNull CredentialManagerService master, @NonNull Object lock, int userId, CredentialProviderInfo providerInfo)61 CredentialManagerServiceImpl( 62 @NonNull CredentialManagerService master, 63 @NonNull Object lock, int userId, CredentialProviderInfo providerInfo) { 64 super(master, lock, userId); 65 Slog.i(TAG, "CredentialManagerServiceImpl constructed for: " 66 + providerInfo.getServiceInfo().getComponentName().flattenToString()); 67 mInfo = providerInfo; 68 } 69 70 @Override // from PerUserSystemService when a new setting based service is to be created 71 @GuardedBy("mLock") newServiceInfoLocked(@onNull ComponentName serviceComponent)72 protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent) 73 throws PackageManager.NameNotFoundException { 74 if (mInfo != null) { 75 Slog.i(TAG, "newServiceInfoLocked, mInfo not null : " 76 + mInfo.getServiceInfo().getComponentName().flattenToString() + " , " 77 + serviceComponent.flattenToString()); 78 } else { 79 Slog.i(TAG, "newServiceInfoLocked, mInfo null, " 80 + serviceComponent.flattenToString()); 81 } 82 mInfo = CredentialProviderInfoFactory.create( 83 getContext(), serviceComponent, 84 mUserId, /*isSystemProvider=*/false); 85 return mInfo.getServiceInfo(); 86 } 87 88 /** 89 * Starts a provider session and associates it with the given request session. 90 */ 91 @Nullable 92 @GuardedBy("mLock") initiateProviderSessionForRequestLocked( RequestSession requestSession, List<String> requestOptions)93 public ProviderSession initiateProviderSessionForRequestLocked( 94 RequestSession requestSession, List<String> requestOptions) { 95 if (!requestOptions.isEmpty() && !isServiceCapableLocked(requestOptions)) { 96 Slog.i(TAG, "Service does not have the required capabilities"); 97 return null; 98 } 99 if (mInfo == null) { 100 Slog.w(TAG, "Initiating provider session for request " 101 + "but mInfo is null. This shouldn't happen"); 102 return null; 103 } 104 final RemoteCredentialService remoteService = new RemoteCredentialService( 105 getContext(), mInfo.getServiceInfo().getComponentName(), mUserId); 106 return requestSession.initiateProviderSession(mInfo, remoteService); 107 } 108 109 /** Return true if at least one capability found. */ 110 @GuardedBy("mLock") isServiceCapableLocked(List<String> requestedOptions)111 boolean isServiceCapableLocked(List<String> requestedOptions) { 112 if (mInfo == null) { 113 return false; 114 } 115 for (String capability : requestedOptions) { 116 if (mInfo.hasCapability(capability)) { 117 return true; 118 } 119 } 120 return false; 121 } 122 123 @GuardedBy("mLock") getCredentialProviderInfo()124 public CredentialProviderInfo getCredentialProviderInfo() { 125 return mInfo; 126 } 127 128 /** 129 * Callback called when an app has been updated. 130 * 131 * @param packageName package of the app being updated. 132 */ 133 @GuardedBy("mLock") handlePackageUpdateLocked(@onNull String packageName)134 protected void handlePackageUpdateLocked(@NonNull String packageName) { 135 if (mInfo != null && mInfo.getServiceInfo() != null 136 && mInfo.getServiceInfo().getComponentName() 137 .getPackageName().equals(packageName)) { 138 try { 139 newServiceInfoLocked(mInfo.getServiceInfo().getComponentName()); 140 } catch (PackageManager.NameNotFoundException e) { 141 Slog.e(TAG, "Issue while updating serviceInfo: " + e.getMessage()); 142 } 143 } 144 } 145 } 146