blob: 31c604face0c63f2d79ff0c0bad9d7ee93706645 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm;
import android.content.Context;
import android.content.pm.PackageStats;
import android.os.Build;
import android.util.Slog;
import dalvik.system.VMRuntime;
import com.android.internal.os.InstallerConnection;
import com.android.server.SystemService;
public final class Installer extends SystemService {
private static final String TAG = "Installer";
private final InstallerConnection mInstaller;
public Installer(Context context) {
super(context);
mInstaller = new InstallerConnection();
}
@Override
public void onStart() {
Slog.i(TAG, "Waiting for installd to be ready.");
ping();
}
public int install(String name, int uid, int gid, String seinfo) {
StringBuilder builder = new StringBuilder("install");
builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(uid);
builder.append(' ');
builder.append(gid);
builder.append(' ');
builder.append(seinfo != null ? seinfo : "!");
return mInstaller.execute(builder.toString());
}
public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
String instructionSet) {
if (!isValidInstructionSet(instructionSet)) {
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
return -1;
}
return mInstaller.patchoat(apkPath, uid, isPublic, pkgName, instructionSet);
}
public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
if (!isValidInstructionSet(instructionSet)) {
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
return -1;
}
return mInstaller.patchoat(apkPath, uid, isPublic, instructionSet);
}
public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
if (!isValidInstructionSet(instructionSet)) {
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
return -1;
}
return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet);
}
public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
String instructionSet, boolean vmSafeMode) {
if (!isValidInstructionSet(instructionSet)) {
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
return -1;
}
return mInstaller.dexopt(apkPath, uid, isPublic, pkgName, instructionSet, vmSafeMode);
}
public int idmap(String targetApkPath, String overlayApkPath, int uid) {
StringBuilder builder = new StringBuilder("idmap");
builder.append(' ');
builder.append(targetApkPath);
builder.append(' ');
builder.append(overlayApkPath);
builder.append(' ');
builder.append(uid);
return mInstaller.execute(builder.toString());
}
public int movedex(String srcPath, String dstPath, String instructionSet) {
if (!isValidInstructionSet(instructionSet)) {
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
return -1;
}
StringBuilder builder = new StringBuilder("movedex");
builder.append(' ');
builder.append(srcPath);
builder.append(' ');
builder.append(dstPath);
builder.append(' ');
builder.append(instructionSet);
return mInstaller.execute(builder.toString());
}
public int rmdex(String codePath, String instructionSet) {
if (!isValidInstructionSet(instructionSet)) {
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
return -1;
}
StringBuilder builder = new StringBuilder("rmdex");
builder.append(' ');
builder.append(codePath);
builder.append(' ');
builder.append(instructionSet);
return mInstaller.execute(builder.toString());
}
public int remove(String name, int userId) {
StringBuilder builder = new StringBuilder("remove");
builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(userId);
return mInstaller.execute(builder.toString());
}
public int rename(String oldname, String newname) {
StringBuilder builder = new StringBuilder("rename");
builder.append(' ');
builder.append(oldname);
builder.append(' ');
builder.append(newname);
return mInstaller.execute(builder.toString());
}
public int fixUid(String name, int uid, int gid) {
StringBuilder builder = new StringBuilder("fixuid");
builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(uid);
builder.append(' ');
builder.append(gid);
return mInstaller.execute(builder.toString());
}
public int deleteCacheFiles(String name, int userId) {
StringBuilder builder = new StringBuilder("rmcache");
builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(userId);
return mInstaller.execute(builder.toString());
}
public int deleteCodeCacheFiles(String name, int userId) {
StringBuilder builder = new StringBuilder("rmcodecache");
builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(userId);
return mInstaller.execute(builder.toString());
}
public int createUserData(String name, int uid, int userId, String seinfo) {
StringBuilder builder = new StringBuilder("mkuserdata");
builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(uid);
builder.append(' ');
builder.append(userId);
builder.append(' ');
builder.append(seinfo != null ? seinfo : "!");
return mInstaller.execute(builder.toString());
}
public int createUserConfig(int userId) {
StringBuilder builder = new StringBuilder("mkuserconfig");
builder.append(' ');
builder.append(userId);
return mInstaller.execute(builder.toString());
}
public int removeUserDataDirs(int userId) {
StringBuilder builder = new StringBuilder("rmuser");
builder.append(' ');
builder.append(userId);
return mInstaller.execute(builder.toString());
}
public int clearUserData(String name, int userId) {
StringBuilder builder = new StringBuilder("rmuserdata");
builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(userId);
return mInstaller.execute(builder.toString());
}
public int markBootComplete(String instructionSet) {
if (!isValidInstructionSet(instructionSet)) {
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
return -1;
}
StringBuilder builder = new StringBuilder("markbootcomplete");
builder.append(' ');
builder.append(instructionSet);
return mInstaller.execute(builder.toString());
}
public boolean ping() {
if (mInstaller.execute("ping") < 0) {
return false;
} else {
return true;
}
}
public int freeCache(long freeStorageSize) {
StringBuilder builder = new StringBuilder("freecache");
builder.append(' ');
builder.append(String.valueOf(freeStorageSize));
return mInstaller.execute(builder.toString());
}
public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath,
String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) {
for (String instructionSet : instructionSets) {
if (!isValidInstructionSet(instructionSet)) {
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
return -1;
}
}
StringBuilder builder = new StringBuilder("getsize");
builder.append(' ');
builder.append(pkgName);
builder.append(' ');
builder.append(persona);
builder.append(' ');
builder.append(apkPath);
builder.append(' ');
// TODO: Extend getSizeInfo to look at the full subdirectory tree,
// not just the first level.
builder.append(libDirPath != null ? libDirPath : "!");
builder.append(' ');
builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
builder.append(' ');
builder.append(asecPath != null ? asecPath : "!");
builder.append(' ');
// TODO: Extend getSizeInfo to look at *all* instrution sets, not
// just the primary.
builder.append(instructionSets[0]);
String s = mInstaller.transact(builder.toString());
String res[] = s.split(" ");
if ((res == null) || (res.length != 5)) {
return -1;
}
try {
pStats.codeSize = Long.parseLong(res[1]);
pStats.dataSize = Long.parseLong(res[2]);
pStats.cacheSize = Long.parseLong(res[3]);
pStats.externalCodeSize = Long.parseLong(res[4]);
return Integer.parseInt(res[0]);
} catch (NumberFormatException e) {
return -1;
}
}
public int moveFiles() {
return mInstaller.execute("movefiles");
}
/**
* Links the 32 bit native library directory in an application's data directory to the
* real location for backward compatibility. Note that no such symlink is created for
* 64 bit shared libraries.
*
* @return -1 on error
*/
public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) {
if (dataPath == null) {
Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
return -1;
} else if (nativeLibPath32 == null) {
Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null");
return -1;
}
StringBuilder builder = new StringBuilder("linklib ");
builder.append(dataPath);
builder.append(' ');
builder.append(nativeLibPath32);
builder.append(' ');
builder.append(userId);
return mInstaller.execute(builder.toString());
}
public boolean restoreconData(String pkgName, String seinfo, int uid) {
StringBuilder builder = new StringBuilder("restorecondata");
builder.append(' ');
builder.append(pkgName);
builder.append(' ');
builder.append(seinfo != null ? seinfo : "!");
builder.append(' ');
builder.append(uid);
return (mInstaller.execute(builder.toString()) == 0);
}
/**
* Returns true iff. {@code instructionSet} is a valid instruction set.
*/
private static boolean isValidInstructionSet(String instructionSet) {
if (instructionSet == null) {
return false;
}
for (String abi : Build.SUPPORTED_ABIS) {
if (instructionSet.equals(VMRuntime.getInstructionSet(abi))) {
return true;
}
}
return false;
}
}