symbian 2nd如何绕过程序管理器的限制

来源:互联网 发布:疯狂美工注册码 编辑:程序博客网 时间:2024/05/16 05:54

symbian 2nd如何绕过程序管理器的限制

 

北京理工大学  20981  陈罡

 

symbian开发中我们经常会用到手机系统自带的程序管理这个软件。这个软件的功能在于它会忠实地把程序的安装操作记录下来,在删除程序的时候它也会忠实地把程序给删除。这种做法对于symbian来说,无疑是最好的选用第三方软件的选择,既可以安装到手机上,又可以无条件的将软件卸载掉。

 

但是这个所谓的程序管理,也有很多弊端。例如,每次都需要把程序的安装包拷贝到手机存储上去,这样安装包一旦大于2M,对于多数s60手机来说,这个程序极有可能引起手机内存不足,请关闭一些程序这样的错误提示,最终导致安装失败。再有就是程序的升级,有的时候不需要整个将sis包重新安装一遍,只是覆盖掉几个dll文件即可,但是很多情况下,开发者都是选择将程序全部重新安装一遍,如果打包的时候升级过sis包的版本,那么将在程序管理中看到多个安装记录。另外目前很多公司都在寻找手机程序预装的方法,其实从其本质来说就是希望程序安装到用户的手机上以后,无法被用户使用普通的程序管理程序卸载。

 

在这里我要讨论一种方式,可以绕过程序管理器的限制,在程序管理里面没有记录,也无法把程序从程序管理器里面卸载,这种方式虽然比较有效,但是程序的卸载操作就需要使用其它的单独的卸载程序才能卸载了。

绕过程序管理器的方法其实很简单,自己编写一个程序管理器即可。很多朋友会想编写一个程序管理器多么多么的复杂,需要熟悉sis文件格式之类的内容。其实一点也不复杂,sis本身就是s60自带的程序管理器支持的文件格式,只有nokia的程序管理器才能够识别。既然我们自己编写程序管理器的话,就不必拘泥于sis格式了。自己的程序可以读取的文件格式就可以自己说得算了。

 

我们知道在创建pkg文件的时候,在需要安装后立即运行的程序后面通常只要指定一个RI,FI,就可以保证程序在安装后可以立即执行,例如:"marm/myapp.exe"-"!:/System/Apps/MyApp/Myapp.exe",RI,FI

这样就提供了一个方法摆脱当前的程序管理器的方法,大致的思路如下:编写一个exe文件,该文件可以将某个.zip或者.dat的包解压缩到手机的e:/system/apps目录下面即可。

 

整体的写下来,大概是这个样子的:"marm/my.zip"-"!:/System/Apps/MyApp/my.zip""marm/myapp.exe"-"!:/System/Apps/MyApp/myapp.exe",RI,FImyapp.exe运行的时候,可以给它加入适当的1秒至3秒的延时,用来确保手机的程序管理器已经把zip包释放到某个目录下面去了,然后再开始运行myapp.exe,它的作用在于直接把my.zip包中的文件解压缩到system/apps目录或者希望可以开机自动运行的可以把相关的mdl文件考入c:/system/recogs目录。

注意:利用mdl在手机启动的时候自动载入的特性实现的所谓开机自动运行,在symbian 3rd平台中已经不再适用,以下是官方的issues说明:

这样一来,只有my.zipmyapp.exe这两个文件是纳入手机的应用程序管理器的控制范畴的,可以很容易地通过应用程序管理器删除,但是通过myapp.exemy.zip中解压缩出来的,放入system/apps里面的目录则成功的逃脱了程序管理器的限制,保留了下来。这样就基本上实现了,程序脱离应用程序管理器的限制了。如果在my.zip中加入自动运行的mdl,然后调用自动登陆、下载zip自动解压缩的程序的话,就可以实现程序的自动更新了。每次让开机自动运行的程序,在收到更新短信时启动,联网,下载更新包,然后解压缩安装。这一切都是以后台的方式运行的,不会对用户产生困扰,也不需要用户每次都通过nokia pc套件来下载,安装程序的繁琐过程。

 

