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.app.AppGlobals;
20import android.app.admin.SystemUpdatePolicy;
21import android.content.ComponentName;
22import android.content.pm.PackageInfo;
23import android.content.pm.PackageManager;
24import android.content.pm.PackageManager.NameNotFoundException;
25import android.os.Environment;
26import android.os.PersistableBundle;
27import android.os.RemoteException;
28import android.util.AtomicFile;
29import android.util.Slog;
30import android.util.Xml;
31
32import com.android.internal.annotations.VisibleForTesting;
33import com.android.internal.util.FastXmlSerializer;
34
35import org.xmlpull.v1.XmlPullParser;
36import org.xmlpull.v1.XmlPullParserException;
37import org.xmlpull.v1.XmlSerializer;
38
39import java.io.File;
40import java.io.FileOutputStream;
41import java.io.IOException;
42import java.io.InputStream;
43import java.io.OutputStream;
44import java.io.PrintWriter;
45import java.nio.charset.StandardCharsets;
46import java.util.HashMap;
47import java.util.Map;
48import java.util.Set;
49
50/**
51 * Stores and restores state for the Device and Profile owners. By definition there can be
52 * only one device owner, but there may be a profile owner for each user.
53 */
54class DeviceOwner {
55    private static final String TAG = "DevicePolicyManagerService";
56
57    private static final String DEVICE_OWNER_XML = "device_owner.xml";
58    private static final String TAG_DEVICE_OWNER = "device-owner";
59    private static final String TAG_DEVICE_INITIALIZER = "device-initializer";
60    private static final String TAG_PROFILE_OWNER = "profile-owner";
61    private static final String ATTR_NAME = "name";
62    private static final String ATTR_PACKAGE = "package";
63    private static final String ATTR_COMPONENT_NAME = "component";
64    private static final String ATTR_USERID = "userId";
65    private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy";
66
67    private AtomicFile fileForWriting;
68
69    // Input/Output streams for testing.
70    private InputStream mInputStreamForTest;
71    private OutputStream mOutputStreamForTest;
72
73    // Internal state for the device owner package.
74    private OwnerInfo mDeviceOwner;
75
76    // Internal state for the device initializer package.
77    private OwnerInfo mDeviceInitializer;
78
79    // Internal state for the profile owner packages.
80    private final HashMap<Integer, OwnerInfo> mProfileOwners = new HashMap<Integer, OwnerInfo>();
81
82    // Local system update policy controllable by device owner.
83    private SystemUpdatePolicy mSystemUpdatePolicy;
84
85    // Private default constructor.
86    private DeviceOwner() {
87    }
88
89    @VisibleForTesting
90    DeviceOwner(InputStream in, OutputStream out) {
91        mInputStreamForTest = in;
92        mOutputStreamForTest = out;
93    }
94
95    /**
96     * Loads the device owner state from disk.
97     */
98    static DeviceOwner load() {
99        DeviceOwner owner = new DeviceOwner();
100        if (new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML).exists()) {
101            owner.readOwnerFile();
102            return owner;
103        } else {
104            return null;
105        }
106    }
107
108    /**
109     * Creates an instance of the device owner object with the device owner set.
110     */
111    static DeviceOwner createWithDeviceOwner(String packageName, String ownerName) {
112        DeviceOwner owner = new DeviceOwner();
113        owner.mDeviceOwner = new OwnerInfo(ownerName, packageName);
114        return owner;
115    }
116
117    /**
118     * Creates an instance of the device owner object with the device initializer set.
119     */
120    static DeviceOwner createWithDeviceInitializer(ComponentName admin) {
121        DeviceOwner owner = new DeviceOwner();
122        owner.mDeviceInitializer = new OwnerInfo(null, admin);
123        return owner;
124    }
125
126    /**
127     * Creates an instance of the device owner object with the profile owner set.
128     */
129    static DeviceOwner createWithProfileOwner(ComponentName admin, String ownerName, int userId) {
130        DeviceOwner owner = new DeviceOwner();
131        owner.mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
132        return owner;
133    }
134
135    String getDeviceOwnerPackageName() {
136        return mDeviceOwner != null ? mDeviceOwner.packageName : null;
137    }
138
139    String getDeviceOwnerName() {
140        return mDeviceOwner != null ? mDeviceOwner.name : null;
141    }
142
143    void setDeviceOwner(String packageName, String ownerName) {
144        mDeviceOwner = new OwnerInfo(ownerName, packageName);
145    }
146
147    void clearDeviceOwner() {
148        mDeviceOwner = null;
149    }
150
151    ComponentName getDeviceInitializerComponent() {
152        return mDeviceInitializer.admin;
153    }
154
155    String getDeviceInitializerPackageName() {
156        return mDeviceInitializer != null ? mDeviceInitializer.packageName : null;
157    }
158
159    void setDeviceInitializer(ComponentName admin) {
160        mDeviceInitializer = new OwnerInfo(null, admin);
161    }
162
163    void clearDeviceInitializer() {
164        mDeviceInitializer = null;
165    }
166
167    boolean hasDeviceInitializer() {
168        return mDeviceInitializer != null;
169    }
170
171    void setProfileOwner(ComponentName admin, String ownerName, int userId) {
172        mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
173    }
174
175    void removeProfileOwner(int userId) {
176        mProfileOwners.remove(userId);
177    }
178
179    ComponentName getProfileOwnerComponent(int userId) {
180        OwnerInfo profileOwner = mProfileOwners.get(userId);
181        return profileOwner != null ? profileOwner.admin : null;
182    }
183
184    String getProfileOwnerName(int userId) {
185        OwnerInfo profileOwner = mProfileOwners.get(userId);
186        return profileOwner != null ? profileOwner.name : null;
187    }
188
189    Set<Integer> getProfileOwnerKeys() {
190        return mProfileOwners.keySet();
191    }
192
193    SystemUpdatePolicy getSystemUpdatePolicy() {
194        return mSystemUpdatePolicy;
195    }
196
197    void setSystemUpdatePolicy(SystemUpdatePolicy systemUpdatePolicy) {
198        mSystemUpdatePolicy = systemUpdatePolicy;
199    }
200
201    void clearSystemUpdatePolicy() {
202        mSystemUpdatePolicy = null;
203    }
204
205    boolean hasDeviceOwner() {
206        return mDeviceOwner != null;
207    }
208
209    static boolean isInstalled(String packageName, PackageManager pm) {
210        try {
211            PackageInfo pi;
212            if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
213                if ((pi.applicationInfo.flags) != 0) {
214                    return true;
215                }
216            }
217        } catch (NameNotFoundException nnfe) {
218            Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
219        }
220        return false;
221    }
222
223    static boolean isInstalledForUser(String packageName, int userHandle) {
224        try {
225            PackageInfo pi = (AppGlobals.getPackageManager())
226                    .getPackageInfo(packageName, 0, userHandle);
227            if (pi != null && pi.applicationInfo.flags != 0) {
228                return true;
229            }
230        } catch (RemoteException re) {
231            throw new RuntimeException("Package manager has died", re);
232        }
233
234        return false;
235    }
236
237    @VisibleForTesting
238    void readOwnerFile() {
239        try {
240            InputStream input = openRead();
241            XmlPullParser parser = Xml.newPullParser();
242            parser.setInput(input, StandardCharsets.UTF_8.name());
243            int type;
244            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT) {
245                if (type!=XmlPullParser.START_TAG) {
246                    continue;
247                }
248
249                String tag = parser.getName();
250                if (tag.equals(TAG_DEVICE_OWNER)) {
251                    String name = parser.getAttributeValue(null, ATTR_NAME);
252                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
253                    mDeviceOwner = new OwnerInfo(name, packageName);
254                } else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
255                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
256                    String initializerComponentStr =
257                            parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
258                    ComponentName admin =
259                            ComponentName.unflattenFromString(initializerComponentStr);
260                    if (admin != null) {
261                        mDeviceInitializer = new OwnerInfo(null, admin);
262                    } else {
263                        mDeviceInitializer = new OwnerInfo(null, packageName);
264                        Slog.e(TAG, "Error parsing device-owner file. Bad component name " +
265                                initializerComponentStr);
266                    }
267                } else if (tag.equals(TAG_PROFILE_OWNER)) {
268                    String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
269                    String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
270                    String profileOwnerComponentStr =
271                            parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
272                    int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
273                    OwnerInfo profileOwnerInfo = null;
274                    if (profileOwnerComponentStr != null) {
275                        ComponentName admin = ComponentName.unflattenFromString(
276                                profileOwnerComponentStr);
277                        if (admin != null) {
278                            profileOwnerInfo = new OwnerInfo(profileOwnerName, admin);
279                        } else {
280                            // This shouldn't happen but switch from package name -> component name
281                            // might have written bad device owner files. b/17652534
282                            Slog.e(TAG, "Error parsing device-owner file. Bad component name " +
283                                    profileOwnerComponentStr);
284                        }
285                    }
286                    if (profileOwnerInfo == null) {
287                        profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName);
288                    }
289                    mProfileOwners.put(userId, profileOwnerInfo);
290                } else if (TAG_SYSTEM_UPDATE_POLICY.equals(tag)) {
291                    mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser);
292                } else {
293                    throw new XmlPullParserException(
294                            "Unexpected tag in device owner file: " + tag);
295                }
296            }
297            input.close();
298        } catch (XmlPullParserException xppe) {
299            Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
300        } catch (IOException ioe) {
301            Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
302        }
303    }
304
305    @VisibleForTesting
306    void writeOwnerFile() {
307        synchronized (this) {
308            writeOwnerFileLocked();
309        }
310    }
311
312    private void writeOwnerFileLocked() {
313        try {
314            OutputStream outputStream = startWrite();
315            XmlSerializer out = new FastXmlSerializer();
316            out.setOutput(outputStream, StandardCharsets.UTF_8.name());
317            out.startDocument(null, true);
318
319            // Write device owner tag
320            if (mDeviceOwner != null) {
321                out.startTag(null, TAG_DEVICE_OWNER);
322                out.attribute(null, ATTR_PACKAGE, mDeviceOwner.packageName);
323                if (mDeviceOwner.name != null) {
324                    out.attribute(null, ATTR_NAME, mDeviceOwner.name);
325                }
326                out.endTag(null, TAG_DEVICE_OWNER);
327            }
328
329            // Write device initializer tag
330            if (mDeviceInitializer != null) {
331                out.startTag(null, TAG_DEVICE_INITIALIZER);
332                out.attribute(null, ATTR_PACKAGE, mDeviceInitializer.packageName);
333                if (mDeviceInitializer.admin != null) {
334                    out.attribute(
335                            null, ATTR_COMPONENT_NAME, mDeviceInitializer.admin.flattenToString());
336                }
337                out.endTag(null, TAG_DEVICE_INITIALIZER);
338            }
339
340            // Write profile owner tags
341            if (mProfileOwners.size() > 0) {
342                for (HashMap.Entry<Integer, OwnerInfo> owner : mProfileOwners.entrySet()) {
343                    out.startTag(null, TAG_PROFILE_OWNER);
344                    OwnerInfo ownerInfo = owner.getValue();
345                    out.attribute(null, ATTR_PACKAGE, ownerInfo.packageName);
346                    out.attribute(null, ATTR_NAME, ownerInfo.name);
347                    out.attribute(null, ATTR_USERID, Integer.toString(owner.getKey()));
348                    if (ownerInfo.admin != null) {
349                        out.attribute(null, ATTR_COMPONENT_NAME, ownerInfo.admin.flattenToString());
350                    }
351                    out.endTag(null, TAG_PROFILE_OWNER);
352                }
353            }
354
355            // Write system update policy tag
356            if (mSystemUpdatePolicy != null) {
357                out.startTag(null, TAG_SYSTEM_UPDATE_POLICY);
358                mSystemUpdatePolicy.saveToXml(out);
359                out.endTag(null, TAG_SYSTEM_UPDATE_POLICY);
360            }
361            out.endDocument();
362            out.flush();
363            finishWrite(outputStream);
364        } catch (IOException ioe) {
365            Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
366        }
367    }
368
369    private InputStream openRead() throws IOException {
370        if (mInputStreamForTest != null) {
371            return mInputStreamForTest;
372        }
373
374        return new AtomicFile(new File(Environment.getSystemSecureDirectory(),
375                DEVICE_OWNER_XML)).openRead();
376    }
377
378    private OutputStream startWrite() throws IOException {
379        if (mOutputStreamForTest != null) {
380            return mOutputStreamForTest;
381        }
382
383        fileForWriting = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
384                DEVICE_OWNER_XML));
385        return fileForWriting.startWrite();
386    }
387
388    private void finishWrite(OutputStream stream) {
389        if (fileForWriting != null) {
390            fileForWriting.finishWrite((FileOutputStream) stream);
391        }
392    }
393
394    private static class OwnerInfo {
395        public final String name;
396        public final String packageName;
397        public final ComponentName admin;
398
399        public OwnerInfo(String name, String packageName) {
400            this.name = name;
401            this.packageName = packageName;
402            this.admin = new ComponentName(packageName, "");
403        }
404
405        public OwnerInfo(String name, ComponentName admin) {
406            this.name = name;
407            this.admin = admin;
408            this.packageName = admin.getPackageName();
409        }
410        public void dump(String prefix, PrintWriter pw) {
411            pw.println(prefix + "admin=" + admin);
412            pw.println(prefix + "name=" + name);
413            pw.println();
414        }
415    }
416
417    public void dump(String prefix, PrintWriter pw) {
418        if (mDeviceOwner != null) {
419            pw.println(prefix + "Device Owner: ");
420            mDeviceOwner.dump(prefix + "  ", pw);
421        }
422        if (mProfileOwners != null) {
423            for (Map.Entry<Integer, OwnerInfo> entry : mProfileOwners.entrySet()) {
424                pw.println(prefix + "Profile Owner (User " + entry.getKey() + "): ");
425                entry.getValue().dump(prefix + "  ", pw);
426            }
427        }
428    }
429}
430