皮皮网

【知道部分源码】【canoe源码】【源码解答】LocationManager源码

2024-11-23 12:37:46 来源:分红记录网站源码

1.如何利用Android编程实现GPS定位
2.Android Binder Hook的实现
3.如何更改安卓手机GPS位置? - 知乎
4.Android中如何解决侧拉栏与主界面的重叠

LocationManager源码

如何利用Android编程实现GPS定位

       æ‚¨å¥½ï¼Œå¾ˆé«˜å…´ä¸ºæ‚¨è§£ç­”。

       ä¸€ã€å‡†å¤‡å·¥ä½œ

       éœ€è¦å¦‚下三种软件:

       1. Eclipse

       2. Android SDK

       3. 开发Android程序的Eclipse 插件

       ä¸ºäº†å¼€å§‹æˆ‘们的工作,首先要安装Eclipse,然后从Google的网站获得Android SDK,并且安装Eclipse插件。

       äºŒã€Activityç±»

       æ¯ä¸€ç§ç§»åŠ¨å¼€å‘环境都有自己的基类。如J2ME应用程序的基类是midlets,BREW的基类是applets,而Android程序的基类是 Activity。这个activity为我们提供了对移动操作系统的基本功能和事件的访问。这个类包含了基本的构造方法,键盘处理,挂起来恢复功能,以 及其他底层的手持设备的访问。实质上,我们的应用程序将是一个Activity类的扩展。在本文中读者将会通过例子学习到如何使用Activity类来编 写Android程序。下面是一个简单的继承Activity的例子。

public class LocateMe extends Activity{   

       public void onCreate(Bundle params){         

              super.onCreate(params);        

              setContentView(R.layout.main);       

             }  

       public boolean onKeyDown(int keyCode, KeyEvent event){           

               return true;            

                 }    

         }

       ä¸‰ Viewç±»

       View类是Android的一个超类,这个类几乎包含了所有的屏幕类型。但它们之间有一些不同。每一个view都有一个用于绘画的画布。这个画布可以用 来进行任意扩展。本文为了方便起见,只涉及到了两个主要的View类型:定义View和Android的XML内容View。在上面的代码中,使用的是 “Hello World” XML View,它是以非常自然的方式开始的。

       å¦‚果我们查看一下新的Android工程,就会发现一个叫main.xml的文件。在这个文件中,通过一个简单的XML文件,描述了一个屏幕的布局。这个 简单的xml文件的内容如下:

<?xml version="1.0" encoding="utf-8"?> 

       <RelativeLayout xmlns:android="/apk/res/android" 

       androidrientation="vertical" 

       android:layout_width="fill_parent" 

       android:layout_height="fill_parent" 

       > 

       <TextView 

       android:layout_width="fill_parent" 

       android:layout_height="wrap_content" 

       android:layout_centerHoriz  

       android:text="ress the center key to locate yourself" 

       /> 

       </RelativeLayout>

       ä¸Šé¢çš„内容的功能看起来非常明显。这个特殊文件定义了一个相关的布局,这就意味着通过一个元素到另一个元素的关系或是它们父元素的关系来描述。对于视图来 说,有一些用于布局的方法,但是在本文中只关注于上述的xml文件。

       RealtiveLayout中包含了一个填充整个屏幕的文本框(也就是我们的LocateMe activity)。这个LocateMe activity在默认情况下是全屏的,因此,文本框将继承这个属性,并且文本框将在屏幕的左上角显示。另外,必须为这个XML文件设置一个引用数,以便 Android可以在源代码中找到它。在默认情况下,这些引用数被保存在R.java中,代码如下:

public final class R{   

       public static final class layout{   

       public static final int main=0x7f;     

           }  

        }

       è§†å›¾ä¹Ÿå¯ä»¥è¢«åµŒå¥—,但和J2ME不同,我们可以将定制的视图和Android团队发布的Widgets一起使用。在J2ME中,开发人员被迫选择 GameCanvas和J2ME应用程序画布。这就意味着如果我们想要一个定制的效果,就必须在GameCanvas上重新设计我们所有的widget。 Android还不仅仅是这些,视图类型也可以混合使用。Android还带了一个 widget库,这个类库包括了滚动条,文本实体,进度条以及其他很多控件。这些标准的widget可以被重载或被按着我们的习惯定制。现在让我们来进入 我们的例子。 

       å››ã€Android实例

       è¿™ä¸ªæ¼”示应用程序将演示了用户的当前的经度和纬度(在文本框中显示)。onCreate构造方法将和上面的例子基本相同,除了在其中加入了键盘处理,现在 让我们看一下onKeyDown的代码。

