首页 > 其他分享 >android 自定义权限问题

android 自定义权限问题

时间:2023-07-31 22:06:17浏览次数:44  
标签:java String 自定义 16 app android 权限 DownloadProvider


读懂Android (1):使用Android内部的DownloadProvider下载文件,并获取cache权限   -- 未审核


   收藏
Android 内部提供了一个DownloadProvider,是一个非常完整的下载工具,提供了很好的外部接口可以被其他应用程序 调用,来完成下载工作。同时也提供和很好的下载、通知、存储等机制。
在Android的Browser等工具里面都用到了这个DownloadProvider。

但是很遗憾的是,这个DownloadProvider不对app开发人员开放,只作为内部使用。

我们现在去探究如何将DownloadProvider拿来给自己用。

让我们先找到DownloadProvider不能用的原因:
先找到它的源代码,在这个位置:/packages/providers/DownloadProvider
打开AndroidManifest.xml文件,里面有几个自定义的权限

<!-- Allows access to the Download Manager -->
     <permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"
         android:label="@string/permlab_downloadManager"
         android:description="@string/permdesc_downloadManager"
         android:protectionLevel="signatureOrSystem" />    <!-- Allows advanced access to the Download Manager -->
     <permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED"
         android:label="@string/permlab_downloadManagerAdvanced"
         android:description="@string/permdesc_downloadManagerAdvanced"
         android:protectionLevel="signatureOrSystem" />    <!-- Allows filesystem access to /cache -->
     <permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
         android:label="@string/permlab_cacheFilesystem"
         android:description="@string/permdesc_cacheFilesystem"
         android:protectionLevel="signature" />    <!-- Allows to send download completed intents -->
     <permission android:name="android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS"
         android:label="@string/permlab_downloadCompletedIntent"
         android:description="@string/permdesc_downloadCompletedIntent"
         android:protectionLevel="signature" />

这 几个权限里面都是android:protectionLevel="signatureOrSystem" 或者   android:protectionLevel="signature", 这个意思是只有你的app拥有system权限,或者和系统一样的签名,才能调用它。

这里是问题的关键。那我们有两种思路:
一种思路是:将这个protectionLevel改成normal,重新编译DownloadProvider工程,让其他app可以直接调用。
另一种思路是:将你自己的app弄成system权限或者和系统一样的签名。

前一种思路已经完全成功了,第二种思路验证了一部分。

先看第一种思路的办法:
1)先将上面几个权限都改成:android:protectionLevel="normal"
2)重新编译DownloadProvider
   mmm packages/providers/DownloadProvider
3) 将编译后的apk替换现有的apk
   因为DownloadProvider.apk是系统app,你可以先给/system以root权限,然后将这个app替换掉。 (作为一个用户app安装也可以,不过重启以后就没有了)
   使用类似 # mount -t ubifs -o remount ubi0:system /system   或者  # mount -o remount ubi0:system /system  给/system rw权限。
   然后通过adb push 将DownloadProvider.apk push到 /system/app/下。系统会自动替换这个app。

4)写一个工程来使用DownloadProvider.
   直接贴源码了:

