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