public boolean onKeyDown(int keyCode, KeyEvent event){   

       if(keyCode != KeyEvent.KEYCODE_DPAD_CENTER || m_bLoading)  

       {   

       return true;  

       }  

       m_bLoading = true;  

       getLocation();  

       return true;  

       }

       ä¸‹é¢è®©æˆ‘们来解释一下这段代码,首先,这段代码检查了当前被按下的键,但还没有开始处理。而是在getLocation方法中处理这一切的。然后,将装载 flag标志以及调用getLocation方法,下面是getLocation方法的代码。

private void getLocation(){   

       Location loc;  

       LocationManager locMan;  

       LocationProvider locPro;  

       List<LocationProvider> proList;  

       setContentView(R.layout.laoding);  

       locMan = (LocationManager) getSystemService(LOCATION_SERVICE);  

       proList = locMan.getProviders();  

       locPro = proList.get(0);  

       loc = locMan.getCurrentLocation(locPro.getName());  

       Lat = (float)loc.getLatitude();  

       Lon = (float)loc.getLongitude();  

       CreateView();  

       setContentView(customView);  

       }

       åˆ°è¿™ä¸ºæ­¢ï¼Œç¨‹åºå¼€å§‹å˜å¾—更有趣了。但是不幸的是,Google关于之方面的文档还是比较少了。在程序的变量声明之后,我们需要演示一些装载信息。 R.layout.loading符合了另一个简单的XML布局视图。通过简单地调用setContentView方法可以使用转载信息重绘屏幕。

       è¯»è€…要注意的是:在编译时,Android会预先将所有的XML布局数据包装起来。如果我们想在编译后变化布局属性,按着规定,我们必须在源程序中做这些 事。

       èŽ·å¾—LocationManager的唯一方法是通过getSystemService()方法的调用。通过使用LocationManager, 我们可以获得一个位置提供者的列表。在一个真实的手持设备中,这个列表包含了一些GPS服务。实际上,我们希望选择更强大,更精确,最后不带有其他附加服 务的GPS。现在,在模拟器中提供了一个用于测试的GPS,这个GPS来自San Francisco。定制的GPS文件可以可以被上传,并进行测试。如果我们要测试更复杂的应用,来自San Francisco的GPS可能并不适合。

       ç›®å‰æˆ‘们可以使用位置管理器和位置提供者进行getCurrentLocation的调用。这个方法返回本机的当前位置的一个快照,这个快照将以 Location对象形式提供。在手持设备中,我们可以获得当前位置的经度和纬度。现在,使用这个虚拟的手持设备,我们可以获得这个例子程序的最终结果: 建立了显示一个定制的视图。

       äº”、使用定制视图

       åœ¨æœ€ç®€å•çš„窗体中,一个Android中的视图仅仅需要重载一个onDraw方法。定制视图可以是复杂的3D实现或是非常简单的文本形式。下面的 CreateView方法列出了上面看到的内容。

public void CreateView(){   

       customView = new CustomView(this);  

       }

       è¿™ä¸ªæ–¹æ³•ç®€å•åœ°è°ƒç”¨äº†CustomView对象的构造方法。CustomView类的定义如下:

public class CustomView extends View{        

          LocateMe overlord;  

       public CustomView(LocateMe pCtx){        

          super(pCtx);       

          overlord = pCtx;  

       }  

         public void onDraw(Canvas cvs){      

         Paint p = new Paint();     

         String sLat = "Latitude: " + overlord.getLat();     

         String sLon = "Longitude: " + overlord.getLon();     

         cvs.drawText(sLat , , , p);     

         cvs.drawText(sLon, , , p);  

       }  

       }

       è¿™ä¸ªå®šåˆ¶çš„Android视图获得了经度和违度的测试数据,并将这些数据显示在屏幕上。这要求一个指向LocateMe的指针,Activity类是整 个应用程序的核心。它的两个方法是构造方法和onDraw方法。这个构造方法调用了超类的构造方法以及引起了Activity指针的中断。onDraw方 法将建立一个新的Paint对象(这个对象封装了颜色、透明度以及其他的主题信息),这个对象将会访问颜色主题。在本程序中,安装了用于显示的字符串,并 使用画布指针将它们画到屏幕上。这个和我们了解的J2ME游戏的画布看起来非常类似。

       å…­ã€Android展望

       ä»Žçº¯ç²¹çš„开发观点看,Android是一个非常强大的SDK。它使用基于XML的布局和定制视图联合了起来。并可以使用滚动条、地图以及其他的组件。所以 的这一切都可以被重载,或由开发人员来定制。但它所提供的文档非常粗糙。在文档中并没有象SMS等技术,但是从整体上来看Android SDK,还是非常有希望的。也非常符合Google承诺的“First Look”SDK。现在我们要做的就是等待Google发布第一个基于Android的手机,并使用它。

       å¦‚若满意,请点击右侧【采纳答案】,如若还有问题,请点击【追问】

       å¸Œæœ›æˆ‘的回答对您有所帮助,望采纳!

                                                                                                                                    ~ O(∩_∩)O~

