PackageInstallerService.java revision 3a44f3f1b446315ef894e01d2ab9b5388c2bd8c4
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;
273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.IPackageInstallerSession;
283a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.content.pm.PackageInstallerParams;
293a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Binder;
303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.FileUtils;
313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.HandlerThread;
323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.Process;
333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserHandle;
343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.UserManager;
353a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.ArraySet;
363a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.Slog;
373a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.util.SparseArray;
383a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
393a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.internal.annotations.GuardedBy;
403a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.internal.util.ArrayUtils;
413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.android.server.IoThread;
423a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport com.google.android.collect.Sets;
433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
443a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport java.io.File;
453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypublic class PackageInstallerService extends IPackageInstaller.Stub {
473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private static final String TAG = "PackageInstaller";
483a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    // TODO: destroy sessions with old timestamps
503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    // TODO: remove outstanding sessions when installer package goes away
513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
523a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final Context mContext;
533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final PackageManagerService mPm;
543a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final AppOpsManager mAppOps;
553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final File mStagingDir;
573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final HandlerThread mInstallThread = new HandlerThread(TAG);
593a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final Callback mCallback = new Callback();
603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @GuardedBy("mSessions")
623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private int mNextSessionId;
633a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @GuardedBy("mSessions")
643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    public PackageInstallerService(Context context, PackageManagerService pm, File stagingDir) {
673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mContext = context;
683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mPm = pm;
693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mStagingDir = stagingDir;
723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mStagingDir.mkdirs();
733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            readSessionsLocked();
763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            // Clean up orphaned staging directories
783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            final ArraySet<String> dirs = Sets.newArraySet(mStagingDir.list());
793a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
803a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                dirs.remove(Integer.toString(mSessions.keyAt(i)));
813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            for (String dirName : dirs) {
833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                Slog.w(TAG, "Deleting orphan session " + dirName);
843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                final File dir = new File(mStagingDir, dirName);
853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                FileUtils.deleteContents(dir);
863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                dir.delete();
873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void readSessionsLocked() {
923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // TODO: implement persisting
933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mSessions.clear();
943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mNextSessionId = 1;
953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void writeSessionsLocked() {
983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // TODO: implement persisting
993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
1003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private void writeSessionsAsync() {
1023a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        IoThread.getHandler().post(new Runnable() {
1033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            @Override
1043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            public void run() {
1053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                synchronized (mSessions) {
1063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                    writeSessionsLocked();
1073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                }
1083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
1093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        });
1103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
1113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
1133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    public int createSession(int userId, String installerPackageName,
1143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            PackageInstallerParams params) {
1153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        final int callingUid = Binder.getCallingUid();
1163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mPm.enforceCrossUserPermission(callingUid, userId, false, TAG);
1173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mAppOps.checkPackage(callingUid, installerPackageName);
1183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1193a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        if (mPm.isUserRestricted(UserHandle.getUserId(callingUid),
1203a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                UserManager.DISALLOW_INSTALL_APPS)) {
1213a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            throw new SecurityException("User restriction prevents installing");
1223a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
1233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1243a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        if ((callingUid == Process.SHELL_UID) || (callingUid == 0)) {
1253a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            params.installFlags |= INSTALL_FROM_ADB;
1263a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        } else {
1273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            params.installFlags &= ~INSTALL_FROM_ADB;
1283a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            params.installFlags &= ~INSTALL_ALL_USERS;
1293a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            params.installFlags |= INSTALL_REPLACE_EXISTING;
1303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
1313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
1333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            final int sessionId = allocateSessionIdLocked();
1343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            final long createdMillis = System.currentTimeMillis();
1353a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            final File sessionDir = new File(mStagingDir, Integer.toString(sessionId));
1363a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            sessionDir.mkdirs();
1373a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1383a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            final PackageInstallerSession session = new PackageInstallerSession(mCallback, mPm,
1393a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                    sessionId, userId, installerPackageName, callingUid, params, createdMillis,
1403a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                    sessionDir, mInstallThread.getLooper());
1413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            mSessions.put(sessionId, session);
1423a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            writeSessionsAsync();
1443a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            return sessionId;
1453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
1463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
1473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1483a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
1493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    public IPackageInstallerSession openSession(int sessionId) {
1503a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
1513a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            final PackageInstallerSession session = mSessions.get(sessionId);
1523a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            if (session == null) {
1533a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                throw new IllegalStateException("Missing session " + sessionId);
1543a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
1553a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            if (Binder.getCallingUid() != session.installerUid) {
1563a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                throw new SecurityException("Caller has no access to session " + sessionId);
1573a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
1583a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            return session;
1593a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
1603a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
1613a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1623a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    private int allocateSessionIdLocked() {
1633a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        if (mSessions.get(mNextSessionId) != null) {
1643a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            throw new IllegalStateException("Next session already allocated");
1653a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
1663a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        return mNextSessionId++;
1673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
1683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
1703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    public int[] getSessions(int userId, String installerPackageName) {
1713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        final int callingUid = Binder.getCallingUid();
1723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mPm.enforceCrossUserPermission(callingUid, userId, false, TAG);
1733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mAppOps.checkPackage(callingUid, installerPackageName);
1743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        int[] matching = new int[0];
1763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        synchronized (mSessions) {
1773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            for (int i = 0; i < mSessions.size(); i++) {
1783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                final int key = mSessions.keyAt(i);
1793a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                final PackageInstallerSession session = mSessions.valueAt(i);
1803a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                if (session.userId == userId
1813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                        && session.installerPackageName.equals(installerPackageName)) {
1823a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                    matching = ArrayUtils.appendInt(matching, key);
1833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey                }
1843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            }
1853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
1863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        return matching;
1873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
1883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
1903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    public void uninstall(int userId, String basePackageName, IPackageDeleteObserver observer) {
1913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        mPm.deletePackageAsUser(basePackageName, observer, userId, 0);
1923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
1933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
1943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    @Override
1953a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    public void uninstallSplit(int userId, String basePackageName, String overlayName,
1963a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            IPackageDeleteObserver observer) {
1973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        // TODO: flesh out once PM has split support
1983a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        throw new UnsupportedOperationException();
1993a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
2003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
2013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    class Callback {
2023a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        public void onProgressChanged(PackageInstallerSession session) {
2033a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            // TODO: notify listeners
2043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
2053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey
2063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        public void onSessionInvalid(PackageInstallerSession session) {
2073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey            writeSessionsAsync();
2083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey        }
2093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey    }
2103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey}
211