• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.content.pm.parsing.result;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.Context;
22 import android.content.pm.ApplicationInfo;
23 import android.content.pm.PackageManager;
24 import android.os.ServiceManager;
25 import android.util.ArrayMap;
26 import android.util.Log;
27 import android.util.Slog;
28 
29 import com.android.internal.compat.IPlatformCompat;
30 import com.android.internal.util.CollectionUtils;
31 
32 /** @hide */
33 public class ParseTypeImpl implements ParseInput, ParseResult<Object> {
34 
35     private static final String TAG = "ParseTypeImpl";
36 
37     public static final boolean DEBUG_FILL_STACK_TRACE = false;
38 
39     public static final boolean DEBUG_LOG_ON_ERROR = false;
40 
41     public static final boolean DEBUG_THROW_ALL_ERRORS = false;
42 
43     @NonNull
44     private final Callback mCallback;
45 
46     private Object mResult;
47 
48     private int mErrorCode = PackageManager.INSTALL_SUCCEEDED;
49 
50     @Nullable
51     private String mErrorMessage;
52 
53     @Nullable
54     private Exception mException;
55 
56     /**
57      * Errors encountered before targetSdkVersion is known.
58      * The size upper bound is the number of longs in {@link DeferredError}
59      */
60     @Nullable
61     private ArrayMap<Long, String> mDeferredErrors = null;
62 
63     private String mPackageName;
64     private int mTargetSdkVersion = -1;
65 
66     /**
67      * Specifically for {@link PackageManager#getPackageArchiveInfo(String, int)} where
68      * {@link IPlatformCompat} cannot be used because the cross-package READ_COMPAT_CHANGE_CONFIG
69      * permission cannot be obtained.
70      */
forParsingWithoutPlatformCompat()71     public static ParseTypeImpl forParsingWithoutPlatformCompat() {
72         return new ParseTypeImpl((changeId, packageName, targetSdkVersion) -> {
73             int gateSdkVersion = DeferredError.getTargetSdkForChange(changeId);
74             if (gateSdkVersion == -1) {
75                 return false;
76             }
77             return targetSdkVersion > gateSdkVersion;
78         });
79     }
80 
81     /**
82      * Assumes {@link Context#PLATFORM_COMPAT_SERVICE} is available to the caller. For use
83      * with {@link android.content.pm.parsing.ApkLiteParseUtils} or similar where parsing is
84      * done outside of {@link com.android.server.pm.PackageManagerService}.
85      */
forDefaultParsing()86     public static ParseTypeImpl forDefaultParsing() {
87         IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
88                 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
89         return new ParseTypeImpl((changeId, packageName, targetSdkVersion) -> {
90             ApplicationInfo appInfo = new ApplicationInfo();
91             appInfo.packageName = packageName;
92             appInfo.targetSdkVersion = targetSdkVersion;
93             try {
94                 return platformCompat.isChangeEnabled(changeId, appInfo);
95             } catch (Exception e) {
96                 // This shouldn't happen, but assume enforcement if it does
97                 Slog.wtf(TAG, "IPlatformCompat query failed", e);
98                 return true;
99             }
100         });
101     }
102 
103     /**
104      * @param callback if nullable, fallback to manual targetSdk > Q check
105      */
106     public ParseTypeImpl(@NonNull Callback callback) {
107         mCallback = callback;
108     }
109 
110     public ParseInput reset() {
111         mResult = null;
112         mErrorCode = PackageManager.INSTALL_SUCCEEDED;
113         mErrorMessage = null;
114         mException = null;
115         if (mDeferredErrors != null) {
116             // If the memory was already allocated, don't bother freeing and re-allocating,
117             // as this could occur hundreds of times depending on what the caller is doing and
118             // how many APKs they're going through.
119             mDeferredErrors.erase();
120         }
121         mTargetSdkVersion = -1;
122         return this;
123     }
124 
125     @Override
126     public <ResultType> ParseResult<ResultType> success(ResultType result) {
127         if (mErrorCode != PackageManager.INSTALL_SUCCEEDED) {
128             Slog.wtf(TAG, "Cannot set to success after set to error, was "
129                     + mErrorMessage, mException);
130         }
131         mResult = result;
132         //noinspection unchecked
133         return (ParseResult<ResultType>) this;
134     }
135 
136     @Override
137     public ParseResult<?> deferError(@NonNull String parseError, long deferredError) {
138         if (DEBUG_THROW_ALL_ERRORS) {
139             return error(parseError);
140         }
141         if (mTargetSdkVersion != -1) {
142             if (mDeferredErrors != null && mDeferredErrors.containsKey(deferredError)) {
143                 // If the map already contains the key, that means it's already been checked and
144                 // found to be disabled. Otherwise it would've failed when mTargetSdkVersion was
145                 // set to non-null.
146                 return success(null);
147             }
148 
149             if (mCallback.isChangeEnabled(deferredError, mPackageName, mTargetSdkVersion)) {
150                 return error(parseError);
151             } else {
152                 if (mDeferredErrors == null) {
153                     mDeferredErrors = new ArrayMap<>();
154                 }
155                 mDeferredErrors.put(deferredError, null);
156                 return success(null);
157             }
158         }
159 
160         if (mDeferredErrors == null) {
161             mDeferredErrors = new ArrayMap<>();
162         }
163 
164         // Only save the first occurrence of any particular error
165         mDeferredErrors.putIfAbsent(deferredError, parseError);
166         return success(null);
167     }
168 
169     @Override
170     public ParseResult<?> enableDeferredError(String packageName, int targetSdkVersion) {
171         mPackageName = packageName;
172         mTargetSdkVersion = targetSdkVersion;
173 
174         int size = CollectionUtils.size(mDeferredErrors);
175         for (int index = size - 1; index >= 0; index--) {
176             long changeId = mDeferredErrors.keyAt(index);
177             String errorMessage = mDeferredErrors.valueAt(index);
178             if (mCallback.isChangeEnabled(changeId, mPackageName, mTargetSdkVersion)) {
179                 return error(errorMessage);
180             } else {
181                 // No point holding onto the string, but need to maintain the key to signal
182                 // that the error was checked with isChangeEnabled and found to be disabled.
183                 mDeferredErrors.setValueAt(index, null);
184             }
185         }
186 
187         return success(null);
188     }
189 
190     @Override
191     public <ResultType> ParseResult<ResultType> skip(@NonNull String parseError) {
192         return error(PackageManager.INSTALL_PARSE_FAILED_SKIPPED, parseError);
193     }
194 
195     @Override
196     public <ResultType> ParseResult<ResultType> error(int parseError) {
197         return error(parseError, null);
198     }
199 
200     @Override
201     public <ResultType> ParseResult<ResultType> error(@NonNull String parseError) {
202         return error(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, parseError);
203     }
204 
205     @Override
206     public <ResultType> ParseResult<ResultType> error(int errorCode,
207             @Nullable String errorMessage) {
208         return error(errorCode, errorMessage, null);
209     }
210 
211     @Override
212     public <ResultType> ParseResult<ResultType> error(ParseResult<?> intentResult) {
213         return error(intentResult.getErrorCode(), intentResult.getErrorMessage(),
214                 intentResult.getException());
215     }
216 
217     @Override
218     public <ResultType> ParseResult<ResultType> error(int errorCode, @Nullable String errorMessage,
219             Exception exception) {
220         mErrorCode = errorCode;
221         mErrorMessage = errorMessage;
222         mException = exception;
223 
224         if (DEBUG_FILL_STACK_TRACE) {
225             if (exception == null) {
226                 mException = new Exception();
227             }
228         }
229 
230         if (DEBUG_LOG_ON_ERROR) {
231             Exception exceptionToLog = mException != null ? mException : new Exception();
232             Log.w(TAG, "ParseInput set to error " + errorCode + ", " + errorMessage,
233                     exceptionToLog);
234         }
235 
236         //noinspection unchecked
237         return (ParseResult<ResultType>) this;
238     }
239 
240     @Override
241     public Object getResult() {
242         return mResult;
243     }
244 
245     @Override
246     public boolean isSuccess() {
247         return mErrorCode == PackageManager.INSTALL_SUCCEEDED;
248     }
249 
250     @Override
251     public boolean isError() {
252         return !isSuccess();
253     }
254 
255     @Override
256     public int getErrorCode() {
257         return mErrorCode;
258     }
259 
260     @Nullable
261     @Override
262     public String getErrorMessage() {
263         return mErrorMessage;
264     }
265 
266     @Nullable
267     @Override
268     public Exception getException() {
269         return mException;
270     }
271 }
272