Android Binder Hook的实现

        Binder Hook 可以 Hook 掉当前进程用到的系统 Service 服务。

        以 LocationManager 为例,在获取一个 LocationManager 时分为两步:

        (1) 获取 IBinder 对象;

        (2) 通过 IBinder 的 asInterface() 方法转化为 LocationMangerService 对象,接着初始化 LocationManager 。

        application 层用到的都是 LocationManager 对象。

        原理:

        整个过程需要利用反射设置一个自定义的 Binder 对象和一个自定义的 Service 对象。由于我们只 Hook 其中一部分的功能,其他功能还需要保留,所以要用动态代理的方式创建自定义对象。

        在理解后面的内容前你需要了解这些知识点:

        Activity 等类在获取系统 Service 时,都是调用 getSystemService(serviceName) 方法获取的。

        Context # getSystemService() 方法最终会调用到 ServiceManager # getService() 方法中。以 LocationManager 对应的 ServiceFetcher 为例,它的 createService() 方法源码如下:

        假如我们要 Hook 掉 LocationManager # getLastKnownLocation() 方法(下文都是)。我们要做的就是让

        ServiceManager.getService(Context.LOCATION_SERVICE) 返回我们自定义的 Binder 对象。

        先看一下这个方法的源码:

        sCache 是一个 Map,缓存了已经向系统请求过的 Binder。如果需要让这个方法返回我们自己的 binder 对象,只需要事先往 sCache 中 put 一个自定义的 Binder 对象就行了。

        在 put 之前,需要先创建出一个自定义的 Binder。这个 Binder 在被 ILocationManager.Stub.asInterface 处理后,可以返回一个自定义的 LocationManagerService 对象。

        先看一下 Binder 的 asInterface() 的实现:

        如果把 queryLocalInterface()方法返回一个自定义的Service,使得走 if 语句内部,不走 else,那就算是Hook 成功了。

        假设我们想让系统的 LocationManager 返回的位置信息全是在天安门(., .)。那我们需要使得 LocatitionManagerService 的 getLastLocation() 方法 返回的全是 (., .)。

        由于我们不能直接拿到系统的这个Service对象,可以先用反射的方式拿到系统的LocationManagerService。然后拦截 getLastLocation() 方法。

        原生的Binder对象在调用 queryLocalInterface() 方法时会返回原生的Service对象。我们希望返回3.1中的自定义Service。所以这里拦截 queryLocalInterface() 方法。

        有了自定义的 Binder 后,将它注入到 ServiceManger 的 sCache 变量中就完成 Hook 了~

        当onClick被调用的时候,Toast和Log都会显示天安门的坐标(., .)。证明Hook成功!

        你甚至可以用Binder Hook的方式Hook掉 ActivityManager。

