第二十期 在Android中修改GPS定位数据的完整方案《手机就是开发板》

article/2025/10/12 2:09:09

https://blog.csdn.net/aggresss/article/details/54323034

        现在很多的应用都是基于位置服务的,而且把位置服务作为重要的参考标准,其实这是很不安全的,位置信息的数据未经过任何加密,而且是从我们的手机中发送出去的,所以是可以修改的。这一期我们来探讨一下如何修改手机中的定位信息。太基础的原理我就不多说了,可以参考前几期文章。
        先整理一下思路,Android在开发者模式下有一个"允许模拟位置选项",它是location service加载 MOCK location provider 实现的,通过这种线程注入的方式修改GPS信息是hacker们最喜欢的方式,但现在很多应用已经可以检测到这种注入方式而被屏蔽掉,也就是说如果我们只在APP层面上想解决方法总是有被检测出来的可能。那我们就得把问题往深了想,通过修改最底层的GPS数据来欺骗APP,在Framework层面上没有任何修改迹象,这样基于APP层面的检测机制就拿我们没有任何办法。
        思路确定后我们来探讨实践路线,首先我们要建立一个管道,让我们想要定位的GPS数据提交到Android操作系统的最底层,也就是Linux Kernel层面;然后我们要修改 GPS的 location report 机制,让它从内核中提取到我们的数据,然后逐层上报到APP层。有点明修栈道暗度陈仓的感觉。
        总体来说分成两部实现:1.建立到系统内核的数据管道;2.修改GPS上报机制。
        这次实验使用的是闲置的小米3W手机,编译源码采用CyanogenMod-13,具体的编译环境搭建和编译方法请参考前几期文章。
        因为Android系统从内核态到APP层要经过很多的层次,所以对于建立数据管道的步骤比较繁琐,我这里分成了5个步骤,对应5个层面来实现,每一步分别对应Android的 Kernel driver,HAL,JNI,Framework,Application。所有的代码我都已上传github中https://github.com/aggresss/PHDemo/  这一期的代码在VirtualPosition 目录下。
下面描述一下实践步骤:
=============分割线1==============
第一步,修改Kernel driver
进入 kernel/xiaomi/cancro/drivers 目录下,新建vp.h文件

#ifndef _VP_ANDROID_H_  
#define _VP_ANDROID_H_  #include <linux/cdev.h>  
#include <linux/semaphore.h>  #define VP_DEVICE_NODE_NAME  "vp"  
#define VP_DEVICE_FILE_NAME  "vp"  
#define VP_DEVICE_PROC_NAME  "vp"  
#define VP_DEVICE_CLASS_NAME "vp"  typedef struct {int toggle;double virtual_latitude;double virtual_longitude;
} VirtualPosition;struct vp_android_dev {  int lamp;VirtualPosition val;struct semaphore sem;  struct cdev dev;  
};    
#endif  


新建vp.c文件

