• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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;
18 
19 import android.content.pm.PackageManager;
20 import android.util.SparseBooleanArray;
21 
22 /**
23  * Tracks the package verification state for a particular package. Each package verification has a
24  * required verifier and zero or more sufficient verifiers. Only one of the sufficient verifier list
25  * must return affirmative to allow the package to be considered verified. If there are zero
26  * sufficient verifiers, then package verification is considered complete.
27  */
28 class PackageVerificationState {
29     private final VerifyingSession mVerifyingSession;
30 
31     private final SparseBooleanArray mSufficientVerifierUids;
32 
33     private final SparseBooleanArray mRequiredVerifierUids;
34     private final SparseBooleanArray mUnrespondedRequiredVerifierUids;
35 
36     private final SparseBooleanArray mExtendedTimeoutUids;
37 
38     private boolean mSufficientVerificationComplete;
39 
40     private boolean mSufficientVerificationPassed;
41 
42     private boolean mRequiredVerificationComplete;
43 
44     private boolean mRequiredVerificationPassed;
45 
46     /**
47      * Create a new package verification state where {@code requiredVerifierUid} is the user ID for
48      * the package that must reply affirmative before things can continue.
49      */
PackageVerificationState(VerifyingSession verifyingSession)50     PackageVerificationState(VerifyingSession verifyingSession) {
51         mVerifyingSession = verifyingSession;
52         mSufficientVerifierUids = new SparseBooleanArray();
53         mRequiredVerifierUids = new SparseBooleanArray();
54         mUnrespondedRequiredVerifierUids = new SparseBooleanArray();
55         mExtendedTimeoutUids = new SparseBooleanArray();
56         mRequiredVerificationComplete = false;
57         mRequiredVerificationPassed = true;
58     }
59 
getVerifyingSession()60     VerifyingSession getVerifyingSession() {
61         return mVerifyingSession;
62     }
63 
64     /** Add the user ID of the required package verifier. */
addRequiredVerifierUid(int uid)65     void addRequiredVerifierUid(int uid) {
66         mRequiredVerifierUids.put(uid, true);
67         mUnrespondedRequiredVerifierUids.put(uid, true);
68     }
69 
70     /** Returns true if the uid a required verifier. */
checkRequiredVerifierUid(int uid)71     boolean checkRequiredVerifierUid(int uid) {
72         return mRequiredVerifierUids.get(uid, false);
73     }
74 
75     /**
76      * Add a verifier which is added to our sufficient list.
77      *
78      * @param uid user ID of sufficient verifier
79      */
addSufficientVerifier(int uid)80     void addSufficientVerifier(int uid) {
81         mSufficientVerifierUids.put(uid, true);
82     }
83 
84     /** Returns true if the uid a sufficient verifier. */
checkSufficientVerifierUid(int uid)85     boolean checkSufficientVerifierUid(int uid) {
86         return mSufficientVerifierUids.get(uid, false);
87     }
88 
setVerifierResponseOnTimeout(int uid, int code)89     void setVerifierResponseOnTimeout(int uid, int code) {
90         if (!checkRequiredVerifierUid(uid)) {
91             return;
92         }
93 
94         // Timeout, not waiting for the sufficient verifiers anymore.
95         mSufficientVerifierUids.clear();
96 
97         // Only if unresponded.
98         if (mUnrespondedRequiredVerifierUids.get(uid, false)) {
99             setVerifierResponse(uid, code);
100         }
101     }
102 
103     /**
104      * Should be called when a verification is received from an agent so the state of the package
105      * verification can be tracked.
106      *
107      * @param uid user ID of the verifying agent
108      */
setVerifierResponse(int uid, int code)109     void setVerifierResponse(int uid, int code) {
110         if (mRequiredVerifierUids.get(uid)) {
111             switch (code) {
112                 case PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT:
113                     mSufficientVerifierUids.clear();
114                     // fall through
115                 case PackageManager.VERIFICATION_ALLOW:
116                     // Two possible options:
117                     // - verification result is true,
118                     // - another verifier set it to false.
119                     // In both cases we don't need to assign anything, just exit.
120                     break;
121                 default:
122                     mRequiredVerificationPassed = false;
123                     // Required verifier rejected, no need to wait for the rest.
124                     mUnrespondedRequiredVerifierUids.clear();
125                     mSufficientVerifierUids.clear();
126                     mExtendedTimeoutUids.clear();
127             }
128 
129             // Responded, no need to extend timeout.
130             mExtendedTimeoutUids.delete(uid);
131 
132             mUnrespondedRequiredVerifierUids.delete(uid);
133             if (mUnrespondedRequiredVerifierUids.size() == 0) {
134                 mRequiredVerificationComplete = true;
135             }
136         } else if (mSufficientVerifierUids.get(uid)) {
137             if (code == PackageManager.VERIFICATION_ALLOW) {
138                 mSufficientVerificationPassed = true;
139                 mSufficientVerificationComplete = true;
140             }
141 
142             mSufficientVerifierUids.delete(uid);
143             if (mSufficientVerifierUids.size() == 0) {
144                 mSufficientVerificationComplete = true;
145             }
146         }
147     }
148 
149     /**
150      * Mark the session as passed required verification.
151      */
passRequiredVerification()152     void passRequiredVerification() {
153         if (mUnrespondedRequiredVerifierUids.size() > 0) {
154             throw new RuntimeException("Required verifiers still present.");
155         }
156         mRequiredVerificationPassed = true;
157         mRequiredVerificationComplete = true;
158     }
159 
160     /**
161      * Returns whether verification is considered complete. This means that the required verifier
162      * and at least one of the sufficient verifiers has returned a positive verification.
163      *
164      * @return {@code true} when verification is considered complete
165      */
isVerificationComplete()166     boolean isVerificationComplete() {
167         if (!mRequiredVerificationComplete) {
168             return false;
169         }
170 
171         if (mSufficientVerifierUids.size() == 0) {
172             return true;
173         }
174 
175         return mSufficientVerificationComplete;
176     }
177 
178     /**
179      * Returns whether installation should be allowed. This should only be called after {@link
180      * #isVerificationComplete()} returns {@code true}.
181      *
182      * @return {@code true} if installation should be allowed
183      */
isInstallAllowed()184     boolean isInstallAllowed() {
185         if (!mRequiredVerificationComplete || !mRequiredVerificationPassed) {
186             return false;
187         }
188 
189         if (mSufficientVerificationComplete) {
190             return mSufficientVerificationPassed;
191         }
192 
193         return true;
194     }
195 
196     /** Extend the timeout for this Package to be verified. */
extendTimeout(int uid)197     boolean extendTimeout(int uid) {
198         if (!checkRequiredVerifierUid(uid) || timeoutExtended(uid)) {
199             return false;
200         }
201         mExtendedTimeoutUids.append(uid, true);
202         return true;
203     }
204 
205     /**
206      * Returns whether the timeout was extended for verification.
207      *
208      * @return {@code true} if a timeout was already extended.
209      */
timeoutExtended(int uid)210     boolean timeoutExtended(int uid) {
211         return mExtendedTimeoutUids.get(uid, false);
212     }
213 
areAllVerificationsComplete()214     boolean areAllVerificationsComplete() {
215         return isVerificationComplete();
216     }
217 }
218