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
17package com.android.server.devicepolicy;
18
19import android.annotation.Nullable;
20import android.app.admin.SystemUpdatePolicy;
21import android.content.ComponentName;
22import android.content.pm.PackageManagerInternal;
23import android.content.pm.UserInfo;
24import android.os.Environment;
25import android.os.UserHandle;
26import android.os.UserManager;
27import android.os.UserManagerInternal;
28import android.util.ArrayMap;
29import android.util.AtomicFile;
30import android.util.Log;
31import android.util.Pair;
32import android.util.Slog;
33import android.util.SparseArray;
34import android.util.Xml;
35
36import com.android.internal.util.FastXmlSerializer;
37
38import org.xmlpull.v1.XmlPullParser;
39import org.xmlpull.v1.XmlPullParserException;
40import org.xmlpull.v1.XmlSerializer;
41
42import java.io.File;
43import java.io.FileOutputStream;
44import java.io.IOException;
45import java.io.InputStream;
46import java.io.PrintWriter;
47import java.nio.charset.StandardCharsets;
48import java.util.List;
49import java.util.Map;
50import java.util.Set;
51
52import 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 */
61class 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