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