• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.pm.local;
18 
19 import android.annotation.CallSuper;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.UserIdInt;
23 import android.content.pm.SigningDetails;
24 import android.os.Binder;
25 import android.os.Build;
26 import android.os.UserHandle;
27 import android.util.ArrayMap;
28 import android.util.apk.ApkSignatureVerifier;
29 
30 import com.android.server.pm.Computer;
31 import com.android.server.pm.PackageManagerLocal;
32 import com.android.server.pm.PackageManagerService;
33 import com.android.server.pm.pkg.PackageState;
34 import com.android.server.pm.pkg.PackageStateInternal;
35 import com.android.server.pm.pkg.SharedUserApi;
36 import com.android.server.pm.snapshot.PackageDataSnapshot;
37 
38 import java.io.IOException;
39 import java.util.Collections;
40 import java.util.List;
41 import java.util.Map;
42 
43 /** @hide */
44 public class PackageManagerLocalImpl implements PackageManagerLocal {
45 
46     private final PackageManagerService mService;
47 
PackageManagerLocalImpl(PackageManagerService service)48     public PackageManagerLocalImpl(PackageManagerService service) {
49         mService = service;
50     }
51 
52     @Override
reconcileSdkData(@ullable String volumeUuid, @NonNull String packageName, @NonNull List<String> subDirNames, int userId, int appId, int previousAppId, @NonNull String seInfo, int flags)53     public void reconcileSdkData(@Nullable String volumeUuid, @NonNull String packageName,
54             @NonNull List<String> subDirNames, int userId, int appId, int previousAppId,
55             @NonNull String seInfo, int flags) throws IOException {
56         mService.reconcileSdkData(volumeUuid, packageName, subDirNames, userId, appId,
57                 previousAppId, seInfo, flags);
58     }
59 
60     @NonNull
61     @Override
withUnfilteredSnapshot()62     public UnfilteredSnapshotImpl withUnfilteredSnapshot() {
63         return new UnfilteredSnapshotImpl(mService.snapshotComputer(false /*allowLiveComputer*/));
64     }
65 
66     @NonNull
67     @Override
withFilteredSnapshot()68     public FilteredSnapshotImpl withFilteredSnapshot() {
69         return withFilteredSnapshot(Binder.getCallingUid(), Binder.getCallingUserHandle());
70     }
71 
72     @NonNull
73     @Override
withFilteredSnapshot(int callingUid, @NonNull UserHandle user)74     public FilteredSnapshotImpl withFilteredSnapshot(int callingUid, @NonNull UserHandle user) {
75         return withFilteredSnapshot(callingUid, user, /* uncommittedPs= */ null);
76     }
77 
78     /**
79      * Creates a {@link FilteredSnapshot} with a uncommitted {@link PackageState} that is used for
80      * dexopt in the art service to get the correct package state before the package is committed.
81      */
82     @NonNull
withFilteredSnapshot(PackageManagerLocal pm, @NonNull PackageState uncommittedPs)83     public static FilteredSnapshotImpl withFilteredSnapshot(PackageManagerLocal pm,
84             @NonNull PackageState uncommittedPs) {
85         return ((PackageManagerLocalImpl) pm).withFilteredSnapshot(Binder.getCallingUid(),
86                 Binder.getCallingUserHandle(), uncommittedPs);
87     }
88 
89     @NonNull
withFilteredSnapshot(int callingUid, @NonNull UserHandle user, @Nullable PackageState uncommittedPs)90     private FilteredSnapshotImpl withFilteredSnapshot(int callingUid, @NonNull UserHandle user,
91             @Nullable PackageState uncommittedPs) {
92         return new FilteredSnapshotImpl(callingUid, user,
93                 mService.snapshotComputer(/* allowLiveComputer= */ false),
94                 /* parentSnapshot= */ null, uncommittedPs);
95     }
96 
97     @Override
addOverrideSigningDetails(@onNull SigningDetails oldSigningDetails, @NonNull SigningDetails newSigningDetails)98     public void addOverrideSigningDetails(@NonNull SigningDetails oldSigningDetails,
99             @NonNull SigningDetails newSigningDetails) {
100         if (!Build.isDebuggable()) {
101             throw new SecurityException("This test API is only available on debuggable builds");
102         }
103         ApkSignatureVerifier.addOverrideSigningDetails(oldSigningDetails, newSigningDetails);
104     }
105 
106     @Override
removeOverrideSigningDetails(@onNull SigningDetails oldSigningDetails)107     public void removeOverrideSigningDetails(@NonNull SigningDetails oldSigningDetails) {
108         if (!Build.isDebuggable()) {
109             throw new SecurityException("This test API is only available on debuggable builds");
110         }
111         ApkSignatureVerifier.removeOverrideSigningDetails(oldSigningDetails);
112     }
113 
114     @Override
clearOverrideSigningDetails()115     public void clearOverrideSigningDetails() {
116         if (!Build.isDebuggable()) {
117             throw new SecurityException("This test API is only available on debuggable builds");
118         }
119         ApkSignatureVerifier.clearOverrideSigningDetails();
120     }
121 
122     private abstract static class BaseSnapshotImpl implements AutoCloseable {
123 
124         private boolean mClosed;
125 
126         @NonNull
127         protected Computer mSnapshot;
128 
BaseSnapshotImpl(@onNull PackageDataSnapshot snapshot)129         private BaseSnapshotImpl(@NonNull PackageDataSnapshot snapshot) {
130             mSnapshot = (Computer) snapshot;
131         }
132 
133         @CallSuper
134         @Override
close()135         public void close() {
136             mClosed = true;
137             mSnapshot = null;
138             // TODO: Recycle snapshots?
139         }
140 
141         @CallSuper
checkClosed()142         protected void checkClosed() {
143             if (mClosed) {
144                 throw new IllegalStateException("Snapshot already closed");
145             }
146         }
147     }
148 
149     private static class UnfilteredSnapshotImpl extends BaseSnapshotImpl implements
150             UnfilteredSnapshot {
151 
152         @Nullable
153         private Map<String, PackageState> mCachedUnmodifiablePackageStates;
154 
155         @Nullable
156         private Map<String, SharedUserApi> mCachedUnmodifiableSharedUsers;
157 
158         @Nullable
159         private Map<String, PackageState> mCachedUnmodifiableDisabledSystemPackageStates;
160 
UnfilteredSnapshotImpl(@onNull PackageDataSnapshot snapshot)161         private UnfilteredSnapshotImpl(@NonNull PackageDataSnapshot snapshot) {
162             super(snapshot);
163         }
164 
165         @Override
filtered(int callingUid, @NonNull UserHandle user)166         public FilteredSnapshot filtered(int callingUid, @NonNull UserHandle user) {
167             return new FilteredSnapshotImpl(callingUid, user, mSnapshot, this,
168                     /* uncommittedPs= */ null);
169         }
170 
171         @SuppressWarnings("RedundantSuppression")
172         @NonNull
173         @Override
getPackageStates()174         public Map<String, PackageState> getPackageStates() {
175             checkClosed();
176 
177             if (mCachedUnmodifiablePackageStates == null) {
178                 mCachedUnmodifiablePackageStates =
179                         Collections.unmodifiableMap(mSnapshot.getPackageStates());
180             }
181             return mCachedUnmodifiablePackageStates;
182         }
183 
184         @SuppressWarnings("RedundantSuppression")
185         @NonNull
186         @Override
getSharedUsers()187         public Map<String, SharedUserApi> getSharedUsers() {
188             checkClosed();
189 
190             if (mCachedUnmodifiableSharedUsers == null) {
191                 mCachedUnmodifiableSharedUsers =
192                         Collections.unmodifiableMap(mSnapshot.getSharedUsers());
193             }
194             return mCachedUnmodifiableSharedUsers;
195         }
196 
197         @SuppressWarnings("RedundantSuppression")
198         @NonNull
199         @Override
getDisabledSystemPackageStates()200         public Map<String, PackageState> getDisabledSystemPackageStates() {
201             checkClosed();
202 
203             if (mCachedUnmodifiableDisabledSystemPackageStates == null) {
204                 mCachedUnmodifiableDisabledSystemPackageStates =
205                         Collections.unmodifiableMap(mSnapshot.getDisabledSystemPackageStates());
206             }
207             return mCachedUnmodifiableDisabledSystemPackageStates;
208         }
209 
210         @Override
close()211         public void close() {
212             super.close();
213             mCachedUnmodifiablePackageStates = null;
214             mCachedUnmodifiableDisabledSystemPackageStates = null;
215         }
216     }
217 
218     private static class FilteredSnapshotImpl extends BaseSnapshotImpl implements
219             FilteredSnapshot {
220 
221         private final int mCallingUid;
222 
223         @UserIdInt
224         private final int mUserId;
225 
226         @Nullable
227         private Map<String, PackageState> mFilteredPackageStates;
228 
229         @Nullable
230         private final UnfilteredSnapshotImpl mParentSnapshot;
231 
232         @Nullable
233         private final PackageState mUncommitPackageState;
234 
FilteredSnapshotImpl(int callingUid, @NonNull UserHandle user, @NonNull PackageDataSnapshot snapshot, @Nullable UnfilteredSnapshotImpl parentSnapshot, @Nullable PackageState uncommittedPs)235         private FilteredSnapshotImpl(int callingUid, @NonNull UserHandle user,
236                 @NonNull PackageDataSnapshot snapshot,
237                 @Nullable UnfilteredSnapshotImpl parentSnapshot,
238                 @Nullable PackageState uncommittedPs) {
239             super(snapshot);
240             mCallingUid = callingUid;
241             mUserId = user.getIdentifier();
242             mParentSnapshot = parentSnapshot;
243             mUncommitPackageState = uncommittedPs;
244         }
245 
246         @Override
checkClosed()247         protected void checkClosed() {
248             if (mParentSnapshot != null) {
249                 mParentSnapshot.checkClosed();
250             }
251 
252             super.checkClosed();
253         }
254 
255         @Override
close()256         public void close() {
257             super.close();
258             mFilteredPackageStates = null;
259         }
260 
261         @Nullable
262         @Override
getPackageState(@onNull String packageName)263         public PackageState getPackageState(@NonNull String packageName) {
264             checkClosed();
265             if (mUncommitPackageState != null
266                     && packageName.equals(mUncommitPackageState.getPackageName())) {
267                 return mUncommitPackageState;
268             }
269             return mSnapshot.getPackageStateFiltered(packageName, mCallingUid, mUserId);
270         }
271 
272         @NonNull
273         @Override
getPackageStates()274         public Map<String, PackageState> getPackageStates() {
275             checkClosed();
276 
277             if (mFilteredPackageStates == null) {
278                 var packageStates = mSnapshot.getPackageStates();
279                 var filteredPackageStates = new ArrayMap<String, PackageState>();
280                 for (int index = 0, size = packageStates.size(); index < size; index++) {
281                     var packageState = packageStates.valueAt(index);
282                     if (mUncommitPackageState != null
283                             && packageState.getPackageName().equals(
284                             mUncommitPackageState.getPackageName())) {
285                         packageState = (PackageStateInternal) mUncommitPackageState;
286                     }
287                     if (!mSnapshot.shouldFilterApplication(packageState, mCallingUid, mUserId)) {
288                         filteredPackageStates.put(packageStates.keyAt(index), packageState);
289                     }
290                 }
291                 mFilteredPackageStates = Collections.unmodifiableMap(filteredPackageStates);
292             }
293 
294             return mFilteredPackageStates;
295         }
296     }
297 }
298