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