/*******************************************
*include file and define functions
*******************************************/
#include <linux/init.h>  
#include <linux/module.h>  
#include <linux/types.h>  
#include <linux/fs.h>  
#include <linux/proc_fs.h>  
#include <linux/device.h>  
#include <asm/uaccess.h>  #include "vp.h"  /*主设备和从设备号变量*/  
static int vp_major = 0;  
static int vp_minor = 0;  /*设备类别和设备变量*/  
static struct class* vp_class = NULL;  
static struct vp_android_dev* vp_dev = NULL;  /*传统的设备文件操作方法*/  
static int vp_open(struct inode* inode, struct file* filp);  
static int vp_release(struct inode* inode, struct file* filp);  
static ssize_t vp_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);  
static ssize_t vp_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);  /*设备文件操作方法表*/  
static struct file_operations vp_fops = {  .owner = THIS_MODULE,  .open = vp_open,  .release = vp_release,  .read = vp_read,  .write = vp_write,   
};  /*访问设置属性方法*/  
static ssize_t vp_lamp_show(struct device* dev, struct device_attribute* attr,  char* buf);  
static ssize_t vp_lamp_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);  /*定义设备属性*/  
static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, vp_lamp_show, vp_lamp_store);/*******************************************
*define traditional file access 
*******************************************/
/*打开设备方法*/  
static int vp_open(struct inode* inode, struct file* filp) {  struct vp_android_dev* dev;          /*将自定义设备结构体保存在文件指针的私有数据域中,以便访问设备时拿来用*/  dev = container_of(inode->i_cdev, struct vp_android_dev, dev);  filp->private_data = dev;  return 0;  
}  /*设备文件释放时调用,空实现*/  
static int vp_release(struct inode* inode, struct file* filp) {  return 0;  
}  /*读取设备的寄存器val的值*/  
static ssize_t vp_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {  ssize_t err = 0;  struct vp_android_dev* dev = filp->private_data;          /*同步访问*/  if(down_interruptible(&(dev->sem))) {  return -ERESTARTSYS;  }  if(count < sizeof(dev->val)) {  goto out;  }          /*将寄存器val的值拷贝到用户提供的缓冲区*/  if(copy_to_user(buf, &(dev->val), sizeof(dev->val))) {  err = -EFAULT;  goto out;  }  err = sizeof(dev->val);  out:  up(&(dev->sem));  return err;  
}  /*写设备的寄存器值val*/  
static ssize_t vp_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {  struct vp_android_dev* dev = filp->private_data;  ssize_t err = 0;          /*同步访问*/  if(down_interruptible(&(dev->sem))) {  return -ERESTARTSYS;          }          if(count != sizeof(dev->val)) {  goto out;          }          /*将用户提供的缓冲区的值写到设备寄存器去*/  if(copy_from_user(&(dev->val), buf, count)) {  err = -EFAULT;  goto out;  }  err = sizeof(dev->val);  out:  up(&(dev->sem));  return err;  
}  /*******************************************
*define devfs access
*******************************************/
/*读取寄存器lamp的值到缓冲区buf中,内部使用*/  
static ssize_t __vp_get_lamp(struct vp_android_dev* dev, char* buf) {  int lamp = 0;          /*同步访问*/  if(down_interruptible(&(dev->sem))) {                  return -ERESTARTSYS;          }          lamp = dev->lamp;          up(&(dev->sem));          return snprintf(buf, PAGE_SIZE, "%d\n", lamp);  
}  /*把缓冲区buf的值写到设备寄存器lamp中去,内部使用*/  
static ssize_t __vp_set_lamp(struct vp_android_dev* dev, const char* buf, size_t count) {  int lamp = 0;          /*将字符串转换成数字*/          lamp = simple_strtol(buf, NULL, 10);          /*同步访问*/          if(down_interruptible(&(dev->sem))) {                  return -ERESTARTSYS;          }          dev->lamp = lamp;          up(&(dev->sem));  return count;  
}  /*读取设备属性lamp*/  
static ssize_t vp_lamp_show(struct device* dev, struct device_attribute* attr, char* buf) {  struct vp_android_dev* hdev = (struct vp_android_dev*)dev_get_drvdata(dev);          return __vp_get_lamp(hdev, buf);  
}  /*写设备属性lamp*/  
static ssize_t vp_lamp_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {   struct vp_android_dev* hdev = (struct vp_android_dev*)dev_get_drvdata(dev);    return __vp_set_lamp(hdev, buf, count);  
}  /*******************************************
*define proc access
*******************************************/
/*读取设备寄存器lamp的值,保存在page缓冲区中*/  
static ssize_t vp_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) {  if(off > 0) {  *eof = 1;  return 0;  }  return __vp_get_lamp(vp_dev, page);  
}  /*把缓冲区的值buff保存到设备寄存器lamp中去*/  
static ssize_t vp_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) {  int err = 0;  char* page = NULL;  if(len > PAGE_SIZE) {  printk(KERN_ALERT"The buff is too large: %lu.\n", len);  return -EFAULT;  }  page = (char*)__get_free_page(GFP_KERNEL);  if(!page) {                  printk(KERN_ALERT"Failed to alloc page.\n");  return -ENOMEM;  }          /*先把用户提供的缓冲区值拷贝到内核缓冲区中去*/  if(copy_from_user(page, buff, len)) {  printk(KERN_ALERT"Failed to copy buff from user.\n");                  err = -EFAULT;  goto out;  }  err = __vp_set_lamp(vp_dev, page, len);  out:  free_page((unsigned long)page);  return err;  
}  /*创建/proc/vp文件*/  
static void vp_create_proc(void) {
struct proc_dir_entry *entry;
entry = create_proc_entry(VP_DEVICE_PROC_NAME, 0, NULL);
if(entry)
{
entry->read_proc = vp_proc_read;
entry->write_proc = vp_proc_write;
}
}  /*删除/proc/vp文件*/  
static void vp_remove_proc(void) {  remove_proc_entry(VP_DEVICE_PROC_NAME, NULL);  
}  /*******************************************
*define load and remove function
*******************************************/
/*初始化设备*/  
static int  __vp_setup_dev(struct vp_android_dev* dev) {  int err;  dev_t devno = MKDEV(vp_major, vp_minor);  memset(dev, 0, sizeof(struct vp_android_dev));  cdev_init(&(dev->dev), &vp_fops);  dev->dev.owner = THIS_MODULE;  dev->dev.ops = &vp_fops;          /*注册字符设备*/  err = cdev_add(&(dev->dev),devno, 1);  if(err) {  return err;  }          /*初始化信号量和寄存器lamp, val的值*/  sema_init(&(dev->sem), 1);  dev->lamp = 7777;  dev->val.toggle = 1;  dev->val.virtual_latitude = 45.104108; dev->val.virtual_longitude = 130.816878; return 0;  
}  /*模块加载方法*/  
static int __init vp_init(void){   int err = -1;  dev_t dev = 0;  struct device* temp = NULL;  printk(KERN_ALERT"Initializing vp device.\n");          /*动态分配主设备和从设备号*/  err = alloc_chrdev_region(&dev, 0, 1, VP_DEVICE_NODE_NAME);  if(err < 0) {  printk(KERN_ALERT"Failed to alloc char dev region.\n");  goto fail;  }  vp_major = MAJOR(dev);  vp_minor = MINOR(dev);          /*分配helo设备结构体变量*/  vp_dev = kmalloc(sizeof(struct vp_android_dev), GFP_KERNEL);  if(!vp_dev) {  err = -ENOMEM;  printk(KERN_ALERT"Failed to alloc vp_dev.\n");  goto unregister;  }          /*初始化设备*/  err = __vp_setup_dev(vp_dev);  if(err) {  printk(KERN_ALERT"Failed to setup dev: %d.\n", err);  goto cleanup;  }          /*在/sys/class/目录下创建设备类别目录vp*/  vp_class = class_create(THIS_MODULE, VP_DEVICE_CLASS_NAME);  if(IS_ERR(vp_class)) {  err = PTR_ERR(vp_class);  printk(KERN_ALERT"Failed to create vp class.\n");  goto destroy_cdev;  }          /*在/dev/目录和/sys/class/vp目录下分别创建设备文件vp*/  temp = device_create(vp_class, NULL, dev, "%s", VP_DEVICE_FILE_NAME);  if(IS_ERR(temp)) {  err = PTR_ERR(temp);  printk(KERN_ALERT"Failed to create vp device.");  goto destroy_class;  }          /*在/sys/class/vp/vp目录下创建属性文件val*/  err = device_create_file(temp, &dev_attr_val);  if(err < 0) {  printk(KERN_ALERT"Failed to create attribute val.");                  goto destroy_device;  }  dev_set_drvdata(temp, vp_dev);          /*创建/proc/vp文件*/  vp_create_proc();  printk(KERN_ALERT"Succedded to initialize vp device.\n");  return 0;  destroy_device:  device_destroy(vp_class, dev);  destroy_class:  class_destroy(vp_class);  destroy_cdev:  cdev_del(&(vp_dev->dev));  cleanup:  kfree(vp_dev);  unregister:  unregister_chrdev_region(MKDEV(vp_major, vp_minor), 1);  fail:  return err;  
}  /*模块卸载方法*/  
static void __exit vp_exit(void) {  dev_t devno = MKDEV(vp_major, vp_minor);  printk(KERN_ALERT"Destroy vp device.\n");          /*删除/proc/vp文件*/  vp_remove_proc();          /*销毁设备类别和设备*/  if(vp_class) {  device_destroy(vp_class, MKDEV(vp_major, vp_minor));  class_destroy(vp_class);  }          /*删除字符设备和释放设备内存*/  if(vp_dev) {  cdev_del(&(vp_dev->dev));  kfree(vp_dev);  }          /*释放设备号*/  unregister_chrdev_region(devno, 1);  
}  MODULE_LICENSE("GPL");  
MODULE_DESCRIPTION("Virtualposition Driver");  module_init(vp_init);  
module_exit(vp_exit);  


