• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 package com.android.server.devicepolicy;
17 
18 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
19 
20 import android.annotation.Nullable;
21 import android.app.admin.SystemUpdateInfo;
22 import android.app.admin.SystemUpdatePolicy;
23 import android.content.ComponentName;
24 import android.os.UserHandle;
25 import android.util.ArrayMap;
26 import android.util.AtomicFile;
27 import android.util.IndentingPrintWriter;
28 import android.util.Log;
29 import android.util.Slog;
30 import android.util.TypedXmlPullParser;
31 import android.util.TypedXmlSerializer;
32 import android.util.Xml;
33 
34 import com.android.internal.annotations.VisibleForTesting;
35 
36 import libcore.io.IoUtils;
37 
38 import org.xmlpull.v1.XmlPullParserException;
39 
40 import java.io.File;
41 import java.io.FileOutputStream;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.time.LocalDate;
45 import java.util.ArrayList;
46 import java.util.List;
47 import java.util.Map;
48 
49 class OwnersData {
50     private static final String TAG = "DevicePolicyManagerService";
51 
52     private static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE
53 
54     // XML storing device owner info, system update policy and pending OTA update information.
55     private static final String DEVICE_OWNER_XML = "device_owner_2.xml";
56     private static final String PROFILE_OWNER_XML = "profile_owner.xml";
57 
58     private static final String TAG_ROOT = "root";
59     private static final String TAG_DEVICE_OWNER = "device-owner";
60     private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy";
61     private static final String TAG_FREEZE_PERIOD_RECORD = "freeze-record";
62     private static final String TAG_PENDING_OTA_INFO = "pending-ota-info";
63     private static final String TAG_PROFILE_OWNER = "profile-owner";
64     // Holds "context" for device-owner, this must not be show up before device-owner.
65     private static final String TAG_DEVICE_OWNER_CONTEXT = "device-owner-context";
66     private static final String TAG_DEVICE_OWNER_TYPE = "device-owner-type";
67     private static final String TAG_DEVICE_OWNER_PROTECTED_PACKAGES =
68             "device-owner-protected-packages";
69 
70     private static final String ATTR_NAME = "name";
71     private static final String ATTR_PACKAGE = "package";
72     private static final String ATTR_COMPONENT_NAME = "component";
73     private static final String ATTR_SIZE = "size";
74     private static final String ATTR_REMOTE_BUGREPORT_URI = "remoteBugreportUri";
75     private static final String ATTR_REMOTE_BUGREPORT_HASH = "remoteBugreportHash";
76     private static final String ATTR_USERID = "userId";
77     private static final String ATTR_FREEZE_RECORD_START = "start";
78     private static final String ATTR_FREEZE_RECORD_END = "end";
79     // Legacy attribute, its presence would mean the profile owner associated with it is
80     // managing a profile on an organization-owned device.
81     private static final String ATTR_CAN_ACCESS_DEVICE_IDS = "canAccessDeviceIds";
82     // New attribute for profile owner of organization-owned device.
83     private static final String ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE =
84             "isPoOrganizationOwnedDevice";
85     private static final String ATTR_DEVICE_OWNER_TYPE_VALUE = "value";
86 
87     // Internal state for the device owner package.
88     OwnerInfo mDeviceOwner;
89     int mDeviceOwnerUserId = UserHandle.USER_NULL;
90 
91     // Device owner type for a managed device.
92     final ArrayMap<String, Integer> mDeviceOwnerTypes = new ArrayMap<>();
93 
94     /** @deprecated moved to {@link ActiveAdmin#protectedPackages}. */
95     @Deprecated
96     @Nullable
97     ArrayMap<String, List<String>> mDeviceOwnerProtectedPackages;
98 
99     // Internal state for the profile owner packages.
100     final ArrayMap<Integer, OwnerInfo> mProfileOwners = new ArrayMap<>();
101 
102     // Local system update policy controllable by device owner.
103     SystemUpdatePolicy mSystemUpdatePolicy;
104     LocalDate mSystemUpdateFreezeStart;
105     LocalDate mSystemUpdateFreezeEnd;
106 
107     // Pending OTA info if there is one.
108     @Nullable
109     SystemUpdateInfo mSystemUpdateInfo;
110     private final PolicyPathProvider mPathProvider;
111 
OwnersData(PolicyPathProvider pathProvider)112     OwnersData(PolicyPathProvider pathProvider) {
113         mPathProvider = pathProvider;
114     }
115 
load(int[] allUsers)116     void load(int[] allUsers) {
117         new DeviceOwnerReadWriter().readFromFileLocked();
118 
119         for (int userId : allUsers) {
120             new ProfileOwnerReadWriter(userId).readFromFileLocked();
121         }
122 
123         OwnerInfo profileOwner = mProfileOwners.get(mDeviceOwnerUserId);
124         ComponentName admin = profileOwner != null ? profileOwner.admin : null;
125         if (mDeviceOwner != null && admin != null) {
126             Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported",
127                     mDeviceOwnerUserId));
128         }
129     }
130 
131     /**
132      * @return true upon success, false otherwise.
133      */
writeDeviceOwner()134     boolean writeDeviceOwner() {
135         if (DEBUG) {
136             Log.d(TAG, "Writing to device owner file");
137         }
138         return new DeviceOwnerReadWriter().writeToFileLocked();
139     }
140 
141     /**
142      * @return true upon success, false otherwise.
143      */
writeProfileOwner(int userId)144     boolean writeProfileOwner(int userId) {
145         if (DEBUG) {
146             Log.d(TAG, "Writing to profile owner file for user " + userId);
147         }
148         return new ProfileOwnerReadWriter(userId).writeToFileLocked();
149     }
150 
dump(IndentingPrintWriter pw)151     void dump(IndentingPrintWriter pw) {
152         boolean needBlank = false;
153         if (mDeviceOwner != null) {
154             pw.println("Device Owner: ");
155             pw.increaseIndent();
156             mDeviceOwner.dump(pw);
157             pw.println("User ID: " + mDeviceOwnerUserId);
158             pw.decreaseIndent();
159             needBlank = true;
160         }
161         if (mSystemUpdatePolicy != null) {
162             if (needBlank) {
163                 pw.println();
164             }
165             pw.println("System Update Policy: " + mSystemUpdatePolicy);
166             needBlank = true;
167         }
168         if (mProfileOwners != null) {
169             for (Map.Entry<Integer, OwnerInfo> entry : mProfileOwners.entrySet()) {
170                 if (needBlank) {
171                     pw.println();
172                 }
173                 pw.println("Profile Owner (User " + entry.getKey() + "): ");
174                 pw.increaseIndent();
175                 entry.getValue().dump(pw);
176                 pw.decreaseIndent();
177                 needBlank = true;
178             }
179         }
180         if (mSystemUpdateInfo != null) {
181             if (needBlank) {
182                 pw.println();
183             }
184             pw.println("Pending System Update: " + mSystemUpdateInfo);
185             needBlank = true;
186         }
187         if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) {
188             if (needBlank) {
189                 pw.println();
190             }
191             pw.println("System update freeze record: "
192                     + getSystemUpdateFreezePeriodRecordAsString());
193             needBlank = true;
194         }
195     }
196 
getSystemUpdateFreezePeriodRecordAsString()197     String getSystemUpdateFreezePeriodRecordAsString() {
198         StringBuilder freezePeriodRecord = new StringBuilder();
199         freezePeriodRecord.append("start: ");
200         if (mSystemUpdateFreezeStart != null) {
201             freezePeriodRecord.append(mSystemUpdateFreezeStart.toString());
202         } else {
203             freezePeriodRecord.append("null");
204         }
205         freezePeriodRecord.append("; end: ");
206         if (mSystemUpdateFreezeEnd != null) {
207             freezePeriodRecord.append(mSystemUpdateFreezeEnd.toString());
208         } else {
209             freezePeriodRecord.append("null");
210         }
211         return freezePeriodRecord.toString();
212     }
213 
214     @VisibleForTesting
getDeviceOwnerFile()215     File getDeviceOwnerFile() {
216         return new File(mPathProvider.getDataSystemDirectory(), DEVICE_OWNER_XML);
217     }
218 
219     @VisibleForTesting
getProfileOwnerFile(int userId)220     File getProfileOwnerFile(int userId) {
221         return new File(mPathProvider.getUserSystemDirectory(userId), PROFILE_OWNER_XML);
222     }
223 
224     private abstract static class FileReadWriter {
225         private final File mFile;
226 
FileReadWriter(File file)227         protected FileReadWriter(File file) {
228             mFile = file;
229         }
230 
shouldWrite()231         abstract boolean shouldWrite();
232 
writeToFileLocked()233         boolean writeToFileLocked() {
234             if (!shouldWrite()) {
235                 if (DEBUG) {
236                     Log.d(TAG, "No need to write to " + mFile);
237                 }
238                 // No contents, remove the file.
239                 if (mFile.exists()) {
240                     if (DEBUG) {
241                         Log.d(TAG, "Deleting existing " + mFile);
242                     }
243                     if (!mFile.delete()) {
244                         Slog.e(TAG, "Failed to remove " + mFile.getPath());
245                     }
246                 }
247                 return true;
248             }
249             if (DEBUG) {
250                 Log.d(TAG, "Writing to " + mFile);
251             }
252 
253             final AtomicFile f = new AtomicFile(mFile);
254             FileOutputStream outputStream = null;
255             try {
256                 outputStream = f.startWrite();
257                 final TypedXmlSerializer out = Xml.resolveSerializer(outputStream);
258 
259                 // Root tag
260                 out.startDocument(null, true);
261                 out.startTag(null, TAG_ROOT);
262 
263                 // Actual content
264                 writeInner(out);
265 
266                 // Close root
267                 out.endTag(null, TAG_ROOT);
268                 out.endDocument();
269                 out.flush();
270 
271                 // Commit the content.
272                 f.finishWrite(outputStream);
273                 outputStream = null;
274 
275             } catch (IOException e) {
276                 Slog.e(TAG, "Exception when writing", e);
277                 if (outputStream != null) {
278                     f.failWrite(outputStream);
279                 }
280                 return false;
281             }
282             return true;
283         }
284 
readFromFileLocked()285         void readFromFileLocked() {
286             if (!mFile.exists()) {
287                 if (DEBUG) {
288                     Log.d(TAG, "" + mFile + " doesn't exist");
289                 }
290                 return;
291             }
292             if (DEBUG) {
293                 Log.d(TAG, "Reading from " + mFile);
294             }
295             final AtomicFile f = new AtomicFile(mFile);
296             InputStream input = null;
297             try {
298                 input = f.openRead();
299                 final TypedXmlPullParser parser = Xml.resolvePullParser(input);
300 
301                 int type;
302                 int depth = 0;
303                 while ((type = parser.next()) != TypedXmlPullParser.END_DOCUMENT) {
304                     switch (type) {
305                         case TypedXmlPullParser.START_TAG:
306                             depth++;
307                             break;
308                         case TypedXmlPullParser.END_TAG:
309                             depth--;
310                             // fallthrough
311                         default:
312                             continue;
313                     }
314                     // Check the root tag
315                     final String tag = parser.getName();
316                     if (depth == 1) {
317                         if (!TAG_ROOT.equals(tag)) {
318                             Slog.e(TAG, "Invalid root tag: " + tag);
319                             return;
320                         }
321                         continue;
322                     }
323                     // readInner() will only see START_TAG at depth >= 2.
324                     if (!readInner(parser, depth, tag)) {
325                         return; // Error
326                     }
327                 }
328             } catch (XmlPullParserException | IOException e) {
329                 Slog.e(TAG, "Error parsing owners information file", e);
330             } finally {
331                 IoUtils.closeQuietly(input);
332             }
333         }
334 
writeInner(TypedXmlSerializer out)335         abstract void writeInner(TypedXmlSerializer out) throws IOException;
336 
readInner(TypedXmlPullParser parser, int depth, String tag)337         abstract boolean readInner(TypedXmlPullParser parser, int depth, String tag);
338     }
339 
340     private class DeviceOwnerReadWriter extends FileReadWriter {
341 
DeviceOwnerReadWriter()342         protected DeviceOwnerReadWriter() {
343             super(getDeviceOwnerFile());
344         }
345 
346         @Override
shouldWrite()347         boolean shouldWrite() {
348             return (mDeviceOwner != null) || (mSystemUpdatePolicy != null)
349                     || (mSystemUpdateInfo != null);
350         }
351 
352         @Override
writeInner(TypedXmlSerializer out)353         void writeInner(TypedXmlSerializer out) throws IOException {
354             if (mDeviceOwner != null) {
355                 mDeviceOwner.writeToXml(out, TAG_DEVICE_OWNER);
356                 out.startTag(null, TAG_DEVICE_OWNER_CONTEXT);
357                 out.attributeInt(null, ATTR_USERID, mDeviceOwnerUserId);
358                 out.endTag(null, TAG_DEVICE_OWNER_CONTEXT);
359 
360             }
361 
362             if (!mDeviceOwnerTypes.isEmpty()) {
363                 for (ArrayMap.Entry<String, Integer> entry : mDeviceOwnerTypes.entrySet()) {
364                     out.startTag(null, TAG_DEVICE_OWNER_TYPE);
365                     out.attribute(null, ATTR_PACKAGE, entry.getKey());
366                     out.attributeInt(null, ATTR_DEVICE_OWNER_TYPE_VALUE, entry.getValue());
367                     out.endTag(null, TAG_DEVICE_OWNER_TYPE);
368                 }
369             }
370 
371             if (mSystemUpdatePolicy != null) {
372                 out.startTag(null, TAG_SYSTEM_UPDATE_POLICY);
373                 mSystemUpdatePolicy.saveToXml(out);
374                 out.endTag(null, TAG_SYSTEM_UPDATE_POLICY);
375             }
376 
377             if (mSystemUpdateInfo != null) {
378                 mSystemUpdateInfo.writeToXml(out, TAG_PENDING_OTA_INFO);
379             }
380 
381             if (mSystemUpdateFreezeStart != null || mSystemUpdateFreezeEnd != null) {
382                 out.startTag(null, TAG_FREEZE_PERIOD_RECORD);
383                 if (mSystemUpdateFreezeStart != null) {
384                     out.attribute(
385                             null, ATTR_FREEZE_RECORD_START, mSystemUpdateFreezeStart.toString());
386                 }
387                 if (mSystemUpdateFreezeEnd != null) {
388                     out.attribute(null, ATTR_FREEZE_RECORD_END, mSystemUpdateFreezeEnd.toString());
389                 }
390                 out.endTag(null, TAG_FREEZE_PERIOD_RECORD);
391             }
392         }
393 
394         @Override
readInner(TypedXmlPullParser parser, int depth, String tag)395         boolean readInner(TypedXmlPullParser parser, int depth, String tag) {
396             if (depth > 2) {
397                 return true; // Ignore
398             }
399             switch (tag) {
400                 case TAG_DEVICE_OWNER:
401                     mDeviceOwner = OwnerInfo.readFromXml(parser);
402                     mDeviceOwnerUserId = UserHandle.USER_SYSTEM; // Set default
403                     break;
404                 case TAG_DEVICE_OWNER_CONTEXT: {
405                     mDeviceOwnerUserId =
406                             parser.getAttributeInt(null, ATTR_USERID, mDeviceOwnerUserId);
407                     break;
408                 }
409                 case TAG_SYSTEM_UPDATE_POLICY:
410                     mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser);
411                     break;
412                 case TAG_PENDING_OTA_INFO:
413                     mSystemUpdateInfo = SystemUpdateInfo.readFromXml(parser);
414                     break;
415                 case TAG_FREEZE_PERIOD_RECORD:
416                     String startDate = parser.getAttributeValue(null, ATTR_FREEZE_RECORD_START);
417                     String endDate = parser.getAttributeValue(null, ATTR_FREEZE_RECORD_END);
418                     if (startDate != null && endDate != null) {
419                         mSystemUpdateFreezeStart = LocalDate.parse(startDate);
420                         mSystemUpdateFreezeEnd = LocalDate.parse(endDate);
421                         if (mSystemUpdateFreezeStart.isAfter(mSystemUpdateFreezeEnd)) {
422                             Slog.e(TAG, "Invalid system update freeze record loaded");
423                             mSystemUpdateFreezeStart = null;
424                             mSystemUpdateFreezeEnd = null;
425                         }
426                     }
427                     break;
428                 case TAG_DEVICE_OWNER_TYPE:
429                     String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
430                     int deviceOwnerType = parser.getAttributeInt(
431                             null, ATTR_DEVICE_OWNER_TYPE_VALUE, DEVICE_OWNER_TYPE_DEFAULT);
432                     mDeviceOwnerTypes.put(packageName, deviceOwnerType);
433                     break;
434                 // Deprecated fields below.
435                 case TAG_DEVICE_OWNER_PROTECTED_PACKAGES:
436                     packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
437                     int protectedPackagesSize = parser.getAttributeInt(null, ATTR_SIZE, 0);
438                     List<String> protectedPackages = new ArrayList<>();
439                     for (int i = 0; i < protectedPackagesSize; i++) {
440                         protectedPackages.add(parser.getAttributeValue(null, ATTR_NAME + i));
441                     }
442                     if (mDeviceOwnerProtectedPackages == null) {
443                         mDeviceOwnerProtectedPackages = new ArrayMap<>();
444                     }
445                     mDeviceOwnerProtectedPackages.put(packageName, protectedPackages);
446                     break;
447                 default:
448                     Slog.e(TAG, "Unexpected tag: " + tag);
449                     return false;
450 
451             }
452             return true;
453         }
454     }
455 
456     private class ProfileOwnerReadWriter extends FileReadWriter {
457         private final int mUserId;
458 
ProfileOwnerReadWriter(int userId)459         ProfileOwnerReadWriter(int userId) {
460             super(getProfileOwnerFile(userId));
461             mUserId = userId;
462         }
463 
464         @Override
shouldWrite()465         boolean shouldWrite() {
466             return mProfileOwners.get(mUserId) != null;
467         }
468 
469         @Override
writeInner(TypedXmlSerializer out)470         void writeInner(TypedXmlSerializer out) throws IOException {
471             final OwnerInfo profileOwner = mProfileOwners.get(mUserId);
472             if (profileOwner != null) {
473                 profileOwner.writeToXml(out, TAG_PROFILE_OWNER);
474             }
475         }
476 
477         @Override
readInner(TypedXmlPullParser parser, int depth, String tag)478         boolean readInner(TypedXmlPullParser parser, int depth, String tag) {
479             if (depth > 2) {
480                 return true; // Ignore
481             }
482             switch (tag) {
483                 case TAG_PROFILE_OWNER:
484                     mProfileOwners.put(mUserId, OwnerInfo.readFromXml(parser));
485                     break;
486                 default:
487                     Slog.e(TAG, "Unexpected tag: " + tag);
488                     return false;
489 
490             }
491             return true;
492         }
493     }
494 
495     static class OwnerInfo {
496         public final String name;
497         public final String packageName;
498         public final ComponentName admin;
499         public String remoteBugreportUri;
500         public String remoteBugreportHash;
501         public boolean isOrganizationOwnedDevice;
502 
OwnerInfo(String name, ComponentName admin, String remoteBugreportUri, String remoteBugreportHash, boolean isOrganizationOwnedDevice)503         OwnerInfo(String name, ComponentName admin, String remoteBugreportUri,
504                 String remoteBugreportHash, boolean isOrganizationOwnedDevice) {
505             this.name = name;
506             this.admin = admin;
507             this.packageName = admin.getPackageName();
508             this.remoteBugreportUri = remoteBugreportUri;
509             this.remoteBugreportHash = remoteBugreportHash;
510             this.isOrganizationOwnedDevice = isOrganizationOwnedDevice;
511         }
512 
writeToXml(TypedXmlSerializer out, String tag)513         public void writeToXml(TypedXmlSerializer out, String tag) throws IOException {
514             out.startTag(null, tag);
515             if (name != null) {
516                 out.attribute(null, ATTR_NAME, name);
517             }
518             if (admin != null) {
519                 out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString());
520             }
521             if (remoteBugreportUri != null) {
522                 out.attribute(null, ATTR_REMOTE_BUGREPORT_URI, remoteBugreportUri);
523             }
524             if (remoteBugreportHash != null) {
525                 out.attribute(null, ATTR_REMOTE_BUGREPORT_HASH, remoteBugreportHash);
526             }
527             if (isOrganizationOwnedDevice) {
528                 out.attributeBoolean(
529                         null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE, isOrganizationOwnedDevice);
530             }
531             out.endTag(null, tag);
532         }
533 
readFromXml(TypedXmlPullParser parser)534         public static OwnerInfo readFromXml(TypedXmlPullParser parser) {
535             final String name = parser.getAttributeValue(null, ATTR_NAME);
536             final String componentName = parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
537             final String remoteBugreportUri =
538                     parser.getAttributeValue(null, ATTR_REMOTE_BUGREPORT_URI);
539             final String remoteBugreportHash =
540                     parser.getAttributeValue(null, ATTR_REMOTE_BUGREPORT_HASH);
541             final String canAccessDeviceIdsStr =
542                     parser.getAttributeValue(null, ATTR_CAN_ACCESS_DEVICE_IDS);
543             final boolean canAccessDeviceIds = "true".equals(canAccessDeviceIdsStr);
544             final String isOrgOwnedDeviceStr =
545                     parser.getAttributeValue(null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE);
546             final boolean isOrgOwnedDevice =
547                     "true".equals(isOrgOwnedDeviceStr) | canAccessDeviceIds;
548 
549             if (componentName == null) {
550                 Slog.e(TAG, "Owner component not found");
551                 return null;
552             }
553             final ComponentName admin = ComponentName.unflattenFromString(componentName);
554             if (admin == null) {
555                 Slog.e(TAG, "Owner component not parsable: " + componentName);
556                 return null;
557             }
558 
559             return new OwnerInfo(
560                     name, admin, remoteBugreportUri, remoteBugreportHash, isOrgOwnedDevice);
561         }
562 
dump(IndentingPrintWriter pw)563         public void dump(IndentingPrintWriter pw) {
564             pw.println("admin=" + admin);
565             pw.println("name=" + name);
566             pw.println("package=" + packageName);
567             pw.println("isOrganizationOwnedDevice=" + isOrganizationOwnedDevice);
568         }
569     }
570 }
571