blob: 327debf944370b7b95a91c2bb18379f2ef675ba3 [file] [log] [blame]
Hai Zhangb7776682018-09-25 15:10:57 -07001/*
2 * Copyright (C) 2018 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
17package com.android.server.role;
18
19import android.annotation.CheckResult;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.annotation.UserIdInt;
23import android.annotation.WorkerThread;
24import android.os.Environment;
25import android.os.Handler;
26import android.util.ArrayMap;
27import android.util.ArraySet;
28import android.util.AtomicFile;
29import android.util.Slog;
30import android.util.Xml;
31
32import com.android.internal.annotations.GuardedBy;
33import com.android.internal.os.BackgroundThread;
Eugene Suslaabdefba2018-11-09 18:06:43 -080034import com.android.internal.util.CollectionUtils;
Hai Zhang33456fb2018-12-05 17:30:35 -080035import com.android.internal.util.dump.DualDumpOutputStream;
Hai Zhangb7776682018-09-25 15:10:57 -070036import com.android.internal.util.function.pooled.PooledLambda;
37
38import libcore.io.IoUtils;
39
40import org.xmlpull.v1.XmlPullParser;
41import org.xmlpull.v1.XmlPullParserException;
42import org.xmlpull.v1.XmlSerializer;
43
44import java.io.File;
45import java.io.FileInputStream;
46import java.io.FileNotFoundException;
47import java.io.FileOutputStream;
48import java.io.IOException;
49import java.nio.charset.StandardCharsets;
Hai Zhang8e60a8f2018-11-20 11:21:09 -080050import java.util.List;
Hai Zhang458cedb2018-12-03 15:41:11 -080051import java.util.Objects;
Hai Zhangb7776682018-09-25 15:10:57 -070052
53/**
54 * Stores the state of roles for a user.
55 */
56public class RoleUserState {
57
58 private static final String LOG_TAG = RoleUserState.class.getSimpleName();
59
60 public static final int VERSION_UNDEFINED = -1;
61
62 private static final String ROLES_FILE_NAME = "roles.xml";
63
Hai Zhangb3e9b9b2018-12-05 18:32:40 -080064 private static final long WRITE_DELAY_MILLIS = 200;
65 private static final long MAX_WRITE_DELAY_MILLIS = 2000;
66
Hai Zhangb7776682018-09-25 15:10:57 -070067 private static final String TAG_ROLES = "roles";
68 private static final String TAG_ROLE = "role";
69 private static final String TAG_HOLDER = "holder";
70 private static final String ATTRIBUTE_VERSION = "version";
71 private static final String ATTRIBUTE_NAME = "name";
Eugene Suslaabdefba2018-11-09 18:06:43 -080072 private static final String ATTRIBUTE_PACKAGES_HASH = "packagesHash";
Hai Zhangb7776682018-09-25 15:10:57 -070073
74 @UserIdInt
75 private final int mUserId;
76
77 @GuardedBy("RoleManagerService.mLock")
Hai Zhang458cedb2018-12-03 15:41:11 -080078 private int mVersion = VERSION_UNDEFINED;
Hai Zhangb7776682018-09-25 15:10:57 -070079
Eugene Suslaabdefba2018-11-09 18:06:43 -080080 @GuardedBy("RoleManagerService.mLock")
Hai Zhang458cedb2018-12-03 15:41:11 -080081 @Nullable
Hai Zhang33456fb2018-12-05 17:30:35 -080082 private String mPackagesHash;
Eugene Suslaabdefba2018-11-09 18:06:43 -080083
Hai Zhangb7776682018-09-25 15:10:57 -070084 /**
85 * Maps role names to its holders' package names. The values should never be null.
86 */
87 @GuardedBy("RoleManagerService.mLock")
Hai Zhang458cedb2018-12-03 15:41:11 -080088 @NonNull
89 private ArrayMap<String, ArraySet<String>> mRoles = new ArrayMap<>();
Hai Zhangb7776682018-09-25 15:10:57 -070090
91 @GuardedBy("RoleManagerService.mLock")
Hai Zhangb3e9b9b2018-12-05 18:32:40 -080092 private long mWritePendingSinceMillis;
93
94 @GuardedBy("RoleManagerService.mLock")
Hai Zhangb7776682018-09-25 15:10:57 -070095 private boolean mDestroyed;
96
Hai Zhang458cedb2018-12-03 15:41:11 -080097 @NonNull
Hai Zhangb7776682018-09-25 15:10:57 -070098 private final Handler mWriteHandler = new Handler(BackgroundThread.getHandler().getLooper());
99
Hai Zhang458cedb2018-12-03 15:41:11 -0800100 private RoleUserState(@UserIdInt int userId) {
Hai Zhangb7776682018-09-25 15:10:57 -0700101 mUserId = userId;
Hai Zhang458cedb2018-12-03 15:41:11 -0800102
Hai Zhang33456fb2018-12-05 17:30:35 -0800103 readLocked();
Hai Zhang458cedb2018-12-03 15:41:11 -0800104 }
105
106 /**
107 * Create a new instance of user state, and read its state from disk if previously persisted.
108 *
109 * @param userId the user id for the new user state
110 *
111 * @return the new user state
112 */
113 @GuardedBy("RoleManagerService.mLock")
114 public static RoleUserState newInstanceLocked(@UserIdInt int userId) {
115 return new RoleUserState(userId);
Hai Zhangb7776682018-09-25 15:10:57 -0700116 }
117
118 /**
119 * Get the version of this user state.
120 */
121 @GuardedBy("RoleManagerService.mLock")
122 public int getVersionLocked() {
123 throwIfDestroyedLocked();
124 return mVersion;
125 }
126
127 /**
128 * Set the version of this user state.
129 *
130 * @param version the version to set
131 */
132 @GuardedBy("RoleManagerService.mLock")
133 public void setVersionLocked(int version) {
134 throwIfDestroyedLocked();
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800135 if (mVersion == version) {
136 return;
137 }
Hai Zhangb7776682018-09-25 15:10:57 -0700138 mVersion = version;
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800139 writeAsyncLocked();
Hai Zhangb7776682018-09-25 15:10:57 -0700140 }
141
142 /**
Hai Zhang458cedb2018-12-03 15:41:11 -0800143 * Get the hash representing the state of packages during the last time initial grants was run.
144 *
145 * @return the hash representing the state of packages
Eugene Suslaabdefba2018-11-09 18:06:43 -0800146 */
147 @GuardedBy("RoleManagerService.mLock")
Hai Zhang33456fb2018-12-05 17:30:35 -0800148 public String getPackagesHashLocked() {
149 return mPackagesHash;
Eugene Suslaabdefba2018-11-09 18:06:43 -0800150 }
151
152 /**
Hai Zhang458cedb2018-12-03 15:41:11 -0800153 * Set the hash representing the state of packages during the last time initial grants was run.
154 *
Hai Zhang33456fb2018-12-05 17:30:35 -0800155 * @param packagesHash the hash representing the state of packages
Eugene Suslaabdefba2018-11-09 18:06:43 -0800156 */
157 @GuardedBy("RoleManagerService.mLock")
Hai Zhang33456fb2018-12-05 17:30:35 -0800158 public void setPackagesHashLocked(@Nullable String packagesHash) {
Hai Zhang458cedb2018-12-03 15:41:11 -0800159 throwIfDestroyedLocked();
Hai Zhang33456fb2018-12-05 17:30:35 -0800160 if (Objects.equals(mPackagesHash, packagesHash)) {
Hai Zhang458cedb2018-12-03 15:41:11 -0800161 return;
162 }
Hai Zhang33456fb2018-12-05 17:30:35 -0800163 mPackagesHash = packagesHash;
Eugene Suslaabdefba2018-11-09 18:06:43 -0800164 writeAsyncLocked();
165 }
166
167 /**
Hai Zhangb7776682018-09-25 15:10:57 -0700168 * Get whether the role is available.
169 *
170 * @param roleName the name of the role to get the holders for
171 *
172 * @return whether the role is available
173 */
174 @GuardedBy("RoleManagerService.mLock")
175 public boolean isRoleAvailableLocked(@NonNull String roleName) {
176 throwIfDestroyedLocked();
177 return mRoles.containsKey(roleName);
178 }
179
180 /**
181 * Get the holders of a role.
182 *
183 * @param roleName the name of the role to query for
184 *
185 * @return the set of role holders. {@code null} should not be returned and indicates an issue.
186 */
187 @GuardedBy("RoleManagerService.mLock")
188 @Nullable
189 public ArraySet<String> getRoleHoldersLocked(@NonNull String roleName) {
190 throwIfDestroyedLocked();
191 return mRoles.get(roleName);
192 }
193
194 /**
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800195 * Set the names of all available roles.
196 *
197 * @param roleNames the names of all the available roles
198 */
199 @GuardedBy("RoleManagerService.mLock")
200 public void setRoleNamesLocked(@NonNull List<String> roleNames) {
201 throwIfDestroyedLocked();
202 boolean changed = false;
203 for (int i = mRoles.size() - 1; i >= 0; i--) {
204 String roleName = mRoles.keyAt(i);
205 if (!roleNames.contains(roleName)) {
206 ArraySet<String> packageNames = mRoles.valueAt(i);
207 if (!packageNames.isEmpty()) {
208 Slog.e(LOG_TAG, "Holders of a removed role should have been cleaned up, role: "
209 + roleName + ", holders: " + packageNames);
210 }
211 mRoles.removeAt(i);
212 changed = true;
213 }
214 }
215 int roleNamesSize = roleNames.size();
216 for (int i = 0; i < roleNamesSize; i++) {
217 String roleName = roleNames.get(i);
218 if (!mRoles.containsKey(roleName)) {
219 mRoles.put(roleName, new ArraySet<>());
220 Slog.i(LOG_TAG, "Added new role: " + roleName);
221 changed = true;
222 }
223 }
224 if (changed) {
225 writeAsyncLocked();
226 }
227 }
228
229 /**
Hai Zhangb7776682018-09-25 15:10:57 -0700230 * Add a holder to a role.
231 *
232 * @param roleName the name of the role to add the holder to
233 * @param packageName the package name of the new holder
234 *
235 * @return {@code false} only if the set of role holders is null, which should not happen and
236 * indicates an issue.
237 */
238 @CheckResult
239 @GuardedBy("RoleManagerService.mLock")
240 public boolean addRoleHolderLocked(@NonNull String roleName, @NonNull String packageName) {
241 throwIfDestroyedLocked();
242 ArraySet<String> roleHolders = mRoles.get(roleName);
243 if (roleHolders == null) {
Hai Zhangb295ac42018-11-16 16:08:18 -0800244 Slog.e(LOG_TAG, "Cannot add role holder for unknown role, role: " + roleName
245 + ", package: " + packageName);
Hai Zhangb7776682018-09-25 15:10:57 -0700246 return false;
247 }
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800248 boolean changed = roleHolders.add(packageName);
249 if (changed) {
250 writeAsyncLocked();
251 }
Hai Zhangb7776682018-09-25 15:10:57 -0700252 return true;
253 }
254
255 /**
256 * Remove a holder from a role.
257 *
258 * @param roleName the name of the role to remove the holder from
259 * @param packageName the package name of the holder to remove
260 *
261 * @return {@code false} only if the set of role holders is null, which should not happen and
262 * indicates an issue.
263 */
264 @CheckResult
265 @GuardedBy("RoleManagerService.mLock")
266 public boolean removeRoleHolderLocked(@NonNull String roleName, @NonNull String packageName) {
267 throwIfDestroyedLocked();
268 ArraySet<String> roleHolders = mRoles.get(roleName);
269 if (roleHolders == null) {
Hai Zhangb295ac42018-11-16 16:08:18 -0800270 Slog.e(LOG_TAG, "Cannot remove role holder for unknown role, role: " + roleName
271 + ", package: " + packageName);
Hai Zhangb7776682018-09-25 15:10:57 -0700272 return false;
273 }
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800274 boolean changed = roleHolders.remove(packageName);
275 if (changed) {
276 writeAsyncLocked();
277 }
Hai Zhangb7776682018-09-25 15:10:57 -0700278 return true;
279 }
280
281 /**
Hai Zhangb7776682018-09-25 15:10:57 -0700282 * Schedule writing the state to file.
283 */
284 @GuardedBy("RoleManagerService.mLock")
Hai Zhang458cedb2018-12-03 15:41:11 -0800285 private void writeAsyncLocked() {
Hai Zhangb7776682018-09-25 15:10:57 -0700286 throwIfDestroyedLocked();
Hai Zhang458cedb2018-12-03 15:41:11 -0800287
Hai Zhangb7776682018-09-25 15:10:57 -0700288 ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>();
Eugene Suslaabdefba2018-11-09 18:06:43 -0800289 for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) {
Hai Zhangb7776682018-09-25 15:10:57 -0700290 String roleName = mRoles.keyAt(i);
291 ArraySet<String> roleHolders = mRoles.valueAt(i);
Hai Zhangb3e9b9b2018-12-05 18:32:40 -0800292
Hai Zhangb7776682018-09-25 15:10:57 -0700293 roleHolders = new ArraySet<>(roleHolders);
294 roles.put(roleName, roleHolders);
295 }
Hai Zhang458cedb2018-12-03 15:41:11 -0800296
Hai Zhangb3e9b9b2018-12-05 18:32:40 -0800297 long currentTimeMillis = System.currentTimeMillis();
298 long writeDelayMillis;
299 if (!mWriteHandler.hasMessagesOrCallbacks()) {
300 mWritePendingSinceMillis = currentTimeMillis;
301 writeDelayMillis = WRITE_DELAY_MILLIS;
302 } else {
303 mWriteHandler.removeCallbacksAndMessages(null);
304 long writePendingDurationMillis = currentTimeMillis - mWritePendingSinceMillis;
305 if (writePendingDurationMillis >= MAX_WRITE_DELAY_MILLIS) {
306 writeDelayMillis = 0;
307 } else {
308 long maxWriteDelayMillis = Math.max(MAX_WRITE_DELAY_MILLIS
309 - writePendingDurationMillis, 0);
310 writeDelayMillis = Math.min(WRITE_DELAY_MILLIS, maxWriteDelayMillis);
311 }
312 }
313
314 mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeSync, this,
Hai Zhang33456fb2018-12-05 17:30:35 -0800315 mVersion, mPackagesHash, roles), writeDelayMillis);
Hai Zhangb3e9b9b2018-12-05 18:32:40 -0800316 Slog.i(LOG_TAG, "Scheduled writing roles.xml");
Hai Zhangb7776682018-09-25 15:10:57 -0700317 }
318
319 @WorkerThread
Hai Zhang458cedb2018-12-03 15:41:11 -0800320 private void writeSync(int version, @Nullable String packagesHash,
321 @NonNull ArrayMap<String, ArraySet<String>> roles) {
Hai Zhangb295ac42018-11-16 16:08:18 -0800322 AtomicFile atomicFile = new AtomicFile(getFile(mUserId), "roles-" + mUserId);
Hai Zhangb7776682018-09-25 15:10:57 -0700323 FileOutputStream out = null;
324 try {
Hai Zhangb295ac42018-11-16 16:08:18 -0800325 out = atomicFile.startWrite();
Hai Zhangb7776682018-09-25 15:10:57 -0700326
327 XmlSerializer serializer = Xml.newSerializer();
328 serializer.setOutput(out, StandardCharsets.UTF_8.name());
329 serializer.setFeature(
330 "http://xmlpull.org/v1/doc/features.html#indent-output", true);
331 serializer.startDocument(null, true);
332
Hai Zhang458cedb2018-12-03 15:41:11 -0800333 serializeRoles(serializer, version, packagesHash, roles);
Hai Zhangb7776682018-09-25 15:10:57 -0700334
335 serializer.endDocument();
Hai Zhangb295ac42018-11-16 16:08:18 -0800336 atomicFile.finishWrite(out);
Hai Zhangb3e9b9b2018-12-05 18:32:40 -0800337 Slog.i(LOG_TAG, "Wrote roles.xml successfully");
Hai Zhangb295ac42018-11-16 16:08:18 -0800338 } catch (IllegalArgumentException | IllegalStateException | IOException e) {
339 Slog.wtf(LOG_TAG, "Failed to write roles.xml, restoring backup", e);
340 if (out != null) {
341 atomicFile.failWrite(out);
342 }
Hai Zhangb7776682018-09-25 15:10:57 -0700343 } finally {
344 IoUtils.closeQuietly(out);
345 }
346 }
347
348 @WorkerThread
349 private void serializeRoles(@NonNull XmlSerializer serializer, int version,
Hai Zhang458cedb2018-12-03 15:41:11 -0800350 @Nullable String packagesHash, @NonNull ArrayMap<String, ArraySet<String>> roles)
Eugene Suslaabdefba2018-11-09 18:06:43 -0800351 throws IOException {
Hai Zhangb7776682018-09-25 15:10:57 -0700352 serializer.startTag(null, TAG_ROLES);
Hai Zhang458cedb2018-12-03 15:41:11 -0800353
Hai Zhangb7776682018-09-25 15:10:57 -0700354 serializer.attribute(null, ATTRIBUTE_VERSION, Integer.toString(version));
Hai Zhang458cedb2018-12-03 15:41:11 -0800355
356 if (packagesHash != null) {
357 serializer.attribute(null, ATTRIBUTE_PACKAGES_HASH, packagesHash);
358 }
359
Hai Zhangb7776682018-09-25 15:10:57 -0700360 for (int i = 0, size = roles.size(); i < size; ++i) {
361 String roleName = roles.keyAt(i);
362 ArraySet<String> roleHolders = roles.valueAt(i);
Hai Zhang458cedb2018-12-03 15:41:11 -0800363
Hai Zhangb7776682018-09-25 15:10:57 -0700364 serializer.startTag(null, TAG_ROLE);
365 serializer.attribute(null, ATTRIBUTE_NAME, roleName);
366 serializeRoleHolders(serializer, roleHolders);
367 serializer.endTag(null, TAG_ROLE);
368 }
Hai Zhang458cedb2018-12-03 15:41:11 -0800369
Hai Zhangb7776682018-09-25 15:10:57 -0700370 serializer.endTag(null, TAG_ROLES);
371 }
372
373 @WorkerThread
374 private void serializeRoleHolders(@NonNull XmlSerializer serializer,
375 @NonNull ArraySet<String> roleHolders) throws IOException {
376 for (int i = 0, size = roleHolders.size(); i < size; ++i) {
377 String roleHolder = roleHolders.valueAt(i);
Hai Zhang458cedb2018-12-03 15:41:11 -0800378
Hai Zhangb7776682018-09-25 15:10:57 -0700379 serializer.startTag(null, TAG_HOLDER);
380 serializer.attribute(null, ATTRIBUTE_NAME, roleHolder);
381 serializer.endTag(null, TAG_HOLDER);
382 }
383 }
384
385 /**
386 * Read the state from file.
387 */
388 @GuardedBy("RoleManagerService.mLock")
Hai Zhang33456fb2018-12-05 17:30:35 -0800389 private void readLocked() {
Hai Zhangb295ac42018-11-16 16:08:18 -0800390 File file = getFile(mUserId);
391 try (FileInputStream in = new AtomicFile(file).openRead()) {
Hai Zhangb7776682018-09-25 15:10:57 -0700392 XmlPullParser parser = Xml.newPullParser();
393 parser.setInput(in, null);
394 parseXmlLocked(parser);
Hai Zhangb3e9b9b2018-12-05 18:32:40 -0800395 Slog.i(LOG_TAG, "Read roles.xml successfully");
Hai Zhangb295ac42018-11-16 16:08:18 -0800396 } catch (FileNotFoundException e) {
397 Slog.i(LOG_TAG, "roles.xml not found");
Hai Zhangb7776682018-09-25 15:10:57 -0700398 } catch (XmlPullParserException | IOException e) {
Hai Zhangb295ac42018-11-16 16:08:18 -0800399 throw new IllegalStateException("Failed to parse roles.xml: " + file, e);
Hai Zhangb7776682018-09-25 15:10:57 -0700400 }
401 }
402
403 private void parseXmlLocked(@NonNull XmlPullParser parser) throws IOException,
404 XmlPullParserException {
Hai Zhangb7776682018-09-25 15:10:57 -0700405 int type;
Hai Zhangb295ac42018-11-16 16:08:18 -0800406 int depth;
407 int innerDepth = parser.getDepth() + 1;
Hai Zhangb7776682018-09-25 15:10:57 -0700408 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
Hai Zhangb295ac42018-11-16 16:08:18 -0800409 && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
410 if (depth > innerDepth || type != XmlPullParser.START_TAG) {
Hai Zhangb7776682018-09-25 15:10:57 -0700411 continue;
412 }
Hai Zhangb295ac42018-11-16 16:08:18 -0800413
Hai Zhangb7776682018-09-25 15:10:57 -0700414 if (parser.getName().equals(TAG_ROLES)) {
415 parseRolesLocked(parser);
416 return;
417 }
418 }
Hai Zhang458cedb2018-12-03 15:41:11 -0800419 Slog.w(LOG_TAG, "Missing <" + TAG_ROLES + "> in roles.xml");
Hai Zhangb7776682018-09-25 15:10:57 -0700420 }
421
422 private void parseRolesLocked(@NonNull XmlPullParser parser) throws IOException,
423 XmlPullParserException {
424 mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION));
Hai Zhang33456fb2018-12-05 17:30:35 -0800425 mPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
Hai Zhang458cedb2018-12-03 15:41:11 -0800426 mRoles.clear();
Hai Zhangb295ac42018-11-16 16:08:18 -0800427
Hai Zhangb7776682018-09-25 15:10:57 -0700428 int type;
Hai Zhangb295ac42018-11-16 16:08:18 -0800429 int depth;
430 int innerDepth = parser.getDepth() + 1;
Hai Zhangb7776682018-09-25 15:10:57 -0700431 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
Hai Zhangb295ac42018-11-16 16:08:18 -0800432 && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
433 if (depth > innerDepth || type != XmlPullParser.START_TAG) {
Hai Zhangb7776682018-09-25 15:10:57 -0700434 continue;
435 }
Hai Zhangb295ac42018-11-16 16:08:18 -0800436
Hai Zhangb7776682018-09-25 15:10:57 -0700437 if (parser.getName().equals(TAG_ROLE)) {
438 String roleName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
439 ArraySet<String> roleHolders = parseRoleHoldersLocked(parser);
440 mRoles.put(roleName, roleHolders);
441 }
442 }
443 }
444
445 @NonNull
446 private ArraySet<String> parseRoleHoldersLocked(@NonNull XmlPullParser parser)
447 throws IOException, XmlPullParserException {
448 ArraySet<String> roleHolders = new ArraySet<>();
Hai Zhangb295ac42018-11-16 16:08:18 -0800449
Hai Zhangb7776682018-09-25 15:10:57 -0700450 int type;
Hai Zhangb295ac42018-11-16 16:08:18 -0800451 int depth;
452 int innerDepth = parser.getDepth() + 1;
Hai Zhangb7776682018-09-25 15:10:57 -0700453 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
Hai Zhangb295ac42018-11-16 16:08:18 -0800454 && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
455 if (depth > innerDepth || type != XmlPullParser.START_TAG) {
Hai Zhangb7776682018-09-25 15:10:57 -0700456 continue;
457 }
Hai Zhangb295ac42018-11-16 16:08:18 -0800458
Hai Zhangb7776682018-09-25 15:10:57 -0700459 if (parser.getName().equals(TAG_HOLDER)) {
460 String roleHolder = parser.getAttributeValue(null, ATTRIBUTE_NAME);
461 roleHolders.add(roleHolder);
462 }
463 }
Hai Zhangb295ac42018-11-16 16:08:18 -0800464
Hai Zhangb7776682018-09-25 15:10:57 -0700465 return roleHolders;
466 }
467
468 /**
Hai Zhang33456fb2018-12-05 17:30:35 -0800469 * Dump this user state.
470 *
471 * @param dumpOutputStream the output stream to dump to
472 */
473 @GuardedBy("RoleManagerService.mLock")
474 public void dumpLocked(@NonNull DualDumpOutputStream dumpOutputStream,
475 @NonNull String fieldName, long fieldId) {
476 throwIfDestroyedLocked();
477
478 long fieldToken = dumpOutputStream.start(fieldName, fieldId);
479 dumpOutputStream.write("user_id", RoleUserStateProto.USER_ID, mUserId);
480 dumpOutputStream.write("version", RoleUserStateProto.VERSION, mVersion);
481 dumpOutputStream.write("packages_hash", RoleUserStateProto.PACKAGES_HASH, mPackagesHash);
482
483 int rolesSize = mRoles.size();
484 for (int rolesIndex = 0; rolesIndex < rolesSize; rolesIndex++) {
485 String roleName = mRoles.keyAt(rolesIndex);
486 ArraySet<String> roleHolders = mRoles.valueAt(rolesIndex);
487
488 long rolesToken = dumpOutputStream.start("roles", RoleUserStateProto.ROLES);
489 dumpOutputStream.write("name", RoleProto.NAME, roleName);
490
491 int roleHoldersSize = roleHolders.size();
492 for (int roleHoldersIndex = 0; roleHoldersIndex < roleHoldersSize; roleHoldersIndex++) {
493 String roleHolder = roleHolders.valueAt(roleHoldersIndex);
494
495 dumpOutputStream.write("holders", RoleProto.HOLDERS, roleHolder);
496 }
497
498 dumpOutputStream.end(rolesToken);
499 }
500
501 dumpOutputStream.end(fieldToken);
502 }
503
504 /**
Hai Zhangb7776682018-09-25 15:10:57 -0700505 * Destroy this state and delete the corresponding file. Any pending writes to the file will be
506 * cancelled and any future interaction with this state will throw an exception.
507 */
508 @GuardedBy("RoleManagerService.mLock")
Hai Zhang33456fb2018-12-05 17:30:35 -0800509 public void destroyLocked() {
Hai Zhangb7776682018-09-25 15:10:57 -0700510 throwIfDestroyedLocked();
511 mWriteHandler.removeCallbacksAndMessages(null);
512 getFile(mUserId).delete();
513 mDestroyed = true;
514 }
515
516 @GuardedBy("RoleManagerService.mLock")
517 private void throwIfDestroyedLocked() {
518 if (mDestroyed) {
519 throw new IllegalStateException("This RoleUserState has already been destroyed");
520 }
521 }
522
523 private static @NonNull File getFile(@UserIdInt int userId) {
524 return new File(Environment.getUserSystemDirectory(userId), ROLES_FILE_NAME);
525 }
526}