添加 Kconfig 文件

config VPtristate "Virtual Position Driver"default nhelpThis is the virtual position driver.


添加 Makefile 文件

obj-$(CONFIG_VP) += vp.o


修改 drivers/Kconfig 文件 在menu "Device Drivers"和endmenu之间添加一行:

source "drivers/vp/Kconfig"  


修改drivers/Makefile文件,添加一行:

obj-$(CONFIG_HELLO) += vp/  


修改 arch/arm/configs目录下的cyanogen_cancro_defconfig 文件,在文件末尾加入

# CONFIG_VP
CONFIG_VP=y

=============分割线2==============
第二步,修改HAL
进入 ./hardware/libhardware/include/hardware 目录,新建 vp.h 文件

#ifndef ANDROID_VP_INTERFACE_H  
#define ANDROID_VP_INTERFACE_H  
#include <hardware/hardware.h>  
__BEGIN_DECLS  /*定义模块ID*/  
#define VP_HARDWARE_MODULE_ID "vp"  //typedef enum{false, true} bool;/*define virtual position structrue*/
typedef struct {int toggle;double virtual_latitude;double virtual_longitude;
} VirtualPosition;/*硬件模块结构体*/  
struct vp_module_t {  struct hw_module_t common;  
};  /*硬件接口结构体*/  
struct vp_device_t {  struct hw_device_t common;  int fd;  int (*set_val)(struct vp_device_t* dev, VirtualPosition val);  int (*get_val)(struct vp_device_t* dev, VirtualPosition* val);  
};  __END_DECLS  #endif  


