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