blob: ce0597435f7155386aaeaba964a4d3e5c3c6100a [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 Zhangb7776682018-09-25 15:10:57 -070035import com.android.internal.util.function.pooled.PooledLambda;
36
37import libcore.io.IoUtils;
38
39import org.xmlpull.v1.XmlPullParser;
40import org.xmlpull.v1.XmlPullParserException;
41import org.xmlpull.v1.XmlSerializer;
42
43import java.io.File;
44import java.io.FileInputStream;
45import java.io.FileNotFoundException;
46import java.io.FileOutputStream;
47import java.io.IOException;
48import java.nio.charset.StandardCharsets;
Hai Zhang8e60a8f2018-11-20 11:21:09 -080049import java.util.List;
Hai Zhang458cedb2018-12-03 15:41:11 -080050import java.util.Objects;
Hai Zhangb7776682018-09-25 15:10:57 -070051
52/**
53 * Stores the state of roles for a user.
54 */
55public class RoleUserState {
56
57 private static final String LOG_TAG = RoleUserState.class.getSimpleName();
58
59 public static final int VERSION_UNDEFINED = -1;
60
61 private static final String ROLES_FILE_NAME = "roles.xml";
62
Hai Zhangb3e9b9b2018-12-05 18:32:40 -080063 private static final long WRITE_DELAY_MILLIS = 200;
64 private static final long MAX_WRITE_DELAY_MILLIS = 2000;
65
Hai Zhangb7776682018-09-25 15:10:57 -070066 private static final String TAG_ROLES = "roles";
67 private static final String TAG_ROLE = "role";
68 private static final String TAG_HOLDER = "holder";
69 private static final String ATTRIBUTE_VERSION = "version";
70 private static final String ATTRIBUTE_NAME = "name";
Eugene Suslaabdefba2018-11-09 18:06:43 -080071 private static final String ATTRIBUTE_PACKAGES_HASH = "packagesHash";
Hai Zhangb7776682018-09-25 15:10:57 -070072
73 @UserIdInt
74 private final int mUserId;
75
76 @GuardedBy("RoleManagerService.mLock")
Hai Zhang458cedb2018-12-03 15:41:11 -080077 private int mVersion = VERSION_UNDEFINED;
Hai Zhangb7776682018-09-25 15:10:57 -070078
Eugene Suslaabdefba2018-11-09 18:06:43 -080079 @GuardedBy("RoleManagerService.mLock")
Hai Zhang458cedb2018-12-03 15:41:11 -080080 @Nullable
81 private String mLastGrantPackagesHash;
Eugene Suslaabdefba2018-11-09 18:06:43 -080082
Hai Zhangb7776682018-09-25 15:10:57 -070083 /**
84 * Maps role names to its holders' package names. The values should never be null.
85 */
86 @GuardedBy("RoleManagerService.mLock")
Hai Zhang458cedb2018-12-03 15:41:11 -080087 @NonNull
88 private ArrayMap<String, ArraySet<String>> mRoles = new ArrayMap<>();
Hai Zhangb7776682018-09-25 15:10:57 -070089
90 @GuardedBy("RoleManagerService.mLock")
Hai Zhangb3e9b9b2018-12-05 18:32:40 -080091 private long mWritePendingSinceMillis;
92
93 @GuardedBy("RoleManagerService.mLock")
Hai Zhangb7776682018-09-25 15:10:57 -070094 private boolean mDestroyed;
95
Hai Zhang458cedb2018-12-03 15:41:11 -080096 @NonNull
Hai Zhangb7776682018-09-25 15:10:57 -070097 private final Handler mWriteHandler = new Handler(BackgroundThread.getHandler().getLooper());
98
Hai Zhang458cedb2018-12-03 15:41:11 -080099 private RoleUserState(@UserIdInt int userId) {
Hai Zhangb7776682018-09-25 15:10:57 -0700100 mUserId = userId;
Hai Zhang458cedb2018-12-03 15:41:11 -0800101
102 readSyncLocked();
103 }
104
105 /**
106 * Create a new instance of user state, and read its state from disk if previously persisted.
107 *
108 * @param userId the user id for the new user state
109 *
110 * @return the new user state
111 */
112 @GuardedBy("RoleManagerService.mLock")
113 public static RoleUserState newInstanceLocked(@UserIdInt int userId) {
114 return new RoleUserState(userId);
Hai Zhangb7776682018-09-25 15:10:57 -0700115 }
116
117 /**
118 * Get the version of this user state.
119 */
120 @GuardedBy("RoleManagerService.mLock")
121 public int getVersionLocked() {
122 throwIfDestroyedLocked();
123 return mVersion;
124 }
125
126 /**
127 * Set the version of this user state.
128 *
129 * @param version the version to set
130 */
131 @GuardedBy("RoleManagerService.mLock")
132 public void setVersionLocked(int version) {
133 throwIfDestroyedLocked();
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800134 if (mVersion == version) {
135 return;
136 }
Hai Zhangb7776682018-09-25 15:10:57 -0700137 mVersion = version;
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800138 writeAsyncLocked();
Hai Zhangb7776682018-09-25 15:10:57 -0700139 }
140
141 /**
Hai Zhang458cedb2018-12-03 15:41:11 -0800142 * Get the hash representing the state of packages during the last time initial grants was run.
143 *
144 * @return the hash representing the state of packages
Eugene Suslaabdefba2018-11-09 18:06:43 -0800145 */
146 @GuardedBy("RoleManagerService.mLock")
147 public String getLastGrantPackagesHashLocked() {
148 return mLastGrantPackagesHash;
149 }
150
151 /**
Hai Zhang458cedb2018-12-03 15:41:11 -0800152 * Set the hash representing the state of packages during the last time initial grants was run.
153 *
154 * @param lastGrantPackagesHash the hash representing the state of packages
Eugene Suslaabdefba2018-11-09 18:06:43 -0800155 */
156 @GuardedBy("RoleManagerService.mLock")
Hai Zhang458cedb2018-12-03 15:41:11 -0800157 public void setLastGrantPackagesHashLocked(@Nullable String lastGrantPackagesHash) {
158 throwIfDestroyedLocked();
159 if (Objects.equals(mLastGrantPackagesHash, lastGrantPackagesHash)) {
160 return;
161 }
Eugene Suslaabdefba2018-11-09 18:06:43 -0800162 mLastGrantPackagesHash = lastGrantPackagesHash;
163 writeAsyncLocked();
164 }
165
166 /**
Hai Zhangb7776682018-09-25 15:10:57 -0700167 * Get whether the role is available.
168 *
169 * @param roleName the name of the role to get the holders for
170 *
171 * @return whether the role is available
172 */
173 @GuardedBy("RoleManagerService.mLock")
174 public boolean isRoleAvailableLocked(@NonNull String roleName) {
175 throwIfDestroyedLocked();
176 return mRoles.containsKey(roleName);
177 }
178
179 /**
180 * Get the holders of a role.
181 *
182 * @param roleName the name of the role to query for
183 *
184 * @return the set of role holders. {@code null} should not be returned and indicates an issue.
185 */
186 @GuardedBy("RoleManagerService.mLock")
187 @Nullable
188 public ArraySet<String> getRoleHoldersLocked(@NonNull String roleName) {
189 throwIfDestroyedLocked();
190 return mRoles.get(roleName);
191 }
192
193 /**
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800194 * Set the names of all available roles.
195 *
196 * @param roleNames the names of all the available roles
197 */
198 @GuardedBy("RoleManagerService.mLock")
199 public void setRoleNamesLocked(@NonNull List<String> roleNames) {
200 throwIfDestroyedLocked();
201 boolean changed = false;
202 for (int i = mRoles.size() - 1; i >= 0; i--) {
203 String roleName = mRoles.keyAt(i);
204 if (!roleNames.contains(roleName)) {
205 ArraySet<String> packageNames = mRoles.valueAt(i);
206 if (!packageNames.isEmpty()) {
207 Slog.e(LOG_TAG, "Holders of a removed role should have been cleaned up, role: "
208 + roleName + ", holders: " + packageNames);
209 }
210 mRoles.removeAt(i);
211 changed = true;
212 }
213 }
214 int roleNamesSize = roleNames.size();
215 for (int i = 0; i < roleNamesSize; i++) {
216 String roleName = roleNames.get(i);
217 if (!mRoles.containsKey(roleName)) {
218 mRoles.put(roleName, new ArraySet<>());
219 Slog.i(LOG_TAG, "Added new role: " + roleName);
220 changed = true;
221 }
222 }
223 if (changed) {
224 writeAsyncLocked();
225 }
226 }
227
228 /**
Hai Zhangb7776682018-09-25 15:10:57 -0700229 * Add a holder to a role.
230 *
231 * @param roleName the name of the role to add the holder to
232 * @param packageName the package name of the new holder
233 *
234 * @return {@code false} only if the set of role holders is null, which should not happen and
235 * indicates an issue.
236 */
237 @CheckResult
238 @GuardedBy("RoleManagerService.mLock")
239 public boolean addRoleHolderLocked(@NonNull String roleName, @NonNull String packageName) {
240 throwIfDestroyedLocked();
241 ArraySet<String> roleHolders = mRoles.get(roleName);
242 if (roleHolders == null) {
Hai Zhangb295ac42018-11-16 16:08:18 -0800243 Slog.e(LOG_TAG, "Cannot add role holder for unknown role, role: " + roleName
244 + ", package: " + packageName);
Hai Zhangb7776682018-09-25 15:10:57 -0700245 return false;
246 }
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800247 boolean changed = roleHolders.add(packageName);
248 if (changed) {
249 writeAsyncLocked();
250 }
Hai Zhangb7776682018-09-25 15:10:57 -0700251 return true;
252 }
253
254 /**
255 * Remove a holder from a role.
256 *
257 * @param roleName the name of the role to remove the holder from
258 * @param packageName the package name of the holder to remove
259 *
260 * @return {@code false} only if the set of role holders is null, which should not happen and
261 * indicates an issue.
262 */
263 @CheckResult
264 @GuardedBy("RoleManagerService.mLock")
265 public boolean removeRoleHolderLocked(@NonNull String roleName, @NonNull String packageName) {
266 throwIfDestroyedLocked();
267 ArraySet<String> roleHolders = mRoles.get(roleName);
268 if (roleHolders == null) {
Hai Zhangb295ac42018-11-16 16:08:18 -0800269 Slog.e(LOG_TAG, "Cannot remove role holder for unknown role, role: " + roleName
270 + ", package: " + packageName);
Hai Zhangb7776682018-09-25 15:10:57 -0700271 return false;
272 }
Hai Zhang8e60a8f2018-11-20 11:21:09 -0800273 boolean changed = roleHolders.remove(packageName);
274 if (changed) {
275 writeAsyncLocked();
276 }
Hai Zhangb7776682018-09-25 15:10:57 -0700277 return true;
278 }
279
280 /**
Hai Zhangb7776682018-09-25 15:10:57 -0700281 * Schedule writing the state to file.
282 */
283 @GuardedBy("RoleManagerService.mLock")
Hai Zhang458cedb2018-12-03 15:41:11 -0800284 private void writeAsyncLocked() {
Hai Zhangb7776682018-09-25 15:10:57 -0700285 throwIfDestroyedLocked();
Hai Zhang458cedb2018-12-03 15:41:11 -0800286
Hai Zhangb7776682018-09-25 15:10:57 -0700287 ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>();
Eugene Suslaabdefba2018-11-09 18:06:43 -0800288 for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) {
Hai Zhangb7776682018-09-25 15:10:57 -0700289 String roleName = mRoles.keyAt(i);
290 ArraySet<String> roleHolders = mRoles.valueAt(i);
Hai Zhangb3e9b9b2018-12-05 18:32:40 -0800291
Hai Zhangb7776682018-09-25 15:10:57 -0700292 roleHolders = new ArraySet<>(roleHolders);
293 roles.put(roleName, roleHolders);
294 }
Hai Zhang458cedb2018-12-03 15:41:11 -0800295
Hai Zhangb3e9b9b2018-12-05 18:32:40 -0800296 long currentTimeMillis = System.currentTimeMillis();
297 long writeDelayMillis;
298 if (!mWriteHandler.hasMessagesOrCallbacks()) {
299 mWritePendingSinceMillis = currentTimeMillis;
300 writeDelayMillis = WRITE_DELAY_MILLIS;
301 } else {
302 mWriteHandler.removeCallbacksAndMessages(null);
303 long writePendingDurationMillis = currentTimeMillis - mWritePendingSinceMillis;
304 if (writePendingDurationMillis >= MAX_WRITE_DELAY_MILLIS) {
305 writeDelayMillis = 0;
306 } else {
307 long maxWriteDelayMillis = Math.max(MAX_WRITE_DELAY_MILLIS
308 - writePendingDurationMillis, 0);
309 writeDelayMillis = Math.min(WRITE_DELAY_MILLIS, maxWriteDelayMillis);
310 }
311 }
312
313 mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeSync, this,
314 mVersion, mLastGrantPackagesHash, roles), writeDelayMillis);
315 Slog.i(LOG_TAG, "Scheduled writing roles.xml");
Hai Zhangb7776682018-09-25 15:10:57 -0700316 }
317
318 @WorkerThread
Hai Zhang458cedb2018-12-03 15:41:11 -0800319 private void writeSync(int version, @Nullable String packagesHash,
320 @NonNull ArrayMap<String, ArraySet<String>> roles) {
Hai Zhangb295ac42018-11-16 16:08:18 -0800321 AtomicFile atomicFile = new AtomicFile(getFile(mUserId), "roles-" + mUserId);
Hai Zhangb7776682018-09-25 15:10:57 -0700322 FileOutputStream out = null;
323 try {
Hai Zhangb295ac42018-11-16 16:08:18 -0800324 out = atomicFile.startWrite();
Hai Zhangb7776682018-09-25 15:10:57 -0700325
326 XmlSerializer serializer = Xml.newSerializer();
327 serializer.setOutput(out, StandardCharsets.UTF_8.name());
328 serializer.setFeature(
329 "http://xmlpull.org/v1/doc/features.html#indent-output", true);
330 serializer.startDocument(null, true);
331
Hai Zhang458cedb2018-12-03 15:41:11 -0800332 serializeRoles(serializer, version, packagesHash, roles);
Hai Zhangb7776682018-09-25 15:10:57 -0700333
334 serializer.endDocument();
Hai Zhangb295ac42018-11-16 16:08:18 -0800335 atomicFile.finishWrite(out);
Hai Zhangb3e9b9b2018-12-05 18:32:40 -0800336 Slog.i(LOG_TAG, "Wrote roles.xml successfully");
Hai Zhangb295ac42018-11-16 16:08:18 -0800337 } catch (IllegalArgumentException | IllegalStateException | IOException e) {
338 Slog.wtf(LOG_TAG, "Failed to write roles.xml, restoring backup", e);
339 if (out != null) {
340 atomicFile.failWrite(out);
341 }
Hai Zhangb7776682018-09-25 15:10:57 -0700342 } finally {
343 IoUtils.closeQuietly(out);
344 }
345 }
346
347 @WorkerThread
348 private void serializeRoles(@NonNull XmlSerializer serializer, int version,
Hai Zhang458cedb2018-12-03 15:41:11 -0800349 @Nullable String packagesHash, @NonNull ArrayMap<String, ArraySet<String>> roles)
Eugene Suslaabdefba2018-11-09 18:06:43 -0800350 throws IOException {
Hai Zhangb7776682018-09-25 15:10:57 -0700351 serializer.startTag(null, TAG_ROLES);
Hai Zhang458cedb2018-12-03 15:41:11 -0800352
Hai Zhangb7776682018-09-25 15:10:57 -0700353 serializer.attribute(null, ATTRIBUTE_VERSION, Integer.toString(version));
Hai Zhang458cedb2018-12-03 15:41:11 -0800354
355 if (packagesHash != null) {
356 serializer.attribute(null, ATTRIBUTE_PACKAGES_HASH, packagesHash);
357 }
358
Hai Zhangb7776682018-09-25 15:10:57 -0700359 for (int i = 0, size = roles.size(); i < size; ++i) {
360 String roleName = roles.keyAt(i);
361 ArraySet<String> roleHolders = roles.valueAt(i);
Hai Zhang458cedb2018-12-03 15:41:11 -0800362
Hai Zhangb7776682018-09-25 15:10:57 -0700363 serializer.startTag(null, TAG_ROLE);
364 serializer.attribute(null, ATTRIBUTE_NAME, roleName);
365 serializeRoleHolders(serializer, roleHolders);
366 serializer.endTag(null, TAG_ROLE);
367 }
Hai Zhang458cedb2018-12-03 15:41:11 -0800368
Hai Zhangb7776682018-09-25 15:10:57 -0700369 serializer.endTag(null, TAG_ROLES);
370 }
371
372 @WorkerThread
373 private void serializeRoleHolders(@NonNull XmlSerializer serializer,
374 @NonNull ArraySet<String> roleHolders) throws IOException {
375 for (int i = 0, size = roleHolders.size(); i < size; ++i) {
376 String roleHolder = roleHolders.valueAt(i);
Hai Zhang458cedb2018-12-03 15:41:11 -0800377
Hai Zhangb7776682018-09-25 15:10:57 -0700378 serializer.startTag(null, TAG_HOLDER);
379 serializer.attribute(null, ATTRIBUTE_NAME, roleHolder);
380 serializer.endTag(null, TAG_HOLDER);
381 }
382 }
383
384 /**
385 * Read the state from file.
386 */
387 @GuardedBy("RoleManagerService.mLock")
Hai Zhang458cedb2018-12-03 15:41:11 -0800388 private void readSyncLocked() {
Hai Zhangb295ac42018-11-16 16:08:18 -0800389 File file = getFile(mUserId);
390 try (FileInputStream in = new AtomicFile(file).openRead()) {
Hai Zhangb7776682018-09-25 15:10:57 -0700391 XmlPullParser parser = Xml.newPullParser();
392 parser.setInput(in, null);
393 parseXmlLocked(parser);
Hai Zhangb3e9b9b2018-12-05 18:32:40 -0800394 Slog.i(LOG_TAG, "Read roles.xml successfully");
Hai Zhangb295ac42018-11-16 16:08:18 -0800395 } catch (FileNotFoundException e) {
396 Slog.i(LOG_TAG, "roles.xml not found");
Hai Zhangb7776682018-09-25 15:10:57 -0700397 } catch (XmlPullParserException | IOException e) {
Hai Zhangb295ac42018-11-16 16:08:18 -0800398 throw new IllegalStateException("Failed to parse roles.xml: " + file, e);
Hai Zhangb7776682018-09-25 15:10:57 -0700399 }
400 }
401
402 private void parseXmlLocked(@NonNull XmlPullParser parser) throws IOException,
403 XmlPullParserException {
Hai Zhangb7776682018-09-25 15:10:57 -0700404 int type;
Hai Zhangb295ac42018-11-16 16:08:18 -0800405 int depth;
406 int innerDepth = parser.getDepth() + 1;
Hai Zhangb7776682018-09-25 15:10:57 -0700407 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
Hai Zhangb295ac42018-11-16 16:08:18 -0800408 && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
409 if (depth > innerDepth || type != XmlPullParser.START_TAG) {
Hai Zhangb7776682018-09-25 15:10:57 -0700410 continue;
411 }
Hai Zhangb295ac42018-11-16 16:08:18 -0800412
Hai Zhangb7776682018-09-25 15:10:57 -0700413 if (parser.getName().equals(TAG_ROLES)) {
414 parseRolesLocked(parser);
415 return;
416 }
417 }
Hai Zhang458cedb2018-12-03 15:41:11 -0800418 Slog.w(LOG_TAG, "Missing <" + TAG_ROLES + "> in roles.xml");
Hai Zhangb7776682018-09-25 15:10:57 -0700419 }
420
421 private void parseRolesLocked(@NonNull XmlPullParser parser) throws IOException,
422 XmlPullParserException {
423 mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION));
Eugene Suslaabdefba2018-11-09 18:06:43 -0800424 mLastGrantPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
Hai Zhang458cedb2018-12-03 15:41:11 -0800425 mRoles.clear();
Hai Zhangb295ac42018-11-16 16:08:18 -0800426
Hai Zhangb7776682018-09-25 15:10:57 -0700427 int type;
Hai Zhangb295ac42018-11-16 16:08:18 -0800428 int depth;
429 int innerDepth = parser.getDepth() + 1;
Hai Zhangb7776682018-09-25 15:10:57 -0700430 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
Hai Zhangb295ac42018-11-16 16:08:18 -0800431 && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
432 if (depth > innerDepth || type != XmlPullParser.START_TAG) {
Hai Zhangb7776682018-09-25 15:10:57 -0700433 continue;
434 }
Hai Zhangb295ac42018-11-16 16:08:18 -0800435
Hai Zhangb7776682018-09-25 15:10:57 -0700436 if (parser.getName().equals(TAG_ROLE)) {
437 String roleName = parser.getAttributeValue(null, ATTRIBUTE_NAME);
438 ArraySet<String> roleHolders = parseRoleHoldersLocked(parser);
439 mRoles.put(roleName, roleHolders);
440 }
441 }
442 }
443
444 @NonNull
445 private ArraySet<String> parseRoleHoldersLocked(@NonNull XmlPullParser parser)
446 throws IOException, XmlPullParserException {
447 ArraySet<String> roleHolders = new ArraySet<>();
Hai Zhangb295ac42018-11-16 16:08:18 -0800448
Hai Zhangb7776682018-09-25 15:10:57 -0700449 int type;
Hai Zhangb295ac42018-11-16 16:08:18 -0800450 int depth;
451 int innerDepth = parser.getDepth() + 1;
Hai Zhangb7776682018-09-25 15:10:57 -0700452 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
Hai Zhangb295ac42018-11-16 16:08:18 -0800453 && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
454 if (depth > innerDepth || type != XmlPullParser.START_TAG) {
Hai Zhangb7776682018-09-25 15:10:57 -0700455 continue;
456 }
Hai Zhangb295ac42018-11-16 16:08:18 -0800457
Hai Zhangb7776682018-09-25 15:10:57 -0700458 if (parser.getName().equals(TAG_HOLDER)) {
459 String roleHolder = parser.getAttributeValue(null, ATTRIBUTE_NAME);
460 roleHolders.add(roleHolder);
461 }
462 }
Hai Zhangb295ac42018-11-16 16:08:18 -0800463
Hai Zhangb7776682018-09-25 15:10:57 -0700464 return roleHolders;
465 }
466
467 /**
468 * Destroy this state and delete the corresponding file. Any pending writes to the file will be
469 * cancelled and any future interaction with this state will throw an exception.
470 */
471 @GuardedBy("RoleManagerService.mLock")
472 public void destroySyncLocked() {
473 throwIfDestroyedLocked();
474 mWriteHandler.removeCallbacksAndMessages(null);
475 getFile(mUserId).delete();
476 mDestroyed = true;
477 }
478
479 @GuardedBy("RoleManagerService.mLock")
480 private void throwIfDestroyedLocked() {
481 if (mDestroyed) {
482 throw new IllegalStateException("This RoleUserState has already been destroyed");
483 }
484 }
485
486 private static @NonNull File getFile(@UserIdInt int userId) {
487 return new File(Environment.getUserSystemDirectory(userId), ROLES_FILE_NAME);
488 }
489}