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