进入到 hardware/libhardware/modules 目录,新建vp目录,并添加vp.c文件

#define LOG_TAG "VpStub"  #include <hardware/hardware.h>  
#include <hardware/vp.h>  
#include <fcntl.h>  
#include <errno.h>  
#include <cutils/log.h>  
#include <cutils/atomic.h>  #define DEVICE_NAME "/dev/vp"  
#define MODULE_NAME "Vp"  
#define MODULE_AUTHOR "aggresss@163.com"  /*设备打开和关闭接口*/  
static int vp_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);  
static int vp_device_close(struct hw_device_t* device);  /*设备访问接口*/  
static int vp_set_val(struct vp_device_t* dev, VirtualPosition val);  
static int vp_get_val(struct vp_device_t* dev, VirtualPosition* val);  /*模块方法表*/  
static struct hw_module_methods_t vp_module_methods = {  open: vp_device_open  
};  /*模块实例变量*/  
struct vp_module_t HAL_MODULE_INFO_SYM = {  common: {  tag: HARDWARE_MODULE_TAG,  version_major: 1,  version_minor: 0,  id: VP_HARDWARE_MODULE_ID,  name: MODULE_NAME,  author: MODULE_AUTHOR,  methods: &vp_module_methods,  }  
};  static int vp_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) {  struct vp_device_t* dev;dev = (struct vp_device_t*)malloc(sizeof(struct vp_device_t));  if(!dev) {  ALOGE("Vp Stub: failed to alloc space");  return -EFAULT;  }  memset(dev, 0, sizeof(struct vp_device_t));  dev->common.tag = HARDWARE_DEVICE_TAG;  dev->common.version = 0;  dev->common.module = (hw_module_t*)module;  dev->common.close = vp_device_close;  dev->set_val = vp_set_val;dev->get_val = vp_get_val;  if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {  ALOGE("Vp Stub: failed to open /dev/vp -- %s.", strerror(errno));free(dev);  return -EFAULT;  }  *device = &(dev->common);  ALOGI("Vp Stub: open /dev/vp successfully.");  return 0;  
}  static int vp_device_close(struct hw_device_t* device) {  struct vp_device_t* vp_device = (struct vp_device_t*)device;  if(vp_device) {  close(vp_device->fd);  free(vp_device);  }  return 0;  
}  static int vp_set_val(struct vp_device_t* dev, VirtualPosition val) {  ALOGI("Vp Stub: set value %d to device.", val);  write(dev->fd, &val, sizeof(val));  return 0;  
}  static int vp_get_val(struct vp_device_t* dev, VirtualPosition* val) {  if(!val) {  ALOGE("Vp Stub: error val pointer");  return -EFAULT;  }  read(dev->fd, val, sizeof(*val));  ALOGI("Vp Stub: get value %d from device", *val);  return 0;  
}  


继续在vp目录下新建Android.mk文件:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := vp.c
LOCAL_MODULE := vp.default
include $(BUILD_SHARED_LIBRARY)

=============分割线3==============
第三步,修改JNI
进入 frameworks/base/services/core/jni 目录,新建com_android_server_VirtualPositionService.cpp文件