如何更改安卓手机GPS位置? - 知乎

       修改安卓手机GPS位置的方法多种多样,包括Xposed隐藏、使用MockLocation、或者直接修改源码。每种方式各有优势与劣势。Xposed隐藏虽然简便但容易被察觉,知道部分源码MockLocation易于识别,而修改源码则费时且局限性较强。为了深入探索GPS定位机制,我们选择阅读并修改Android系统源码。

       修改GPS的关键在于切断硬件模块与系统框架之间的通讯,通过模仿硬件向框架发送位置信息。canoe源码这一过程主要通过GnssCallback实现。GnssCallback在GPS信息变化后通知上层应用,例如位置、状态或精度变化。在系统框架中,GPS硬件模块在获取新位置时会调用java函数reportLocation。

       为了彻底切断HAL层与框架的通讯,我们需修改GnssLocationProvider.cpp文件。在框架层面,我们添加了一个公共函数至LocationManager.java,以进一步控制GPS行为。源码解答之后,完成ROM的编译,并在APK中利用这些自定义功能。

       市面上存在许多修改GPS位置的软件,但它们通常不完全满足特定需求。对于有定制需求的用户,深入理解原理并自主修改源码是更理想的选择。作为拥有十年逆向技术经验的专家,如果你对技术有疑问或需求,欢迎随时咨询交流。

       此外,百亿源码为了增加代码的实用性,我们提供了一个模拟胰岛素泵的类InsulinPump。该类模拟了胰岛素泵的运行机制,包括电量、血糖值、注射胰岛素量等参数的管理。通过类的方法run、getInsulinQuantity、setInsulinQuantity、getBattery、setBattery、crycpy源码getBloodSugar、setBloodSugar和adjust,可以实现胰岛素量的调整与管理,为特殊需求提供解决方案。

Android中如何解决侧拉栏与主界面的重叠

       你要定制一个Android系统,你想用你自己的Launcher(Home)作主界面来替换Android自己的Home,而且不希望用户安装的Launcher来替换掉你的Launcher.

       我们可以通过修改Framework来实现这样的功能。

       这里以Android2.1的源代码为例来实际说明。

       1)首先了解一下Android的启动过程。

       Android系统的启动先从Zygote开始启动,然后......(中间的过程就不说了).....一直到了SystemServer(framework)这个地方,看到这段代码:

       /

