PackageInstallerService.java revision 6c833e07a05c48ca60ee4d72421bf8b1e78dc710
13a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey/*
23a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Copyright (C) 2014 The Android Open Source Project
33a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey *
43a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
53a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * you may not use this file except in compliance with the License.
63a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * You may obtain a copy of the License at
73a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey *
83a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
93a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey *
103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * See the License for the specific language governing permissions and
143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * limitations under the License.
153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey */
163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypackage com.android.server.pm;
183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_ALL_USERS;
203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_FROM_ADB;
213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_REPLACE_EXISTING;
223a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.app.AppOpsManager;
243a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.Context;
253a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageDeleteObserver;
263a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstaller;
27bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport android.content.pm.IPackageInstallerObserver;
283a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstallerSession;
29bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport android.content.pm.InstallSessionInfo;
30bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport android.content.pm.InstallSessionParams;
313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Binder;
323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.FileUtils;
333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.HandlerThread;
343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Process;
35a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteCallbackList;
36a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.os.RemoteException;
37ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.os.SELinux;
383a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserHandle;
393a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserManager;
40ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.ErrnoException;
41ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport android.system.Os;
423a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.ArraySet;
43a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.util.ExceptionUtils;
443a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.Slog;
453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.SparseArray;
463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.internal.annotations.GuardedBy;
48a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter;
493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.server.IoThread;
503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.google.android.collect.Sets;
513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
523a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.io.File;
53ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.FilenameFilter;
54ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.IOException;
55bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.ArrayList;
56bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.List;
573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypublic class PackageInstallerService extends IPackageInstaller.Stub {
593a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private static final String TAG = "PackageInstaller";
603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    // TODO: destroy sessions with old timestamps
623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    // TODO: remove outstanding sessions when installer package goes away
636c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey    // TODO: notify listeners in other users when package has been installed there
643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final Context mContext;
663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final PackageManagerService mPm;
673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final AppOpsManager mAppOps;
683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final File mStagingDir;
70ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    private final HandlerThread mInstallThread;
713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final Callback mCallback = new Callback();
733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @GuardedBy("mSessions")
753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private int mNextSessionId;
763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @GuardedBy("mSessions")
773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
79a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    private RemoteCallbackList<IPackageInstallerObserver> mObservers = new RemoteCallbackList<>();
80a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
81ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    private static final FilenameFilter sStageFilter = new FilenameFilter() {
82ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        @Override
83ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        public boolean accept(File dir, String name) {
84ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            return name.startsWith("vmdl") && name.endsWith(".tmp");
85ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
86ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    };
87ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    public PackageInstallerService(Context context, PackageManagerService pm, File stagingDir) {
893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mContext = context;
903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mPm = pm;
913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mStagingDir = stagingDir;
94ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
95ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        mInstallThread = new HandlerThread(TAG);
96ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        mInstallThread.start();
973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            readSessionsLocked();
1003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            // Clean up orphaned staging directories
102ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            final ArraySet<File> stages = Sets.newArraySet(mStagingDir.listFiles(sStageFilter));
1033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
104ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
105ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                stages.remove(session.sessionStageDir);
106ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            }
107ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            for (File stage : stages) {
108ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                Slog.w(TAG, "Deleting orphan stage " + stage);
109ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                if (stage.isDirectory()) {
110ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                    FileUtils.deleteContents(stage);
111ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                }
112ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                stage.delete();
1133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
114ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
115ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    }
116ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
117ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    @Deprecated
118ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    public File allocateSessionDir() throws IOException {
119ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        synchronized (mSessions) {
120ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            try {
121ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                final int sessionId = allocateSessionIdLocked();
122ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                return prepareSessionStageDir(sessionId);
123ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            } catch (IllegalStateException e) {
124ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey                throw new IOException(e);
1253a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
1263a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
1273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
1283a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1293a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void readSessionsLocked() {
1303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // TODO: implement persisting
1313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mSessions.clear();
1323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mNextSessionId = 1;
1333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
1343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1353a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void writeSessionsLocked() {
1363a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // TODO: implement persisting
1373a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
1383a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1393a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void writeSessionsAsync() {
1403a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        IoThread.getHandler().post(new Runnable() {
1413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            @Override
1423a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            public void run() {
1433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                synchronized (mSessions) {
1443a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                    writeSessionsLocked();
1453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                }
1463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
1473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        });
1483a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
1493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
151bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    public int createSession(String installerPackageName, InstallSessionParams params,
152ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            int userId) {
1533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        final int callingUid = Binder.getCallingUid();
154a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        mPm.enforceCrossUserPermission(callingUid, userId, true, "createSession");
1553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        if (mPm.isUserRestricted(UserHandle.getUserId(callingUid),
1573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                UserManager.DISALLOW_INSTALL_APPS)) {
1583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            throw new SecurityException("User restriction prevents installing");
1593a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
1603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        if ((callingUid == Process.SHELL_UID) || (callingUid == 0)) {
1623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            params.installFlags |= INSTALL_FROM_ADB;
1633a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        } else {
164ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            mAppOps.checkPackage(callingUid, installerPackageName);
165ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
1663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            params.installFlags &= ~INSTALL_FROM_ADB;
1673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            params.installFlags &= ~INSTALL_ALL_USERS;
1683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            params.installFlags |= INSTALL_REPLACE_EXISTING;
1693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
1703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1716c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey        if (params.mode == InstallSessionParams.MODE_INVALID) {
1726c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey            throw new IllegalArgumentException("Params must have valid mode set");
1736c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey        }
1746c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey
175a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        // Sanity check that install could fit
176a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        if (params.deltaSize > 0) {
177a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            try {
178a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                mPm.freeStorage(params.deltaSize);
179a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            } catch (IOException e) {
180a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                throw ExceptionUtils.wrap(e);
181a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
182a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
183a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
184a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final int sessionId;
185a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final PackageInstallerSession session;
1863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
187a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            sessionId = allocateSessionIdLocked();
188a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
1893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            final long createdMillis = System.currentTimeMillis();
190ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            final File sessionStageDir = prepareSessionStageDir(sessionId);
1913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
192a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            session = new PackageInstallerSession(mCallback, mPm, sessionId, userId,
193a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                    installerPackageName, callingUid, params, createdMillis, sessionStageDir,
194a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                    mInstallThread.getLooper());
1953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            mSessions.put(sessionId, session);
1963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
197a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
198a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        notifySessionCreated(session.generateInfo());
199a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        writeSessionsAsync();
200a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        return sessionId;
2013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
2023a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
2033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
2043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    public IPackageInstallerSession openSession(int sessionId) {
2053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
2063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
2073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            if (session == null) {
2083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                throw new IllegalStateException("Missing session " + sessionId);
2093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
2103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            if (Binder.getCallingUid() != session.installerUid) {
2113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
2123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
2133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            return session;
2143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
2153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
2163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
2173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private int allocateSessionIdLocked() {
2183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        if (mSessions.get(mNextSessionId) != null) {
2193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            throw new IllegalStateException("Next session already allocated");
2203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
2213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        return mNextSessionId++;
2223a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
2233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
224ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    private File prepareSessionStageDir(int sessionId) {
225ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        final File file = new File(mStagingDir, "vmdl" + sessionId + ".tmp");
226ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
227ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        if (file.exists()) {
228ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            throw new IllegalStateException();
229ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
230ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
231ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        try {
232ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            Os.mkdir(file.getAbsolutePath(), 0755);
233ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            Os.chmod(file.getAbsolutePath(), 0755);
234ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        } catch (ErrnoException e) {
235ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            // This purposefully throws if directory already exists
236ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            throw new IllegalStateException("Failed to prepare session dir", e);
237ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
238ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
239ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        if (!SELinux.restorecon(file)) {
240ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            throw new IllegalStateException("Failed to prepare session dir");
241ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        }
242ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
243ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey        return file;
244ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    }
245ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey
2463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
247bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    public List<InstallSessionInfo> getSessions(int userId) {
248a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getSessions");
2493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
250bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey        final List<InstallSessionInfo> result = new ArrayList<>();
2513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
2523a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
2533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
254bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey                if (session.userId == userId) {
255bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey                    result.add(session.generateInfo());
2563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                }
2573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
2583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
259bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey        return result;
2603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
2613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
2623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
263bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    public void uninstall(String packageName, int flags, IPackageDeleteObserver observer,
264ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            int userId) {
265a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall");
266bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey        mPm.deletePackageAsUser(packageName, observer, userId, flags);
2673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
2683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
2693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
270ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey    public void uninstallSplit(String basePackageName, String overlayName, int flags,
271ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey            IPackageDeleteObserver observer, int userId) {
272a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstallSplit");
273a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
2743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // TODO: flesh out once PM has split support
2753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        throw new UnsupportedOperationException();
2763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
2773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
278bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    @Override
279bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    public void registerObserver(IPackageInstallerObserver observer, int userId) {
280a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "registerObserver");
281a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
282a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        // TODO: consider restricting to active launcher app only
283a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        mObservers.register(observer, new UserHandle(userId));
284bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    }
285bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey
286bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    @Override
287bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    public void unregisterObserver(IPackageInstallerObserver observer, int userId) {
288a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "unregisterObserver");
289a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        mObservers.unregister(observer);
290a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
291a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
292a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    private int getSessionUserId(int sessionId) {
293a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        synchronized (mSessions) {
294a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            return UserHandle.getUserId(mSessions.get(sessionId).installerUid);
295a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
296a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
297a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
298a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    private void notifySessionCreated(InstallSessionInfo info) {
299a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final int userId = getSessionUserId(info.sessionId);
300a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final int n = mObservers.beginBroadcast();
301a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        for (int i = 0; i < n; i++) {
302a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            final IPackageInstallerObserver observer = mObservers.getBroadcastItem(i);
303a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            final UserHandle user = (UserHandle) mObservers.getBroadcastCookie(i);
304a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            if (userId == user.getIdentifier()) {
305a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                try {
306a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                    observer.onSessionCreated(info);
307a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                } catch (RemoteException ignored) {
308a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                }
309a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
310a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
311a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        mObservers.finishBroadcast();
312a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
313a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
314a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    private void notifySessionProgress(int sessionId, int progress) {
315a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final int userId = getSessionUserId(sessionId);
316a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final int n = mObservers.beginBroadcast();
317a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        for (int i = 0; i < n; i++) {
318a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            final IPackageInstallerObserver observer = mObservers.getBroadcastItem(i);
319a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            final UserHandle user = (UserHandle) mObservers.getBroadcastCookie(i);
320a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            if (userId == user.getIdentifier()) {
321a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                try {
322a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                    observer.onSessionProgress(sessionId, progress);
323a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                } catch (RemoteException ignored) {
324a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                }
325a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
326a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
327a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        mObservers.finishBroadcast();
328a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
329a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
330a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    private void notifySessionFinished(int sessionId, boolean success) {
331a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final int userId = getSessionUserId(sessionId);
332a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        final int n = mObservers.beginBroadcast();
333a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        for (int i = 0; i < n; i++) {
334a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            final IPackageInstallerObserver observer = mObservers.getBroadcastItem(i);
335a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            final UserHandle user = (UserHandle) mObservers.getBroadcastCookie(i);
336a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            if (userId == user.getIdentifier()) {
337a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                try {
338a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                    observer.onSessionFinished(sessionId, success);
339a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                } catch (RemoteException ignored) {
340a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                }
341a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
342a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
343a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        mObservers.finishBroadcast();
344a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    }
345a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey
346a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey    void dump(IndentingPrintWriter pw) {
347a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.println("Active install sessions:");
348a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.increaseIndent();
349a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        synchronized (mSessions) {
350a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            final int N = mSessions.size();
351a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            for (int i = 0; i < N; i++) {
352a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
353a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                session.dump(pw);
354a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                pw.println();
355a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
356a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        }
357a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.println();
358a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        pw.decreaseIndent();
359bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey    }
360bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey
3613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    class Callback {
362a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        public void onSessionProgress(PackageInstallerSession session, int progress) {
363a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            notifySessionProgress(session.sessionId, progress);
3643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
3653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
366a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey        public void onSessionFinished(PackageInstallerSession session, boolean success) {
367a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            notifySessionFinished(session.sessionId, success);
368a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            synchronized (mSessions) {
369a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey                mSessions.remove(session.sessionId);
370a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey            }
3713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            writeSessionsAsync();
3723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
3733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
3743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey}
375