#define LOG_TAG "VirtualPositionService"  
#include "jni.h"  
#include "JNIHelp.h"  
#include "android_runtime/AndroidRuntime.h"  
#include <utils/misc.h>  
#include <utils/Log.h>  
#include <hardware/hardware.h>  
#include <hardware/vp.h>  
#include <stdio.h>  namespace android  
{  VirtualPosition virtual_position = {1, 0.0, 0.0};/*在硬件抽象层中定义的硬件访问结构体,参考<hardware/vp.h>*/  struct vp_device_t* vp_device = NULL;  /*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/  static void vp_setVal() {  ALOGI("VirtualPosition JNI: set value to device.");  if(!vp_device) {  ALOGI("VirtualPosition JNI: device is not open.");  return;  }  vp_device->set_val(vp_device, virtual_position);  }  /*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/  static void vp_getVal() {  if(!vp_device) {  ALOGI("VirtualPosition JNI: device is not open.");  }  vp_device->get_val(vp_device, &virtual_position);  ALOGI("VirtualPosition JNI: get value from device.");  }  /*通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/  static inline int vp_device_open(const hw_module_t* module, struct vp_device_t** device) {  return module->methods->open(module, VP_HARDWARE_MODULE_ID, (struct hw_device_t**)device);  }  /*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/  static jboolean vp_init(JNIEnv* env, jclass clazz) {  vp_module_t* module;  ALOGI("VirtualPosition JNI: initializing......");  if(hw_get_module(VP_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {  ALOGI("VirtualPosition JNI: vp Stub found.");  if(vp_device_open(&(module->common), &vp_device) == 0) {  ALOGI("VirtualPosition JNI: vp device is open.");  return 0;  }  ALOGE("VirtualPosition JNI: failed to open vp device.");  return -1;  }  ALOGE("VirtualPosition JNI: failed to get vp stub module.");  return -1;        }  static void android_server_VirtualPositionService_set_virtual_toggle(JNIEnv* env, jclass clazz, jint tog){virtual_position.toggle = tog;vp_setVal();}static jint android_server_VirtualPositionService_get_virtual_toggle(JNIEnv* env, jclass clazz){vp_getVal();return virtual_position.toggle;}static void android_server_VirtualPositionService_set_virtual_latitude(JNIEnv* env, jclass clazz, jdouble vlat){virtual_position.virtual_latitude = vlat;vp_setVal();}static jdouble android_server_VirtualPositionService_get_virtual_latitude(JNIEnv* env, jclass clazz){vp_getVal();return virtual_position.virtual_latitude;}static void android_server_VirtualPositionService_set_virtual_longitude(JNIEnv* env, jclass clazz, jdouble vlon){virtual_position.virtual_longitude = vlon;vp_setVal();}static jdouble android_server_VirtualPositionService_get_virtual_longitude(JNIEnv* env, jclass clazz){vp_getVal();return virtual_position.virtual_longitude;}/*JNI方法表*/  static const JNINativeMethod method_table[] = {  {"init_native","()Z", (void*)vp_init},  {"native_set_virtual_toggle","(I)V",(void*)android_server_VirtualPositionService_set_virtual_toggle},{"native_get_virtual_toggle","()I",(void*)android_server_VirtualPositionService_get_virtual_toggle},{"native_set_virtual_latitude","(D)V",(void*)android_server_VirtualPositionService_set_virtual_latitude},{"native_get_virtual_latitude","()D",(void*)android_server_VirtualPositionService_get_virtual_latitude},{"native_set_virtual_longitude","(D)V",(void*)android_server_VirtualPositionService_set_virtual_longitude},{"native_get_virtual_longitude","()D",(void*)android_server_VirtualPositionService_get_virtual_longitude},};  /*注册JNI方法*/  int register_android_server_VirtualPositionService(JNIEnv *env) {  return jniRegisterNativeMethods(env, "com/android/server/VirtualPositionService", method_table, NELEM(method_table));  }  
};  


修改同目录下的onload.cpp文件,首先在namespace android增加com_android_server_VirtualPositionService函数声明:

namespace android {  ..............................................................................................  int register_android_server_VirtualPositionService(JNIEnv *env);  };  
在JNI_onLoad增加register_android_server_VirtualPositionService函数调用:
extern "C" jint JNI_onLoad(JavaVM* vm, void* reserved)  {  .................................................................................................  register_android_server_VirtualPositionService(env);  .................................................................................................  }  


修改同目录下的Android.mk文件,在LOCAL_SRC_FILES变量中增加一行:

LOCAL_SRC_FILES:= \  com_android_server_AlarmManagerService.cpp \  com_android_server_BatteryService.cpp \  com_android_server_InputManager.cpp \  com_android_server_LightsService.cpp \  com_android_server_PowerManagerService.cpp \  com_android_server_SystemServer.cpp \  com_android_server_UsbService.cpp \  com_android_server_VibratorService.cpp \  com_android_server_location_GpsLocationProvider.cpp \  com_android_server_VirtualPositionService.cpp \ onload.cpp  

=============分割线4==============
第四步,修改Framework
进入到frameworks/base/core/java/android/os目录,新增VirtualPositionService.aidl接口定义文件

package android.os;interface IVirtualPositionService {void setVirtualToggle(int tog);int getVirtualToggle();void setVirtualLatitude(double vlat);double getVirtualLatitude();void setVirtualLongitude(double vlon);double getVirtualLongitude();
}


然后进入 frameworks/base目录,打开Android.mk文件,修改LOCAL_SRC_FILES变量的值,增加IVirtualPosition.aidl源文件:

LOCAL_SRC_FILES += /
....................................................................
core/java/android/os/IVibratorService.aidl /
core/java/android/os/IVirtualPosition.aidl /
core/java/android/service/urlrenderer/IUrlRendererService.aidl /
.....................................................................


进入到frameworks/base/services/java/com/android/server目录,新增VirtualPositionService.java文件

