gpt4 book ai didi

android - 从 Android 中的 shell 命令安装/卸载

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:07:06 26 4
gpt4 key购买 nike

我想在 Android 中实现一个静默的 installer-from-apk-file 和 unistaller-package。该主题已在 SO 和其他地方进行了广泛讨论,但由于某些我遗漏的原因,我无法应用任何主题。这个范围显然很难实现,因为如果成功的话,这将是 Android 中的严重安全漏洞。但是,我需要为一个特殊项目实现它,而不是为消费者市场。有两种方法:

  1. 通过调整 PackageManager 安装程序(实际上只是为了删除用户接受对话框),从源代码(例如 AOSP 或 Cyanogen mod)生成自定义 ROM。
  2. 通过以 super 用户身份创建进程并执行“adb shell pm install”以编程方式完成此操作。我之前在/system/xbin 中安装了“su”,并在运行时测试了 RootTools.rootIsAvailable()。

对于第一种情况,我深入研究了 Froyo 的源代码,但使用 @hide 标记的方法进入了死胡同。第二次,我首先尝试了来自终端的命令

adb shell pm install /mnt/sdcard/HelloAndroid.apk

adb shell pm uninstall com.example.helloandroid

两者都工作正常。然后,我使用了以下代码,该开发正在 root 模拟器 (2.2 - Froyo) 上进行测试:

