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