1 /*
2  * Copyright (C) 2008 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.server.pm;
18 
19 import android.annotation.Nullable;
20 import android.content.Context;
21 import android.content.pm.PackageStats;
22 import android.os.Build;
23 import android.text.TextUtils;
24 import android.util.Slog;
25 
26 import dalvik.system.VMRuntime;
27 
28 import com.android.internal.os.InstallerConnection;
29 import com.android.server.SystemService;
30 
31 public final class Installer extends SystemService {
32     private static final String TAG = "Installer";
33 
34     private final InstallerConnection mInstaller;
35 
Installer(Context context)36     public Installer(Context context) {
37         super(context);
38         mInstaller = new InstallerConnection();
39     }
40 
41     @Override
onStart()42     public void onStart() {
43         Slog.i(TAG, "Waiting for installd to be ready.");
44         mInstaller.waitForConnection();
45     }
46 
escapeNull(String arg)47     private static String escapeNull(String arg) {
48         if (TextUtils.isEmpty(arg)) {
49             return "!";
50         } else {
51             if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
52                 throw new IllegalArgumentException(arg);
53             }
54             return arg;
55         }
56     }
57 
58     @Deprecated
install(String name, int uid, int gid, String seinfo)59     public int install(String name, int uid, int gid, String seinfo) {
60         return install(null, name, uid, gid, seinfo);
61     }
62 
install(String uuid, String name, int uid, int gid, String seinfo)63     public int install(String uuid, String name, int uid, int gid, String seinfo) {
64         StringBuilder builder = new StringBuilder("install");
65         builder.append(' ');
66         builder.append(escapeNull(uuid));
67         builder.append(' ');
68         builder.append(name);
69         builder.append(' ');
70         builder.append(uid);
71         builder.append(' ');
72         builder.append(gid);
73         builder.append(' ');
74         builder.append(seinfo != null ? seinfo : "!");
75         return mInstaller.execute(builder.toString());
76     }
77 
dexopt(String apkPath, int uid, boolean isPublic, String instructionSet, int dexoptNeeded)78     public int dexopt(String apkPath, int uid, boolean isPublic,
79             String instructionSet, int dexoptNeeded) {
80         if (!isValidInstructionSet(instructionSet)) {
81             Slog.e(TAG, "Invalid instruction set: " + instructionSet);
82             return -1;
83         }
84 
85         return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded);
86     }
87 
dexopt(String apkPath, int uid, boolean isPublic, String pkgName, String instructionSet, int dexoptNeeded, boolean vmSafeMode, boolean debuggable, @Nullable String outputPath)88     public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
89             String instructionSet, int dexoptNeeded, boolean vmSafeMode,
90             boolean debuggable, @Nullable String outputPath) {
91         if (!isValidInstructionSet(instructionSet)) {
92             Slog.e(TAG, "Invalid instruction set: " + instructionSet);
93             return -1;
94         }
95         return mInstaller.dexopt(apkPath, uid, isPublic, pkgName,
96                 instructionSet, dexoptNeeded, vmSafeMode,
97                 debuggable, outputPath);
98     }
99 
idmap(String targetApkPath, String overlayApkPath, int uid)100     public int idmap(String targetApkPath, String overlayApkPath, int uid) {
101         StringBuilder builder = new StringBuilder("idmap");
102         builder.append(' ');
103         builder.append(targetApkPath);
104         builder.append(' ');
105         builder.append(overlayApkPath);
106         builder.append(' ');
107         builder.append(uid);
108         return mInstaller.execute(builder.toString());
109     }
110 
movedex(String srcPath, String dstPath, String instructionSet)111     public int movedex(String srcPath, String dstPath, String instructionSet) {
112         if (!isValidInstructionSet(instructionSet)) {
113             Slog.e(TAG, "Invalid instruction set: " + instructionSet);
114             return -1;
115         }
116 
117         StringBuilder builder = new StringBuilder("movedex");
118         builder.append(' ');
119         builder.append(srcPath);
120         builder.append(' ');
121         builder.append(dstPath);
122         builder.append(' ');
123         builder.append(instructionSet);
124         return mInstaller.execute(builder.toString());
125     }
126 
rmdex(String codePath, String instructionSet)127     public int rmdex(String codePath, String instructionSet) {
128         if (!isValidInstructionSet(instructionSet)) {
129             Slog.e(TAG, "Invalid instruction set: " + instructionSet);
130             return -1;
131         }
132 
133         StringBuilder builder = new StringBuilder("rmdex");
134         builder.append(' ');
135         builder.append(codePath);
136         builder.append(' ');
137         builder.append(instructionSet);
138         return mInstaller.execute(builder.toString());
139     }
140 
141     /**
142      * Removes packageDir or its subdirectory
143      */
rmPackageDir(String packageDir)144     public int rmPackageDir(String packageDir) {
145         StringBuilder builder = new StringBuilder("rmpackagedir");
146         builder.append(' ');
147         builder.append(packageDir);
148         return mInstaller.execute(builder.toString());
149     }
150 
151     @Deprecated
remove(String name, int userId)152     public int remove(String name, int userId) {
153         return remove(null, name, userId);
154     }
155 
remove(String uuid, String name, int userId)156     public int remove(String uuid, String name, int userId) {
157         StringBuilder builder = new StringBuilder("remove");
158         builder.append(' ');
159         builder.append(escapeNull(uuid));
160         builder.append(' ');
161         builder.append(name);
162         builder.append(' ');
163         builder.append(userId);
164         return mInstaller.execute(builder.toString());
165     }
166 
rename(String oldname, String newname)167     public int rename(String oldname, String newname) {
168         StringBuilder builder = new StringBuilder("rename");
169         builder.append(' ');
170         builder.append(oldname);
171         builder.append(' ');
172         builder.append(newname);
173         return mInstaller.execute(builder.toString());
174     }
175 
176     @Deprecated
fixUid(String name, int uid, int gid)177     public int fixUid(String name, int uid, int gid) {
178         return fixUid(null, name, uid, gid);
179     }
180 
fixUid(String uuid, String name, int uid, int gid)181     public int fixUid(String uuid, String name, int uid, int gid) {
182         StringBuilder builder = new StringBuilder("fixuid");
183         builder.append(' ');
184         builder.append(escapeNull(uuid));
185         builder.append(' ');
186         builder.append(name);
187         builder.append(' ');
188         builder.append(uid);
189         builder.append(' ');
190         builder.append(gid);
191         return mInstaller.execute(builder.toString());
192     }
193 
194     @Deprecated
deleteCacheFiles(String name, int userId)195     public int deleteCacheFiles(String name, int userId) {
196         return deleteCacheFiles(null, name, userId);
197     }
198 
deleteCacheFiles(String uuid, String name, int userId)199     public int deleteCacheFiles(String uuid, String name, int userId) {
200         StringBuilder builder = new StringBuilder("rmcache");
201         builder.append(' ');
202         builder.append(escapeNull(uuid));
203         builder.append(' ');
204         builder.append(name);
205         builder.append(' ');
206         builder.append(userId);
207         return mInstaller.execute(builder.toString());
208     }
209 
210     @Deprecated
deleteCodeCacheFiles(String name, int userId)211     public int deleteCodeCacheFiles(String name, int userId) {
212         return deleteCodeCacheFiles(null, name, userId);
213     }
214 
deleteCodeCacheFiles(String uuid, String name, int userId)215     public int deleteCodeCacheFiles(String uuid, String name, int userId) {
216         StringBuilder builder = new StringBuilder("rmcodecache");
217         builder.append(' ');
218         builder.append(escapeNull(uuid));
219         builder.append(' ');
220         builder.append(name);
221         builder.append(' ');
222         builder.append(userId);
223         return mInstaller.execute(builder.toString());
224     }
225 
226     @Deprecated
createUserData(String name, int uid, int userId, String seinfo)227     public int createUserData(String name, int uid, int userId, String seinfo) {
228         return createUserData(null, name, uid, userId, seinfo);
229     }
230 
createUserData(String uuid, String name, int uid, int userId, String seinfo)231     public int createUserData(String uuid, String name, int uid, int userId, String seinfo) {
232         StringBuilder builder = new StringBuilder("mkuserdata");
233         builder.append(' ');
234         builder.append(escapeNull(uuid));
235         builder.append(' ');
236         builder.append(name);
237         builder.append(' ');
238         builder.append(uid);
239         builder.append(' ');
240         builder.append(userId);
241         builder.append(' ');
242         builder.append(seinfo != null ? seinfo : "!");
243         return mInstaller.execute(builder.toString());
244     }
245 
createUserConfig(int userId)246     public int createUserConfig(int userId) {
247         StringBuilder builder = new StringBuilder("mkuserconfig");
248         builder.append(' ');
249         builder.append(userId);
250         return mInstaller.execute(builder.toString());
251     }
252 
253     @Deprecated
removeUserDataDirs(int userId)254     public int removeUserDataDirs(int userId) {
255         return removeUserDataDirs(null, userId);
256     }
257 
removeUserDataDirs(String uuid, int userId)258     public int removeUserDataDirs(String uuid, int userId) {
259         StringBuilder builder = new StringBuilder("rmuser");
260         builder.append(' ');
261         builder.append(escapeNull(uuid));
262         builder.append(' ');
263         builder.append(userId);
264         return mInstaller.execute(builder.toString());
265     }
266 
copyCompleteApp(String fromUuid, String toUuid, String packageName, String dataAppName, int appId, String seinfo)267     public int copyCompleteApp(String fromUuid, String toUuid, String packageName,
268             String dataAppName, int appId, String seinfo) {
269         StringBuilder builder = new StringBuilder("cpcompleteapp");
270         builder.append(' ');
271         builder.append(escapeNull(fromUuid));
272         builder.append(' ');
273         builder.append(escapeNull(toUuid));
274         builder.append(' ');
275         builder.append(packageName);
276         builder.append(' ');
277         builder.append(dataAppName);
278         builder.append(' ');
279         builder.append(appId);
280         builder.append(' ');
281         builder.append(seinfo);
282         return mInstaller.execute(builder.toString());
283     }
284 
285     @Deprecated
clearUserData(String name, int userId)286     public int clearUserData(String name, int userId) {
287         return clearUserData(null, name, userId);
288     }
289 
clearUserData(String uuid, String name, int userId)290     public int clearUserData(String uuid, String name, int userId) {
291         StringBuilder builder = new StringBuilder("rmuserdata");
292         builder.append(' ');
293         builder.append(escapeNull(uuid));
294         builder.append(' ');
295         builder.append(name);
296         builder.append(' ');
297         builder.append(userId);
298         return mInstaller.execute(builder.toString());
299     }
300 
markBootComplete(String instructionSet)301     public int markBootComplete(String instructionSet) {
302         if (!isValidInstructionSet(instructionSet)) {
303             Slog.e(TAG, "Invalid instruction set: " + instructionSet);
304             return -1;
305         }
306 
307         StringBuilder builder = new StringBuilder("markbootcomplete");
308         builder.append(' ');
309         builder.append(instructionSet);
310         return mInstaller.execute(builder.toString());
311     }
312 
313     @Deprecated
freeCache(long freeStorageSize)314     public int freeCache(long freeStorageSize) {
315         return freeCache(null, freeStorageSize);
316     }
317 
freeCache(String uuid, long freeStorageSize)318     public int freeCache(String uuid, long freeStorageSize) {
319         StringBuilder builder = new StringBuilder("freecache");
320         builder.append(' ');
321         builder.append(escapeNull(uuid));
322         builder.append(' ');
323         builder.append(String.valueOf(freeStorageSize));
324         return mInstaller.execute(builder.toString());
325     }
326 
327     @Deprecated
getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath, String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats)328     public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath,
329             String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) {
330         return getSizeInfo(null, pkgName, persona, apkPath, libDirPath, fwdLockApkPath, asecPath,
331                 instructionSets, pStats);
332     }
333 
getSizeInfo(String uuid, String pkgName, int persona, String apkPath, String libDirPath, String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats)334     public int getSizeInfo(String uuid, String pkgName, int persona, String apkPath,
335             String libDirPath, String fwdLockApkPath, String asecPath, String[] instructionSets,
336             PackageStats pStats) {
337         for (String instructionSet : instructionSets) {
338             if (!isValidInstructionSet(instructionSet)) {
339                 Slog.e(TAG, "Invalid instruction set: " + instructionSet);
340                 return -1;
341             }
342         }
343 
344         StringBuilder builder = new StringBuilder("getsize");
345         builder.append(' ');
346         builder.append(escapeNull(uuid));
347         builder.append(' ');
348         builder.append(pkgName);
349         builder.append(' ');
350         builder.append(persona);
351         builder.append(' ');
352         builder.append(apkPath);
353         builder.append(' ');
354         // TODO: Extend getSizeInfo to look at the full subdirectory tree,
355         // not just the first level.
356         builder.append(libDirPath != null ? libDirPath : "!");
357         builder.append(' ');
358         builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
359         builder.append(' ');
360         builder.append(asecPath != null ? asecPath : "!");
361         builder.append(' ');
362         // TODO: Extend getSizeInfo to look at *all* instrution sets, not
363         // just the primary.
364         builder.append(instructionSets[0]);
365 
366         String s = mInstaller.transact(builder.toString());
367         String res[] = s.split(" ");
368 
369         if ((res == null) || (res.length != 5)) {
370             return -1;
371         }
372         try {
373             pStats.codeSize = Long.parseLong(res[1]);
374             pStats.dataSize = Long.parseLong(res[2]);
375             pStats.cacheSize = Long.parseLong(res[3]);
376             pStats.externalCodeSize = Long.parseLong(res[4]);
377             return Integer.parseInt(res[0]);
378         } catch (NumberFormatException e) {
379             return -1;
380         }
381     }
382 
moveFiles()383     public int moveFiles() {
384         return mInstaller.execute("movefiles");
385     }
386 
387     @Deprecated
linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId)388     public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) {
389         return linkNativeLibraryDirectory(null, dataPath, nativeLibPath32, userId);
390     }
391 
392     /**
393      * Links the 32 bit native library directory in an application's data directory to the
394      * real location for backward compatibility. Note that no such symlink is created for
395      * 64 bit shared libraries.
396      *
397      * @return -1 on error
398      */
linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32, int userId)399     public int linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32,
400             int userId) {
401         if (dataPath == null) {
402             Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
403             return -1;
404         } else if (nativeLibPath32 == null) {
405             Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null");
406             return -1;
407         }
408 
409         StringBuilder builder = new StringBuilder("linklib");
410         builder.append(' ');
411         builder.append(escapeNull(uuid));
412         builder.append(' ');
413         builder.append(dataPath);
414         builder.append(' ');
415         builder.append(nativeLibPath32);
416         builder.append(' ');
417         builder.append(userId);
418 
419         return mInstaller.execute(builder.toString());
420     }
421 
422     @Deprecated
restoreconData(String pkgName, String seinfo, int uid)423     public boolean restoreconData(String pkgName, String seinfo, int uid) {
424         return restoreconData(null, pkgName, seinfo, uid);
425     }
426 
restoreconData(String uuid, String pkgName, String seinfo, int uid)427     public boolean restoreconData(String uuid, String pkgName, String seinfo, int uid) {
428         StringBuilder builder = new StringBuilder("restorecondata");
429         builder.append(' ');
430         builder.append(escapeNull(uuid));
431         builder.append(' ');
432         builder.append(pkgName);
433         builder.append(' ');
434         builder.append(seinfo != null ? seinfo : "!");
435         builder.append(' ');
436         builder.append(uid);
437         return (mInstaller.execute(builder.toString()) == 0);
438     }
439 
createOatDir(String oatDir, String dexInstructionSet)440     public int createOatDir(String oatDir, String dexInstructionSet) {
441         StringBuilder builder = new StringBuilder("createoatdir");
442         builder.append(' ');
443         builder.append(oatDir);
444         builder.append(' ');
445         builder.append(dexInstructionSet);
446         return mInstaller.execute(builder.toString());
447     }
448 
449 
linkFile(String relativePath, String fromBase, String toBase)450     public int linkFile(String relativePath, String fromBase, String toBase) {
451         StringBuilder builder = new StringBuilder("linkfile");
452         builder.append(' ');
453         builder.append(relativePath);
454         builder.append(' ');
455         builder.append(fromBase);
456         builder.append(' ');
457         builder.append(toBase);
458         return mInstaller.execute(builder.toString());
459     }
460 
461     /**
462      * Returns true iff. {@code instructionSet} is a valid instruction set.
463      */
isValidInstructionSet(String instructionSet)464     private static boolean isValidInstructionSet(String instructionSet) {
465         if (instructionSet == null) {
466             return false;
467         }
468 
469         for (String abi : Build.SUPPORTED_ABIS) {
470             if (instructionSet.equals(VMRuntime.getInstructionSet(abi))) {
471                 return true;
472             }
473         }
474 
475         return false;
476     }
477 }
478