@Override
public void onClick(View v) {
switch (v.getId())
{
case R.id.btnInstall:
try {
install = Runtime.getRuntime().exec("su\n");
DataOutputStream os = new DataOutputStream(install.getOutputStream());
os.writeBytes("pm install /mnt/sdcard/HelloAndroid.apk\n");
os.writeBytes("exit\n");
os.flush();
install.waitFor();

if (install.exitValue() == 0) {
Toast.makeText(MainActivity.this, "Success!", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(MainActivity.this, "Failure. Exit code: "+String.valueOf(install.exitValue()), Toast.LENGTH_LONG).show();
}
}
catch (InterruptedException e) {
logError(e);
}
catch (IOException e) {
logError(e);
}
break;

case R.id.btnUninstall:
try {
install = Runtime.getRuntime().exec("su\n");
install=Runtime.getRuntime().exec("pm uninstall "+txtPackageName.getText().toString()+"\n");

} catch (Exception e) {
logError(e);
}
break;
}

}

为了避免拼写错误和其他修饰,我硬编码了安装命令的 apk 文件参数;在 'case R.id.btnInstall' 上,命令未执行,退出为“失败”,退出值为 1,表示“找不到该类”;不知道那是什么意思...我感谢您的帮助!

编辑:我有干净的解决方案,我会在有时间和正确形式的代码后尽快发布 A-Z 的答案!!

最佳答案

正如我在这里 promise 的那样,这是解决此问题的方法,除了必须将整个应用程序安装在/system/app 目录中之外,无需对系统进行任何强制操作。我已经关注,然后对此处的优秀文章进行了一些修复:http://paulononaka.wordpress.com/2011/07/02/how-to-install-a-application-in-background-on-android/ .我已经下载了文章中引用的 zip 文件,(我尽量保持相同的类名):

  1. 创建了一个新项目和一个主要 Activity 作为切入点

package com.example.silentinstuninst;

import java.io.File;
import java.lang.reflect.InvocationTargetException;

import com.example.instuninsthelper.ApplicationManager;
import com.example.instuninsthelper.OnDeletedPackage;
import com.example.instuninsthelper.OnInstalledPackage;

import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener {

Process install;
Button btnInstall, btnUninstall;
EditText txtApkFileName, txtPackageName;

public static final String TAG = "SilentInstall/Uninstall";

private static ApplicationManager am;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

initializeValues();

}

private void initializeValues() {

btnInstall = (Button) findViewById(R.id.btnInstall);
btnUninstall = (Button) findViewById(R.id.btnUninstall);
txtApkFileName = (EditText) findViewById(R.id.txtApkFilePath);
txtPackageName = (EditText) findViewById(R.id.txtPackageName);

btnInstall.setOnClickListener(this);
btnUninstall.setOnClickListener(this);

try {
am = new ApplicationManager(this);
am.setOnInstalledPackage(new OnInstalledPackage() {

public void packageInstalled(String packageName, int returnCode) {
if (returnCode == ApplicationManager.INSTALL_SUCCEEDED) {
Log.d(TAG, "Install succeeded");
} else {
Log.d(TAG, "Install failed: " + returnCode);
}
}
});

am.setOnDeletedPackage(new OnDeletedPackage() {
public void packageDeleted(boolean succeeded) {
Log.d(TAG, "Uninstall succeeded");
}
});

} catch (Exception e) {
logError(e);
}
}

private void logError(Exception e) {
e.printStackTrace();
Toast.makeText(this, R.string.error+e.getMessage(), Toast.LENGTH_LONG).show();
}

@Override
public void onClick(View v) {
switch (v.getId())
{
case R.id.btnInstall:
// InstallUninstall.Install(txtApkFileName.getText().toString());
try {
am.installPackage(Environment.getExternalStorageDirectory() +
File.separator + txtApkFileName.getText().toString());
} catch (IllegalArgumentException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalAccessException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (InvocationTargetException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} // install package
break;

case R.id.btnUninstall:
// InstallUninstall.Uninstall(txtPackageName.getText().toString());
try {
am.uninstallPackage(txtPackageName.getText().toString());
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logError(e);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logError(e);
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logError(e);
}
break;
}
}
}
  1. 在/src 中创建包 com.example.instunsthelper。我在那里添加了 ApplicationManager.java 和 OnInstalledPackage.java 文件
  2. 在 ApplicationManager 类中插入以下代码:

private OnDeletedPackage onDeletedPackage;
class PackageDeleteObserver extends IPackageDeleteObserver.Stub {

public void packageDeleted(boolean succeeded) throws RemoteException {
if (onDeletedPackage != null) {
onDeletedPackage.packageDeleted(succeeded);
}
}

}
  1. 创建,在相同的 com.example.instunsthelper 下使用以下代码打包文件 OnDeletedPackage.java:

package com.example.instuninsthelper;
public interface OnDeletedPackage {
public void packageDeleted(boolean succeeded);
}
  1. 在 android.content.pm 包中(命名空间不应更改)我修改了 IPackageDeleteObserver.java,结果如下:

package android.content.pm;

public interface IPackageDeleteObserver extends android.os.IInterface {

public abstract static class Stub extends android.os.Binder implements android.content.pm.IPackageDeleteObserver {
public Stub() {
throw new RuntimeException("Stub!");
}

public static android.content.pm.IPackageDeleteObserver asInterface(android.os.IBinder obj) {
throw new RuntimeException("Stub!");
}

public android.os.IBinder asBinder() {
throw new RuntimeException("Stub!");
}

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException {
throw new RuntimeException("Stub!");
}
}

public abstract void packageDeleted(boolean succeeded)
throws android.os.RemoteException;
}
  1. 在 Eclipse 中构建应用程序并将其部署到模拟器
  2. 在模拟器中:home button > Settings > applications > ...uninstall the application(因为它没有安装在/system/app,我们只需要生成apk文件)
  3. 执行以下操作来启动模拟器(以便我们可以写入/system/app;我使用的其他解决方案是生成一个自定义 ROM,并将此应用程序包含在/system/app 中):
  4. 从控制台转到项目的/bin 目录,然后输入: * adb push .apk/system/app
  5. 最后,始终从控制台输入: * adb shell am start -n com.example.silentinstuninst/com.example.silentinstuninst.MainActivity
  6. 享受吧!

关于android - 从 Android 中的 shell 命令安装/卸载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14871570/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com