1 /*
2  * Copyright (C) 2020 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.pm.verify.domain;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresPermission;
23 import android.annotation.UserIdInt;
24 import android.content.Intent;
25 import android.content.pm.IntentFilterVerificationInfo;
26 import android.content.pm.PackageManager;
27 import android.content.pm.PackageManager.NameNotFoundException;
28 import android.content.pm.ResolveInfo;
29 import android.content.pm.verify.domain.DomainSet;
30 import android.content.pm.verify.domain.DomainVerificationInfo;
31 import android.content.pm.verify.domain.DomainVerificationManager;
32 import android.content.pm.verify.domain.DomainVerificationState;
33 import android.os.Binder;
34 import android.os.UserHandle;
35 import android.util.IndentingPrintWriter;
36 import android.util.Pair;
37 
38 import com.android.modules.utils.TypedXmlPullParser;
39 import com.android.modules.utils.TypedXmlSerializer;
40 import com.android.server.pm.Computer;
41 import com.android.server.pm.PackageSetting;
42 import com.android.server.pm.Settings;
43 import com.android.server.pm.pkg.PackageStateInternal;
44 import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
45 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
46 
47 import org.xmlpull.v1.XmlPullParserException;
48 
49 import java.io.IOException;
50 import java.util.List;
51 import java.util.Set;
52 import java.util.UUID;
53 import java.util.function.Function;
54 
55 public interface DomainVerificationManagerInternal {
56 
57     UUID DISABLED_ID = new UUID(0, 0);
58 
59     /**
60      * The app was not installed for the user.
61      */
62     int APPROVAL_LEVEL_NOT_INSTALLED = -4;
63 
64     /**
65      * The app was not enabled for the user.
66      */
67     int APPROVAL_LEVEL_DISABLED = -3;
68 
69     /**
70      * The app has not declared this domain in a valid web intent-filter in their manifest, and so
71      * would never be able to be approved for this domain.
72      */
73     int APPROVAL_LEVEL_UNDECLARED = -2;
74 
75     /**
76      * The app has declared this domain as a valid autoVerify domain, but it failed or has not
77      * succeeded verification.
78      */
79     int APPROVAL_LEVEL_UNVERIFIED = -1;
80 
81     /**
82      * The app has not been approved for this domain and should never be able to open it through
83      * an implicit web intent.
84      */
85     int APPROVAL_LEVEL_NONE = 0;
86 
87     /**
88      * The app has been approved through the legacy
89      * {@link PackageManager#updateIntentVerificationStatusAsUser(String, int, int)} API, which has
90      * been preserved for migration purposes, but is otherwise ignored. Corresponds to
91      * {@link PackageManager#INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK} and
92      * {@link PackageManager#INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK}.
93      *
94      * This should be used as the cutoff for showing a picker if no better approved app exists
95      * during the legacy transition period.
96      *
97      * TODO(b/177923646): The legacy values can be removed once the Settings API changes are
98      * shipped. These values are not stable, so just deleting the constant and shifting others is
99      * fine.
100      */
101     int APPROVAL_LEVEL_LEGACY_ASK = 1;
102 
103     /**
104      * The app has been approved through the legacy
105      * {@link PackageManager#updateIntentVerificationStatusAsUser(String, int, int)} API, which has
106      * been preserved for migration purposes, but is otherwise ignored. Corresponds to
107      * {@link PackageManager#INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS}.
108      */
109     int APPROVAL_LEVEL_LEGACY_ALWAYS = 2;
110 
111     /**
112      * The app has been chosen by the user through
113      * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)},
114      * indicating an explicit choice to use this app to open an unverified domain.
115      */
116     int APPROVAL_LEVEL_SELECTION = 3;
117 
118     /**
119      * The app is approved through the digital asset link statement being hosted at the domain
120      * it is capturing. This is set through
121      * {@link DomainVerificationManager#setDomainVerificationStatus(UUID, Set, int)} by
122      * the domain verification agent on device.
123      */
124     int APPROVAL_LEVEL_VERIFIED = 4;
125 
126     /**
127      * The app has been installed as an instant app, which grants it total authority on the domains
128      * that it declares. It is expected that the package installer validate the domains the app
129      * declares against the digital asset link statements before allowing it to be installed.
130      *
131      * The user is still able to disable instant app link handling through
132      * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String, boolean)}.
133      */
134     int APPROVAL_LEVEL_INSTANT_APP = 5;
135 
136     /**
137      * Defines the possible values for
138      * {@link #approvalLevelForDomain(PackageStateInternal, Intent, int, int)} which sorts packages
139      * by approval priority. A higher numerical value means the package should override all lower
140      * values. This means that comparison using less/greater than IS valid.
141      *
142      * Negative values are possible, used for tracking specific reasons for why an app doesn't have
143      * approval.
144      */
145     @IntDef({
146             APPROVAL_LEVEL_NOT_INSTALLED,
147             APPROVAL_LEVEL_DISABLED,
148             APPROVAL_LEVEL_UNDECLARED,
149             APPROVAL_LEVEL_UNVERIFIED,
150             APPROVAL_LEVEL_NONE,
151             APPROVAL_LEVEL_LEGACY_ASK,
152             APPROVAL_LEVEL_LEGACY_ALWAYS,
153             APPROVAL_LEVEL_SELECTION,
154             APPROVAL_LEVEL_VERIFIED,
155             APPROVAL_LEVEL_INSTANT_APP
156     })
157     @interface ApprovalLevel {
158     }
159 
approvalLevelToDebugString(@pprovalLevel int level)160     static String approvalLevelToDebugString(@ApprovalLevel int level) {
161         switch (level) {
162             case APPROVAL_LEVEL_NOT_INSTALLED:
163                 return "NOT_INSTALLED";
164             case APPROVAL_LEVEL_DISABLED:
165                 return "DISABLED";
166             case APPROVAL_LEVEL_UNDECLARED:
167                 return "UNDECLARED";
168             case APPROVAL_LEVEL_UNVERIFIED:
169                 return "UNVERIFIED";
170             case APPROVAL_LEVEL_NONE:
171                 return "NONE";
172             case APPROVAL_LEVEL_LEGACY_ASK:
173                 return "LEGACY_ASK";
174             case APPROVAL_LEVEL_LEGACY_ALWAYS:
175                 return "LEGACY_ALWAYS";
176             case APPROVAL_LEVEL_SELECTION:
177                 return "USER_SELECTION";
178             case APPROVAL_LEVEL_VERIFIED:
179                 return "VERIFIED";
180             case APPROVAL_LEVEL_INSTANT_APP:
181                 return "INSTANT_APP";
182             default:
183                 return "UNKNOWN";
184         }
185     }
186 
187     /** @see DomainVerificationManager#getDomainVerificationInfo(String) */
188     @Nullable
189     @RequiresPermission(anyOf = {
190             android.Manifest.permission.DOMAIN_VERIFICATION_AGENT,
191             android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
192     })
getDomainVerificationInfo(@onNull String packageName)193     DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
194             throws NameNotFoundException;
195 
196     /**
197      * Generate a new domain set ID to be used for attaching new packages.
198      */
199     @NonNull
generateNewId()200     UUID generateNewId();
201 
setConnection(@onNull Connection connection)202     void setConnection(@NonNull Connection connection);
203 
204     @NonNull
getProxy()205     DomainVerificationProxy getProxy();
206 
207     /**
208      * Update the proxy implementation that talks to the domain verification agent on device. The
209      * default proxy is a stub that does nothing, and broadcast functionality will only work once a
210      * real implementation is attached.
211      */
setProxy(@onNull DomainVerificationProxy proxy)212     void setProxy(@NonNull DomainVerificationProxy proxy);
213 
214     /**
215      * @see DomainVerificationProxy.BaseConnection#runMessage(int, Object)
216      */
runMessage(int messageCode, Object object)217     boolean runMessage(int messageCode, Object object);
218 
219     /**
220      * Restores or creates internal state for the new package. This can either be from scanning a
221      * package at boot, or a truly new installation on the device. It is expected that the {@link
222      * PackageSetting#getDomainSetId()} already be set to the correct value.
223      * <p>
224      * If this is from scan, there should be a pending state that was previous read using {@link
225      * #readSettings(TypedXmlPullParser)}, which will be attached as-is to the package. In this
226      * case, a broadcast will not be sent to the domain verification agent on device, as it is
227      * assumed nothing has changed since the device rebooted.
228      * <p>
229      * If this is a new install, state will be restored from a previous call to {@link
230      * #restoreSettings(Computer, TypedXmlPullParser)}, or a new one will be generated. In either case, a
231      * broadcast will be sent to the domain verification agent so it may re-run any verification
232      * logic for the newly associated domains.
233      * <p>
234      * Optionally, the caller can specify a set of domains that are already pre-verified by the
235      * installer. These domains, if specified with autoVerify in the manifest, will be regarded as
236      * verified as soon as the app is installed, until the domain verification agent sends back the
237      * real verification results.
238      * <p>
239      * This method will mutate internal {@link DomainVerificationPkgState} and so will hold the
240      * internal lock. This should never be called from within the domain verification classes
241      * themselves.
242      * <p>
243      * This will NOT call {@link #writeSettings(Computer, TypedXmlSerializer, boolean, int)}. That must be
244      * handled by the caller.
245      */
addPackage(@onNull PackageStateInternal newPkgSetting, @Nullable DomainSet preVerifiedDomains)246     void addPackage(@NonNull PackageStateInternal newPkgSetting,
247                     @Nullable DomainSet preVerifiedDomains);
248 
249     /**
250      * Migrates verification state from a previous install to a new one. It is expected that the
251      * {@link PackageStateInternal#getDomainSetId()} already be set to the correct value, usually from
252      * {@link #generateNewId()}. This will preserve {@link DomainVerificationState#STATE_SUCCESS}
253      * domains under the assumption that the new package will pass the same server side config as
254      * the previous package, as they have matching signatures.
255      * <p>
256      * Optionally, the caller can specify a set of domains that are already pre-verified by the
257      * installer. These domains, if specified with autoVerify in the manifest, will be regarded as
258      * verified as soon as the app is updated, until the domain verification agent sends back the
259      * real verification results.
260      * <p>
261      * This method will mutate internal {@link DomainVerificationPkgState} and so will hold the
262      * internal lock. This should never be called from within the domain verification classes
263      * themselves.
264      * <p>
265      * This will NOT call {@link #writeSettings(Computer, TypedXmlSerializer, boolean, int)}. That must be
266      * handled by the caller.
267      */
migrateState(@onNull PackageStateInternal oldPkgSetting, @NonNull PackageStateInternal newPkgSetting, @Nullable DomainSet preVerifiedDomains)268     void migrateState(@NonNull PackageStateInternal oldPkgSetting,
269             @NonNull PackageStateInternal newPkgSetting, @Nullable DomainSet preVerifiedDomains);
270 
271     /**
272      * Serializes the entire internal state. This is equivalent to a full backup of the existing
273      * verification state. This write includes legacy state, as a sibling tag the modern state.
274      *
275      * @param snapshot
276      * @param includeSignatures Whether to include the package signatures in the output, mainly
277      *                          used for backing up the user settings and ensuring they're
278      *                          re-attached to the same package.
279      * @param userId The user to write out. Supports {@link UserHandle#USER_ALL} if all users
280      */
writeSettings(@onNull Computer snapshot, @NonNull TypedXmlSerializer serializer, boolean includeSignatures, @UserIdInt int userId)281     void writeSettings(@NonNull Computer snapshot, @NonNull TypedXmlSerializer serializer,
282             boolean includeSignatures, @UserIdInt int userId) throws IOException;
283 
284     /**
285      * Read back a list of {@link DomainVerificationPkgState}s previously written by {@link
286      * #writeSettings(Computer, TypedXmlSerializer, boolean, int)}. Assumes that the
287      * {@link DomainVerificationPersistence#TAG_DOMAIN_VERIFICATIONS} tag has already been entered.
288      * <p>
289      * This is expected to only be used to re-attach states for packages already known to be on the
290      * device. If restoring from a backup, use {@link #restoreSettings(Computer, TypedXmlPullParser)}.
291      */
readSettings(@onNull Computer snapshot, @NonNull TypedXmlPullParser parser)292     void readSettings(@NonNull Computer snapshot, @NonNull TypedXmlPullParser parser)
293             throws IOException, XmlPullParserException;
294 
295     /**
296      * Read back data from
297      * {@link DomainVerificationLegacySettings#writeSettings(TypedXmlSerializer)}. Assumes that the
298      * {@link DomainVerificationLegacySettings#TAG_DOMAIN_VERIFICATIONS_LEGACY} tag has already
299      * been entered.
300      */
readLegacySettings(@onNull TypedXmlPullParser parser)301     void readLegacySettings(@NonNull TypedXmlPullParser parser)
302             throws IOException, XmlPullParserException;
303 
304     /**
305      * Remove all state for the given package.
306      */
clearPackage(@onNull String packageName)307     void clearPackage(@NonNull String packageName);
308 
309     /**
310      * Remove all state for the given package for the given user.
311      */
clearPackageForUser(@onNull String packageName, @UserIdInt int userId)312     void clearPackageForUser(@NonNull String packageName, @UserIdInt int userId);
313 
314     /**
315      * Delete all the state for a user. This can be because the user has been removed from the
316      * device, or simply that the state for a user should be deleted.
317      */
clearUser(@serIdInt int userId)318     void clearUser(@UserIdInt int userId);
319 
320     /**
321      * Restore a list of {@link DomainVerificationPkgState}s previously written by {@link
322      * #writeSettings(Computer, TypedXmlSerializer, boolean, int)}. Assumes that the
323      * {@link DomainVerificationPersistence#TAG_DOMAIN_VERIFICATIONS}
324      * tag has already been entered.
325      * <p>
326      * This is <b>only</b> for restore, and will override package states, ignoring if their {@link
327      * DomainVerificationInfo#getIdentifier()}s match. It's expected that any restored domains
328      * marked
329      * as success verify against the server correctly, although the verification agent may decide
330      * to
331      * re-verify them when it gets the chance.
332      */
333     /*
334      * TODO(b/170746586): Figure out how to verify that package signatures match at snapshot time
335      *  and restore time.
336      */
restoreSettings(@onNull Computer snapshot, @NonNull TypedXmlPullParser parser)337     void restoreSettings(@NonNull Computer snapshot, @NonNull TypedXmlPullParser parser)
338             throws IOException, XmlPullParserException;
339 
340     /**
341      * Set aside a legacy {@link IntentFilterVerificationInfo} that will be restored to a pending
342      * {@link DomainVerificationPkgState} once it's added through
343      * {@link #addPackage(PackageSetting)}.
344      */
addLegacySetting(@onNull String packageName, @NonNull IntentFilterVerificationInfo info)345     void addLegacySetting(@NonNull String packageName, @NonNull IntentFilterVerificationInfo info);
346 
347     /**
348      * Set aside a legacy user selection that will be restored to a pending
349      * {@link DomainVerificationPkgState} once it's added through
350      * {@link #addPackage(PackageSetting)}.
351      *
352      * @return true if state changed successfully
353      */
setLegacyUserState(@onNull String packageName, @UserIdInt int userId, int state)354     boolean setLegacyUserState(@NonNull String packageName, @UserIdInt int userId, int state);
355 
356     /**
357      * Until the legacy APIs are entirely removed, returns the legacy state from the previously
358      * written info stored in {@link Settings}.
359      */
getLegacyState(@onNull String packageName, @UserIdInt int userId)360     int getLegacyState(@NonNull String packageName, @UserIdInt int userId);
361 
362     /**
363      * Print the verification state and user selection state of a package.
364      *
365      * @param snapshot
366      * @param packageName        the package whose state to change, or all packages if none is
367      *                           specified
368      * @param userId             the specific user to print, or null to skip printing user selection
369  *                           states, supports {@link UserHandle#USER_ALL}
370      */
printState(@onNull Computer snapshot, @NonNull IndentingPrintWriter writer, @Nullable String packageName, @Nullable @UserIdInt Integer userId)371     void printState(@NonNull Computer snapshot, @NonNull IndentingPrintWriter writer,
372             @Nullable String packageName, @Nullable @UserIdInt Integer userId)
373             throws NameNotFoundException;
374 
375     @NonNull
getShell()376     DomainVerificationShell getShell();
377 
378     @NonNull
getCollector()379     DomainVerificationCollector getCollector();
380 
381     /**
382      * Filters the provided list down to the {@link ResolveInfo} objects that should be allowed
383      * to open the domain inside the {@link Intent}. It is possible for no packages represented in
384      * the list to be approved, in which case an empty list will be returned.
385      *
386      * @return the filtered list and the corresponding approval level
387      */
388     @NonNull
filterToApprovedApp(@onNull Intent intent, @NonNull List<ResolveInfo> infos, @UserIdInt int userId, @NonNull Function<String, PackageStateInternal> pkgSettingFunction)389     Pair<List<ResolveInfo>, Integer> filterToApprovedApp(@NonNull Intent intent,
390             @NonNull List<ResolveInfo> infos, @UserIdInt int userId,
391             @NonNull Function<String, PackageStateInternal> pkgSettingFunction);
392 
393     /**
394      * Check at what precedence a package resolving a URI is approved to takeover the domain.
395      * This can be because the domain was auto-verified for the package, or if the user manually
396      * chose to enable the domain for the package. If an app is auto-verified, it will be
397      * preferred over apps that were manually selected.
398      *
399      * NOTE: This should not be used for filtering intent resolution. See
400      * {@link #filterToApprovedApp(Intent, List, int, Function)} for that.
401      */
402     @ApprovalLevel
approvalLevelForDomain(@onNull PackageStateInternal pkgSetting, @NonNull Intent intent, @PackageManager.ResolveInfoFlagsBits long resolveInfoFlags, @UserIdInt int userId)403     int approvalLevelForDomain(@NonNull PackageStateInternal pkgSetting, @NonNull Intent intent,
404             @PackageManager.ResolveInfoFlagsBits long resolveInfoFlags, @UserIdInt int userId);
405 
406     /**
407      * @return the domain verification set ID for the given package, or null if the ID is
408      * unavailable
409      */
410     @Nullable
getDomainVerificationInfoId(@onNull String packageName)411     UUID getDomainVerificationInfoId(@NonNull String packageName);
412 
413     @DomainVerificationManager.Error
414     @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT)
setDomainVerificationStatusInternal(int callingUid, @NonNull UUID domainSetId, @NonNull Set<String> domains, int state)415     int setDomainVerificationStatusInternal(int callingUid, @NonNull UUID domainSetId,
416             @NonNull Set<String> domains, int state) throws NameNotFoundException;
417 
418 
419     interface Connection extends DomainVerificationEnforcer.Callback {
420 
421         /**
422          * Notify that a settings change has been made and that eventually
423          * {@link #writeSettings(Computer, TypedXmlSerializer, boolean, int)} should be invoked by the parent.
424          */
scheduleWriteSettings()425         void scheduleWriteSettings();
426 
427         /**
428          * Delegate to {@link Binder#getCallingUid()} to allow mocking in tests.
429          */
getCallingUid()430         int getCallingUid();
431 
432         /**
433          * Delegate to {@link UserHandle#getCallingUserId()} to allow mocking in tests.
434          */
435         @UserIdInt
getCallingUserId()436         int getCallingUserId();
437 
438         /**
439          * @see DomainVerificationProxy.BaseConnection#schedule(int, java.lang.Object)
440          */
schedule(int code, @Nullable Object object)441         void schedule(int code, @Nullable Object object);
442 
443         @UserIdInt
getAllUserIds()444         int[] getAllUserIds();
445 
446         @NonNull
snapshot()447         Computer snapshot();
448     }
449 }
450