115a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root/*
215a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Copyright (C) 2010 The Android Open Source Project
315a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *
415a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Licensed under the Apache License, Version 2.0 (the "License");
515a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * you may not use this file except in compliance with the License.
615a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * You may obtain a copy of the License at
715a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *
815a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *      http://www.apache.org/licenses/LICENSE-2.0
915a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *
1015a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Unless required by applicable law or agreed to in writing, software
1115a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * distributed under the License is distributed on an "AS IS" BASIS,
1215a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1315a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * See the License for the specific language governing permissions and
1415a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * limitations under the License.
1515a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root */
1615a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root
17c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapupackage com.android.defcontainer;
18c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu
19f5121a9b802c6ddd3661ed5cae602380dbe67090Kenny Rootimport android.app.IntentService;
20742e790294b3441b79f715fe447069b63c6065dbJeff Sharkeyimport android.content.Context;
21c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.content.Intent;
22e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackbornimport android.content.pm.IPackageManager;
237767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackbornimport android.content.pm.PackageCleanItem;
24a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapuimport android.content.pm.PackageInfoLite;
25e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackbornimport android.content.pm.PackageManager;
265b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapuimport android.content.pm.PackageParser;
27be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkeyimport android.content.pm.PackageParser.PackageLite;
28275e085d5a42ced54bb79e40ff76c77539e7d82dJeff Sharkeyimport android.content.pm.PackageParser.PackageParserException;
29a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.res.ObbInfo;
30a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.res.ObbScanner;
319a4a45762219f43903f54d5f29157dc6b3881557Jeff Sharkeyimport android.os.Binder;
32752cd922f7091dfd5401faf70dc248934a9dbb6dJeff Sharkeyimport android.os.Environment.UserEnvironment;
33b18f899241231991e314c40990eb8e9f703732d4Jeff Sharkeyimport android.os.FileUtils;
34c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.os.IBinder;
35c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.os.ParcelFileDescriptor;
36c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.os.Process;
37c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.os.RemoteException;
38c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.os.ServiceManager;
391ebd74acf9977daa42133507e970dab88e08f0efKenny Rootimport android.util.Slog;
40c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu
4163d0a067997cecf9c6e97a17852f9b657bbba48eJeff Sharkeyimport com.android.internal.app.IMediaContainerService;
4263d0a067997cecf9c6e97a17852f9b657bbba48eJeff Sharkeyimport com.android.internal.content.PackageHelper;
43be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkeyimport com.android.internal.os.IParcelFileDescriptorFactory;
44be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkeyimport com.android.internal.util.ArrayUtils;
4563d0a067997cecf9c6e97a17852f9b657bbba48eJeff Sharkey
4657dcf5b177b56195421535938544f32d8b591b42Jeff Sharkeyimport libcore.io.IoUtils;
4757dcf5b177b56195421535938544f32d8b591b42Jeff Sharkey
48c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport java.io.File;
49c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport java.io.FileInputStream;
50c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport java.io.IOException;
51c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport java.io.InputStream;
52f5121a9b802c6ddd3661ed5cae602380dbe67090Kenny Rootimport java.io.OutputStream;
53ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
54be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey/**
55be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey * Service that offers to inspect and copy files that may reside on removable
56be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey * storage. This is designed to prevent the system process from holding onto
57be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey * open files that cause the kernel to kill it when the underlying device is
58be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey * removed.
59c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu */
60e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackbornpublic class DefaultContainerService extends IntentService {
61c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu    private static final String TAG = "DefContainer";
62c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu
63be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey    // TODO: migrate native code unpacking to always be a derivative work
64be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey
65c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu    private IMediaContainerService.Stub mBinder = new IMediaContainerService.Stub() {
66ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        /**
67be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         * Copy package to the target location.
68ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward         *
69be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         * @param packagePath absolute path to the package to be copied. Can be
70be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         *            a single monolithic APK file or a cluster directory
71be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         *            containing one or more APKs.
72ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward         * @return returns status code according to those in
73ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward         *         {@link PackageManager}
74c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu         */
7557dcf5b177b56195421535938544f32d8b591b42Jeff Sharkey        @Override
76be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey        public int copyPackage(String packagePath, IParcelFileDescriptorFactory target) {
77be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey            if (packagePath == null || target == null) {
78f5121a9b802c6ddd3661ed5cae602380dbe67090Kenny Root                return PackageManager.INSTALL_FAILED_INVALID_URI;
79f5121a9b802c6ddd3661ed5cae602380dbe67090Kenny Root            }
80f5121a9b802c6ddd3661ed5cae602380dbe67090Kenny Root
81be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey            PackageLite pkg = null;
82f5121a9b802c6ddd3661ed5cae602380dbe67090Kenny Root            try {
83be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey                final File packageFile = new File(packagePath);
84be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey                pkg = PackageParser.parsePackageLite(packageFile, 0);
85be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey                return copyPackageInner(pkg, target);
86be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey            } catch (PackageParserException | IOException | RemoteException e) {
87be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey                Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
88f5121a9b802c6ddd3661ed5cae602380dbe67090Kenny Root                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
89c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu            }
90c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu        }
915b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu
92ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward        /**
93be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         * Parse given package and return minimal details.
946431d11cd420536aaa9d93ae510a3151ccc4df1dNarayan Kamath         *
95be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         * @param packagePath absolute path to the package to be copied. Can be
96be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         *            a single monolithic APK file or a cluster directory
97be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         *            containing one or more APKs.
985b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu         */
99275e085d5a42ced54bb79e40ff76c77539e7d82dJeff Sharkey        @Override
100742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey        public PackageInfoLite getMinimalPackageInfo(String packagePath, int flags,
101742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                String abiOverride) {
102742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            final Context context = DefaultContainerService.this;
103ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
104742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            PackageInfoLite ret = new PackageInfoLite();
105ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward            if (packagePath == null) {
106ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward                Slog.i(TAG, "Invalid package file " + packagePath);
107a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
108a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu                return ret;
1093602f76d417b0940a26f28b7ad892abcfe03ef7cSuchi Amalapurapu            }
110ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
111be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey            final File packageFile = new File(packagePath);
112be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey            final PackageParser.PackageLite pkg;
113742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            final long sizeBytes;
114275e085d5a42ced54bb79e40ff76c77539e7d82dJeff Sharkey            try {
115be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey                pkg = PackageParser.parsePackageLite(packageFile, 0);
116f8bb2445ff28d64d12d81d91539bb419f69e7874Jeff Sharkey                sizeBytes = PackageHelper.calculateInstalledSize(pkg, abiOverride);
117742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey            } catch (PackageParserException | IOException e) {
118742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);
1191ebd74acf9977daa42133507e970dab88e08f0efKenny Root
120be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey                if (!packageFile.exists()) {
1211ebd74acf9977daa42133507e970dab88e08f0efKenny Root                    ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
1221ebd74acf9977daa42133507e970dab88e08f0efKenny Root                } else {
1231ebd74acf9977daa42133507e970dab88e08f0efKenny Root                    ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
1241ebd74acf9977daa42133507e970dab88e08f0efKenny Root                }
1251ebd74acf9977daa42133507e970dab88e08f0efKenny Root
126a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu                return ret;
1275b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu            }
128ceb1b0bfaea56251796b08c07b963de7403d84ebAnonymous Coward
1299a4a45762219f43903f54d5f29157dc6b3881557Jeff Sharkey            final int recommendedInstallLocation;
1309a4a45762219f43903f54d5f29157dc6b3881557Jeff Sharkey            final long token = Binder.clearCallingIdentity();
1319a4a45762219f43903f54d5f29157dc6b3881557Jeff Sharkey            try {
1329a4a45762219f43903f54d5f29157dc6b3881557Jeff Sharkey                recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
1339a4a45762219f43903f54d5f29157dc6b3881557Jeff Sharkey                        pkg.packageName, pkg.installLocation, sizeBytes, flags);
1349a4a45762219f43903f54d5f29157dc6b3881557Jeff Sharkey            } finally {
1359a4a45762219f43903f54d5f29157dc6b3881557Jeff Sharkey                Binder.restoreCallingIdentity(token);
1369a4a45762219f43903f54d5f29157dc6b3881557Jeff Sharkey            }
1379a4a45762219f43903f54d5f29157dc6b3881557Jeff Sharkey
138a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu            ret.packageName = pkg.packageName;
13988d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey            ret.splitNames = pkg.splitNames;
1407767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn            ret.versionCode = pkg.versionCode;
1413accca05ddcad9d0b1b313eae49f273e39121d3cDianne Hackborn            ret.versionCodeMajor = pkg.versionCodeMajor;
14288d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey            ret.baseRevisionCode = pkg.baseRevisionCode;
14388d2a3c0e1b4a8c53a489db5d627beb80b1b9957Jeff Sharkey            ret.splitRevisionCodes = pkg.splitRevisionCodes;
144930d3af75f9e9663222f4c4a1d75b326cf811e35Kenny Root            ret.installLocation = pkg.installLocation;
14505ca4c90644921df9193d92b2abdc81ef77e4a62Kenny Root            ret.verifiers = pkg.verifiers;
1469a4a45762219f43903f54d5f29157dc6b3881557Jeff Sharkey            ret.recommendedInstallLocation = recommendedInstallLocation;
147ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath            ret.multiArch = pkg.multiArch;
1481ebd74acf9977daa42133507e970dab88e08f0efKenny Root
149a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu            return ret;
1505b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu        }
1518a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu
15257dcf5b177b56195421535938544f32d8b591b42Jeff Sharkey        @Override
153a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public ObbInfo getObbInfo(String filename) {
15405105f7abe02b2dff91d6260b3628c8b97816babKenny Root            try {
15505105f7abe02b2dff91d6260b3628c8b97816babKenny Root                return ObbScanner.getObbInfo(filename);
15605105f7abe02b2dff91d6260b3628c8b97816babKenny Root            } catch (IOException e) {
1571ebd74acf9977daa42133507e970dab88e08f0efKenny Root                Slog.d(TAG, "Couldn't get OBB info for " + filename);
15805105f7abe02b2dff91d6260b3628c8b97816babKenny Root                return null;
15905105f7abe02b2dff91d6260b3628c8b97816babKenny Root            }
160a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
161aa183e2c9a279cb6aef7dc77855facfae795b6f8Kenny Root
162aa183e2c9a279cb6aef7dc77855facfae795b6f8Kenny Root        @Override
163183ce028f10442dd6ada59de8fa531d690134663Dianne Hackborn        public void clearDirectory(String path) throws RemoteException {
164183ce028f10442dd6ada59de8fa531d690134663Dianne Hackborn            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
165183ce028f10442dd6ada59de8fa531d690134663Dianne Hackborn
166183ce028f10442dd6ada59de8fa531d690134663Dianne Hackborn            final File directory = new File(path);
167183ce028f10442dd6ada59de8fa531d690134663Dianne Hackborn            if (directory.exists() && directory.isDirectory()) {
168183ce028f10442dd6ada59de8fa531d690134663Dianne Hackborn                eraseFiles(directory);
169183ce028f10442dd6ada59de8fa531d690134663Dianne Hackborn            }
170183ce028f10442dd6ada59de8fa531d690134663Dianne Hackborn        }
171cea3743499f4bb8e5f28a2e57686d7af313169c5Kenny Root
172be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey        /**
173be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         * Calculate estimated footprint of given package post-installation.
174be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         *
175be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         * @param packagePath absolute path to the package to be copied. Can be
176be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         *            a single monolithic APK file or a cluster directory
177be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         *            containing one or more APKs.
178be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey         */
179cea3743499f4bb8e5f28a2e57686d7af313169c5Kenny Root        @Override
180f8bb2445ff28d64d12d81d91539bb419f69e7874Jeff Sharkey        public long calculateInstalledSize(String packagePath, String abiOverride)
181f8bb2445ff28d64d12d81d91539bb419f69e7874Jeff Sharkey                throws RemoteException {
182cea3743499f4bb8e5f28a2e57686d7af313169c5Kenny Root            final File packageFile = new File(packagePath);
183be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey            final PackageParser.PackageLite pkg;
184cea3743499f4bb8e5f28a2e57686d7af313169c5Kenny Root            try {
185be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey                pkg = PackageParser.parsePackageLite(packageFile, 0);
186f8bb2445ff28d64d12d81d91539bb419f69e7874Jeff Sharkey                return PackageHelper.calculateInstalledSize(pkg, abiOverride);
187be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey            } catch (PackageParserException | IOException e) {
188742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                Slog.w(TAG, "Failed to calculate installed size: " + e);
189742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey                return Long.MAX_VALUE;
190cea3743499f4bb8e5f28a2e57686d7af313169c5Kenny Root            }
191cea3743499f4bb8e5f28a2e57686d7af313169c5Kenny Root        }
192c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu    };
193c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu
194e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn    public DefaultContainerService() {
195e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn        super("DefaultContainerService");
196e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn        setIntentRedelivery(true);
197e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn    }
198e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn
199e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn    @Override
200e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn    protected void onHandleIntent(Intent intent) {
201e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn        if (PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE.equals(intent.getAction())) {
202752cd922f7091dfd5401faf70dc248934a9dbb6dJeff Sharkey            final IPackageManager pm = IPackageManager.Stub.asInterface(
203e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn                    ServiceManager.getService("package"));
204752cd922f7091dfd5401faf70dc248934a9dbb6dJeff Sharkey            PackageCleanItem item = null;
205e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn            try {
206752cd922f7091dfd5401faf70dc248934a9dbb6dJeff Sharkey                while ((item = pm.nextPackageToClean(item)) != null) {
207752cd922f7091dfd5401faf70dc248934a9dbb6dJeff Sharkey                    final UserEnvironment userEnv = new UserEnvironment(item.userId);
2087f392defccfae54dc8169e5ad82c2616e0713c8eJeff Sharkey                    eraseFiles(userEnv.buildExternalStorageAppDataDirs(item.packageName));
2097f392defccfae54dc8169e5ad82c2616e0713c8eJeff Sharkey                    eraseFiles(userEnv.buildExternalStorageAppMediaDirs(item.packageName));
210752cd922f7091dfd5401faf70dc248934a9dbb6dJeff Sharkey                    if (item.andCode) {
2117f392defccfae54dc8169e5ad82c2616e0713c8eJeff Sharkey                        eraseFiles(userEnv.buildExternalStorageAppObbDirs(item.packageName));
2127767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn                    }
213e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn                }
214e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn            } catch (RemoteException e) {
215e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn            }
216e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn        }
217e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn    }
218e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn
2197f392defccfae54dc8169e5ad82c2616e0713c8eJeff Sharkey    void eraseFiles(File[] paths) {
2207f392defccfae54dc8169e5ad82c2616e0713c8eJeff Sharkey        for (File path : paths) {
2217f392defccfae54dc8169e5ad82c2616e0713c8eJeff Sharkey            eraseFiles(path);
2227f392defccfae54dc8169e5ad82c2616e0713c8eJeff Sharkey        }
2237f392defccfae54dc8169e5ad82c2616e0713c8eJeff Sharkey    }
2247f392defccfae54dc8169e5ad82c2616e0713c8eJeff Sharkey
225e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn    void eraseFiles(File path) {
226e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn        if (path.isDirectory()) {
227e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn            String[] files = path.list();
228e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn            if (files != null) {
229e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn                for (String file : files) {
230e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn                    eraseFiles(new File(path, file));
231e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn                }
232e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn            }
233e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn        }
234e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn        path.delete();
235e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn    }
236be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey
237be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey    @Override
238c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu    public IBinder onBind(Intent intent) {
239c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu        return mBinder;
240c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu    }
241c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu
242be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey    private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)
243be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey            throws IOException, RemoteException {
244bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        copyFile(pkg.baseCodePath, target, "base.apk");
245be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey        if (!ArrayUtils.isEmpty(pkg.splitNames)) {
246d746057f2414cba2bdc69257cc5be8cb681bb592Jeff Sharkey            for (int i = 0; i < pkg.splitNames.length; i++) {
247bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                copyFile(pkg.splitCodePaths[i], target, "split_" + pkg.splitNames[i] + ".apk");
248d746057f2414cba2bdc69257cc5be8cb681bb592Jeff Sharkey            }
249be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey        }
250be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey
251d746057f2414cba2bdc69257cc5be8cb681bb592Jeff Sharkey        return PackageManager.INSTALL_SUCCEEDED;
252d746057f2414cba2bdc69257cc5be8cb681bb592Jeff Sharkey    }
253d746057f2414cba2bdc69257cc5be8cb681bb592Jeff Sharkey
254bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey    private void copyFile(String sourcePath, IParcelFileDescriptorFactory target, String targetName)
255bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            throws IOException, RemoteException {
256d746057f2414cba2bdc69257cc5be8cb681bb592Jeff Sharkey        Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
257be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey        InputStream in = null;
258be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey        OutputStream out = null;
259be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey        try {
260d746057f2414cba2bdc69257cc5be8cb681bb592Jeff Sharkey            in = new FileInputStream(sourcePath);
261be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey            out = new ParcelFileDescriptor.AutoCloseOutputStream(
262d746057f2414cba2bdc69257cc5be8cb681bb592Jeff Sharkey                    target.open(targetName, ParcelFileDescriptor.MODE_READ_WRITE));
263b18f899241231991e314c40990eb8e9f703732d4Jeff Sharkey            FileUtils.copy(in, out);
264be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey        } finally {
265be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey            IoUtils.closeQuietly(out);
266be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey            IoUtils.closeQuietly(in);
267be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey        }
268be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey    }
269c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu}
270