1eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad/*
2eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Copyright (C) 2016 The Android Open Source Project
3eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad *
4eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Licensed under the Apache License, Version 2.0 (the "License");
5eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * you may not use this file except in compliance with the License.
6eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * You may obtain a copy of the License at
7eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad *
8eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad *      http://www.apache.org/licenses/LICENSE-2.0
9eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad *
10eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Unless required by applicable law or agreed to in writing, software
11eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * distributed under the License is distributed on an "AS IS" BASIS,
12eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * See the License for the specific language governing permissions and
14eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * limitations under the License.
15eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad */
16eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
17eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadpackage com.android.server.om;
18eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
19eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport static com.android.server.om.OverlayManagerService.DEBUG;
20eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport static com.android.server.om.OverlayManagerService.TAG;
21eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
22eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.annotation.NonNull;
23eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.content.om.OverlayInfo;
24eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.content.pm.PackageInfo;
25eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.os.UserHandle;
26eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport android.util.Slog;
27eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
28eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport com.android.server.pm.Installer.InstallerException;
29eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport com.android.server.pm.Installer;
30eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
31eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport java.io.DataInputStream;
32eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport java.io.File;
33eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport java.io.FileInputStream;
34eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadimport java.io.IOException;
35eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
36eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad/**
37eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Handle the creation and deletion of idmap files.
38eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad *
39eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * The actual work is performed by the idmap binary, launched through Installer
40eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * and installd.
41eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad *
42eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad * Note: this class is subclassed in the OMS unit tests, and hence not marked as final.
43eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad */
44eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstadclass IdmapManager {
45eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    private final Installer mInstaller;
46eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
47eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    IdmapManager(final Installer installer) {
48eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        mInstaller = installer;
49eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
50eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
51eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    boolean createIdmap(@NonNull final PackageInfo targetPackage,
52eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            @NonNull final PackageInfo overlayPackage, int userId) {
53eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible
54eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        if (DEBUG) {
55eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            Slog.d(TAG, "create idmap for " + targetPackage.packageName + " and "
56eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    + overlayPackage.packageName);
57eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        }
58eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final int sharedGid = UserHandle.getSharedAppGid(targetPackage.applicationInfo.uid);
59eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final String targetPath = targetPackage.applicationInfo.getBaseCodePath();
60eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
61eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        try {
62eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            mInstaller.idmap(targetPath, overlayPath, sharedGid);
63eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        } catch (InstallerException e) {
64eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            Slog.w(TAG, "failed to generate idmap for " + targetPath + " and "
65eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad                    + overlayPath + ": " + e.getMessage());
66eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            return false;
67eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        }
68eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        return true;
69eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
70eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
71eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) {
72eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible
73eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        if (DEBUG) {
74eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            Slog.d(TAG, "remove idmap for " + oi.baseCodePath);
75eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        }
76eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        try {
77eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            mInstaller.removeIdmap(oi.baseCodePath);
78eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        } catch (InstallerException e) {
79eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            Slog.w(TAG, "failed to remove idmap for " + oi.baseCodePath + ": " + e.getMessage());
80eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            return false;
81eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        }
82eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        return true;
83eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
84eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
85eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    boolean idmapExists(@NonNull final OverlayInfo oi) {
86eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        // unused OverlayInfo.userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible
87eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        return new File(getIdmapPath(oi.baseCodePath)).isFile();
88eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
89eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
90eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) {
91eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible
92eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        return new File(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath())).isFile();
93eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
94eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
95eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    boolean isDangerous(@NonNull final PackageInfo overlayPackage, final int userId) {
96eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible
97eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        return isDangerous(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath()));
98eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
99eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
100eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    private String getIdmapPath(@NonNull final String baseCodePath) {
101eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        final StringBuilder sb = new StringBuilder("/data/resource-cache/");
102eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        sb.append(baseCodePath.substring(1).replace('/', '@'));
103eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        sb.append("@idmap");
104eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        return sb.toString();
105eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
106eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad
107eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    private boolean isDangerous(@NonNull final String idmapPath) {
108eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        try (DataInputStream dis = new DataInputStream(new FileInputStream(idmapPath))) {
109eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            final int magic = dis.readInt();
110eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            final int version = dis.readInt();
111eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            final int dangerous = dis.readInt();
112eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            return dangerous != 0;
113eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        } catch (IOException e) {
114eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad            return true;
115eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad        }
116eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad    }
117eabc9e95768e7ac9acc3b32dc9ac2edf99c9e2c5Mårten Kongstad}
118