**

       * This method is called from Zygote to initialize the system. This will cause the native

       * services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back

       * up into init2() to start the Android services.

       */

       native public static void init1(String[] args);

       public static void main(String[] args) {

       if (SamplingProfilerIntegration.isEnabled()) {

       SamplingProfilerIntegration.start();

       timer = new Timer();

       timer.schedule(new TimerTask() {

       @Override

       public void run() {

       SamplingProfilerIntegration.writeSnapshot("system_server");

       }

       }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);

       }

       // The system server has to run all of the time, so it needs to be

       // as efficient as possible with its memory usage.

       VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

       System.loadLibrary("android_servers");

       init1(args);

       }

       public static final void init2() {

       Log.i(TAG, "Entered the Android system server!");

       Thread thr = new ServerThread();

       thr.setName("android.server.ServerThread");

       thr.start();

       }

       }

       从SystemServer的main函数开始启动各种服务。

       首先启动init1,然后启动init2.

       从上面的注释可以看到:init1这个方法时被Zygote调用来初始化系统的,init1会启动native的服务如SurfaceFlinger,AudioFlinger等等,这些工作做完以后会回调init2来启动Android的service。

       这里我们主要来关注init2的过程。

       init2中启动ServerThread线程,

       ServerThread中启动了一系列的服务,比如这些:

       ActivityManagerService

       EntropyService

       PowerManagerService

       TelephonyRegistry

       PackageManagerService

       AccountManagerService

       BatteryService

       HardwareService

       Watchdog

       SensorService

       BluetoothService

       StatusBarService

       ClipboardService

       InputMethodManagerService

       NetStatService

       ConnectivityService

       AccessibilityManagerService

       NotificationManagerService

       MountService

       DeviceStorageMonitorService

       LocationManagerService

       SearchManagerService

       FallbackCheckinService

       WallpaperManagerService

       AudioService

       BackupManagerService

       AppWidgetService

       这些大大小小的服务起来以后,开始

       ((ActivityManagerService)ActivityManagerNative.getDefault()).systemReady()

       在systemReady后开始开始启动Launcher。

       在寻找Launcher的时候是根据HOME的filter(在Manifest中定义的<category android:name="android.intent.category.HOME" />)来过滤。

       然后根据filter出来的HOME来启动,如果只有一个HOME,则启动这个HOME,如果用户自己装了HOME,那就会弹出来一个列表供用户选择。

       我们现在希望从这里弹出我们自己定制的Launcher,同时也不希望弹出选择HOME的界面,我们不希望用户修改我们的home,比如我们的home上放了好多广告,以及强制安装的程序,不希望用户把它干掉。

       我们可以通过这样来实现:

       2) 定义一个私有的filter选项,然后用这个选项来过滤HOME.

       一般情况下我们使用Manifest中定义的<category android:name="android.intent.category.HOME"来过滤的,我们现在增加一个私有的HOME_FIRST过滤。

       在Intent.java(frameworks/base/core/java/android/content/Intent.java)中添加两行代码

       //lixinso:添加CATEGORY_HOME_FIRST

       @SdkConstant(SdkConstantType.INTENT_CATEGORY)

       public static final String CATEGORY_HOME_FIRST = "android.intent.category.HOME_FIRST";

       3)修改和CATEGORY_HOME相关的所有的地方,都改成HOME_FIRST,主要是framework中的这几个地方:

       frameworks/base/services/java/com/android/server/am/ActivityManagerService.java中

       //intent.addCategory(Intent.CATEGORY_HOME);

       改成intent.addCategory(Intent.CATEGORY_HOME_FIRST); //lixinso:

       //if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {

       改成if (r.intent.hasCategory(Intent.CATEGORY_HOME_FIRST)) { //lixinso: Intent.CATEGORY_HOME -> Intent.CATEGORY_HOME_FIRST

       frameworks/base/services/java/com/android/server/am/HistoryRecorder.java中

       // _intent.hasCategory(Intent.CATEGORY_HOME) &&

       改成 _intent.hasCategory(Intent.CATEGORY_HOME_FIRST) && //lixinso: Intent.CATEGORY_HOME->Intent.CATEGORY_HOME_FIRST

       frameworks/policies/base/mid/com/android/internal/policy/impl/MidWindowManager.java中

       //mHomeIntent.addCategory(Intent.CATEGORY_HOME);

       改成 mHomeIntent.addCategory(Intent.CATEGORY_HOME_FIRST); //lixinso

       frameworks/policies/base/mid/com/android/internal/policy/impl/RecentApplicationsDialog.java中

       //new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),0);

       改成 new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME_FIRST),0); //lixinso

       frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java中

       //mHomeIntent.addCategory(Intent.CATEGORY_HOME);

       改成 mHomeIntent.addCategory(Intent.CATEGORY_HOME_FIRST); //lixinso

       frameworks/policies/base/phone/com/android/internal/policy/impl/RecentApplicationsDialog.java中

       //ResolveInfo homeInfo = pm.resolveActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),0);

       改成 ResolveInfo homeInfo = pm.resolveActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME_FIRST),0); //lixinso

       4) 写一个自己的Launcher.

       可以参考android sample中的Launcher,或者android源代码中的 /packages/apps/Launcher 来写。

       在Launcher中标记其是不是Launcher的最关键的代码时Manifest中的filter:android:name="android.intent.category.HOME"

       现在我们定义了自己的filter,那么,我们在我们自己写的Launcher中将Manifest改为:

       <application android:process="android.process.acore3" android:icon="@drawable/icon" android:label="@string/app_name">

       <activity android:name=".FirstAppActivity"

       android:label="@string/app_name">

       <intent-filter>

       <action android:name="android.intent.action.MAIN" />

       <category android:name="android.intent.category.HOME_FIRST" />

       <category android:name="android.intent.category.DEFAULT" />

       <category android:name="android.intent.category.MONKEY" />

       </intent-filter>

       </activity>

       </application>

       然后将编译好的apk放到/out/target/product/generic/system/app目录下。

       5)将Android自带的Launcher删除掉,包括源代码(packages/apps/Launcher)和apk(/out/target/product/generic/system/app/Launcher.apk)。

       6)

       做完这些工作,就可以重新编译Android了,我们可以编译修改过的几个相关的包。

       如果之前编译过了Android源码,可以用mmm命令来编译部分的改动。

       这里需要这样编译:

       $ . build/envsetup.sh

       $ mmm frameworks/base

       $ mmm frameworks/base/services/java

       $ mmm frameworks/policies/base/mid

       $ mmm frameworks/policies/base/phone

       7)

       编译完成后重新生成img文件。

       $ make snod

       8) 现在可以启动Android模拟器来看效果了。

       首先设置环境变量:

       $ export ANDROID_PRODUCT_OUT= ./out/target/product/generic

       然后切换到

       $ cd ./out/host/linux-x/bin

       运行

       $ ./emulator

       这样我们启动的模拟器里面用的image就是我们刚才编译好的自己定制的东西了。

       从模拟器上可以看到启动的Launcher是我们自己的Launcher,不会出现默认的Launcher了,也不会出现选择界面。

       9)我们再验证一下,如果用户装上了一个其他的Launcher(Home)会怎么样。

       从网上找一个一般的Launcher或者自己写一个一般的Launcher装上去,重新启动,不会出现选择界面。

       按HOME键也不会出来两个HOME来选择。