package com.android.server;  
import android.content.Context;  
import android.os.IVirtualPositionService;  
import android.util.Slog;  public class VirtualPositionService extends IVirtualPositionService.Stub {  private static final String TAG = "VirtualPositionService";  VirtualPositionService() {  init_native();  }  public void setVirtualToggle(int tog) {native_set_virtual_toggle(tog);}public int getVirtualToggle(){return native_get_virtual_toggle();}public void setVirtualLatitude(double vlat) {native_set_virtual_latitude(vlat);}public double getVirtualLatitude(){return native_get_virtual_latitude();}public void setVirtualLongitude(double vlon) {native_set_virtual_longitude(vlon);}public double getVirtualLongitude() {return native_get_virtual_longitude();}private static native boolean init_native();private static native void native_set_virtual_toggle(int tog);private static native int native_get_virtual_toggle();private static native void native_set_virtual_latitude(double vlat);private static native double native_get_virtual_latitude();private static native void native_set_virtual_longitude(double vlon);private static native double native_get_virtual_longitude();};  


修改同目录的SystemServer.java文件,在ServerThread::run函数中增加加载VirtualPositionService的代码:


@Override
public void run() {
....................................................................................
try {
Slog.i(TAG, "DiskStats Service");
ServiceManager.addService("diskstats", new DiskStatsService(context));
} catch (Throwable e) {
Slog.e(TAG, "Failure starting DiskStats Service", e);
}
try {
Slog.i(TAG, "VirtualPosition Service");
ServiceManager.addService("virtualposition", new VirtualPositionService());
} catch (Throwable e) {
Slog.e(TAG, "Failure starting VirtualPosition Service", e);
}
......................................................................................
} 


然后需要修改sepolicy文件,具体的文件在github上,请下载使用。


=============分割线5==============
第五步,修改application
APP的文件比较多,请到github上下载,这里只贴具体的逻辑代码:

package com.example.phdemo.myapplication;import android.os.RemoteException;
import android.app.Activity;
import android.os.ServiceManager;
import android.os.Bundle;
import android.widget.CompoundButton;
import android.os.IVirtualPositionService;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ToggleButton;
import android.widget.CompoundButton.OnCheckedChangeListener;public class MainActivity extends Activity implements View.OnClickListener {private final static String LOG_TAG = "com.example.phdemo.virtualposition";private IVirtualPositionService virtualpositionService = null;
private ToggleButton toggleButton = null;
private EditText altitudeValueText = null;private EditText longitudeValueText = null;private Button getButton = null;private Button setButton = null;private Button clearButton = null;/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);virtualpositionService = IVirtualPositionService.Stub.asInterface(ServiceManager.getService("virtualposition"));toggleButton=(ToggleButton)findViewById(R.id.toggleButton);
altitudeValueText = (EditText)findViewById(R.id.altitude_value);
longitudeValueText = (EditText)findViewById(R.id.longitude_value);getButton = (Button)findViewById(R.id.button_get);setButton = (Button)findViewById(R.id.button_set);clearButton = (Button)findViewById(R.id.button_clear);getButton.setOnClickListener(this);setButton.setOnClickListener(this);clearButton.setOnClickListener(this);try{ int val_tog = virtualpositionService.getVirtualToggle();if(val_tog == 1){toggleButton.setChecked(true);}else{toggleButton.setChecked(false);}} catch (Exception e) {}toggleButton.setOnCheckedChangeListener(new OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
toggleButton.setChecked(isChecked);
try{virtualpositionService.setVirtualToggle(isChecked?1:0);}catch(Exception e){}
}
});Log.i(LOG_TAG, "VirtualPosition Activity Created");}@Overridepublic void onClick(View v) {if(v.equals(getButton)) {try {double val_altitude = virtualpositionService.getVirtualLatitude();String text_altitude = String.valueOf(val_altitude);altitudeValueText.setText(text_altitude);
double val_longitude = virtualpositionService.getVirtualLongitude();String text_longitude = String.valueOf(val_longitude);longitudeValueText.setText(text_longitude);
int val_tog = virtualpositionService.getVirtualToggle();if(val_tog == 1){toggleButton.setChecked(true);}else{toggleButton.setChecked(false);}} catch (Exception e) {Log.e(LOG_TAG, "Remote Exception while reading value from GpsLocationProvider.");}}else if(v.equals(setButton)) {try {String text_altitude = altitudeValueText.getText().toString();
String text_longitude = longitudeValueText.getText().toString();double val_altitude = Double.parseDouble(text_altitude);
double val_longitude = Double.parseDouble(text_longitude);virtualpositionService.setVirtualLatitude(val_altitude);
virtualpositionService.setVirtualLongitude(val_longitude);} catch (Exception e) {Log.e(LOG_TAG, "Remote Exception while writing value to GpsLocationProvider.");}}else if(v.equals(clearButton)) {String text = "";altitudeValueText.setText(text);
longitudeValueText.setText(text);}}
}

