1 /*
2  * Copyright (C) 2014 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.devicepolicy;
18 
19 import android.annotation.Nullable;
20 import android.app.AppOpsManagerInternal;
21 import android.app.admin.SystemUpdateInfo;
22 import android.app.admin.SystemUpdatePolicy;
23 import android.content.ComponentName;
24 import android.content.pm.PackageManager;
25 import android.content.pm.PackageManagerInternal;
26 import android.content.pm.UserInfo;
27 import android.os.Binder;
28 import android.os.Environment;
29 import android.os.UserHandle;
30 import android.os.UserManager;
31 import android.os.UserManagerInternal;
32 import android.util.ArrayMap;
33 import android.util.AtomicFile;
34 import android.util.Log;
35 import android.util.Pair;
36 import android.util.Slog;
37 import android.util.SparseArray;
38 import android.util.SparseIntArray;
39 import android.util.Xml;
40 
41 import com.android.internal.annotations.VisibleForTesting;
42 import com.android.internal.util.FastXmlSerializer;
43 import com.android.server.LocalServices;
44 
45 import org.xmlpull.v1.XmlPullParser;
46 import org.xmlpull.v1.XmlPullParserException;
47 import org.xmlpull.v1.XmlSerializer;
48 
49 import java.io.File;
50 import java.io.FileOutputStream;
51 import java.io.IOException;
52 import java.io.InputStream;
53 import java.io.PrintWriter;
54 import java.nio.charset.StandardCharsets;
55 import java.time.LocalDate;
56 import java.util.List;
57 import java.util.Map;
58 import java.util.Objects;
59 import java.util.Set;
60 
61 import libcore.io.IoUtils;
62 
63 /**
64  * Stores and restores state for the Device and Profile owners and related device-wide information.
65  * By definition there can be only one device owner, but there may be a profile owner for each user.
66  *
67  * <p>This class is thread safe, so individual methods can safely be called without locking.
68  * However, caller must still synchronize on their side to ensure integrity between multiple calls.
69  */
70 class Owners {
71     private static final String TAG = "DevicePolicyManagerService";
72 
73     private static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE
74 
75     private static final String DEVICE_OWNER_XML_LEGACY = "device_owner.xml";
76 
77     // XML storing device owner info, system update policy and pending OTA update information.
78     private static final String DEVICE_OWNER_XML = "device_owner_2.xml";
79 
80     private static final String PROFILE_OWNER_XML = "profile_owner.xml";
81 
82     private static final String TAG_ROOT = "root";
83 
84     private static final String TAG_DEVICE_OWNER = "device-owner";
85     private static final String TAG_DEVICE_INITIALIZER = "device-initializer";
86     private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy";
87     private static final String TAG_FREEZE_PERIOD_RECORD = "freeze-record";
88     private static final String TAG_PENDING_OTA_INFO = "pending-ota-info";
89     private static final String TAG_PROFILE_OWNER = "profile-owner";
90     // Holds "context" for device-owner, this must not be show up before device-owner.
91     private static final String TAG_DEVICE_OWNER_CONTEXT = "device-owner-context";
92 
93     private static final String ATTR_NAME = "name";
94     private static final String ATTR_PACKAGE = "package";
95     private static final String ATTR_COMPONENT_NAME = "component";
96     private static final String ATTR_REMOTE_BUGREPORT_URI = "remoteBugreportUri";
97     private static final String ATTR_REMOTE_BUGREPORT_HASH = "remoteBugreportHash";
98     private static final String ATTR_USERID = "userId";
99     private static final String ATTR_USER_RESTRICTIONS_MIGRATED = "userRestrictionsMigrated";
100     private static final String ATTR_FREEZE_RECORD_START = "start";
101     private static final String ATTR_FREEZE_RECORD_END = "end";
102 
103     private final UserManager mUserManager;
104     private final UserManagerInternal mUserManagerInternal;
105     private final PackageManagerInternal mPackageManagerInternal;
106 
107     private boolean mSystemReady;
108 
109     // Internal state for the device owner package.
110     private OwnerInfo mDeviceOwner;
111 
112     private int mDeviceOwnerUserId = UserHandle.USER_NULL;
113 
114     // Internal state for the profile owner packages.
115     private final ArrayMap<Integer, OwnerInfo> mProfileOwners = new ArrayMap<>();
116 
117     // Local system update policy controllable by device owner.
118     private SystemUpdatePolicy mSystemUpdatePolicy;
119     private LocalDate mSystemUpdateFreezeStart;
120     private LocalDate mSystemUpdateFreezeEnd;
121 
122     // Pending OTA info if there is one.
123     @Nullable
124     private SystemUpdateInfo mSystemUpdateInfo;
125 
126     private final Object mLock = new Object();
127     private final Injector mInjector;
128 
Owners(UserManager userManager, UserManagerInternal userManagerInternal, PackageManagerInternal packageManagerInternal)129     public Owners(UserManager userManager,
130             UserManagerInternal userManagerInternal,
131             PackageManagerInternal packageManagerInternal) {
132         this(userManager, userManagerInternal, packageManagerInternal, new Injector());
133     }
134 
135     @VisibleForTesting
Owners(UserManager userManager, UserManagerInternal userManagerInternal, PackageManagerInternal packageManagerInternal, Injector injector)136     Owners(UserManager userManager,
137             UserManagerInternal userManagerInternal,
138             PackageManagerInternal packageManagerInternal,
139             Injector injector) {
140         mUserManager = userManager;
141         mUserManagerInternal = userManagerInternal;
142         mPackageManagerInternal = packageManagerInternal;
143         mInjector = injector;
144     }
145 
146     /**
147      * Load configuration from the disk.
148      */
load()149     void load() {
150         synchronized (mLock) {
151             // First, try to read from the legacy file.
152             final File legacy = getLegacyConfigFile();
153 
154             final List<UserInfo> users = mUserManager.getUsers(true);
155 
156             if (readLegacyOwnerFileLocked(legacy)) {
157                 if (DEBUG) {
158                     Log.d(TAG, "Legacy config file found.");
159                 }
160 
161                 // Legacy file exists, write to new files and remove the legacy one.
162                 writeDeviceOwner();
163                 for (int userId : getProfileOwnerKeys()) {
164                     writeProfileOwner(userId);
165                 }
166                 if (DEBUG) {
167                     Log.d(TAG, "Deleting legacy config file");
168                 }
169                 if (!legacy.delete()) {
170                     Slog.e(TAG, "Failed to remove the legacy setting file");
171                 }
172             } else {
173                 // No legacy file, read from the new format files.
174                 new DeviceOwnerReadWriter().readFromFileLocked();
175 
176                 for (UserInfo ui : users) {
177                     new ProfileOwnerReadWriter(ui.id).readFromFileLocked();
178                 }
179             }
180             mUserManagerInternal.setDeviceManaged(hasDeviceOwner());
181             for (UserInfo ui : users) {
182                 mUserManagerInternal.setUserManaged(ui.id, hasProfileOwner(ui.id));
183             }
184             if (hasDeviceOwner() && hasProfileOwner(getDeviceOwnerUserId())) {
185                 Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported",
186                         getDeviceOwnerUserId()));
187             }
188             pushToPackageManagerLocked();
189             pushToAppOpsLocked();
190         }
191     }
192 
pushToPackageManagerLocked()193     private void pushToPackageManagerLocked() {
194         final SparseArray<String> po = new SparseArray<>();
195         for (int i = mProfileOwners.size() - 1; i >= 0; i--) {
196             po.put(mProfileOwners.keyAt(i), mProfileOwners.valueAt(i).packageName);
197         }
198         mPackageManagerInternal.setDeviceAndProfileOwnerPackages(
199                 mDeviceOwnerUserId, (mDeviceOwner != null ? mDeviceOwner.packageName : null),
200                 po);
201     }
202 
getDeviceOwnerPackageName()203     String getDeviceOwnerPackageName() {
204         synchronized (mLock) {
205             return mDeviceOwner != null ? mDeviceOwner.packageName : null;
206         }
207     }
208 
getDeviceOwnerUserId()209     int getDeviceOwnerUserId() {
210         synchronized (mLock) {
211             return mDeviceOwnerUserId;
212         }
213     }
214 
215     @Nullable
getDeviceOwnerUserIdAndComponent()216     Pair<Integer, ComponentName> getDeviceOwnerUserIdAndComponent() {
217         synchronized (mLock) {
218             if (mDeviceOwner == null) {
219                 return null;
220             } else {
221                 return Pair.create(mDeviceOwnerUserId, mDeviceOwner.admin);
222             }
223         }
224     }
225 
getDeviceOwnerName()226     String getDeviceOwnerName() {
227         synchronized (mLock) {
228             return mDeviceOwner != null ? mDeviceOwner.name : null;
229         }
230     }
231 
getDeviceOwnerComponent()232     ComponentName getDeviceOwnerComponent() {
233         synchronized (mLock) {
234             return mDeviceOwner != null ? mDeviceOwner.admin : null;
235         }
236     }
237 
getDeviceOwnerRemoteBugreportUri()238     String getDeviceOwnerRemoteBugreportUri() {
239         synchronized (mLock) {
240             return mDeviceOwner != null ? mDeviceOwner.remoteBugreportUri : null;
241         }
242     }
243 
getDeviceOwnerRemoteBugreportHash()244     String getDeviceOwnerRemoteBugreportHash() {
245         synchronized (mLock) {
246             return mDeviceOwner != null ? mDeviceOwner.remoteBugreportHash : null;
247         }
248     }
249 
setDeviceOwner(ComponentName admin, String ownerName, int userId)250     void setDeviceOwner(ComponentName admin, String ownerName, int userId) {
251         if (userId < 0) {
252             Slog.e(TAG, "Invalid user id for device owner user: " + userId);
253             return;
254         }
255         synchronized (mLock) {
256             // For a newly set DO, there's no need for migration.
257             setDeviceOwnerWithRestrictionsMigrated(admin, ownerName, userId,
258                     /* userRestrictionsMigrated =*/ true);
259         }
260     }
261 
262     // Note this should be only called during migration.  Normally when DO is set,
263     // userRestrictionsMigrated should always be true.
setDeviceOwnerWithRestrictionsMigrated(ComponentName admin, String ownerName, int userId, boolean userRestrictionsMigrated)264     void setDeviceOwnerWithRestrictionsMigrated(ComponentName admin, String ownerName, int userId,
265             boolean userRestrictionsMigrated) {
266         synchronized (mLock) {
267             mDeviceOwner = new OwnerInfo(ownerName, admin, userRestrictionsMigrated,
268                     /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/ null);
269             mDeviceOwnerUserId = userId;
270 
271             mUserManagerInternal.setDeviceManaged(true);
272             pushToPackageManagerLocked();
273             pushToAppOpsLocked();
274         }
275     }
276 
clearDeviceOwner()277     void clearDeviceOwner() {
278         synchronized (mLock) {
279             mDeviceOwner = null;
280             mDeviceOwnerUserId = UserHandle.USER_NULL;
281 
282             mUserManagerInternal.setDeviceManaged(false);
283             pushToPackageManagerLocked();
284             pushToAppOpsLocked();
285         }
286     }
287 
setProfileOwner(ComponentName admin, String ownerName, int userId)288     void setProfileOwner(ComponentName admin, String ownerName, int userId) {
289         synchronized (mLock) {
290             // For a newly set PO, there's no need for migration.
291             mProfileOwners.put(userId, new OwnerInfo(ownerName, admin,
292                     /* userRestrictionsMigrated =*/ true, /* remoteBugreportUri =*/ null,
293                     /* remoteBugreportHash =*/ null));
294             mUserManagerInternal.setUserManaged(userId, true);
295             pushToPackageManagerLocked();
296             pushToAppOpsLocked();
297         }
298     }
299 
removeProfileOwner(int userId)300     void removeProfileOwner(int userId) {
301         synchronized (mLock) {
302             mProfileOwners.remove(userId);
303             mUserManagerInternal.setUserManaged(userId, false);
304             pushToPackageManagerLocked();
305             pushToAppOpsLocked();
306         }
307     }
308 
transferProfileOwner(ComponentName target, int userId)309     void transferProfileOwner(ComponentName target, int userId) {
310         synchronized (mLock) {
311             final OwnerInfo ownerInfo = mProfileOwners.get(userId);
312             final OwnerInfo newOwnerInfo = new OwnerInfo(target.getPackageName(), target,
313                     ownerInfo.userRestrictionsMigrated, ownerInfo.remoteBugreportUri,
314                     ownerInfo.remoteBugreportHash);
315             mProfileOwners.put(userId, newOwnerInfo);
316             pushToPackageManagerLocked();
317             pushToAppOpsLocked();
318         }
319     }
320 
transferDeviceOwnership(ComponentName target)321     void transferDeviceOwnership(ComponentName target) {
322         synchronized (mLock) {
323             // We don't set a name because it's not used anyway.
324             // See DevicePolicyManagerService#getDeviceOwnerName
325             mDeviceOwner = new OwnerInfo(null, target,
326                     mDeviceOwner.userRestrictionsMigrated, mDeviceOwner.remoteBugreportUri,
327                     mDeviceOwner.remoteBugreportHash);
328             pushToPackageManagerLocked();
329             pushToAppOpsLocked();
330         }
331     }
332 
getProfileOwnerComponent(int userId)333     ComponentName getProfileOwnerComponent(int userId) {
334         synchronized (mLock) {
335             OwnerInfo profileOwner = mProfileOwners.get(userId);
336             return profileOwner != null ? profileOwner.admin : null;
337         }
338     }
339 
getProfileOwnerName(int userId)340     String getProfileOwnerName(int userId) {
341         synchronized (mLock) {
342             OwnerInfo profileOwner = mProfileOwners.get(userId);
343             return profileOwner != null ? profileOwner.name : null;
344         }
345     }
346 
getProfileOwnerPackage(int userId)347     String getProfileOwnerPackage(int userId) {
348         synchronized (mLock) {
349             OwnerInfo profileOwner = mProfileOwners.get(userId);
350             return profileOwner != null ? profileOwner.packageName : null;
351         }
352     }
353 
getProfileOwnerKeys()354     Set<Integer> getProfileOwnerKeys() {
355         synchronized (mLock) {
356             return mProfileOwners.keySet();
357         }
358     }
359 
getSystemUpdatePolicy()360     SystemUpdatePolicy getSystemUpdatePolicy() {
361         synchronized (mLock) {
362             return mSystemUpdatePolicy;
363         }
364     }
365 
setSystemUpdatePolicy(SystemUpdatePolicy systemUpdatePolicy)366     void setSystemUpdatePolicy(SystemUpdatePolicy systemUpdatePolicy) {
367         synchronized (mLock) {
368             mSystemUpdatePolicy = systemUpdatePolicy;
369         }
370     }
371 
clearSystemUpdatePolicy()372     void clearSystemUpdatePolicy() {
373         synchronized (mLock) {
374             mSystemUpdatePolicy = null;
375         }
376     }
377 
getSystemUpdateFreezePeriodRecord()378     Pair<LocalDate, LocalDate> getSystemUpdateFreezePeriodRecord() {
379         synchronized (mLock) {
380             return new Pair<>(mSystemUpdateFreezeStart, mSystemUpdateFreezeEnd);
381         }
382     }
383 
getSystemUpdateFreezePeriodRecordAsString()384     String getSystemUpdateFreezePeriodRecordAsString() {
385         StringBuilder freezePeriodRecord = new StringBuilder();
386         freezePeriodRecord.append("start: ");
387         if (mSystemUpdateFreezeStart != null) {
388             freezePeriodRecord.append(mSystemUpdateFreezeStart.toString());
389         } else {
390             freezePeriodRecord.append("null");
391         }
392         freezePeriodRecord.append("; end: ");
393         if (mSystemUpdateFreezeEnd != null) {
394             freezePeriodRecord.append(mSystemUpdateFreezeEnd.toString());
395         } else {
396             freezePeriodRecord.append("null");
397         }
398         return freezePeriodRecord.toString();
399     }
400 
401     /**
402      * Returns {@code true} if the freeze period record is changed, {@code false} otherwise.
403      */
setSystemUpdateFreezePeriodRecord(LocalDate start, LocalDate end)404     boolean setSystemUpdateFreezePeriodRecord(LocalDate start, LocalDate end) {
405         boolean changed = false;
406         synchronized (mLock) {
407             if (!Objects.equals(mSystemUpdateFreezeStart, start)) {
408                 mSystemUpdateFreezeStart = start;
409                 changed = true;
410             }
411             if (!Objects.equals(mSystemUpdateFreezeEnd, end)) {
412                 mSystemUpdateFreezeEnd = end;
413                 changed = true;
414             }
415         }
416         return changed;
417     }
418 
hasDeviceOwner()419     boolean hasDeviceOwner() {
420         synchronized (mLock) {
421             return mDeviceOwner != null;
422         }
423     }
424 
isDeviceOwnerUserId(int userId)425     boolean isDeviceOwnerUserId(int userId) {
426         synchronized (mLock) {
427             return mDeviceOwner != null && mDeviceOwnerUserId == userId;
428         }
429     }
430 
hasProfileOwner(int userId)431     boolean hasProfileOwner(int userId) {
432         synchronized (mLock) {
433             return getProfileOwnerComponent(userId) != null;
434         }
435     }
436 
437     /**
438      * @return true if user restrictions need to be migrated for DO.
439      */
getDeviceOwnerUserRestrictionsNeedsMigration()440     boolean getDeviceOwnerUserRestrictionsNeedsMigration() {
441         synchronized (mLock) {
442             return mDeviceOwner != null && !mDeviceOwner.userRestrictionsMigrated;
443         }
444     }
445 
446     /**
447      * @return true if user restrictions need to be migrated for PO.
448      */
getProfileOwnerUserRestrictionsNeedsMigration(int userId)449     boolean getProfileOwnerUserRestrictionsNeedsMigration(int userId) {
450         synchronized (mLock) {
451             OwnerInfo profileOwner = mProfileOwners.get(userId);
452             return profileOwner != null && !profileOwner.userRestrictionsMigrated;
453         }
454     }
455 
456     /** Sets the user restrictions migrated flag, and also writes to the file. */
setDeviceOwnerUserRestrictionsMigrated()457     void setDeviceOwnerUserRestrictionsMigrated() {
458         synchronized (mLock) {
459             if (mDeviceOwner != null) {
460                 mDeviceOwner.userRestrictionsMigrated = true;
461             }
462             writeDeviceOwner();
463         }
464     }
465 
466     /** Sets the remote bugreport uri and hash, and also writes to the file. */
setDeviceOwnerRemoteBugreportUriAndHash(String remoteBugreportUri, String remoteBugreportHash)467     void setDeviceOwnerRemoteBugreportUriAndHash(String remoteBugreportUri,
468             String remoteBugreportHash) {
469         synchronized (mLock) {
470             if (mDeviceOwner != null) {
471                 mDeviceOwner.remoteBugreportUri = remoteBugreportUri;
472                 mDeviceOwner.remoteBugreportHash = remoteBugreportHash;
473             }
474             writeDeviceOwner();
475         }
476     }
477 
478     /** Sets the user restrictions migrated flag, and also writes to the file.  */
setProfileOwnerUserRestrictionsMigrated(int userId)479     void setProfileOwnerUserRestrictionsMigrated(int userId) {
480         synchronized (mLock) {
481             OwnerInfo profileOwner = mProfileOwners.get(userId);
482             if (profileOwner != null) {
483                 profileOwner.userRestrictionsMigrated = true;
484             }
485             writeProfileOwner(userId);
486         }
487     }
488 
readLegacyOwnerFileLocked(File file)489     private boolean readLegacyOwnerFileLocked(File file) {
490         if (!file.exists()) {
491             // Already migrated or the device has no owners.
492             return false;
493         }
494         try {
495             InputStream input = new AtomicFile(file).openRead();
496             XmlPullParser parser = Xml.newPullParser();
497             parser.setInput(input, StandardCharsets.UTF_8.name());
498             int type;
499             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT) {
500                 if (type!=XmlPullParser.START_TAG) {
501                     continue;
502                 }
503 
504                 String tag = parser.getName();
505                 if (tag.equals(TAG_DEVICE_OWNER)) {
506                     String name = parser.getAttributeValue(null, ATTR_NAME);
507                     String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
508                     mDeviceOwner = new OwnerInfo(name, packageName,
509                             /* userRestrictionsMigrated =*/ false, /* remoteBugreportUri =*/ null,
510                             /* remoteBugreportHash =*/ null);
511                     mDeviceOwnerUserId = UserHandle.USER_SYSTEM;
512                 } else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
513                     // Deprecated tag
514                 } else if (tag.equals(TAG_PROFILE_OWNER)) {
515                     String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
516                     String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
517                     String profileOwnerComponentStr =
518                             parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
519                     int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
520                     OwnerInfo profileOwnerInfo = null;
521                     if (profileOwnerComponentStr != null) {
522                         ComponentName admin = ComponentName.unflattenFromString(
523                                 profileOwnerComponentStr);
524                         if (admin != null) {
525                             profileOwnerInfo = new OwnerInfo(profileOwnerName, admin,
526                                 /* userRestrictionsMigrated =*/ false, null, null);
527                         } else {
528                             // This shouldn't happen but switch from package name -> component name
529                             // might have written bad device owner files. b/17652534
530                             Slog.e(TAG, "Error parsing device-owner file. Bad component name " +
531                                     profileOwnerComponentStr);
532                         }
533                     }
534                     if (profileOwnerInfo == null) {
535                         profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName,
536                                 /* userRestrictionsMigrated =*/ false,
537                                 /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/ null);
538                     }
539                     mProfileOwners.put(userId, profileOwnerInfo);
540                 } else if (TAG_SYSTEM_UPDATE_POLICY.equals(tag)) {
541                     mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser);
542                 } else {
543                     throw new XmlPullParserException(
544                             "Unexpected tag in device owner file: " + tag);
545                 }
546             }
547             input.close();
548         } catch (XmlPullParserException|IOException e) {
549             Slog.e(TAG, "Error parsing device-owner file", e);
550         }
551         return true;
552     }
553 
writeDeviceOwner()554     void writeDeviceOwner() {
555         synchronized (mLock) {
556             if (DEBUG) {
557                 Log.d(TAG, "Writing to device owner file");
558             }
559             new DeviceOwnerReadWriter().writeToFileLocked();
560         }
561     }
562 
writeProfileOwner(int userId)563     void writeProfileOwner(int userId) {
564         synchronized (mLock) {
565             if (DEBUG) {
566                 Log.d(TAG, "Writing to profile owner file for user " + userId);
567             }
568             new ProfileOwnerReadWriter(userId).writeToFileLocked();
569         }
570     }
571 
572     /**
573      * Saves the given {@link SystemUpdateInfo} if it is different from the existing one, or if
574      * none exists.
575      *
576      * @return Whether the saved system update information has changed.
577      */
saveSystemUpdateInfo(@ullable SystemUpdateInfo newInfo)578     boolean saveSystemUpdateInfo(@Nullable SystemUpdateInfo newInfo) {
579         synchronized (mLock) {
580             // Check if we already have the same update information.
581             if (Objects.equals(newInfo, mSystemUpdateInfo)) {
582                 return false;
583             }
584 
585             mSystemUpdateInfo = newInfo;
586             new DeviceOwnerReadWriter().writeToFileLocked();
587             return true;
588         }
589     }
590 
591     @Nullable
getSystemUpdateInfo()592     public SystemUpdateInfo getSystemUpdateInfo() {
593         synchronized (mLock) {
594             return mSystemUpdateInfo;
595         }
596     }
597 
pushToAppOpsLocked()598     void pushToAppOpsLocked() {
599         if (!mSystemReady) {
600             return;
601         }
602         final long ident = Binder.clearCallingIdentity();
603         try {
604             final SparseIntArray owners = new SparseIntArray();
605             if (mDeviceOwner != null) {
606                 final int uid = mPackageManagerInternal.getPackageUid(mDeviceOwner.packageName,
607                         PackageManager.MATCH_ALL | PackageManager.MATCH_KNOWN_PACKAGES,
608                         mDeviceOwnerUserId);
609                 if (uid >= 0) {
610                     owners.put(mDeviceOwnerUserId, uid);
611                 }
612             }
613             if (mProfileOwners != null) {
614                 for (int poi = mProfileOwners.size() - 1; poi >= 0; poi--) {
615                     final int uid = mPackageManagerInternal.getPackageUid(
616                             mProfileOwners.valueAt(poi).packageName,
617                             PackageManager.MATCH_ALL | PackageManager.MATCH_KNOWN_PACKAGES,
618                             mProfileOwners.keyAt(poi));
619                     if (uid >= 0) {
620                         owners.put(mProfileOwners.keyAt(poi), uid);
621                     }
622                 }
623             }
624             AppOpsManagerInternal appops = LocalServices.getService(AppOpsManagerInternal.class);
625             if (appops != null) {
626                 appops.setDeviceAndProfileOwners(owners.size() > 0 ? owners : null);
627             }
628         } finally {
629             Binder.restoreCallingIdentity(ident);
630         }
631     }
632 
systemReady()633     public void systemReady() {
634         synchronized (mLock) {
635             mSystemReady = true;
636             pushToAppOpsLocked();
637         }
638     }
639 
640     private abstract static class FileReadWriter {
641         private final File mFile;
642 
FileReadWriter(File file)643         protected FileReadWriter(File file) {
644             mFile = file;
645         }
646 
shouldWrite()647         abstract boolean shouldWrite();
648 
writeToFileLocked()649         void writeToFileLocked() {
650             if (!shouldWrite()) {
651                 if (DEBUG) {
652                     Log.d(TAG, "No need to write to " + mFile);
653                 }
654                 // No contents, remove the file.
655                 if (mFile.exists()) {
656                     if (DEBUG) {
657                         Log.d(TAG, "Deleting existing " + mFile);
658                     }
659                     if (!mFile.delete()) {
660                         Slog.e(TAG, "Failed to remove " + mFile.getPath());
661                     }
662                 }
663                 return;
664             }
665             if (DEBUG) {
666                 Log.d(TAG, "Writing to " + mFile);
667             }
668 
669             final AtomicFile f = new AtomicFile(mFile);
670             FileOutputStream outputStream = null;
671             try {
672                 outputStream = f.startWrite();
673                 final XmlSerializer out = new FastXmlSerializer();
674                 out.setOutput(outputStream, StandardCharsets.UTF_8.name());
675 
676                 // Root tag
677                 out.startDocument(null, true);
678                 out.startTag(null, TAG_ROOT);
679 
680                 // Actual content
681                 writeInner(out);
682 
683                 // Close root
684                 out.endTag(null, TAG_ROOT);
685                 out.endDocument();
686                 out.flush();
687 
688                 // Commit the content.
689                 f.finishWrite(outputStream);
690                 outputStream = null;
691 
692             } catch (IOException e) {
693                 Slog.e(TAG, "Exception when writing", e);
694                 if (outputStream != null) {
695                     f.failWrite(outputStream);
696                 }
697             }
698         }
699 
readFromFileLocked()700         void readFromFileLocked() {
701             if (!mFile.exists()) {
702                 if (DEBUG) {
703                     Log.d(TAG, "" + mFile + " doesn't exist");
704                 }
705                 return;
706             }
707             if (DEBUG) {
708                 Log.d(TAG, "Reading from " + mFile);
709             }
710             final AtomicFile f = new AtomicFile(mFile);
711             InputStream input = null;
712             try {
713                 input = f.openRead();
714                 final XmlPullParser parser = Xml.newPullParser();
715                 parser.setInput(input, StandardCharsets.UTF_8.name());
716 
717                 int type;
718                 int depth = 0;
719                 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
720                     switch (type) {
721                         case XmlPullParser.START_TAG:
722                             depth++;
723                             break;
724                         case XmlPullParser.END_TAG:
725                             depth--;
726                             // fallthrough
727                         default:
728                             continue;
729                     }
730                     // Check the root tag
731                     final String tag = parser.getName();
732                     if (depth == 1) {
733                         if (!TAG_ROOT.equals(tag)) {
734                             Slog.e(TAG, "Invalid root tag: " + tag);
735                             return;
736                         }
737                         continue;
738                     }
739                     // readInner() will only see START_TAG at depth >= 2.
740                     if (!readInner(parser, depth, tag)) {
741                         return; // Error
742                     }
743                 }
744             } catch (XmlPullParserException | IOException e) {
745                 Slog.e(TAG, "Error parsing owners information file", e);
746             } finally {
747                 IoUtils.closeQuietly(input);
748             }
749         }
750 
writeInner(XmlSerializer out)751         abstract void writeInner(XmlSerializer out) throws IOException;
752 
readInner(XmlPullParser parser, int depth, String tag)753         abstract boolean readInner(XmlPullParser parser, int depth, String tag);
754     }
755 
756     private class DeviceOwnerReadWriter extends FileReadWriter {
757 
DeviceOwnerReadWriter()758         protected DeviceOwnerReadWriter() {
759             super(getDeviceOwnerFile());
760         }
761 
762         @Override
shouldWrite()763         boolean shouldWrite() {
764             return (mDeviceOwner != null) || (mSystemUpdatePolicy != null)
765                     || (mSystemUpdateInfo != null);
766         }
767 
768         @Override
writeInner(XmlSerializer out)769         void writeInner(XmlSerializer out) throws IOException {
770             if (mDeviceOwner != null) {
771                 mDeviceOwner.writeToXml(out, TAG_DEVICE_OWNER);
772                 out.startTag(null, TAG_DEVICE_OWNER_CONTEXT);
773                 out.attribute(null, ATTR_USERID, String.valueOf(mDeviceOwnerUserId));
774                 out.endTag(null, TAG_DEVICE_OWNER_CONTEXT);
775             }
776 
777             if (mSystemUpdatePolicy != null) {
778                 out.startTag(null, TAG_SYSTEM_UPDATE_POLICY);
779                 mSystemUpdatePolicy.saveToXml(out);
780                 out.endTag(null, TAG_SYSTEM_UPDATE_POLICY);
781             }
782 
783             if (mSystemUpdateInfo != null) {
784                 mSystemUpdateInfo.writeToXml(out, TAG_PENDING_OTA_INFO);
785             }
786 
787             if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) {
788                 out.startTag(null, TAG_FREEZE_PERIOD_RECORD);
789                 if (mSystemUpdateFreezeStart != null) {
790                     out.attribute(null, ATTR_FREEZE_RECORD_START,
791                             mSystemUpdateFreezeStart.toString());
792                 }
793                 if (mSystemUpdateFreezeEnd != null) {
794                     out.attribute(null, ATTR_FREEZE_RECORD_END, mSystemUpdateFreezeEnd.toString());
795                 }
796                 out.endTag(null, TAG_FREEZE_PERIOD_RECORD);
797             }
798         }
799 
800         @Override
readInner(XmlPullParser parser, int depth, String tag)801         boolean readInner(XmlPullParser parser, int depth, String tag) {
802             if (depth > 2) {
803                 return true; // Ignore
804             }
805             switch (tag) {
806                 case TAG_DEVICE_OWNER:
807                     mDeviceOwner = OwnerInfo.readFromXml(parser);
808                     mDeviceOwnerUserId = UserHandle.USER_SYSTEM; // Set default
809                     break;
810                 case TAG_DEVICE_OWNER_CONTEXT: {
811                     final String userIdString =
812                             parser.getAttributeValue(null, ATTR_USERID);
813                     try {
814                         mDeviceOwnerUserId = Integer.parseInt(userIdString);
815                     } catch (NumberFormatException e) {
816                         Slog.e(TAG, "Error parsing user-id " + userIdString);
817                     }
818                     break;
819                 }
820                 case TAG_DEVICE_INITIALIZER:
821                     // Deprecated tag
822                     break;
823                 case TAG_SYSTEM_UPDATE_POLICY:
824                     mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser);
825                     break;
826                 case TAG_PENDING_OTA_INFO:
827                     mSystemUpdateInfo = SystemUpdateInfo.readFromXml(parser);
828                     break;
829                 case TAG_FREEZE_PERIOD_RECORD:
830                     String startDate = parser.getAttributeValue(null, ATTR_FREEZE_RECORD_START);
831                     String endDate = parser.getAttributeValue(null, ATTR_FREEZE_RECORD_END);
832                     if (startDate != null && endDate != null) {
833                         mSystemUpdateFreezeStart = LocalDate.parse(startDate);
834                         mSystemUpdateFreezeEnd = LocalDate.parse(endDate);
835                         if (mSystemUpdateFreezeStart.isAfter(mSystemUpdateFreezeEnd)) {
836                             Slog.e(TAG, "Invalid system update freeze record loaded");
837                             mSystemUpdateFreezeStart = null;
838                             mSystemUpdateFreezeEnd = null;
839                         }
840                     }
841                     break;
842                 default:
843                     Slog.e(TAG, "Unexpected tag: " + tag);
844                     return false;
845 
846             }
847             return true;
848         }
849     }
850 
851     private class ProfileOwnerReadWriter extends FileReadWriter {
852         private final int mUserId;
853 
ProfileOwnerReadWriter(int userId)854         ProfileOwnerReadWriter(int userId) {
855             super(getProfileOwnerFile(userId));
856             mUserId = userId;
857         }
858 
859         @Override
shouldWrite()860         boolean shouldWrite() {
861             return mProfileOwners.get(mUserId) != null;
862         }
863 
864         @Override
writeInner(XmlSerializer out)865         void writeInner(XmlSerializer out) throws IOException {
866             final OwnerInfo profileOwner = mProfileOwners.get(mUserId);
867             if (profileOwner != null) {
868                 profileOwner.writeToXml(out, TAG_PROFILE_OWNER);
869             }
870         }
871 
872         @Override
readInner(XmlPullParser parser, int depth, String tag)873         boolean readInner(XmlPullParser parser, int depth, String tag) {
874             if (depth > 2) {
875                 return true; // Ignore
876             }
877             switch (tag) {
878                 case TAG_PROFILE_OWNER:
879                     mProfileOwners.put(mUserId, OwnerInfo.readFromXml(parser));
880                     break;
881                 default:
882                     Slog.e(TAG, "Unexpected tag: " + tag);
883                     return false;
884 
885             }
886             return true;
887         }
888     }
889 
890     static class OwnerInfo {
891         public final String name;
892         public final String packageName;
893         public final ComponentName admin;
894         public boolean userRestrictionsMigrated;
895         public String remoteBugreportUri;
896         public String remoteBugreportHash;
897 
OwnerInfo(String name, String packageName, boolean userRestrictionsMigrated, String remoteBugreportUri, String remoteBugreportHash)898         public OwnerInfo(String name, String packageName, boolean userRestrictionsMigrated,
899                 String remoteBugreportUri, String remoteBugreportHash) {
900             this.name = name;
901             this.packageName = packageName;
902             this.admin = new ComponentName(packageName, "");
903             this.userRestrictionsMigrated = userRestrictionsMigrated;
904             this.remoteBugreportUri = remoteBugreportUri;
905             this.remoteBugreportHash = remoteBugreportHash;
906         }
907 
OwnerInfo(String name, ComponentName admin, boolean userRestrictionsMigrated, String remoteBugreportUri, String remoteBugreportHash)908         public OwnerInfo(String name, ComponentName admin, boolean userRestrictionsMigrated,
909                 String remoteBugreportUri, String remoteBugreportHash) {
910             this.name = name;
911             this.admin = admin;
912             this.packageName = admin.getPackageName();
913             this.userRestrictionsMigrated = userRestrictionsMigrated;
914             this.remoteBugreportUri = remoteBugreportUri;
915             this.remoteBugreportHash = remoteBugreportHash;
916         }
917 
writeToXml(XmlSerializer out, String tag)918         public void writeToXml(XmlSerializer out, String tag) throws IOException {
919             out.startTag(null, tag);
920             out.attribute(null, ATTR_PACKAGE, packageName);
921             if (name != null) {
922                 out.attribute(null, ATTR_NAME, name);
923             }
924             if (admin != null) {
925                 out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString());
926             }
927             out.attribute(null, ATTR_USER_RESTRICTIONS_MIGRATED,
928                     String.valueOf(userRestrictionsMigrated));
929             if (remoteBugreportUri != null) {
930                 out.attribute(null, ATTR_REMOTE_BUGREPORT_URI, remoteBugreportUri);
931             }
932             if (remoteBugreportHash != null) {
933                 out.attribute(null, ATTR_REMOTE_BUGREPORT_HASH, remoteBugreportHash);
934             }
935             out.endTag(null, tag);
936         }
937 
readFromXml(XmlPullParser parser)938         public static OwnerInfo readFromXml(XmlPullParser parser) {
939             final String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
940             final String name = parser.getAttributeValue(null, ATTR_NAME);
941             final String componentName =
942                     parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
943             final String userRestrictionsMigratedStr =
944                     parser.getAttributeValue(null, ATTR_USER_RESTRICTIONS_MIGRATED);
945             final boolean userRestrictionsMigrated =
946                     ("true".equals(userRestrictionsMigratedStr));
947             final String remoteBugreportUri = parser.getAttributeValue(null,
948                     ATTR_REMOTE_BUGREPORT_URI);
949             final String remoteBugreportHash = parser.getAttributeValue(null,
950                     ATTR_REMOTE_BUGREPORT_HASH);
951 
952             // Has component name?  If so, return [name, component]
953             if (componentName != null) {
954                 final ComponentName admin = ComponentName.unflattenFromString(componentName);
955                 if (admin != null) {
956                     return new OwnerInfo(name, admin, userRestrictionsMigrated,
957                             remoteBugreportUri, remoteBugreportHash);
958                 } else {
959                     // This shouldn't happen but switch from package name -> component name
960                     // might have written bad device owner files. b/17652534
961                     Slog.e(TAG, "Error parsing owner file. Bad component name " +
962                             componentName);
963                 }
964             }
965 
966             // Else, build with [name, package]
967             return new OwnerInfo(name, packageName, userRestrictionsMigrated, remoteBugreportUri,
968                     remoteBugreportHash);
969         }
970 
dump(String prefix, PrintWriter pw)971         public void dump(String prefix, PrintWriter pw) {
972             pw.println(prefix + "admin=" + admin);
973             pw.println(prefix + "name=" + name);
974             pw.println(prefix + "package=" + packageName);
975         }
976     }
977 
dump(String prefix, PrintWriter pw)978     public void dump(String prefix, PrintWriter pw) {
979         boolean needBlank = false;
980         if (mDeviceOwner != null) {
981             pw.println(prefix + "Device Owner: ");
982             mDeviceOwner.dump(prefix + "  ", pw);
983             pw.println(prefix + "  User ID: " + mDeviceOwnerUserId);
984             needBlank = true;
985         }
986         if (mSystemUpdatePolicy != null) {
987             if (needBlank) {
988                 pw.println();
989             }
990             pw.println(prefix + "System Update Policy: " + mSystemUpdatePolicy);
991             needBlank = true;
992         }
993         if (mProfileOwners != null) {
994             for (Map.Entry<Integer, OwnerInfo> entry : mProfileOwners.entrySet()) {
995                 if (needBlank) {
996                     pw.println();
997                 }
998                 pw.println(prefix + "Profile Owner (User " + entry.getKey() + "): ");
999                 entry.getValue().dump(prefix + "  ", pw);
1000                 needBlank = true;
1001             }
1002         }
1003         if (mSystemUpdateInfo != null) {
1004             if (needBlank) {
1005                 pw.println();
1006             }
1007             pw.println(prefix + "Pending System Update: " + mSystemUpdateInfo);
1008             needBlank = true;
1009         }
1010         if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) {
1011             if (needBlank) {
1012                 pw.println();
1013             }
1014             pw.println(prefix + "System update freeze record: "
1015                     + getSystemUpdateFreezePeriodRecordAsString());
1016             needBlank = true;
1017         }
1018     }
1019 
1020     @VisibleForTesting
getLegacyConfigFile()1021     File getLegacyConfigFile() {
1022         return new File(mInjector.environmentGetDataSystemDirectory(), DEVICE_OWNER_XML_LEGACY);
1023     }
1024 
1025     @VisibleForTesting
getDeviceOwnerFile()1026     File getDeviceOwnerFile() {
1027         return new File(mInjector.environmentGetDataSystemDirectory(), DEVICE_OWNER_XML);
1028     }
1029 
1030     @VisibleForTesting
getProfileOwnerFile(int userId)1031     File getProfileOwnerFile(int userId) {
1032         return new File(mInjector.environmentGetUserSystemDirectory(userId), PROFILE_OWNER_XML);
1033     }
1034 
1035     @VisibleForTesting
1036     public static class Injector {
environmentGetDataSystemDirectory()1037         File environmentGetDataSystemDirectory() {
1038             return Environment.getDataSystemDirectory();
1039         }
1040 
environmentGetUserSystemDirectory(int userId)1041         File environmentGetUserSystemDirectory(int userId) {
1042             return Environment.getUserSystemDirectory(userId);
1043         }
1044     }
1045 }
1046