PackageInstallerSession.java revision a10311434778ea1be1621c2251c0c8c2966f337b
1d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi/*
2d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi * Copyright (C) 2014 The Android Open Source Project
3d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi *
4d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License");
5d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi * you may not use this file except in compliance with the License.
6d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi * You may obtain a copy of the License at
7d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi *
8d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi *      http://www.apache.org/licenses/LICENSE-2.0
9d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi *
10d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi * Unless required by applicable law or agreed to in writing, software
11d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS,
12d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi * See the License for the specific language governing permissions and
14d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi * limitations under the License.
15d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi */
16d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
17d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivipackage com.android.server.pm;
18d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
19d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
20d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
21d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
22d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
23d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport static android.system.OsConstants.O_CREAT;
24d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport static android.system.OsConstants.O_WRONLY;
25d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
26d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.content.pm.ApplicationInfo;
27d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.content.pm.IPackageInstallObserver2;
28d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.content.pm.IPackageInstallerSession;
29d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.content.pm.InstallSessionInfo;
30d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.content.pm.InstallSessionParams;
31d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.content.pm.PackageManager;
32d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.content.pm.PackageParser;
33d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.content.pm.PackageParser.ApkLite;
34d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.content.pm.PackageParser.PackageParserException;
35d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.content.pm.Signature;
36d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.os.Bundle;
37d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.os.FileBridge;
38d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.os.FileUtils;
39d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.os.Handler;
40d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.os.Looper;
41d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.os.Message;
42d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.os.ParcelFileDescriptor;
43d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.os.Process;
44d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.os.RemoteException;
45d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.os.UserHandle;
46d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.system.ErrnoException;
47d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.system.Os;
48d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.system.OsConstants;
49d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.system.StructStat;
50d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.util.ArraySet;
51d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.util.ExceptionUtils;
52d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.util.MathUtils;
53d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport android.util.Slog;
54d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
55d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport com.android.internal.util.ArrayUtils;
56d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport com.android.internal.util.IndentingPrintWriter;
57d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport com.android.internal.util.Preconditions;
58d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
59d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport libcore.io.Libcore;
60d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
61d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport java.io.File;
62d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport java.io.FileDescriptor;
63d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport java.io.IOException;
64d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Triviimport java.util.ArrayList;
65d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
66d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivipublic class PackageInstallerSession extends IPackageInstallerSession.Stub {
67d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private static final String TAG = "PackageInstaller";
68d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
69d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    // TODO: enforce INSTALL_ALLOW_TEST
70d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    // TODO: enforce INSTALL_ALLOW_DOWNGRADE
71d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    // TODO: handle INSTALL_EXTERNAL, INSTALL_INTERNAL
72d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
73d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private final PackageInstallerService.Callback mCallback;
74d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private final PackageManagerService mPm;
75d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private final Handler mHandler;
76d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
77d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    public final int sessionId;
78d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    public final int userId;
79d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    public final String installerPackageName;
80d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    /** UID not persisted */
81d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    public final int installerUid;
82d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    public final InstallSessionParams params;
83d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    public final long createdMillis;
84d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    public final File sessionStageDir;
85d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
86d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private static final int MSG_INSTALL = 0;
87d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
88d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private Handler.Callback mHandlerCallback = new Handler.Callback() {
89d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        @Override
90d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        public boolean handleMessage(Message msg) {
91d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            synchronized (mLock) {
92d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                if (msg.obj != null) {
93d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    mRemoteObserver = (IPackageInstallObserver2) msg.obj;
94d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                }
95d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
96d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                try {
97d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    installLocked();
98d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                } catch (PackageManagerException e) {
99d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    Slog.e(TAG, "Install failed: " + e);
100d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    destroyInternal();
101d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    try {
102d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                        mRemoteObserver.packageInstalled(mPackageName, null, e.error,
103d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                                e.getMessage());
104d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    } catch (RemoteException ignored) {
105d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    }
106d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    mCallback.onSessionFinished(PackageInstallerSession.this, false);
107d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                }
108d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
109d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                return true;
110d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            }
111d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        }
112d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    };
113d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
114d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private final Object mLock = new Object();
115d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
116d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private int mClientProgress;
117d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private int mProgress = 0;
118d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
119d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private String mPackageName;
120d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private int mVersionCode;
121d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private Signature[] mSignatures;
122d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
123d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private boolean mMutationsAllowed;
124d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private boolean mPermissionsConfirmed;
125d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private boolean mInvalid;
126d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
127d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private ArrayList<FileBridge> mBridges = new ArrayList<>();
128d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
129d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private IPackageInstallObserver2 mRemoteObserver;
130d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
131d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    public PackageInstallerSession(PackageInstallerService.Callback callback,
132d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            PackageManagerService pm, int sessionId, int userId, String installerPackageName,
133d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            int installerUid, InstallSessionParams params, long createdMillis, File sessionStageDir,
134d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            Looper looper) {
135d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        mCallback = callback;
136d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        mPm = pm;
137d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        mHandler = new Handler(looper, mHandlerCallback);
138d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
139d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        this.sessionId = sessionId;
140d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        this.userId = userId;
141d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        this.installerPackageName = installerPackageName;
142d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        this.installerUid = installerUid;
143d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        this.params = params;
144d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        this.createdMillis = createdMillis;
145d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        this.sessionStageDir = sessionStageDir;
146d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
147d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // Check against any explicitly provided signatures
148d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        mSignatures = params.signatures;
149d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
150d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // TODO: splice in flag when restoring persisted session
151d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        mMutationsAllowed = true;
152d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
153d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        if (pm.checkPermission(android.Manifest.permission.INSTALL_PACKAGES, installerPackageName)
154d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                == PackageManager.PERMISSION_GRANTED) {
155d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            mPermissionsConfirmed = true;
156d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        }
157d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        if (installerUid == Process.SHELL_UID || installerUid == 0) {
158d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            mPermissionsConfirmed = true;
159d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        }
160d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    }
161d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
162d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    public InstallSessionInfo generateInfo() {
163d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        final InstallSessionInfo info = new InstallSessionInfo();
164d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
165d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        info.sessionId = sessionId;
166d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        info.installerPackageName = installerPackageName;
167d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        info.progress = mProgress;
168d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
169d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        info.fullInstall = params.fullInstall;
170d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        info.packageName = params.packageName;
171d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        info.icon = params.icon;
172d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        info.title = params.title;
173d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
174d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        return info;
175d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    }
176d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
177d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    @Override
178d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    public void setClientProgress(int progress) {
179d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        mClientProgress = progress;
180d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        mProgress = MathUtils.constrain((mClientProgress * 8 * 100) / (params.progressMax * 10), 0, 80);
181d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        mCallback.onSessionProgress(this, mProgress);
182d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    }
183d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
184d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    @Override
185d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    public void addClientProgress(int progress) {
186d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        setClientProgress(mClientProgress + progress);
187d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    }
188d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
189d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    @Override
190d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
191d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        try {
192d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            return openWriteInternal(name, offsetBytes, lengthBytes);
193d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        } catch (IOException e) {
194d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            throw ExceptionUtils.wrap(e);
195d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        }
196d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    }
197d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
198d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)
199d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            throws IOException {
200d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // TODO: relay over to DCS when installing to ASEC
201d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
202d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // Quick sanity check of state, and allocate a pipe for ourselves. We
203d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // then do heavy disk allocation outside the lock, but this open pipe
204d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // will block any attempted install transitions.
205d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        final FileBridge bridge;
206d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        synchronized (mLock) {
207d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            if (!mMutationsAllowed) {
208d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                throw new IllegalStateException("Mutations not allowed");
209d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            }
210d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
211d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            bridge = new FileBridge();
212d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            mBridges.add(bridge);
213d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        }
214d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
215d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        try {
216d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            // Use installer provided name for now; we always rename later
217d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            if (!FileUtils.isValidExtFilename(name)) {
218d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                throw new IllegalArgumentException("Invalid name: " + name);
219d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            }
220d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            final File target = new File(sessionStageDir, name);
221d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
222d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
223d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    O_CREAT | O_WRONLY, 0644);
224d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            Os.chmod(target.getAbsolutePath(), 0644);
225d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
226d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            // If caller specified a total length, allocate it for them. Free up
227d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            // cache space to grow, if needed.
228d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            if (lengthBytes > 0) {
229d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                final StructStat stat = Libcore.os.fstat(targetFd);
230d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                final long deltaBytes = lengthBytes - stat.st_size;
231d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                if (deltaBytes > 0) {
232d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    mPm.freeStorage(deltaBytes);
233d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                }
234d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                Libcore.os.posix_fallocate(targetFd, 0, lengthBytes);
235d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            }
236d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
237d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            if (offsetBytes > 0) {
238d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                Libcore.os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
239d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            }
240d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
241d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            bridge.setTargetFile(targetFd);
242d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            bridge.start();
243d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            return new ParcelFileDescriptor(bridge.getClientSocket());
244d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
245d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        } catch (ErrnoException e) {
246d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            throw e.rethrowAsIOException();
247d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        }
248d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    }
249d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
250d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    @Override
251d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    public void install(IPackageInstallObserver2 observer) {
252d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        Preconditions.checkNotNull(observer);
253d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        mHandler.obtainMessage(MSG_INSTALL, observer).sendToTarget();
254d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    }
255d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
256d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private void installLocked() throws PackageManagerException {
257d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        if (mInvalid) {
258d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            throw new PackageManagerException(INSTALL_FAILED_ALREADY_EXISTS, "Invalid session");
259d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        }
260d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
261d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // Verify that all writers are hands-off
262d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        if (mMutationsAllowed) {
263d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            for (FileBridge bridge : mBridges) {
264d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                if (!bridge.isClosed()) {
265d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
266d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                            "Files still open");
267d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                }
268d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            }
269d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            mMutationsAllowed = false;
270d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
271d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            // TODO: persist disabled mutations before going forward, since
272d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            // beyond this point we may have hardlinks to the valid install
273d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        }
274d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
275d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // Verify that stage looks sane with respect to existing application.
276d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // This currently only ensures packageName, versionCode, and certificate
277d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // consistency.
278d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        validateInstallLocked();
279d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
280d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        Preconditions.checkNotNull(mPackageName);
281d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        Preconditions.checkNotNull(mSignatures);
282d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
283d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        if (!mPermissionsConfirmed) {
284d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            // TODO: async confirm permissions with user
285d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            // when they confirm, we'll kick off another install() pass
286d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            throw new SecurityException("Caller must hold INSTALL permission");
287d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        }
288d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
289d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // Inherit any packages and native libraries from existing install that
290d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // haven't been overridden.
291d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        if (!params.fullInstall) {
292d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            spliceExistingFilesIntoStage();
293d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        }
294d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
295d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // TODO: surface more granular state from dexopt
296d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        mCallback.onSessionProgress(this, 90);
297d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
298d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // TODO: for ASEC based applications, grow and stream in packages
299d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
300d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // We've reached point of no return; call into PMS to install the stage.
301d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // Regardless of success or failure we always destroy session.
302d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        final IPackageInstallObserver2 remoteObserver = mRemoteObserver;
303d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
304d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            @Override
305d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            public void packageInstalled(String basePackageName, Bundle extras, int returnCode,
306d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    String msg) {
307d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                destroyInternal();
308d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                try {
309d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    remoteObserver.packageInstalled(basePackageName, extras, returnCode, msg);
310d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                } catch (RemoteException ignored) {
311d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                }
312d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
313d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                mCallback.onSessionFinished(PackageInstallerSession.this, success);
314d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            }
315d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        };
316d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
317d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        mPm.installStage(mPackageName, this.sessionStageDir, localObserver, params,
318d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                installerPackageName, installerUid, new UserHandle(userId));
319d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    }
320d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
321d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    /**
322d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi     * Validate install by confirming that all application packages are have
323d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi     * consistent package name, version code, and signing certificates.
324d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi     * <p>
325d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi     * Renames package files in stage to match split names defined inside.
326d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi     */
327d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi    private void validateInstallLocked() throws PackageManagerException {
328d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        mPackageName = null;
329d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        mVersionCode = -1;
330d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
331d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        final File[] files = sessionStageDir.listFiles();
332d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        if (ArrayUtils.isEmpty(files)) {
333d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
334d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        }
335d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
336d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        final ArraySet<String> seenSplits = new ArraySet<>();
337d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
338d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        // Verify that all staged packages are internally consistent
339d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi        for (File file : files) {
340d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            final ApkLite info;
341d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            try {
342d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                info = PackageParser.parseApkLite(file, PackageParser.PARSE_GET_SIGNATURES);
343d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            } catch (PackageParserException e) {
344d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
345d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                        "Failed to parse " + file + ": " + e);
346d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            }
347d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
348d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            if (!seenSplits.add(info.splitName)) {
349d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
350d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                        "Split " + info.splitName + " was defined multiple times");
351d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            }
352d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
353d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            // Use first package to define unknown values
354d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            if (mPackageName == null) {
355d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                mPackageName = info.packageName;
356d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                mVersionCode = info.versionCode;
357d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            }
358d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            if (mSignatures == null) {
359d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                mSignatures = info.signatures;
360d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            }
361d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
362d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            assertPackageConsistent(String.valueOf(file), info.packageName, info.versionCode,
363d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                    info.signatures);
364d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi
365d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            // Take this opportunity to enforce uniform naming
366d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            final String name;
367d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            if (info.splitName == null) {
368d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                name = "base.apk";
369d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            } else {
370d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi                name = "split_" + info.splitName + ".apk";
371d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            }
372d4838ed14a169f5981c0adc2edcb24559a913fe6Jean-Michel Trivi            if (!FileUtils.isValidExtFilename(name)) {
373                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
374                        "Invalid filename: " + name);
375            }
376            if (!file.getName().equals(name)) {
377                file.renameTo(new File(file.getParentFile(), name));
378            }
379        }
380
381        // TODO: shift package signature verification to installer; we're
382        // currently relying on PMS to do this.
383        // TODO: teach about compatible upgrade keysets.
384
385        if (params.fullInstall) {
386            // Full installs must include a base package
387            if (!seenSplits.contains(null)) {
388                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
389                        "Full install must include a base package");
390            }
391
392        } else {
393            // Partial installs must be consistent with existing install.
394            final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
395            if (app == null) {
396                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
397                        "Missing existing base package for " + mPackageName);
398            }
399
400            final ApkLite info;
401            try {
402                info = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
403                        PackageParser.PARSE_GET_SIGNATURES);
404            } catch (PackageParserException e) {
405                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
406                        "Failed to parse existing base " + app.getBaseCodePath() + ": " + e);
407            }
408
409            assertPackageConsistent("Existing base", info.packageName, info.versionCode,
410                    info.signatures);
411        }
412    }
413
414    private void assertPackageConsistent(String tag, String packageName, int versionCode,
415            Signature[] signatures) throws PackageManagerException {
416        if (!mPackageName.equals(packageName)) {
417            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
418                    + packageName + " inconsistent with " + mPackageName);
419        }
420        if (mVersionCode != versionCode) {
421            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
422                    + " version code " + versionCode + " inconsistent with "
423                    + mVersionCode);
424        }
425        if (!Signature.areExactMatch(mSignatures, signatures)) {
426            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
427                    tag + " signatures are inconsistent");
428        }
429    }
430
431    /**
432     * Application is already installed; splice existing files that haven't been
433     * overridden into our stage.
434     */
435    private void spliceExistingFilesIntoStage() throws PackageManagerException {
436        final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
437        final File existingDir = new File(app.getBaseCodePath());
438
439        try {
440            linkTreeIgnoringExisting(existingDir, sessionStageDir);
441        } catch (ErrnoException e) {
442            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
443                    "Failed to splice into stage");
444        }
445    }
446
447    /**
448     * Recursively hard link all files from source directory tree to target.
449     * When a file already exists in the target tree, it leaves that file
450     * intact.
451     */
452    private void linkTreeIgnoringExisting(File sourceDir, File targetDir) throws ErrnoException {
453        final File[] sourceContents = sourceDir.listFiles();
454        if (ArrayUtils.isEmpty(sourceContents)) return;
455
456        for (File sourceFile : sourceContents) {
457            final File targetFile = new File(targetDir, sourceFile.getName());
458
459            if (sourceFile.isDirectory()) {
460                targetFile.mkdir();
461                linkTreeIgnoringExisting(sourceFile, targetFile);
462            } else {
463                Libcore.os.link(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath());
464            }
465        }
466    }
467
468    @Override
469    public void destroy() {
470        try {
471            destroyInternal();
472        } finally {
473            mCallback.onSessionFinished(this, false);
474        }
475    }
476
477    private void destroyInternal() {
478        synchronized (mLock) {
479            mInvalid = true;
480        }
481        FileUtils.deleteContents(sessionStageDir);
482        sessionStageDir.delete();
483    }
484
485    void dump(IndentingPrintWriter pw) {
486        pw.println("Session " + sessionId + ":");
487        pw.increaseIndent();
488
489        pw.printPair("userId", userId);
490        pw.printPair("installerPackageName", installerPackageName);
491        pw.printPair("installerUid", installerUid);
492        pw.printPair("createdMillis", createdMillis);
493        pw.printPair("sessionStageDir", sessionStageDir);
494        pw.println();
495
496        params.dump(pw);
497
498        pw.printPair("mClientProgress", mClientProgress);
499        pw.printPair("mProgress", mProgress);
500        pw.printPair("mMutationsAllowed", mMutationsAllowed);
501        pw.printPair("mPermissionsConfirmed", mPermissionsConfirmed);
502        pw.printPair("mBridges", mBridges.size());
503        pw.println();
504
505        pw.decreaseIndent();
506    }
507}
508