=============分割线6==============
最后一步,在JNI层面修改location report 机制。
进入 frameworks/base/services/core/jni 目录,修改com_android_server_location_GpsLocationProvider.cpp文件:
在全局变量部分加入

// add by aggresss
static int vp_fd = open("/dev/vp", O_RDWR); 
static VirtualPosition vp_val;


修改location_callback函数:

static void location_callback(GpsLocation* location)
{JNIEnv* env = AndroidRuntime::getJNIEnv();//add by aggresssread(vp_fd, &vp_val, sizeof(VirtualPosition));if(vp_val.toggle  == 1){env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags,(jdouble)vp_val.virtual_latitude, (jdouble)vp_val.virtual_longitude,(jdouble)location->altitude,(jfloat)location->speed, (jfloat)location->bearing,(jfloat)location->accuracy, (jlong)location->timestamp);checkAndClearExceptionFromCallback(env, __FUNCTION__);}else{env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags,(jdouble)location->latitude, (jdouble)location->longitude,(jdouble)location->altitude,(jfloat)location->speed, (jfloat)location->bearing,(jfloat)location->accuracy, (jlong)location->timestamp);checkAndClearExceptionFromCallback(env, __FUNCTION__);}
}

=============我是完成的分割线==============
完成后,重新编译固件,开机后启动VirtualPosition的APP,设置你想要的坐标,想在哪就在哪了。
        
          


http://chatgpt.dhexx.cn/article/Js6NPlC7.shtml

相关文章

Android-Framework-GPS定位原理和修改

一、 Android定位功能原理概述 1.1 Android三种定位提供方式。 Android 应用层获取定位可以通过三种定位提供方式&#xff1a;gps&#xff0c;network&#xff0c;passive。 gps –>&#xff08;GPS&#xff0c;AGPS&#xff09;&#xff1a; GPS位置提供者的名称。该提供商…

HDFS命令

用法 1.hadoop xxx hadoop fs命令可用于其他文件系统&#xff0c;不止是hdfs文件系统内也就是说该命令的使用范围更广&#xff0c;可以用于HDFS、Local FS等不同的文件系统 2.hdfs xxx hdfs dfs命令只用于hdfs文件系统 命令 1.用户命令 fsck&#xff1a;磁盘检查dfs&…

hadoop之hdfs命令

目录 1&#xff1a;创建目录 2、查看文件&#xff0c;ls 没有cd命令&#xff0c; 需要指定绝对路径 3&#xff1a;上传文件 put&#xff08;要先把数据上传到linux本地然后再上传&#xff09; 4&#xff1a;下载文件 get 5:复制 cp 6&#xff1a;查看文件内容 cat , 如果数…

hadoop(五)-hdfs命令行基本命令

HDFS是存取数据的分布式文件系统&#xff0c;那么对HDFS的操作&#xff0c;就是文件系统的基本操作&#xff0c;比如文件的创建、修改、删除、修改权限等&#xff0c;文件夹的创建、删除、重命名等。对HDFS的操作命令类似于Linux的shell对文件的操作&#xff0c;如ls、mkdir、r…

hadoop中上输入hdfs 相关命令显示无法找到问题

问题可能是没有在主目录配置你自己hadoop相关环境变量 解决方法&#xff1a; 1&#xff1a;切换到主目录&#xff0c;输入命令cd ~ 2:输入如下命令进入编辑&#xff1a; 3&#xff1a;在编辑页面最底部&#xff0c;输入如下命令&#xff1a; 4&#xff1a;退出保存编辑输入命令…

HDFS的命令操作

1&#xff09;基本语法 bin/hdfs dfs 具体命令 2) 常用命令实操 &#xff08;1&#xff09;-help&#xff1a;输出这个命令参数 bin/hdfs dfs -help rm &#xff08;2&#xff09;-ls: 显示目录信息 hdfs dfs -ls / &#xff08;3&#xff09;-mkdir&#xff1a;在hdfs上创…

【hadoop系列】Hadoop HDFS命令

格式&#xff1a;hadoop fs -命令 主要有如下的命令&#xff1a; 命令说明hadoop fs -mkdir创建HDFS目录hadoop fs -ls列出HDFS目录hadoop fs -copyFromLocal使用-copyFromLocal复制本地文件&#xff08;local&#xff09;到HDFShadoop fs -put使用-put复制本地&#xff08;lo…

【hadoop系列】Hadoop HDFS命令

格式&#xff1a;hadoop fs -命令 主要有如下的命令&#xff1a; 命令 说明 hadoop fs -mkdir 创建HDFS目录 hadoop fs -ls 列出HDFS目录 hadoop fs -copyFromLocal 使用-copyFromLocal复制本地文件&#xff08;local&#xff09;到HDFS hadoop fs -put 使用-put复制…

