1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.packageinstaller.wear; 18 19 import android.content.Context; 20 import android.net.Uri; 21 import android.os.ParcelFileDescriptor; 22 import android.system.ErrnoException; 23 import android.system.Os; 24 import android.text.TextUtils; 25 import android.util.Log; 26 27 import org.tukaani.xz.LZMAInputStream; 28 import org.tukaani.xz.XZInputStream; 29 30 import java.io.File; 31 import java.io.FileOutputStream; 32 import java.io.IOException; 33 import java.io.InputStream; 34 35 public class WearPackageUtil { 36 private static final String TAG = "WearablePkgInstaller"; 37 38 private static final String COMPRESSION_LZMA = "lzma"; 39 private static final String COMPRESSION_XZ = "xz"; 40 getTemporaryFile(Context context, String packageName)41 public static File getTemporaryFile(Context context, String packageName) { 42 try { 43 File newFileDir = new File(context.getFilesDir(), "tmp"); 44 newFileDir.mkdirs(); 45 Os.chmod(newFileDir.getAbsolutePath(), 0771); 46 File newFile = new File(newFileDir, packageName + ".apk"); 47 return newFile; 48 } catch (ErrnoException e) { 49 Log.e(TAG, "Failed to open.", e); 50 return null; 51 } 52 } 53 getIconFile(final Context context, final String packageName)54 public static File getIconFile(final Context context, final String packageName) { 55 try { 56 File newFileDir = new File(context.getFilesDir(), "images/icons"); 57 newFileDir.mkdirs(); 58 Os.chmod(newFileDir.getAbsolutePath(), 0771); 59 return new File(newFileDir, packageName + ".icon"); 60 } catch (ErrnoException e) { 61 Log.e(TAG, "Failed to open.", e); 62 return null; 63 } 64 } 65 66 /** 67 * In order to make sure that the Wearable Asset Manager has a reasonable apk that can be used 68 * by the PackageManager, we will parse it before sending it to the PackageManager. 69 * Unfortunately, PackageParser needs a file to parse. So, we have to temporarily convert the fd 70 * to a File. 71 * 72 * @param context 73 * @param fd FileDescriptor to convert to File 74 * @param packageName Name of package, will define the name of the file 75 * @param compressionAlg Can be null. For ALT mode the APK will be compressed. We will 76 * decompress it here 77 */ getFileFromFd(Context context, ParcelFileDescriptor fd, String packageName, String compressionAlg)78 public static File getFileFromFd(Context context, ParcelFileDescriptor fd, 79 String packageName, String compressionAlg) { 80 File newFile = getTemporaryFile(context, packageName); 81 if (fd == null || fd.getFileDescriptor() == null) { 82 return null; 83 } 84 InputStream fr = new ParcelFileDescriptor.AutoCloseInputStream(fd); 85 try { 86 if (TextUtils.equals(compressionAlg, COMPRESSION_XZ)) { 87 fr = new XZInputStream(fr); 88 } else if (TextUtils.equals(compressionAlg, COMPRESSION_LZMA)) { 89 fr = new LZMAInputStream(fr); 90 } 91 } catch (IOException e) { 92 Log.e(TAG, "Compression was set to " + compressionAlg + ", but could not decode ", e); 93 return null; 94 } 95 96 int nRead; 97 byte[] data = new byte[1024]; 98 try { 99 final FileOutputStream fo = new FileOutputStream(newFile); 100 while ((nRead = fr.read(data, 0, data.length)) != -1) { 101 fo.write(data, 0, nRead); 102 } 103 fo.flush(); 104 fo.close(); 105 Os.chmod(newFile.getAbsolutePath(), 0644); 106 return newFile; 107 } catch (IOException e) { 108 Log.e(TAG, "Reading from Asset FD or writing to temp file failed ", e); 109 return null; 110 } catch (ErrnoException e) { 111 Log.e(TAG, "Could not set permissions on file ", e); 112 return null; 113 } finally { 114 try { 115 fr.close(); 116 } catch (IOException e) { 117 Log.e(TAG, "Failed to close the file from FD ", e); 118 } 119 } 120 } 121 122 /** 123 * @return com.google.com from expected formats like 124 * Uri: package:com.google.com, package:/com.google.com, package://com.google.com 125 */ getSanitizedPackageName(Uri packageUri)126 public static String getSanitizedPackageName(Uri packageUri) { 127 String packageName = packageUri.getEncodedSchemeSpecificPart(); 128 if (packageName != null) { 129 return packageName.replaceAll("^/+", ""); 130 } 131 return packageName; 132 } 133 } 134