DownloadActivity.Java 
 package com.xxxx.usedownload;
  
 import java.io.FileNotFoundException;
 import java.NET .URI;import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Bundle;
 import android.webkit.URLUtil; /**
  * @author lixinso
  * 使用DownloadProvider
  */
 public class DownloadActivity extends Activity {
      @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);
         
         //String url = "http://192.168.200.76:8080/webserver/dancing-skeleton.3gp ";
         String contentDisposition = "attachment; filename=/"dancing-skeleton.3gp/"";
         String mimetype = "video/3GPP ";
         
         String filename = URLUtil.guessFileName(url,contentDisposition, mimetype);
         
         URI uri = null;
          
         try {
             // Undo the percent-encoding that KURL may have done.
             String newUrl = new String(URLUtil.decode(url.getBytes()));
             // Parse the url into pieces
             WebAddress w = new WebAddress(newUrl);
             String frag = null;
             String query = null;
             String path = w.mPath;
             // Break the path into path, query, and fragment
             if (path.length() > 0) {
                 // Strip the fragment
                 int idx = path.lastIndexOf('#');
                 if (idx != -1) {
                     frag = path.substring(idx + 1);
                     path = path.substring(0, idx);
                 }
                 idx = path.lastIndexOf('?');
                 if (idx != -1) {
                     query = path.substring(idx + 1);
                     path = path.substring(0, idx);
                 }
             }
             uri = new URI(w.mScheme, w.mAuthInfo, w.mHost, w.mPort, path,
                     query, frag);
         } catch (Exception e) {
             //Log.e(LOGTAG, "Could not parse url for download: " + url, e);
             return;
         }
         
         ContentValues values = new ContentValues();
         values.put("uri", uri.toString());
         values.put("useragent", "Mozilla/5.0 (linux ; U; Android 1.5; en-us; SDK Build/CUPCAKE) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari /525.20.1");
         values.put("notificationpackage", getPackageName());
         values.put("notificationclass", "HelloWorld");
         values.put("visibility", 1);
         values.put("mimetype", mimetype);
         values.put("hint", filename);
         values.put("description", uri.getHost());
         values.put("total_bytes", 1349528);
         values.put("destination", 1);
         
         
          
         //这些参数参考:DownloadProvider工程中的:Helpers.java
         //public static DownloadFileInfo generateSaveFile(
         //        Context context,
         //      String url,
         //        String hint,
         //        String contentDisposition,
         //        String contentLocation,
         //        String mimeType,
         //        int destination,
         //        int contentLength) throws FileNotFoundException {
         //以及:  framework里的Downloads.java;
         
         
         ContentResolver mResolver = getContentResolver();
         mResolver.insert(Uri.parse("content://downloads/download"), values);
         
     }
 }AndroidManifest.xml
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android "
       package="com.xxxx.usedownload"
       android:versionCode="1"
       android:versionName="1.0">
     <application android:icon="@drawable/icon" android:label="@string/app_name">
         <activity android:name=".DownloadActivity"
                   android:label="@string/app_name">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
  
     </application>
     <uses-sdk android:minSdkVersion="7" />
     
     <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
     <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER" />
     <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED" />
     <uses-permission android:name="android.permission.ACCESS_DRM" />
      <uses-permission android:name="android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.INSTALL_DRM" />
     
 </manifest>

代码里面引用了ParseException和WebAddress两个类,可以从Android源代码里找到copy进来,在这里frameworks/base/core/java/android/net。

代码里面有几个地方比较重要的:
a) 通过往DownloadProvider提供的ContentProvider “content://downloads/download” 中插入数据就能触发DownloadProvider的执行。
b) values.put("destination", 1); 是下载文件存储在什么地方, 如果没有这个参数,默认保存在sdcard的download 下面 (Constants.java 中的 DEFAULT_DL_SUBDIR = "/download" )
   如果指定为1,是往内存的 /cache目录下存东西 (在/frameworks/base/core/java/android/provider/Downloads.java中定义, public static final int DESTINATION_CACHE_PARTITION = 1; )
b) 注意Manifest中的一堆权限: ACCESS_DOWNLOAD_MANAGER是最基本的权限,这样可以使用DownloadProvider下载。
   如果需要destination=1,则需要 ACCESS_DOWNLOAD_MANAGER权限。(Downloads.java中的注释 : All file types are allowed, and only the initiating
     application can access the file (indirectly through a content provider). This requires the android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED permission.)

如果没有这个权限,在往 content://downloads/download插入的时候有权限问题报错:
09-16 17:16:38.062: ERROR/DatabaseUtils(763): Writing exception to parcel
09-16 17:16:38.062: ERROR/DatabaseUtils(763): java.lang.SecurityException: unauthorized destination code
09-16 17:16:38.062: ERROR/DatabaseUtils(763):     at com.android.providers.downloads.DownloadProvider.insert(DownloadProvider.java:277)
09-16 17:16:38.062: ERROR/DatabaseUtils(763):     at android.content.ContentProvider$Transport.insert(ContentProvider.java:150)
09-16 17:16:38.062: ERROR/DatabaseUtils(763):     at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:140)
09-16 17:16:38.062: ERROR/DatabaseUtils(763):     at android.os.Binder.execTransact(Binder.java:287)
09-16 17:16:38.062: ERROR/DatabaseUtils(763):     at dalvik.system.NativeStart.run(Native Method)
09-16 17:16:38.102: DEBUG/AndroidRuntime(4086): Shutting down VM