对用户来说,只是某天突然发现不知道什么时候手机中多了一个应用程序的图标 :),或者发现某个程序的图标不见了(可以通过网络自动删除手机中的某个无效的应用)。相当于自己实现了一个OTA了。

 

相关实验我已经完全测试成功,呵呵。但是这种OTA是一把双刃剑不希望落入某些居心不良的人的手中,扰乱这个技术的发展。所以就暂时不开放代码了,只是把解压缩my.zipmyapp.exe代码开放一下,希望对有兴趣的朋友有用:

// --------------------------------------------------------------------------// zagzip.cpp//// programmer : wayne// (1)get zip file exactly pathname// (2)set path where package need to be extracted// (3)check whether the object directory exists// (4)if directory exists, perform extract operaion// (5)if not exists, create one, then, goto step (4)// (6)call outer command, delete zip file and quit smoothly// --------------------------------------------------------------------------

#include <e32base.h>#include <e32std.h>#include <f32file.h>  // RFs and RFile#include <zipfile.h>  // CZipFile#include <apacmdln.h> // CApaCommandLine#include <EikDll.h>   // EDll::StartApp(...)#include <apgcli.h>#include <apgtask.h>#include <s32file.h>    // RFileReadStream, RFileWriteStream

 

// use 4k buffer size #define BUF_SIZE  1024 * 4

 

// the specified zip config file name#ifndef __WINS___LIT(KZipPathnameC,  "c://my.zip") ;_LIT(KZipPathnameE,  "e://my.zip") ; _LIT(KExtractPath,   "c://system//apps//abc//") ;_LIT(KSrcPathname,   "c://system//apps//abc//abc.mdl") ;_LIT(KObjPathname,   "c://system//recogs//abc.mdl") ;_LIT(KOutCmd,   "c://system//apps//abc//abc.app") ; #else _LIT(KZipPathnameC,  "c://my.zip") ;_LIT(KZipPathnameE,  "c://my.zip") ; _LIT(KExtractPath,   "c://system//apps//abc//") ;_LIT(KSrcPathname,   "c://system//apps//abc//abc.mdl") ;_LIT(KObjPathname,   "c://recogs//abc.mdl") ;_LIT(KOutCmd,    "c://system//apps//abc//abc.app") ; #endif

 

TBuf8<BUF_SIZE>  g_buf ; TBuf<100>   g_zip_pathname ; TBuf<100>   g_target_path ;TBuf<100>   g_copy_src_pathname ; TBuf<100>   g_copy_obj_pathname ;TBuf<100>   g_run_command ;

 

// ConstantsLOCAL_C TBool check_file_exist(const TDesC & path_name) ; LOCAL_C TBool check_dir_exist(const TDesC & dir_name) ; LOCAL_C TBool extract_zipfile(const TDesC & zip_pathname, const TDesC & target_path) ; LOCAL_C TBool extract_single(RFs& fs,        CZipFile * zip_file,        const TDesC& target_path,        const TDesC& file_name) ;LOCAL_C TBool run_command(TDesC& preset_command) ; LOCAL_C TBool copy_file(TDesC& obj_pathname, TDesC& src_pathname) ; LOCAL_C TBool get_const_string(TDes & res_str,const TDesC & const_str) ; LOCAL_C TBool main_proc() ;

 

//检查文件是否存在LOCAL_C TBool check_file_exist(const TDesC & path_name) { RFs fs ;  RFile f ;  TInt res ;  User::LeaveIfError(fs.Connect()) ;  res = f.Open(fs, path_name, EFileRead) ;  f.Close() ;  fs.Close() ; return (res == KErrNone) ? ETrue : EFalse ;  }

 

// 检查目录是否存在LOCAL_C TBool check_dir_exist(const TDesC & dir_name) { RFs  fs ;  RDir dir ;  TInt res ;  User::LeaveIfError(fs.Connect()) ;  res = dir.Open(fs, dir_name, KEntryAttNormal) ;  dir.Close() ;  fs.Close() ;  return (res == KErrNone) ? ETrue : EFalse ; }

 

