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