DefaultContainerService.java revision 930d3af75f9e9663222f4c4a1d75b326cf811e35
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 19c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport com.android.internal.app.IMediaContainerService; 205b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapuimport com.android.internal.content.PackageHelper; 21c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.content.Intent; 22e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackbornimport android.content.pm.IPackageManager; 235b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapuimport android.content.pm.PackageInfo; 24a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapuimport android.content.pm.PackageInfoLite; 25e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackbornimport android.content.pm.PackageManager; 265b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapuimport android.content.pm.PackageParser; 27c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.net.Uri; 28e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackbornimport android.os.Environment; 29c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.os.IBinder; 30c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.os.ParcelFileDescriptor; 31c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.os.Process; 32c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.os.RemoteException; 33c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.os.ServiceManager; 345b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapuimport android.os.StatFs; 35e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackbornimport android.app.IntentService; 365b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapuimport android.util.DisplayMetrics; 37c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.util.Log; 38c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu 39c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport java.io.File; 40c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport java.io.FileInputStream; 41c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport java.io.FileNotFoundException; 42c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport java.io.FileOutputStream; 43c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport java.io.IOException; 44c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport java.io.InputStream; 45c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu 46c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapuimport android.os.FileUtils; 475b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapuimport android.provider.Settings; 48c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu 49c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu/* 50c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * This service copies a downloaded apk to a file passed in as 51c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * a ParcelFileDescriptor or to a newly created container specified 52c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * by parameters. The DownloadManager gives access to this process 53c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * based on its uid. This process also needs the ACCESS_DOWNLOAD_MANAGER 54c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * permission to access apks downloaded via the download manager. 55c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu */ 56e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackbornpublic class DefaultContainerService extends IntentService { 57c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu private static final String TAG = "DefContainer"; 58cf6eaeaae9e6745dd6e07540812c79821d7043c2Suchi Amalapurapu private static final boolean localLOGV = true; 59c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu 60c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu private IMediaContainerService.Stub mBinder = new IMediaContainerService.Stub() { 61c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu /* 62c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * Creates a new container and copies resource there. 63c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * @param paackageURI the uri of resource to be copied. Can be either 64c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * a content uri or a file uri 65679bba339ef6948091180c776d6a284cddd812f5Suchi Amalapurapu * @param cid the id of the secure container that should 66c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * be used for creating a secure container into which the resource 67c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * will be copied. 68c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * @param key Refers to key used for encrypting the secure container 69c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * @param resFileName Name of the target resource file(relative to newly 70c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * created secure container) 71c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * @return Returns the new cache path where the resource has been copied into 72c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * 73c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu */ 74c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu public String copyResourceToContainer(final Uri packageURI, 75679bba339ef6948091180c776d6a284cddd812f5Suchi Amalapurapu final String cid, 76c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu final String key, final String resFileName) { 77679bba339ef6948091180c776d6a284cddd812f5Suchi Amalapurapu if (packageURI == null || cid == null) { 78c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return null; 79c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 80679bba339ef6948091180c776d6a284cddd812f5Suchi Amalapurapu return copyResourceInner(packageURI, cid, key, resFileName); 81c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 82c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu 83c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu /* 84c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * Copy specified resource to output stream 85c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * @param packageURI the uri of resource to be copied. Should be a 86c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * file uri 87c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * @param outStream Remote file descriptor to be used for copying 88c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu * @return Returns true if copy succeded or false otherwise. 89c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu */ 90c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu public boolean copyResource(final Uri packageURI, 91c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu ParcelFileDescriptor outStream) { 92c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu if (packageURI == null || outStream == null) { 93c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return false; 94c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 95c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu ParcelFileDescriptor.AutoCloseOutputStream 96c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu autoOut = new ParcelFileDescriptor.AutoCloseOutputStream(outStream); 97c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return copyFile(packageURI, autoOut); 98c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 995b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu 1005b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu /* 1015b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu * Determine the recommended install location for package 1025b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu * specified by file uri location. 1035b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu * @param fileUri the uri of resource to be copied. Should be a 1045b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu * file uri 105a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu * @return Returns PackageInfoLite object containing 106a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu * the package info and recommended app location. 1075b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu */ 10814b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu public PackageInfoLite getMinimalPackageInfo(final Uri fileUri, int flags) { 109a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu PackageInfoLite ret = new PackageInfoLite(); 1103602f76d417b0940a26f28b7ad892abcfe03ef7cSuchi Amalapurapu if (fileUri == null) { 1113602f76d417b0940a26f28b7ad892abcfe03ef7cSuchi Amalapurapu Log.i(TAG, "Invalid package uri " + fileUri); 112a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK; 113a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu return ret; 1143602f76d417b0940a26f28b7ad892abcfe03ef7cSuchi Amalapurapu } 1153602f76d417b0940a26f28b7ad892abcfe03ef7cSuchi Amalapurapu String scheme = fileUri.getScheme(); 1163602f76d417b0940a26f28b7ad892abcfe03ef7cSuchi Amalapurapu if (scheme != null && !scheme.equals("file")) { 1175b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu Log.w(TAG, "Falling back to installing on internal storage only"); 118a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_INTERNAL; 119a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu return ret; 1205b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu } 1213602f76d417b0940a26f28b7ad892abcfe03ef7cSuchi Amalapurapu String archiveFilePath = fileUri.getPath(); 1225b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu PackageParser packageParser = new PackageParser(archiveFilePath); 1235b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu File sourceFile = new File(archiveFilePath); 1245b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu DisplayMetrics metrics = new DisplayMetrics(); 1255b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu metrics.setToDefaults(); 126a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu PackageParser.PackageLite pkg = packageParser.parsePackageLite( 127a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu archiveFilePath, 0); 1288946dd3355fc1dcbad872c0546e356474d4cc5deSuchi Amalapurapu // Nuke the parser reference right away and force a gc 1298946dd3355fc1dcbad872c0546e356474d4cc5deSuchi Amalapurapu packageParser = null; 1308a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Runtime.getRuntime().gc(); 1315b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu if (pkg == null) { 1325b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu Log.w(TAG, "Failed to parse package"); 133a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK; 134a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu return ret; 1355b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu } 136a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu ret.packageName = pkg.packageName; 137930d3af75f9e9663222f4c4a1d75b326cf811e35Kenny Root ret.installLocation = pkg.installLocation; 13814b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation, archiveFilePath, flags); 139a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu return ret; 1405b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu } 1418a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu 1428a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu public boolean checkFreeStorage(boolean external, Uri fileUri) { 1438a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu return checkFreeStorageInner(external, fileUri); 1448a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 145c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu }; 146c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu 147e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn public DefaultContainerService() { 148e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn super("DefaultContainerService"); 149e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn setIntentRedelivery(true); 150e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn } 151e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn 152e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn @Override 153e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn protected void onHandleIntent(Intent intent) { 154e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn if (PackageManager.ACTION_CLEAN_EXTERNAL_STORAGE.equals(intent.getAction())) { 155e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn IPackageManager pm = IPackageManager.Stub.asInterface( 156e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn ServiceManager.getService("package")); 157e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn String pkg = null; 158e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn try { 159e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn while ((pkg=pm.nextPackageToClean(pkg)) != null) { 160e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn eraseFiles(Environment.getExternalStorageAppDataDirectory(pkg)); 161e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn eraseFiles(Environment.getExternalStorageAppMediaDirectory(pkg)); 162e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn } 163e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn } catch (RemoteException e) { 164e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn } 165e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn } 166e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn } 167e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn 168e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn void eraseFiles(File path) { 169e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn if (path.isDirectory()) { 170e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn String[] files = path.list(); 171e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn if (files != null) { 172e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn for (String file : files) { 173e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn eraseFiles(new File(path, file)); 174e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn } 175e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn } 176e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn } 177e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn path.delete(); 178e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn } 179e83cefcef07f9ac025642c1ffec76b4c7ab39cf2Dianne Hackborn 180c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu public IBinder onBind(Intent intent) { 181c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return mBinder; 182c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 183c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu 184679bba339ef6948091180c776d6a284cddd812f5Suchi Amalapurapu private String copyResourceInner(Uri packageURI, String newCid, String key, String resFileName) { 1858a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // Make sure the sdcard is mounted. 1868a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu String status = Environment.getExternalStorageState(); 1878a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (!status.equals(Environment.MEDIA_MOUNTED)) { 1888a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Log.w(TAG, "Make sure sdcard is mounted."); 1898a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu return null; 1908a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 191c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu // Create new container at newCachePath 192c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu String codePath = packageURI.getPath(); 193679bba339ef6948091180c776d6a284cddd812f5Suchi Amalapurapu File codeFile = new File(codePath); 194c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu String newCachePath = null; 195c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu // Create new container 196679bba339ef6948091180c776d6a284cddd812f5Suchi Amalapurapu if ((newCachePath = PackageHelper.createSdDir(codeFile, 197a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu newCid, key, Process.myUid())) == null) { 198a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu Log.e(TAG, "Failed to create container " + newCid); 199a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu return null; 200c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 201a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu if (localLOGV) Log.i(TAG, "Created container for " + newCid 202a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu + " at path : " + newCachePath); 203a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu File resFile = new File(newCachePath, resFileName); 204a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu if (!FileUtils.copyFile(new File(codePath), resFile)) { 205a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu Log.e(TAG, "Failed to copy " + codePath + " to " + resFile); 206a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu // Clean up container 207a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu PackageHelper.destroySdDir(newCid); 208c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return null; 209c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 210a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile); 211a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu if (!PackageHelper.finalizeSdDir(newCid)) { 212a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu Log.e(TAG, "Failed to finalize " + newCid + " at path " + newCachePath); 213a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu // Clean up container 214a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu PackageHelper.destroySdDir(newCid); 215a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu } 216a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu if (localLOGV) Log.i(TAG, "Finalized container " + newCid); 217a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu if (PackageHelper.isContainerMounted(newCid)) { 218a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu if (localLOGV) Log.i(TAG, "Unmounting " + newCid + 219a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu " at path " + newCachePath); 220a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu // Force a gc to avoid being killed. 221a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu Runtime.getRuntime().gc(); 222a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu PackageHelper.unMountSdDir(newCid); 223a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu } else { 224a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu if (localLOGV) Log.i(TAG, "Container " + newCid + " not mounted"); 225a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu } 226c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return newCachePath; 227c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 228c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu 229c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu public static boolean copyToFile(InputStream inputStream, FileOutputStream out) { 230c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu try { 231c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu byte[] buffer = new byte[4096]; 232c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu int bytesRead; 233c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu while ((bytesRead = inputStream.read(buffer)) >= 0) { 234c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu out.write(buffer, 0, bytesRead); 235c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 236c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return true; 237c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } catch (IOException e) { 238c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu Log.i(TAG, "Exception : " + e + " when copying file"); 239c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return false; 240c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 241c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 242c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu 243c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu public static boolean copyToFile(File srcFile, FileOutputStream out) { 244c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu InputStream inputStream = null; 245c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu try { 246c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu inputStream = new FileInputStream(srcFile); 247c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return copyToFile(inputStream, out); 248c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } catch (IOException e) { 249c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return false; 250c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } finally { 251c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu try { if (inputStream != null) inputStream.close(); } catch (IOException e) {} 252c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 253c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 254c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu 255c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu private boolean copyFile(Uri pPackageURI, FileOutputStream outStream) { 2563602f76d417b0940a26f28b7ad892abcfe03ef7cSuchi Amalapurapu String scheme = pPackageURI.getScheme(); 2573602f76d417b0940a26f28b7ad892abcfe03ef7cSuchi Amalapurapu if (scheme == null || scheme.equals("file")) { 258c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu final File srcPackageFile = new File(pPackageURI.getPath()); 259c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu // We copy the source package file to a temp file and then rename it to the 260c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu // destination file in order to eliminate a window where the package directory 261c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu // scanner notices the new package file but it's not completely copied yet. 262c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu if (!copyToFile(srcPackageFile, outStream)) { 263c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu Log.e(TAG, "Couldn't copy file: " + srcPackageFile); 264c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return false; 265c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 2663602f76d417b0940a26f28b7ad892abcfe03ef7cSuchi Amalapurapu } else if (scheme.equals("content")) { 267c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu ParcelFileDescriptor fd = null; 268c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu try { 269c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu fd = getContentResolver().openFileDescriptor(pPackageURI, "r"); 270c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } catch (FileNotFoundException e) { 271c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu Log.e(TAG, "Couldn't open file descriptor from download service. Failed with exception " + e); 272c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return false; 273c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 274c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu if (fd == null) { 275c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu Log.e(TAG, "Couldn't open file descriptor from download service (null)."); 276c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return false; 277c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } else { 278c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu if (localLOGV) { 279c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu Log.v(TAG, "Opened file descriptor from download service."); 280c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 281c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu ParcelFileDescriptor.AutoCloseInputStream 282c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu dlStream = new ParcelFileDescriptor.AutoCloseInputStream(fd); 283c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu // We copy the source package file to a temp file and then rename it to the 284c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu // destination file in order to eliminate a window where the package directory 285c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu // scanner notices the new package file but it's not completely copied yet. 286c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu if (!copyToFile(dlStream, outStream)) { 287c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu Log.e(TAG, "Couldn't copy " + pPackageURI + " to temp file."); 288c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return false; 289c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 290c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 291c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } else { 292c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI); 293c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return false; 294c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 295c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu return true; 296c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu } 2975b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu 2985b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu // Constants related to app heuristics 2995b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu // No-installation limit for internal flash: 10% or less space available 3005b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu private static final double LOW_NAND_FLASH_TRESHOLD = 0.1; 3015b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu 3025b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu // SD-to-internal app size threshold: currently set to 1 MB 3035b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024); 3045b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu private static final int ERR_LOC = -1; 3055b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu 306a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu private int recommendAppInstallLocation(int installLocation, 30714b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu String archiveFilePath, int flags) { 30814b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu boolean checkInt = false; 30914b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu boolean checkExt = false; 31014b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu boolean checkBoth = false; 31114b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu check_inner : { 31214b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu // Check flags. 31314b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) { 31414b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu // Check for forward locked app 31514b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu checkInt = true; 31614b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu break check_inner; 31714b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu } else if ((flags & PackageManager.INSTALL_INTERNAL) != 0) { 31814b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu // Explicit flag to install internally. 31914b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu // Check internal storage and return 32014b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu checkInt = true; 32114b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu break check_inner; 32214b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu } else if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) { 32314b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu // Explicit flag to install externally. 32414b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu // Check external storage and return 32514b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu checkExt = true; 32614b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu break check_inner; 32714b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu } 32814b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu // Check for manifest option 32914b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { 33014b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu checkInt = true; 33114b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu break check_inner; 33214b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu } else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) { 33314b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu checkExt = true; 33414b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu checkBoth = true; 33514b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu break check_inner; 33614b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) { 33714b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu checkInt = true; 33814b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu checkBoth = true; 33914b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu break check_inner; 34014b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu } 34140e472521a544f26cb6956995788f7c36fff1404Suchi Amalapurapu // Pick user preference 34240e472521a544f26cb6956995788f7c36fff1404Suchi Amalapurapu int installPreference = Settings.System.getInt(getApplicationContext() 34314b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu .getContentResolver(), 34440e472521a544f26cb6956995788f7c36fff1404Suchi Amalapurapu Settings.Secure.DEFAULT_INSTALL_LOCATION, 34540e472521a544f26cb6956995788f7c36fff1404Suchi Amalapurapu PackageHelper.APP_INSTALL_AUTO); 34640e472521a544f26cb6956995788f7c36fff1404Suchi Amalapurapu if (installPreference == PackageHelper.APP_INSTALL_INTERNAL) { 34740e472521a544f26cb6956995788f7c36fff1404Suchi Amalapurapu checkInt = true; 34840e472521a544f26cb6956995788f7c36fff1404Suchi Amalapurapu break check_inner; 34940e472521a544f26cb6956995788f7c36fff1404Suchi Amalapurapu } else if (installPreference == PackageHelper.APP_INSTALL_EXTERNAL) { 35040e472521a544f26cb6956995788f7c36fff1404Suchi Amalapurapu checkExt = true; 35140e472521a544f26cb6956995788f7c36fff1404Suchi Amalapurapu break check_inner; 35214b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu } 35314b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu // Fall back to default policy if nothing else is specified. 35414b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu checkInt = true; 35514b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu } 35614b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu 3575b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu // Package size = code size + cache size + data size 3585b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu // If code size > 1 MB, install on SD card. 3595b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu // Else install on internal NAND flash, unless space on NAND is less than 10% 360a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu String status = Environment.getExternalStorageState(); 361a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu long availSDSize = -1; 3628a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu boolean mediaAvailable = false; 363a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu if (status.equals(Environment.MEDIA_MOUNTED)) { 364a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu StatFs sdStats = new StatFs( 365a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu Environment.getExternalStorageDirectory().getPath()); 366a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu availSDSize = (long)sdStats.getAvailableBlocks() * 367a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu (long)sdStats.getBlockSize(); 3688a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu mediaAvailable = true; 3695b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu } 370a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath()); 371a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu long totalInternalSize = (long)internalStats.getBlockCount() * 372a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu (long)internalStats.getBlockSize(); 373a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu long availInternalSize = (long)internalStats.getAvailableBlocks() * 374a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu (long)internalStats.getBlockSize(); 3755b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu 376a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu double pctNandFree = (double)availInternalSize / (double)totalInternalSize; 3775b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu 3785b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu File apkFile = new File(archiveFilePath); 3795b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu long pkgLen = apkFile.length(); 38014b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu 3815b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu // To make final copy 3825b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu long reqInstallSize = pkgLen; 383cf6eaeaae9e6745dd6e07540812c79821d7043c2Suchi Amalapurapu // For dex files. Just ignore and fail when extracting. Max limit of 2Gig for now. 384cf6eaeaae9e6745dd6e07540812c79821d7043c2Suchi Amalapurapu long reqInternalSize = 0; 3855b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD); 386a2b6c3775ed6b8924232d6a01bae4a19740a15f8Suchi Amalapurapu boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalSize); 38714b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu boolean fitsOnSd = false; 38814b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu if (mediaAvailable && (reqInstallSize < availSDSize)) { 38914b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu // If we do not have an internal size requirement 39014b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu // don't do a threshold check. 39114b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu if (reqInternalSize == 0) { 39214b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu fitsOnSd = true; 39314b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu } else if ((reqInternalSize < availInternalSize) && intThresholdOk) { 39414b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu fitsOnSd = true; 39514b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu } 39614b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu } 3975b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu boolean fitsOnInt = intThresholdOk && intAvailOk; 39814b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu if (checkInt) { 39914b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu // Check for internal memory availability 40014b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu if (fitsOnInt) { 40114b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu return PackageHelper.RECOMMEND_INSTALL_INTERNAL; 4025b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu } 40314b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu } else if (checkExt) { 40414b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu if (fitsOnSd) { 40514b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; 4065b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu } 4075b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu } 40814b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu if (checkBoth) { 40914b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu // Check for internal first 41014b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu if (fitsOnInt) { 41114b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu return PackageHelper.RECOMMEND_INSTALL_INTERNAL; 41214b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu } 41314b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu // Check for external next 41414b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu if (fitsOnSd) { 41514b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; 4165b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu } 4175b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu } 418d345bb6e5b42ff644ce224fe57e4d7b4e546a48dSuchi Amalapurapu if ((checkExt || checkBoth) && !mediaAvailable) { 41914b6abda1309631d49d4bebbb0317a7e1dfc0a50Suchi Amalapurapu return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE; 4205b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu } 4218a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE; 4228a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 4238a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu 4248a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu private boolean checkFreeStorageInner(boolean external, Uri packageURI) { 4258a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu File apkFile = new File(packageURI.getPath()); 4268a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu long size = apkFile.length(); 4278a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (external) { 4288a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu String status = Environment.getExternalStorageState(); 4298a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu long availSDSize = -1; 4308a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (status.equals(Environment.MEDIA_MOUNTED)) { 4318a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu StatFs sdStats = new StatFs( 4328a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.getExternalStorageDirectory().getPath()); 4338a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu availSDSize = (long)sdStats.getAvailableBlocks() * 4348a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu (long)sdStats.getBlockSize(); 4358a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 4368a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu return availSDSize > size; 4378a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 4388a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath()); 4398a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu long totalInternalSize = (long)internalStats.getBlockCount() * 4408a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu (long)internalStats.getBlockSize(); 4418a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu long availInternalSize = (long)internalStats.getAvailableBlocks() * 4428a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu (long)internalStats.getBlockSize(); 4438a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu 4448a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu double pctNandFree = (double)availInternalSize / (double)totalInternalSize; 4458a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // To make final copy 4468a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu long reqInstallSize = size; 4478a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // For dex files. Just ignore and fail when extracting. Max limit of 2Gig for now. 4488a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu long reqInternalSize = 0; 4498a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD); 4508a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalSize); 4518a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu return intThresholdOk && intAvailOk; 4525b993ce7bc29e43a3215a50ce6ce5d6550d4e5e2Suchi Amalapurapu } 453c028be4f3b8c7476b46859f66c3f33d528adf181Suchi Amalapurapu} 454