HDFS命令行操作

HDFS的命令行接口类似传统的Shell命令&#xff0c;可以通过命令行接口与HDFS系统进行交互&#xff0c;从而对系统中的文件进行读取、移动、创建操作。 命令行接口有两种格式如下&#xff1a; hadoop fs -命令 文件路径 hdfs dfs -命令 文件路径执行hadoop fs 或者 hdfs dfs可…

HDFS基础命令

通过vi在Linux本地创建三个文本文件&#xff1a;txt1.txt、txt2.txt、txt3.txt。文件里面随意输入些内容。 命令如下&#xff1a; vi txt1.txt vi txt2.txt vi txt3.txt (1)列出子目录或子文件 列出 HDFS 当前用户家目录下的文件及文件夹(前提&#xff1a;家目录已经存在&…

(超详细)HDFS常用命令及HDFS API基础编程

HDFS常用命令及基础编程 JunLeon——go big or go home 目录 HDFS常用命令及基础编程 一、HDFS概述 1、什么是HDFS&#xff1f; 2、HDFS数据存储模式——数据块&#xff08;block&#xff09; 3、HDFS的副本存放策略及机架感知 &#xff08;1&#xff09;副本存放策略&a…

HDFS常用命令汇总

HDFS常用命令汇总 一、前言信息二、帮助信息查看1、查看帮助信息2、帮助文档&#xff08;附带命令的详细说明&#xff09; 三、常用命令1、创建目录2、查看目录下的内容3、上传文件4、上传并删除源文件5、查看文件内容6、查看文件开头内容7、查看文件末尾内容8、下载文件9、合并…

大数据笔记 | HDFS 常用操作命令

目录 一、HDFS 命令前缀 二、ls 命令 三、put 命令 四、moveFromLocal 命令 五、get 命令 六、rm 命令 七、mkdir 命令 八、cp 命令 九、mv 命令 十、cat 命令 十一、appendToFile 命令 十二、总结 HDFS 是 Hadoop Distributed File System 的简写&#xff0c;即 H…

HTML encode Decode

System.Web.dll中&#xff0c;System.Web.HttpUtility.HtmlEncode(string s)方法的原理是这样的&#xff1a; 首先判断传入的字符串是否为null&#xff0c;如果是&#xff0c;则返回null if (s null ) ... { return null; } 然后&#xff0c;尝试在传入的字符…

html代码

hello 这是一个模拟黑客的玩意 <!DOCTYPE html> <html xmlns"http://www.w3.org/1999/xhtml"><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"> <meta charset"UTF-8"><li…

C# .net 几种HtmlEncode,HtmlDecode的区别

一、C#中的编码 HttpUtility.HtmlDecode、HttpUtility.HtmlEncode与Server.HtmlDecode、Server.HtmlEncode与HttpServerUtility.HtmlDecode、HttpServerUtility.HtmlEncode的区别&#xff1f; 它们与下面一般手工写的代码有什么区别&#xff1f; [c-sharp] view plaincopy pu…

【C#】C#中的HtmlEncode与HtmlDecode:HttpUtility.HtmlEncode,Server.HtmlEncode,WebUtility.HtmlEncode

HtmlEncode(String) 将字符串转换为 HTML 编码字符串。 HtmlDecode(String) 将已经为 HTTP 传输进行过 HTML 编码的字符串转换为已解码的字符串。 在web端项目中通常使用HttpUtility.HtmlEecode&#xff0c;HttpUtility.HtmlDecode&#xff0c;Server.HtmlEncode&#xff0c;Se…

js htmlEncode

javascript处理HTML的Encode(转码)和Decode(解码)总结 HTML的Encode(转码)和解码(Decode)在平时的开发中也是经常要处理的&#xff0c;在这里总结了使用javascript处理HTML的Encode(转码)和解码(Decode)的常用方式 一、用浏览器内部转换器实现转换 1.1.用浏览器内部转换器实现…

READNE.md 语法

标题列表引用代码块链接图片分割线表格 1. 标题 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ###### 六级标题 2. 列表 2.1 有序列表 直接在前面写数字序号&#xff1a; 1. a 2. bc 3. 1234 2.2 无序列表 有三种方式&#xff1a;""、&qu…

# 今天要讲一下我所用的md语法

今天要讲一下我所用的md语法 首先md是一种标记语言&#xff0c;我们不要把它想的过于复杂&#xff0c;其实对于经常探索新知识的人来说上手速度非常快。 下面讲一下基本语法 标题语法 一级标题&#xff1a;# Heading level 1二级标题&#xff1a;## Heading level 2二级标题&…