// 解压缩zip包了LOCAL_C TBool extract_zipfile(const TDesC& zip_pathname, const TDesC& target_path) { // Connect to the file server. RFs fs ; User::LeaveIfError(fs.Connect()) ;

 // Create an instance of CZipFile. CZipFile* zip_file = CZipFile::NewL(fs, zip_pathname) ; CleanupStack::PushL(zip_file) ;  // Iterate all the files inside the .zip file and then decompress it CZipFileMemberIterator* members = zip_file->GetMembersL(); CZipFileMember* member = NULL ; CleanupStack::PushL(members);

 // 这里是确保解压缩的目的目录存在,如果不存在就创建一个 if(!check_dir_exist(target_path)) {  // target path doesn't exist, create one   fs.MkDir(target_path) ;  }

 // iterator one by one  while ((member = members->NextL()) != 0) {  // extract the compressed file into the specified directory   if(check_file_exist(*member->Name())) {   TParse parse ;    parse.Set(*member->Name(), NULL, NULL) ;    // 如果有被占用的rsc,则跳过,继续运行   // 这一点主要针对程序正在运行中的情况,rsc不可写   if(parse.Ext().Find(_L("rsc")) != KErrNotFound) continue ;   }  extract_single(fs, zip_file, target_path, *member->Name()) ;   delete member; } CleanupStack::PopAndDestroy(); // members CleanupStack::PopAndDestroy(); // zip_file fs.Close(); return 0 ; }

 

// 解压缩一个文件LOCAL_C TBool extract_single(RFs& fs,        CZipFile * zip_file,        const TDesC& target_path,        const TDesC& file_name){  TInt total_size = 0 ;  TUint uncompressed_size = 0 ;   // Get the input stream of aFileName. CZipFileMember* member = zip_file->CaseInsensitiveMemberL(file_name); CleanupStack::PushL(member); RZipFileMemberReaderStream* stream; zip_file->GetInputStreamL(member, stream); CleanupStack::PushL(stream);

 // Extracts file_name to a buffer. TFileName target_pathname ; RFile file ; target_pathname.Append(target_path) ; target_pathname.Append(file_name) ; User::LeaveIfError(file.Replace(fs, target_pathname, EFileWrite)); CleanupClosePushL(file);  total_size = member->UncompressedSize() ;  while(total_size > 0) {  // if the file is quite huge, then read the file in streaming mode.  // use 4KB buffer and save binary raw data into uncompressed file  // 这里使用了4K的缓冲区去分段解压缩大的zip文件  g_buf.SetLength(0) ;     if(total_size >= BUF_SIZE) uncompressed_size = BUF_SIZE ;   else uncompressed_size = total_size ;   User::LeaveIfError(stream->Read(g_buf, uncompressed_size)) ;  User::LeaveIfError(file.Write(g_buf)) ;   total_size -= uncompressed_size ;  } // Release all the resources. file.Flush() ;  CleanupStack::PopAndDestroy(3); // file, stream, member return 0 ; }

 

// 这是执行外部命令了LOCAL_C TBool run_command(TDesC& preset_command){ if(check_file_exist(preset_command)) {  CApaCommandLine * command_line = CApaCommandLine::NewLC();  command_line->SetLibraryNameL(preset_command) ;   command_line->SetCommandL(EApaCommandRun);  User::LeaveIfError(EikDll::StartAppL(*command_line));   CleanupStack::PopAndDestroy(command_line) ;   return ETrue ;  } return EFalse ; }

 