因为DownloadProvider.java中有这段代码:
        if (dest != null) {
            if (getContext().checkCallingPermission(Downloads.PERMISSION_ACCESS_ADVANCED)
                    != PackageManager.PERMISSION_GRANTED
                    && dest != Downloads.DESTINATION_EXTERNAL
                    && dest != Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE) {
                throw new SecurityException("unauthorized destination code");
            }
所以:要往/cache目录下存东西,一定要记得这个权限哦。

实际运行起来,只加这个权限往/cache下存东西还不够,就又把其他一堆权限都加上了,具体哪些有用还没细看。

5) 将这个app直接以普通app安装上去,运行,可以看到下载成功到/cache里了。

第二种思路就是想办法获得system权限或者签名:
这样不修改DownloadProvider的代码,不动它。
而 是将自己编写的app做完以后放到/packages/app目录下和整个系统一起编译,将其编译到img中的系统app下 这样编译完成以后运行,使用编译的img运行模拟器。在模拟器中启动自己写的调用DownloadProvider的app,发现竟然也是可以调用的。
不过这种方法在模拟器上成功了,但是在真机上没成功,可能还有些问题没解决。第一种方法是完全成功的。


标签:java,String,自定义,16,app,android,权限,DownloadProvider
From: https://blog.51cto.com/u_3124497/6913724

相关文章

  • Android开发精华教程
    [下载]GoogleAndroid开发精华教程Android是Google于2007年11月5日宣布的基于Linux平台的开源手机操作系统的名称,该平台由操作系统、中间件、用户界面和应用软件组成,号称是首个为移动终端打造的真正开放和完整的移动软件。本文汇总整理了时下关于GoogleAndroid技术教程的下载......
  • android listView控件学习之一
    androidlistView控件学习之一1.基本应用:1>res/layout/main.xml<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"......
  • android程序调用另一个android应用…
    android程序调用另一个android应用程序请求:例子:    newComponentName("com.gwsoft.player.activity","com.gwsoft.player.activity.PlayerActivity");newIntent();newBundle();"resUrl",resurl);......
  • android画图-----shape的使用文档…
    在GradientDrawable1试图中终于把shape学会了,以前总是似懂非懂,现在终于把里面的东西搞清楚了,同时也挺佩服谷歌的用心,故意设置一些陷阱吧,不认真对待还真以为没有啥效果呢。setContentView(R.layout.shape_drawable_1)shape_drawable_1代码如下:<ScrollViewxmlns:android="htt......
  • 自定义Android组件之带图像的TextV…
    本文为新书《Android/OPhone开发完全讲义》的内容连载。《Android/OPhone开发完全讲义》一书将在近期出版,敬请关注。 Android系统支持的图像格式)的TextView组件。在编写代码之前,先看一下Android组件的配置代码。1.<TextViewandroid:id="@+id/textview1"android:layout_width......
  • Android permission 访问权限大全
    Androidpermission访问权限大全AndroidAndroidpermission0Commentsandroidmanifest.xml中声明相关权限请求,完整列表如下:android.permission.ACCESS_CHECKIN_PROPERTIES允许读写访问”properties”表在checkin数据库中,改值可以修改上传(Allowsread/writeaccess......
  • android学习之TransitionDrawable …
    Drawable的例子,体现出Drawable的强大功能。AndroidSDK中说明了Drawable主要的作用是:在XML中定义各种动画,然后把XML当作Drawable资源来读取,通过Drawable显示动画。下面举个使用TransitionDrawable的例子,创建一个Android工程,然后再这个工程的基础上修改,修改过程如下:1、去掉layout......
  • android 弹出对话框之 AlertDialog
    1.在测试时,如何实现一个提示可以使用Toast.makeText(this,"这是一个提示",Toast.LENGTH_SHORT).show();//从资源文件string.xml里面取提示信息Toast.makeText(this,getString(R.string.welcome),Toast.LENGTH_SHORT).show();这个提示会几秒钟后消失2.可以使用AlertD......
  • android 单元测试之 JUnit
    android里面做单元测试第一,JUnit。     实用范围:     东西,比如业务逻辑,数据封装,数值计算等等。并不能测试androidapi。第二,采用Instrumentation.Android单元测试的主入口是InstrumentationTestRunner。它相当于JUnit当中TestRunner的作用。你可以将Instrumentat......
  • 配置samba-解决samba没有写权限的问题
    其他配置过程不重复写了,用户名添加好后,添加如下配置到/etc/samba/smb.conf可解决没有写权限的问题[usr_name]path=/home/usr_nameavailable=yesvalidusers=usr_namewriteable=yesguestok=yesbrowseable=yescreatemask=0664directorymask=......