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; 18 19 import android.os.Process; 20 import android.util.Log; 21 22 import com.android.server.utils.SnapshotCache; 23 import com.android.server.utils.WatchedArrayList; 24 import com.android.server.utils.WatchedSparseArray; 25 import com.android.server.utils.Watcher; 26 27 /** 28 * A wrapper over {@link WatchedArrayList} that tracks the current (app ID -> SettingBase) mapping 29 * for non-system apps. Also tracks system app settings in an {@link WatchedSparseArray}. 30 */ 31 final class AppIdSettingMap { 32 /** 33 * We use an ArrayList instead of an SparseArray for non system apps because the number of apps 34 * might be big, and only ArrayList gives us a constant lookup time. For a given app ID, the 35 * index to the corresponding SettingBase object is (appId - FIRST_APPLICATION_ID). If an app ID 36 * doesn't exist (i.e., app is not installed), we fill the corresponding entry with null. 37 */ 38 private final WatchedArrayList<SettingBase> mNonSystemSettings; 39 private final SnapshotCache<WatchedArrayList<SettingBase>> mNonSystemSettingsSnapshot; 40 private final WatchedSparseArray<SettingBase> mSystemSettings; 41 private final SnapshotCache<WatchedSparseArray<SettingBase>> mSystemSettingsSnapshot; 42 private int mFirstAvailableAppId = Process.FIRST_APPLICATION_UID; 43 AppIdSettingMap()44 AppIdSettingMap() { 45 mNonSystemSettings = new WatchedArrayList<>(); 46 mNonSystemSettingsSnapshot = new SnapshotCache.Auto<>( 47 mNonSystemSettings, mNonSystemSettings, "AppIdSettingMap.mNonSystemSettings"); 48 mSystemSettings = new WatchedSparseArray<>(); 49 mSystemSettingsSnapshot = new SnapshotCache.Auto<>( 50 mSystemSettings, mSystemSettings, "AppIdSettingMap.mSystemSettings"); 51 } 52 AppIdSettingMap(AppIdSettingMap orig)53 AppIdSettingMap(AppIdSettingMap orig) { 54 mNonSystemSettings = orig.mNonSystemSettingsSnapshot.snapshot(); 55 mNonSystemSettingsSnapshot = new SnapshotCache.Sealed<>(); 56 mSystemSettings = orig.mSystemSettingsSnapshot.snapshot(); 57 mSystemSettingsSnapshot = new SnapshotCache.Sealed<>(); 58 } 59 60 /** Returns true if the requested AppID was valid and not already registered. */ registerExistingAppId(int appId, SettingBase setting, Object name)61 public boolean registerExistingAppId(int appId, SettingBase setting, Object name) { 62 if (appId >= Process.FIRST_APPLICATION_UID) { 63 int size = mNonSystemSettings.size(); 64 final int index = appId - Process.FIRST_APPLICATION_UID; 65 // fill the array until our index becomes valid 66 while (index >= size) { 67 mNonSystemSettings.add(null); 68 size++; 69 } 70 if (mNonSystemSettings.get(index) != null) { 71 PackageManagerService.reportSettingsProblem(Log.WARN, 72 "Adding duplicate app id: " + appId 73 + " name=" + name); 74 return false; 75 } 76 mNonSystemSettings.set(index, setting); 77 } else { 78 if (mSystemSettings.get(appId) != null) { 79 PackageManagerService.reportSettingsProblem(Log.WARN, 80 "Adding duplicate shared id: " + appId 81 + " name=" + name); 82 return false; 83 } 84 mSystemSettings.put(appId, setting); 85 } 86 return true; 87 } 88 getSetting(int appId)89 public SettingBase getSetting(int appId) { 90 if (appId >= Process.FIRST_APPLICATION_UID) { 91 final int size = mNonSystemSettings.size(); 92 final int index = appId - Process.FIRST_APPLICATION_UID; 93 return index < size ? mNonSystemSettings.get(index) : null; 94 } else { 95 return mSystemSettings.get(appId); 96 } 97 } 98 removeSetting(int appId)99 public void removeSetting(int appId) { 100 if (appId >= Process.FIRST_APPLICATION_UID) { 101 final int size = mNonSystemSettings.size(); 102 final int index = appId - Process.FIRST_APPLICATION_UID; 103 if (index < size) { 104 mNonSystemSettings.set(index, null); 105 } 106 } else { 107 mSystemSettings.remove(appId); 108 } 109 setFirstAvailableAppId(appId + 1); 110 } 111 112 // This should be called (at least) whenever an application is removed setFirstAvailableAppId(int uid)113 private void setFirstAvailableAppId(int uid) { 114 if (uid > mFirstAvailableAppId) { 115 mFirstAvailableAppId = uid; 116 } 117 } 118 replaceSetting(int appId, SettingBase setting)119 public void replaceSetting(int appId, SettingBase setting) { 120 if (appId >= Process.FIRST_APPLICATION_UID) { 121 final int size = mNonSystemSettings.size(); 122 final int index = appId - Process.FIRST_APPLICATION_UID; 123 if (index < size) { 124 mNonSystemSettings.set(index, setting); 125 } else { 126 PackageManagerService.reportSettingsProblem(Log.WARN, 127 "Error in package manager settings: calling replaceAppIdLpw to" 128 + " replace SettingBase at appId=" + appId 129 + " but nothing is replaced."); 130 } 131 } else { 132 mSystemSettings.put(appId, setting); 133 } 134 } 135 136 /** Returns a new AppID or -1 if we could not find an available AppID to assign */ acquireAndRegisterNewAppId(SettingBase obj)137 public int acquireAndRegisterNewAppId(SettingBase obj) { 138 final int size = mNonSystemSettings.size(); 139 for (int i = mFirstAvailableAppId - Process.FIRST_APPLICATION_UID; i < size; i++) { 140 if (mNonSystemSettings.get(i) == null) { 141 mNonSystemSettings.set(i, obj); 142 return Process.FIRST_APPLICATION_UID + i; 143 } 144 } 145 146 // None left? 147 if (size > (Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID)) { 148 return -1; 149 } 150 151 mNonSystemSettings.add(obj); 152 return Process.FIRST_APPLICATION_UID + size; 153 } 154 snapshot()155 public AppIdSettingMap snapshot() { 156 return new AppIdSettingMap(this); 157 } 158 registerObserver(Watcher observer)159 public void registerObserver(Watcher observer) { 160 mNonSystemSettings.registerObserver(observer); 161 mSystemSettings.registerObserver(observer); 162 } 163 } 164