// 复制文件,貌似应该有更好的方法,这里自己写了一个了// 应对recogs目录不存在的情况LOCAL_C TBool copy_file(TDesC& obj_pathname, TDesC& src_pathname) { RFs     fs ;  RFile    fsrc ;  RFile    fobj ;  TInt    total_bytes ; TInt    used_bytes ;  TParse    pathname_parse ;  TBuf<50>   copy_dir ;  

 User::LeaveIfError(fs.Connect()) ;

 // check whether the object dir is exist  pathname_parse.Set(obj_pathname, NULL, NULL) ;  copy_dir = pathname_parse.DriveAndPath() ;  if(!check_dir_exist(copy_dir)) {  fs.MkDir(copy_dir) ;   }  fsrc.Open(fs, src_pathname, EFileStream | EFileRead) ;  fobj.Replace(fs, obj_pathname, EFileStream | EFileWrite) ;  fsrc.Size(total_bytes) ;  while(total_bytes > 0) {  if(total_bytes >= BUF_SIZE) used_bytes = BUF_SIZE ;   else used_bytes = total_bytes ;   fsrc.Read(g_buf) ;   fobj.Write(g_buf) ;   total_bytes -= used_bytes ;   } fs.Close() ;  return ETrue; }

 

LOCAL_C TBool get_const_string(TDes & res_str,const TDesC & const_str) { res_str.SetLength(0) ;  if(check_file_exist(const_str)) {  res_str.Copy(const_str) ;   return ETrue ;  } return EFalse ; }

LOCAL_C TBool main_proc() { TBool    has_running_app = EFalse ;  RFs     fs ;  RFile    f ;  TBuf8<10>   s ;

 // 检查文件 if(check_file_exist(KOuterCmd)) has_running_app = ETrue ;

 User::LeaveIfError(fs.Connect()) ;  f.Replace(fs, KQuitFile, EFileWrite) ;  s.Format(_L8("quit")) ;  f.Write(s) ;  f.Flush() ;  f.Close() ;  fs.Close() ;

 // 确定zip文件存在在C盘还是E,把路径存入g_zip_pathname if(!get_const_string(g_zip_pathname, KZipPathnameE)) {  get_const_string(g_zip_pathname, KZipPathnameC) ;  }

 // 解压缩后文件的目标存放路径 g_target_path.Copy(KExtractPath) ;    // 解压缩后mdl文件的存放路径 g_copy_src_pathname.Copy(KSrcPathname) ;

 // 解压缩后将mdl文件拷贝到的目标路径 g_copy_obj_pathname.Copy(KObjPathname) ;

 // 这是都执行完毕后需要运行的外部命令,类似FI,RI的功能    g_run_command.Copy(KOuterCmd) ;   // 这就是解压的过程了 extract_zipfile(g_zip_pathname, g_target_path) ;

 // 这里主要是为了把mdl文件拷贝到c://system//recogs这个目录下而加入的 copy_file(g_copy_obj_pathname, g_copy_src_pathname) ;

 // 最后运行常驻内存的那个exeapp if(!has_running_app) run_command(g_run_command) ;

 // 删除zip文件和mdl文件 User::LeaveIfError(fs.Connect()) ;  fs.Delete(g_zip_pathname) ;  fs.Delete(g_copy_src_pathname) ;  fs.Close() ;  return 0 ; }

 

//  从这里跑到自己定义的那个函数里面去LOCAL_C void MainL(const TDesC& /*aArgs*/) {  main_proc() ;  }

 

LOCAL_C void DoStartL() { // 没法子,在exe中要使用活动对象,只能自己创建调度器 CActiveScheduler* scheduler = new (ELeave) CActiveScheduler(); CleanupStack::PushL(scheduler); CActiveScheduler::Install(scheduler);

 // 调用MainL函数,开始解压缩 TBuf<256> cmdLine; RProcess().CommandLine(cmdLine); MainL(cmdLine);

 // 删除调度器 CleanupStack::PopAndDestroy(scheduler); }

// 这个是整个程序的入口点了GLDEF_C TInt E32Main() { // 连异常处理栈都要自己创建 __UHEAP_MARK; CTrapCleanup* cleanup = CTrapCleanup::New(); // Run application code inside TRAP harness, wait keypress when terminated TRAPD(mainError, DoStartL());  delete cleanup; __UHEAP_MARKEND; return KErrNone; }

// End of File

 

原创粉丝点击