首页 文章 精选 留言 我的

精选列表

搜索[子流程],共10000篇文章
优秀的个人博客,低调大师

hive执行流程(2)-CommandProcessor相关类

在 上一篇的CliDriver类中介绍了CliDriver类会引用到CommandProcessor相关类,主要是根据命令来判断具体实现类,比如通过本地的hive cli启动时,运行hive的命令(非list/source/shell命令等)时在processCmd方法中有如下实现: 1 2 3 4 5 6 7 8 try { CommandProcessorproc=CommandProcessorFactory.get(tokens,(HiveConf)conf); //根据命令判断具体的CommandProcessor实现类 ret=processLocalCmd(cmd,proc,ss); } catch (SQLExceptione){ console.printError( "Failedprocessingcommand" +tokens[ 0 ]+ "" +e.getLocalizedMessage(), org.apache.hadoop.util.StringUtils.stringifyException(e)); ret= 1 ; } 具体的决定什么样的命令对应什么样的具体实现类由 CommandProcessorFactory 规定:如果是set,reset,dfs,add delete,compile等命令,返回对应的CommandProcessor实现类。其余有效命令比如select,insert 都是返回Driver类。 CommandProcessor相关类在org.apache.hadoop.hive.ql.processors包中,类的具体的uml图如下: 简单看下几个类的实现: 1.HiveCommand类,是一个迭代类,定义了非sql的一些语句 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public enum HiveCommand{ SET(), RESET(), DFS(), ADD(), DELETE(), COMPILE(); private static final Set<String>COMMANDS= new HashSet<String>(); static { for (HiveCommandcommand:HiveCommand.values()){ COMMANDS.add(command.name()); } } public static HiveCommandfind(String[]command){ if ( null ==command){ return null ; } Stringcmd=command[ 0 ]; if (cmd!= null ){ cmd=cmd.trim().toUpperCase(); if (command.length> 1 && "role" .equalsIgnoreCase(command[ 1 ])){ //specialhandlingforsetroler1statement return null ; } else if (COMMANDS.contains(cmd)){ return HiveCommand.valueOf(cmd); } } return null ; } } 2.CommandProcessorFactory 类,主要用于获取具体的命令实现类 主要定义了get和getForHiveCommand方法 方法调用get----->getForHiveCommand,其中getForHiveCommand会调HiveCommand类,HiveCommand类是一个枚举类型,定义了一些命令。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 getForHiveCommand方法中: public static CommandProcessorgetForHiveCommand(String[]cmd,HiveConfconf) throws SQLException{ HiveCommandhiveCommand=HiveCommand.find(cmd); //sql语句返回值为null if (hiveCommand== null ||isBlank(cmd[ 0 ])){ return null ; } if (conf== null ){ conf= new HiveConf(); } Set<String>availableCommands= new HashSet<String>(); for (StringavailableCommand:conf.getVar(HiveConf.ConfVars.HIVE_SECURITY_COMMAND_WHITELIST).split( "," )){ availableCommands.add(availableCommand.toLowerCase().trim()); } if (!availableCommands.contains(cmd[ 0 ].trim().toLowerCase())){ throw new SQLException( "Insufficientprivilegestoexecute" +cmd[ 0 ], "42000" ); } switch (hiveCommand){ //每种语句对应的具体的processor类 case SET: return new SetProcessor(); case RESET: return new ResetProcessor(); case DFS: SessionStatess=SessionState.get(); return new DfsProcessor(ss.getConf()); case ADD: return new AddResourceProcessor(); case DELETE: return new DeleteResourceProcessor(); case COMPILE: return new CompileProcessor(); default : throw new AssertionError( "UnknownHiveCommand" +hiveCommand); } } get方法: public static CommandProcessorget(String[]cmd,HiveConfconf) throws SQLException{ CommandProcessorresult=getForHiveCommand(cmd,conf); if (result!= null ){ return result; //如果result不为空,即命令在HiveCommand的迭代器中定义的话,直接返回对应的结果 } if (isBlank(cmd[ 0 ])){ return null ; } else { //为空的话返回Driver类的实例 if (conf== null ){ return new Driver(); } Driverdrv=mapDrivers.get(conf); if (drv== null ){ drv= new Driver(); mapDrivers.put(conf,drv); } drv.init(); return drv; } } 3.CommandProcessorResponse类封装了processor的返回信息,比如返回码,错误信息等。 4.CommandProcessor 类是一个接口,具体的实现类由下面几个: 1 AddResourceProcessor/CompileProcessor/DeleteResourceProcessor/DfsProcessor/ResetProcessor/SetProcessor/Driver 主要实现方法在各个实现类的run方法中,run方法返回一个CommandProcessorResponse的对象。 下面简单的说下常用的几个实现类: a.AddResourceProcessor类是处理add xxx命令的。 主要有两个步骤: 1)判断命令的合法性(长度,类型是否在FILE,JAR,ARCHIVE3种之内) 2)调用SessionState的add_resource方法( 1 2 SessionState.add_resource方法---->调用SessionState.downloadResource---> 调用FileSystem的copyToLocalFile方法,把文件下载到本地 ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public CommandProcessorResponserun(Stringcommand){ SessionStatess=SessionState.get(); command= new VariableSubstitution().substitute(ss.getConf(),command); String[]tokens=command.split( "\\s+" ); SessionState.ResourceTypet; if (tokens.length< 2 ||(t=SessionState.find_resource_type(tokens[ 0 ]))== null ){ console.printError( "Usage:add[" +StringUtils.join(SessionState.ResourceType.values(), "|" ) + "]<value>[<value>]*" ); return new CommandProcessorResponse( 1 ); } for ( int i= 1 ;i<tokens.length;i++){ StringresourceFile=ss.add_resource(t,tokens[i]); if (resourceFile== null ){ StringerrMsg=tokens[i]+ "doesnotexist." ; return new CommandProcessorResponse( 1 ,errMsg, null ); } } return new CommandProcessorResponse( 0 ); } b.相反的DeleteResourceProcessor是用来处理delete xxx命令的。 最终调用了SessionState的delete_resource方法,把resource从HashMap中去掉。 1 2 3 4 5 6 7 8 9 10 11 12 SessionState的delete_resource方法 public boolean delete_resource(ResourceTypet,Stringvalue){ if (resource_map.get(t)== null ){ return false ; } if (t.hook!= null ){ if (!t.hook.postHook(resource_map.get(t),value)){ return false ; } } return (resource_map.get(t).remove(value)); } c.DfsProcessor类用来处理dfs 命令,即已“!dfs”开头的命令,最终调用了FsShell的run方法 d.SetProcessor类用来处理set xxx等命令,可以用来设置参数,变量等。 设置参数时 1)以system: 开头的调用了System.getProperties().setProperty方法。 比如 1 2 3 hive>setsystem:user.name=xxxx; hive>setsystem:user.name; system:user.name=xxxx 2)以hiveconf:开头: 调用了HiveConf的verifyAndSet方法 3)以hivevar:开头: ss.getHiveVariables().put方法 Driver的实现比较复杂,放在下篇讲解。 本文转自菜菜光 51CTO博客,原文链接:http://blog.51cto.com/caiguangguang/1566936,如需转载请自行联系原作者

优秀的个人博客,低调大师

android休眠唤醒驱动流程分析【转】

转自:http://blog.csdn.net/hanmengaidudu/article/details/11777501 标准linux休眠过程: l power management notifiers are executed with PM_SUSPEND_PREPARE l tasks are frozen l target system sleep state is announced to the platform-handling code l devices are suspended l platform-specific global suspend preparation methods are executed l non-boot CPUs are taken off-line l interrupts are disabled on the remaining (main) CPU l late suspend of devices is carried out (一般有一些BUS driver的动作进行)‏ l platform-specific global methods are invoked to put the system to sleep 标准linux唤醒过程: l the main CPU is switched to the appropriate mode, if necessary l early resume of devices is carried out (一般有一些BUS driver的动作进行)‏ l interrupts are enabled on the main CPU l non-boot CPUs are enabled l platform-specific global resume preparation methods are invoked l devices are woken up l tasks are thawed l power management notifiers are executed with PM_POST_SUSPEND 用户可以通过sys文件系统控制系统进入休眠: 查看系统支持的休眠方式: #cat /sys/power/state 常见有standby(suspend to RAM)、mem(suspend to RAM)和disk(suspend to disk),只是standby耗电更多,返回到正常工作状态的时间更短。 通过#echo mem > /sys/power/state让系统进入休眠。 Android休眠与唤醒 android是在传统的linux内核电源管理设计的基础上,结合手机设计的实际需求而进化出的一套电源管理系统,其核心内容有:wakelock、early_suspend与late_resume。 wakelock在Android的电源管理系统中扮演一个核心的角色。wakelock是一种锁的机制,只要有人拿着这个锁,系统就无法进入休眠,可以被用户态程序和内核获得。这个锁可以是有超时的或者是没有超时的,超时的锁会在时间过去以后自动解锁。如果没有锁了或者超时了,内核就会启动休眠的那套机制来进入休眠。 当系统在启动完毕后,会自己去加一把名为“main“的锁,而当系统有意愿去睡眠时则会先去释放这把“main”锁,在android中,在early_suspend的最后一步会去释放“main”锁(wake_unlock: main)。释放完后则会去检查是否还有其他存在的锁,如果没有则直接进入睡眠过程。 它的缺点是,如果有某一应用获锁而不释放或者因一直在执行某种操作而没时间来释放的话,则会导致系统一直进入不了睡眠状态,功耗过大。 early_suspend:先与linux内核的睡眠过程被调用。一般在手机系统的设计中对背光的操作等采用此类方法,因为背光需要的能耗过大。当然此操作与late_resume是配套使用的。一些在内核中要预先进行处理的事件可以先注册上early_suspend函数,当系统要进入睡眠之前会首先调用这些注册的函数。 本文中,linux kernel版本为linux-2.6.29,android版本为android 2.1 与android休眠唤醒主要相关的文件主要有: l linux_source/kernel/power/main.c l linux_source/kernel/power/earlysuspend.c l linux_source/kernel/power/wakelock.c l linux_source/kernel/power/process.c l linux_source/driver/base/power/main.c l linux_source/arch/xxx/mach-xxx/pm.c或linux_source/arch/xxx/plat-xxx/pm.c Android休眠过程如下: 当用户读写/sys/power/state时,linux_source/kernel/power/main.c中的state_store()函数会被调用。其中,android的early_suspend会执行request_suspend_state(state);而标准的linux休眠则执行error = enter_state(state); static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { #ifdef CONFIG_SUSPEND #ifdef CONFIG_EARLYSUSPEND suspend_state_t state = PM_SUSPEND_ON; #else suspend_state_t state = PM_SUSPEND_STANDBY; #endif const char * const *s; #endif char *p; int len; int error = -EINVAL; p = memchr(buf, '\n', n); len = p ? p - buf : n; /* First, check if we are requested to hibernate */ if (len == 4 && !strncmp(buf, "disk", len)) { error = hibernate(); goto Exit; } #ifdef CONFIG_SUSPEND for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) { if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) break; } if (state < PM_SUSPEND_MAX && *s) #ifdef CONFIG_EARLYSUSPEND if (state == PM_SUSPEND_ON || valid_state(state)) { error = 0; request_suspend_state(state); } #else error = enter_state(state); #endif #endif Exit: return error ? error : n; } 在request_suspend_state(state)函数中,会调用early_suspend_work的工作队列,从而进入early_suspend()函数中。 static DECLARE_WORK(early_suspend_work, early_suspend); void request_suspend_state(suspend_state_t new_state) { unsigned long irqflags; int old_sleep; spin_lock_irqsave(&state_lock, irqflags); old_sleep = state & SUSPEND_REQUESTED; if (debug_mask & DEBUG_USER_STATE) { struct timespec ts; struct rtc_time tm; getnstimeofday(&ts); rtc_time_to_tm(ts.tv_sec, &tm); pr_info("request_suspend_state: %s (%d->%d) at %lld " "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", new_state != PM_SUSPEND_ON ? "sleep" : "wakeup", requested_suspend_state, new_state, ktime_to_ns(ktime_get()), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); } if (!old_sleep && new_state != PM_SUSPEND_ON) { state |= SUSPEND_REQUESTED; queue_work(suspend_work_queue, &early_suspend_work); } else if (old_sleep && new_state == PM_SUSPEND_ON) { state &= ~SUSPEND_REQUESTED; wake_lock(&main_wake_lock); queue_work(suspend_work_queue, &late_resume_work); } requested_suspend_state = new_state; spin_unlock_irqrestore(&state_lock, irqflags); } 在early_suspend()函数中,首先要判断当前请求的状态是否还是suspend,若不是,则直接退出了;若是,函数会调用已经注册的early_suspend的函数。然后同步文件系统,最后释放main_wake_lock。 static void early_suspend(struct work_struct *work) { struct early_suspend *pos; unsigned long irqflags; int abort = 0; mutex_lock(&early_suspend_lock); spin_lock_irqsave(&state_lock, irqflags); if (state == SUSPEND_REQUESTED) state |= SUSPENDED; else abort = 1; spin_unlock_irqrestore(&state_lock, irqflags); if (abort) { if (debug_mask & DEBUG_SUSPEND) pr_info("early_suspend: abort, state %d\n", state); mutex_unlock(&early_suspend_lock); goto abort; } if (debug_mask & DEBUG_SUSPEND) pr_info("early_suspend: call handlers\n"); list_for_each_entry(pos, &early_suspend_handlers, link) { if (pos->suspend != NULL) pos->suspend(pos); } mutex_unlock(&early_suspend_lock); if (debug_mask & DEBUG_SUSPEND) pr_info("early_suspend: sync\n"); sys_sync(); abort: spin_lock_irqsave(&state_lock, irqflags); if (state == SUSPEND_REQUESTED_AND_SUSPENDED) wake_unlock(&main_wake_lock); spin_unlock_irqrestore(&state_lock, irqflags); } 在wake_unlock()中,删除链表中wake_lock节点,判断当前是否存在wake_lock,若wake_lock的数目为0,则调用工作队列suspend_work,进入suspend状态。 static DECLARE_WORK(suspend_work, suspend); void wake_unlock(struct wake_lock *lock) { int type; unsigned long irqflags; spin_lock_irqsave(&list_lock, irqflags); type = lock->flags & WAKE_LOCK_TYPE_MASK; #ifdef CONFIG_WAKELOCK_STAT wake_unlock_stat_locked(lock, 0); #endif if (debug_mask & DEBUG_WAKE_LOCK) pr_info("wake_unlock: %s\n", lock->name); lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE); list_del(&lock->link); list_add(&lock->link, &inactive_locks); if (type == WAKE_LOCK_SUSPEND) { long has_lock = has_wake_lock_locked(type); if (has_lock > 0) { if (debug_mask & DEBUG_EXPIRE) pr_info("wake_unlock: %s, start expire timer, " "%ld\n", lock->name, has_lock); mod_timer(&expire_timer, jiffies + has_lock); } else { if (del_timer(&expire_timer)) if (debug_mask & DEBUG_EXPIRE) pr_info("wake_unlock: %s, stop expire " "timer\n", lock->name); if (has_lock == 0) queue_work(suspend_work_queue, &suspend_work); } if (lock == &main_wake_lock) { if (debug_mask & DEBUG_SUSPEND) print_active_locks(WAKE_LOCK_SUSPEND); #ifdef CONFIG_WAKELOCK_STAT update_sleep_wait_stats_locked(0); #endif } } spin_unlock_irqrestore(&list_lock, irqflags); } 在suspend()函数中,先判断当前是否有wake_lock,若有,则退出;然后同步文件系统,最后调用pm_suspend()函数。 static void suspend(struct work_struct *work) { int ret; int entry_event_num; if (has_wake_lock(WAKE_LOCK_SUSPEND)) { if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: abort suspend\n"); return; } entry_event_num = current_event_num; sys_sync(); if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: enter suspend\n"); ret = pm_suspend(requested_suspend_state); if (debug_mask & DEBUG_EXIT_SUSPEND) { struct timespec ts; struct rtc_time tm; getnstimeofday(&ts); rtc_time_to_tm(ts.tv_sec, &tm); pr_info("suspend: exit suspend, ret = %d " "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); } if (current_event_num == entry_event_num) { if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: pm_suspend returned with no event\n"); wake_lock_timeout(&unknown_wakeup, HZ / 2); } } 在pm_suspend()函数中,enter_state()函数被调用,从而进入 标准linux休眠过程。 intpm_suspend(suspend_state_t state) { if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX) return enter_state(state); return -EINVAL; } 在enter_state()函数中,首先检查一些状态参数,再同步文件系统,然后调用suspend_prepare()来冻结进程,最后调用suspend_devices_and_enter()让外设进入休眠。 static intenter_state(suspend_state_t state) { int error; if (!valid_state(state)) return -ENODEV; if (!mutex_trylock(&pm_mutex)) return -EBUSY; printk(KERN_INFO "PM: Syncing filesystems ... "); sys_sync(); printk("done.\n"); pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); error = suspend_prepare(); if (error) goto Unlock; if (suspend_test(TEST_FREEZER)) goto Finish; pr_debug("PM: Entering %s sleep\n", pm_states[state]); error = suspend_devices_and_enter(state); Finish: pr_debug("PM: Finishing wakeup.\n"); suspend_finish(); Unlock: mutex_unlock(&pm_mutex); return error; } 在suspend_prepare()函数中,先通过pm_prepare_console();给suspend分配一个虚拟终端来输出信息,再广播一个系统进入suspend的通报,关闭用户态的helper进程,然后调用suspend_freeze_processes()来冻结进程,最后会尝试释放一些内存。 static int suspend_prepare(void) { int error; unsigned int free_pages; if (!suspend_ops || !suspend_ops->enter) return -EPERM; pm_prepare_console(); error = pm_notifier_call_chain(PM_SUSPEND_PREPARE); if (error) goto Finish; error = usermodehelper_disable(); if (error) goto Finish; if (suspend_freeze_processes()){ error = -EAGAIN; goto Thaw; } free_pages = global_page_state(NR_FREE_PAGES); if (free_pages < FREE_PAGE_NUMBER) { pr_debug("PM: free some memory\n"); shrink_all_memory(FREE_PAGE_NUMBER - free_pages); if (nr_free_pages() < FREE_PAGE_NUMBER) { error = -ENOMEM; printk(KERN_ERR "PM: No enough memory\n"); } } if (!error) return 0; Thaw: suspend_thaw_processes(); usermodehelper_enable(); Finish: pm_notifier_call_chain(PM_POST_SUSPEND); pm_restore_console(); return error; } 在suspend_freeze_processes()函数中调用了freeze_processes()函数,而freeze_processes()函数中又调用了try_to_freeze_tasks()来完成冻结任务。在冻结过程中,会判断当前进程是否有wake_lock,若有,则冻结失败,函数会放弃冻结。 static int try_to_freeze_tasks(bool sig_only) { struct task_struct *g, *p; unsigned long end_time; unsigned int todo; struct timeval start, end; u64 elapsed_csecs64; unsigned int elapsed_csecs; unsigned int wakeup = 0; do_gettimeofday(&start); end_time = jiffies + TIMEOUT; do { todo = 0; read_lock(&tasklist_lock); do_each_thread(g, p) { if (frozen(p) || !freezeable(p)) continue; if (!freeze_task(p, sig_only)) continue; /* * Now that we've done set_freeze_flag, don't * perturb a task in TASK_STOPPED or TASK_TRACED. * It is "frozen enough".If the task does wake * up, it will immediately call try_to_freeze. */ if (!task_is_stopped_or_traced(p) && !freezer_should_skip(p)) todo++; } while_each_thread(g, p); read_unlock(&tasklist_lock); yield(); /* Yield is okay here */ if (todo && has_wake_lock(WAKE_LOCK_SUSPEND)) { wakeup = 1; break; } if (time_after(jiffies, end_time)) break; } while (todo); do_gettimeofday(&end); elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start); do_div(elapsed_csecs64, NSEC_PER_SEC / 100); elapsed_csecs = elapsed_csecs64; if (todo) { /* This does not unfreeze processes that are already frozen * (we have slightly ugly calling convention in that respect, * and caller must call thaw_processes() if something fails), * but it cleans up leftover PF_FREEZE requests. */ if(wakeup) { printk("\n"); printk(KERN_ERR "Freezing of %s aborted\n", sig_only ? "user space " : "tasks "); } else { printk("\n"); printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds " "(%d tasks refusing to freeze):\n", elapsed_csecs / 100, elapsed_csecs % 100, todo); show_state(); } read_lock(&tasklist_lock); do_each_thread(g, p) { task_lock(p); if (freezing(p) && !freezer_should_skip(p)) printk(KERN_ERR " %s\n", p->comm); cancel_freezing(p); task_unlock(p); } while_each_thread(g, p); read_unlock(&tasklist_lock); } else { printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100, elapsed_csecs % 100); } return todo ? -EBUSY : 0; } 到现在,所有的进程(也包括workqueue/kthread)都已经停止了,内核态进程有可能在停止的时候握有一些信号量,所以如果这时候在外设里面去解锁这个信号量有可能会发生死锁,所以在外设suspend()函数里面作lock/unlock锁要非常小心,建议不要在外设的suspend()里面等待锁。而且suspend的过程中,有一些log是无法输出的,所以一旦出现问题,非常难调试。 回到 enter_state()函数中,再冻结进程完成后,调用suspend_devices_and_enter()函数让外设进入休眠。该函数中,首先休眠串口(之后不能再显示log,解决方法为在kernel配置选项的cmd_line中,添加”no_console_suspend”选项),再通过device_suspend()函数调用各驱动的suspend函数。 当外设进入休眠后,suspend_ops->prepare()被调用,suspend_ops是板级的PM操作(本文中粉红色的函数,依赖于具体的平台),以s3c6410为例,其注册在linux_source/arch/arm/plat-s3c64xx/pm.c中,只定义了suspend_ops->enter()函数。 static struct platform_suspend_ops s3c6410_pm_ops = { .enter = s3c6410_pm_enter, .valid = suspend_valid_only_mem, }; 接下来,多CPU中的非启动CPU被关闭。 int suspend_devices_and_enter(suspend_state_t state) { int error; if (!suspend_ops) return -ENOSYS; if (suspend_ops->begin) { error = suspend_ops->begin(state); if (error) goto Close; } suspend_console(); suspend_test_start(); error = device_suspend(PMSG_SUSPEND); if (error) { printk(KERN_ERR "PM: Some devices failed to suspend\n"); goto Recover_platform; } suspend_test_finish("suspend devices"); if (suspend_test(TEST_DEVICES)) goto Recover_platform; if (suspend_ops->prepare) { error = suspend_ops->prepare(); if (error) goto Resume_devices; } if (suspend_test(TEST_PLATFORM)) goto Finish; error = disable_nonboot_cpus(); if (!error && !suspend_test(TEST_CPUS)) suspend_enter(state); enable_nonboot_cpus(); Finish: if (suspend_ops->finish) suspend_ops->finish(); Resume_devices: suspend_test_start(); device_resume(PMSG_RESUME); suspend_test_finish("resume devices"); resume_console(); Close: if (suspend_ops->end) suspend_ops->end(); return error; Recover_platform: if (suspend_ops->recover) suspend_ops->recover(); goto Resume_devices; } 接下来suspend_enter()被调用,该函数首先关闭IRQ,然后调用device_power_down(),它会调用suspend_late()函数,这个函数是系统真正进入休眠最后调用的函数,通常会在这个函数中作最后的检查,接下来休眠所有的系统设备和总线。最后调用suspend_pos->enter()来使CPU进入省电状态。这时候,整个休眠过程完成,代码的执行也就停在这里了。 static int suspend_enter(suspend_state_t state) { int error = 0; device_pm_lock(); #ifdef CONFIG_CPU_FREQ cpufreq_get_cpufreq_name(0); strcpy(governor_name, cpufreq_governor_name); if(strnicmp(governor_name, userspace_governor, CPUFREQ_NAME_LEN)) { cpufreq_set_policy(0, "performance"); } #endif /* CONFIG_CPU_FREQ */ arch_suspend_disable_irqs(); BUG_ON(!irqs_disabled()); if ((error = device_power_down(PMSG_SUSPEND))){ printk(KERN_ERR "PM: Some devices failed to power down\n"); goto Done; } error = sysdev_suspend(PMSG_SUSPEND); if (!error) { if (!suspend_test(TEST_CORE)) error = suspend_ops->enter(state); sysdev_resume(); } device_power_up(PMSG_RESUME); Done: arch_suspend_enable_irqs(); #ifdef CONFIG_CPU_FREQ if(strnicmp(governor_name, userspace_governor, CPUFREQ_NAME_LEN)) { cpufreq_set_policy(0, governor_name); } #endif /* CONFIG_CPU_FREQ */ BUG_ON(irqs_disabled()); device_pm_unlock(); return error; } 在suspend_pos->enter()所对应的函数中,代码最终停止在pm_cpu_sleep();处。 static int s3c6410_pm_enter(suspend_state_t state) { …… s3c6410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save)); s3c6410_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); s3c6410_pm_do_save(core_save, ARRAY_SIZE(core_save)); s3c6410_pm_do_save(sromc_save, ARRAY_SIZE(sromc_save)); /* Clear WAKEUP_STAT register for next wakeup -jc.lee */ /* If this register do not be cleared, Wakeup will be failed */ __raw_writel(__raw_readl(S3C_WAKEUP_STAT), S3C_WAKEUP_STAT); #ifdef CONFIG_MACH_SMDK6410 /* ALL sub block "ON" before enterring sleep mode - EVT0 bug*/ __raw_writel(0xffffff00, S3C_NORMAL_CFG); /* Open all clock gate to enter sleep mode - EVT0 bug*/ __raw_writel(0xffffffff, S3C_HCLK_GATE); __raw_writel(0xffffffff, S3C_PCLK_GATE); __raw_writel(0xffffffff, S3C_SCLK_GATE); …… /* s3c6410_cpu_save will also act as our return point from when * we resume as it saves its own register state, so use the return * code to differentiate return from save and return from sleep */ if (s3c6410_cpu_save(regs_save) == 0) { flush_cache_all(); pm_cpu_sleep(); } /* restore the cpu state */ cpu_init(); __raw_writel(s3c_eint_mask_val, S3C_EINT_MASK); /* restore the system state */ s3c6410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); s3c6410_pm_do_restore(sromc_save, ARRAY_SIZE(sromc_save)); …… } Android唤醒过程如下: 如果在休眠中系统被中断或者其他事件唤醒,接下来的代码就从suspend完成的地方开始执行,以s3c6410为例,即pm.c中的s3c6410_pm_enter()中的cpu_init(),然后执行suspend_enter()的sysdev_resume()函数,唤醒系统设备和总线,使能系统中断。 static int suspend_enter(suspend_state_t state) { int error = 0; device_pm_lock(); #ifdef CONFIG_CPU_FREQ cpufreq_get_cpufreq_name(0); strcpy(governor_name, cpufreq_governor_name); if(strnicmp(governor_name, userspace_governor, CPUFREQ_NAME_LEN)) { cpufreq_set_policy(0, "performance"); } #endif /* CONFIG_CPU_FREQ */ arch_suspend_disable_irqs(); BUG_ON(!irqs_disabled()); if ((error = device_power_down(PMSG_SUSPEND))) { printk(KERN_ERR "PM: Some devices failed to power down\n"); goto Done; } error = sysdev_suspend(PMSG_SUSPEND); if (!error) { if (!suspend_test(TEST_CORE)) error = suspend_ops->enter(state);//suspend过程完成处 sysdev_resume(); } device_power_up(PMSG_RESUME); Done: arch_suspend_enable_irqs(); #ifdef CONFIG_CPU_FREQ if(strnicmp(governor_name, userspace_governor, CPUFREQ_NAME_LEN)) { cpufreq_set_policy(0, governor_name); } #endif /* CONFIG_CPU_FREQ */ BUG_ON(irqs_disabled()); device_pm_unlock(); return error; } 然后回到suspend_devices_and_enter()函数中,使能休眠时候停止掉的非启动CPU,继续唤醒每个设备,使能终端。 int suspend_devices_and_enter(suspend_state_t state) { int error; if (!suspend_ops) return -ENOSYS; if (suspend_ops->begin) { error = suspend_ops->begin(state); if (error) goto Close; } suspend_console(); suspend_test_start(); error = device_suspend(PMSG_SUSPEND); if (error) { printk(KERN_ERR "PM: Some devices failed to suspend\n"); goto Recover_platform; } suspend_test_finish("suspend devices"); if (suspend_test(TEST_DEVICES)) goto Recover_platform; if (suspend_ops->prepare) { error = suspend_ops->prepare(); if (error) goto Resume_devices; } if (suspend_test(TEST_PLATFORM)) goto Finish; error = disable_nonboot_cpus(); if (!error && !suspend_test(TEST_CPUS)) suspend_enter(state);//suspend过程完成处 enable_nonboot_cpus(); Finish: if (suspend_ops->finish) suspend_ops->finish(); Resume_devices: suspend_test_start(); device_resume(PMSG_RESUME); suspend_test_finish("resume devices"); resume_console(); Close: if (suspend_ops->end) suspend_ops->end(); return error; Recover_platform: if (suspend_ops->recover) suspend_ops->recover(); goto Resume_devices; } 当suspend_devices_and_enter()执行完成后,系统外设已经唤醒,但进程依然是冻结的状态,返回到enter_state函数中,调用suspend_finish()函数。 static int enter_state(suspend_state_t state) { int error; if (!valid_state(state)) return -ENODEV; if (!mutex_trylock(&pm_mutex)) return -EBUSY; printk(KERN_INFO "PM: Syncing filesystems ... "); sys_sync(); printk("done.\n"); pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); error = suspend_prepare(); if (error) goto Unlock; if (suspend_test(TEST_FREEZER)) goto Finish; pr_debug("PM: Entering %s sleep\n", pm_states[state]); error = suspend_devices_and_enter(state);//suspend过程完成处 Finish: pr_debug("PM: Finishing wakeup.\n"); suspend_finish(); Unlock: mutex_unlock(&pm_mutex); return error; } 在suspend_finish()函数中,解冻进程和任务,使能用户空间helper进程,广播一个系统从suspend状态退出的notify,唤醒终端。 static void suspend_finish(void) { suspend_thaw_processes(); usermodehelper_enable(); pm_notifier_call_chain(PM_POST_SUSPEND); pm_restore_console(); } 当所有的唤醒已经结束以后,用户进程都已经开始运行了,但没点亮屏幕,唤醒通常会是以下的几种原因: 如果是来电,那么Modem会通过发送命令给rild来让rild通知WindowManager有来电响应,这样就会远程调用PowerManagerService来写”on”到/sys/power/state来调用late resume(),执行点亮屏幕等操作。 用户按键事件会送到WindowManager中,WindowManager会处理这些按键事件,按键分为几种情况,如果按键不是唤醒键,那么WindowManager会主动放弃wakeLock来使系统进入再次休眠;如果按键是唤醒键,那么WindowManger就会调用PowerManagerService中的接口来执行late Resume。 当”on”被写入到/sys/power/state之后,同early_suspend过程,request_suspend_state()被调用,只是执行的工作队列变为 late_resume_work。在late_resume函数中,唤醒调用了early_suspend的设备。 static DECLARE_WORK(late_resume_work, late_resume); static void late_resume(struct work_struct *work) { struct early_suspend *pos; unsigned long irqflags; int abort = 0; mutex_lock(&early_suspend_lock); spin_lock_irqsave(&state_lock, irqflags); if (state == SUSPENDED) state &= ~SUSPENDED; else abort = 1; spin_unlock_irqrestore(&state_lock, irqflags); if (abort) { if (debug_mask & DEBUG_SUSPEND) pr_info("late_resume: abort, state %d\n", state); goto abort; } if (debug_mask & DEBUG_SUSPEND) pr_info("late_resume: call handlers\n"); list_for_each_entry_reverse(pos, &early_suspend_handlers, link) if (pos->resume != NULL) pos->resume(pos); if (debug_mask & DEBUG_SUSPEND) pr_info("late_resume: done\n"); abort: mutex_unlock(&early_suspend_lock); } 关于wake_lock 在上文中,已经介绍了wakelock机制,下面从代码的角度进行介绍。 wakelock有3种类型,常用为WAKE_LOCK_SUSPEND,作用是防止系统进入睡眠。其他类型不是很清楚。 enum { WAKE_LOCK_SUSPEND, /* Prevent suspend */ WAKE_LOCK_IDLE, /* Prevent low power idle */ WAKE_LOCK_TYPE_COUNT }; Wakelock有加锁和解锁2种操作,加锁有2种方式,第一种是永久加锁(wake_lock),这种锁必须手动的解锁;另一种是超时锁(wake_lock_timeout),这种锁在过去指定时间后,会自动解锁。 void wake_lock(struct wake_lock *lock) { wake_lock_internal(lock, 0, 0); } void wake_lock_timeout(struct wake_lock *lock, long timeout) { wake_lock_internal(lock, timeout, 1); } 对于wakelock,timeout = has_timeout = 0;直接加锁后,然后退出; static void wake_lock_internal( struct wake_lock *lock, long timeout, int has_timeout) { int type; unsigned long irqflags; long expire_in; spin_lock_irqsave(&list_lock, irqflags); type = lock->flags & WAKE_LOCK_TYPE_MASK; BUG_ON(type >= WAKE_LOCK_TYPE_COUNT); BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED)); #ifdef CONFIG_WAKELOCK_STAT if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) { if (debug_mask & DEBUG_WAKEUP) pr_info("wakeup wake lock: %s\n", lock->name); wait_for_wakeup = 0; lock->stat.wakeup_count++; } if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) && (long)(lock->expires - jiffies) <= 0) { wake_unlock_stat_locked(lock, 0); lock->stat.last_time = ktime_get(); } #endif if (!(lock->flags & WAKE_LOCK_ACTIVE)) { lock->flags |= WAKE_LOCK_ACTIVE; #ifdef CONFIG_WAKELOCK_STAT lock->stat.last_time = ktime_get(); #endif } list_del(&lock->link); if (has_timeout){ if (debug_mask & DEBUG_WAKE_LOCK) pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n", lock->name, type, timeout / HZ, (timeout % HZ) * MSEC_PER_SEC / HZ); lock->expires = jiffies + timeout; lock->flags |= WAKE_LOCK_AUTO_EXPIRE; list_add_tail(&lock->link, &active_wake_locks[type]); } else { if (debug_mask & DEBUG_WAKE_LOCK) pr_info("wake_lock: %s, type %d\n", lock->name, type); lock->expires = LONG_MAX; lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE; list_add(&lock->link, &active_wake_locks[type]); } if (type == WAKE_LOCK_SUSPEND) { current_event_num++; #ifdef CONFIG_WAKELOCK_STAT if (lock == &main_wake_lock) update_sleep_wait_stats_locked(1); else if (!wake_lock_active(&main_wake_lock)) update_sleep_wait_stats_locked(0); #endif if (has_timeout) expire_in = has_wake_lock_locked(type); else expire_in = -1; if (expire_in > 0) { if (debug_mask & DEBUG_EXPIRE) pr_info("wake_lock: %s, start expire timer, " "%ld\n", lock->name, expire_in); mod_timer(&expire_timer, jiffies + expire_in); } else { if (del_timer(&expire_timer)) if (debug_mask & DEBUG_EXPIRE) pr_info("wake_lock: %s, stop expire timer\n", lock->name); if (expire_in == 0) queue_work(suspend_work_queue, &suspend_work); } } spin_unlock_irqrestore(&list_lock, irqflags); } 而对于wake_lock_timeout,在经过timeout时间后,才加锁。再判断当前持有wakelock时,启动另一个定时器,在expire_timer的回调函数中再次判断是否持有wakelock。 static void expire_wake_locks(unsigned long data) { long has_lock; unsigned long irqflags; if (debug_mask & DEBUG_EXPIRE) pr_info("expire_wake_locks: start\n"); spin_lock_irqsave(&list_lock, irqflags); if (debug_mask & DEBUG_SUSPEND) print_active_locks(WAKE_LOCK_SUSPEND); has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND); if (debug_mask & DEBUG_EXPIRE) pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock); if (has_lock == 0) queue_work(suspend_work_queue, &suspend_work); spin_unlock_irqrestore(&list_lock, irqflags); } static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0); 在wakelock中,有2个地方可以让系统从early_suspend进入suspend状态。分别是: l 在 wake_unlock中,解锁之后,若没有其他的wakelock,则进入suspend。 l 在超时锁的定时器超时后,定时器的回调函数,会判断有没有其他的wakelock,若没有,则进入suspend 本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/4956676.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Elasticsearch + php + msyql+nginx安装流程

sudo yum -y install gcc gcc-c++ autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-develglib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devele krb5 krb5-devel libidn libidn-devel openssl openssl-devel openldap openldap-devel nss_ldap openldap-clients openldap-servers #nginx所需要的库文件件 sudo yum -y install pcre-deve l zlib-deve l gd gd-deve l freetype net-tools yum -y install pcre* #PHP依赖的库文件 sudo yum -y install gd-devel libjpeg-devel libpng-devel freetype-devel libxml2-devel curl-devel yum -y install mysql mysql-devel //尽可能用源码编译安装 yum -y install mysql-server //尽可能用源码编译安装 mysql -uroot -p #登陆方式 3.登录MySQL修改密码 mysql -uroot -S /opt/mysql/3306/mysql.sock mysql> flush privileges; mysql> set password for root@'localhost'= password('miaohr1qaz'); 4.登录数据库给multi用户添加权限 mysql -uroot -S /opt/mysql/3306/mysql.sock -pmiaohr1qaz mysql> GRANT SHUTDOWN ON *.* TO 'multi'@'localhost' IDENTIFIED BY 'multi'; 5.设置root远程访问 mysql> UPDATE mysql.user SET Host='%' WHERE Host='localhost'; mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'; mysql> FLUSH PRIVILEGES; nginx 安装 ./configure --prefix=/usr/nginx make make install 匹配nginx.conf开启 location ~ \.php$ { root html; fastcgi_pass 127.0.0.1:9000 fastcgi_index index.php fastcgi_param SCRIPT_FILENAME /usr/nginx/html$fastcgi_script_name; include fastcgi_params; } 启动nginx /usr/nginx/sbin/nginx 重启 /usr/nginx/sbin/nginx -s reload php安装方法 mysql_config 没有的话是因为没有安装mysql-devel (mysql_config 是一个绿色的可执行文件) ./configure --prefix=/data/local/php \ --enable-fpm \ --with-zlib \ --enable-mbstring \ --with-openssl \ --with-mysqli \ --enable-mysqlnd \ --with-mysql-sock \ --with-gd \ --enable-gd-native-ttf \ --enable-pdo \ --with-pdo-mysql \ --with-gettext \ --with-curl \ --enable-sockets \ --enable-bcmath \ --enable-xml \ --with-bz2 \ --enable-zip \ -enable-pcntl make make install 从php的解压包里 cp php.ini-development /usr/php/lib/php.ini 在/usr/php/etc/里 cp /usr/php/etc/php-fpm.conf.default /usr/php/etc/php-fpm.conf date.timezone = “Asia/Shanghai” default_charset = "utf-8" 然后启动nginx,mysql 和/usr/php/sbin/php-fpm ps aux | grep -c php-fpm 查看状态 服务器1 cluster.name: ejiqun node.name: node1 node.rack: r1 #机架号 最好不同 path.data: /elastic_data/data path.logs: /elastic_data/logs network.host: 192.168.1.210 http.port: 9200 transport.tcp.port: 9300 #设置节点之间交互的端口号 discovery.zen.ping.timeout: 120s #设置集群中自动发现其他节点时ping连接的超时时间 discovery.zen.ping.multicast.enabled: true #设置是否打开多播发现节点 discovery.zen.ping.unicast.hosts: ["192.168.1.210:9300", "192.168.1.211:9300"] 服务器2 cluster.name: ejiqun node.name: node2 node.rack: r2 #机架号 最好不同 path.data: /elastic_data/data path.logs: /elastic_data/logs network.host: 192.168.1.211 http.port: 9200 transport.tcp.port: 9300 #设置节点之间交互的端口号 discovery.zen.ping.timeout: 120s #设置集群中自动发现其他节点时ping连接的超时时间 discovery.zen.ping.multicast.enabled: true #设置是否打开多播发现节点 discovery.zen.ping.unicast.hosts: ["192.168.1.210:9300", "192.168.1.211:9300"] 安装jdk 去http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html中下载jdk的安装文件。由于我的Linux是32位的,因此我下载jdk-8u25-linux-i586.tar.gz文件。 新建/usr/java文件夹,将jdk-8u25-linux-i586.tar.gz放到该文件夹中,并将工作目录切换到/usr/java目录下。 执行命令tar -zxvf jdk-8u25-linux-i586.gz 进行解压,解压后发现/usr/java多了一个jdk1.8.0_25文件夹。 通过以上步骤,jdk就已经全部安装完成了。下面,就是环境变量的配置。 配置环境变量 使用vim /etc/profile编辑profile文件 在/etc/profile底部加入如下内容 JAVA_HOME=/usr/java/jdk1.8.0_25 PATH=$JAVA_HOME/bin:$PATH CLASSPATH=$JAVA_HOME/jre/lib/ext:$JAVA_HOME/lib/tools.jar export PATH JAVA_HOME CLASSPATH 以上,环境变量配置完成。需要注意的是,PATH在配置的时候,一定要把$JAVA_HOME/bin放在前面,不然使用java命令时,系统会找到以前的java,再不往下找了。这样java这个可执行文件运行的目录其实不在$JAVA_HOME/bin下,而在其它目录下,会造成很大的问题。 还要注意,以前其它教程写的CLASSPATH=$JAVA_HOME/lib.tools.jar,不知道以前的版本是怎么样的,现在的版本是没有这样的jar包的。 最后使用source /etc/profile让profile文件立即生效。 命令测试 使用javac命令,不会出现command not found错误 使用java -version,出现版本为java version "1.8.0_25" echo $JAVA_HOME, echo $CLASSPATH, echo $PATH,看看自己的配置是否都正确。 elasticsearch-jdbc使用 第一步:环境匹配 1)elasticsearch 2.3.3 成功安装部署 2)mysql安装成功,增删改查无误~~。 3)要保证elasticsearch-jdbc的版本要与elasticsearch的版本是一致的(下面的内容会提示下载)。否则会报错,无法进行之后的步骤。 (例如elasticsearch-jdbc-2.3.3.0-dist.zip(对应的你的elaseticsearh-2.3.3) 第二步:下载JDBC工具 选择你需要的版本进行下载。(例如elasticsearch-jdbc-2.3.3.0-dist.zip(对应的你的elaseticsearh-2.3.3) ,下载后缀为dist.zip的即可) 地址: http://xbib.org/repository/org/xbib/elasticsearch/importer/elasticsearch-jdbc/ 解压下载的文件unzip elasticsearch-jdbc-2.3.3.0-dist.zip 解压下载的文件unzip elasticsearch-jdbc-2.3.3.0-dist.zip 创建mysql脚本计划任务 cd /elasticsearch-jdbc-2.3.3.0/bin/ (在bin目录下建立我们的新脚本) vi import_es.sh #!/bin/sh bin=/elasticsearch-jdbc-2.3.3.1/bin lib=/elasticsearch-jdbc-2.3.3.1/lib echo '{ "type" : "jdbc", "jdbc": { "elasticsearch.autodiscover":true, "elasticsearch.cluster":"ejiqun", "url":"jdbc:mysql://10.0.8.7:3306/bo", "user":"caiyun", "password":"bo2016.", "sql":"select email from members", "elasticsearch" : { "host" : "192.168.48.129", "port" : 9300 }, "index" : "test", "type" : "ffcs" } }' | java \ -cp "${lib}/*" \ -Dlog4j.configurationFile=${bin}/log4j2.xml \ org.xbib.tools.Runner \ org.xbib.tools.JDBCImporter 为 import_es.sh 添加可执行权限。 chmod a+x import_es.sh //(a+x 是给所有人加上可执行权限,包括所有者,所属组,和其他人 o+x 只是给其他人加上可执行权限) 执行脚本:./import_es.sh 第五步:检测数据是否新增成功 curl 'localhost:9200/_cat/indices?pretty' //索引是否有新增呢?? curl -XGET 'http://localhost:9200/test/ffcs/_search?pretty' //抓取显示数据 通过各种条件查询 curl 'localhost:9200/test/ffcs/_search?pretty' -d ' { "filter":{"term":{"name":"john"}} }'

优秀的个人博客,低调大师

Hadoop YARN 的工作流程简述

1、Client 向 YARN 提交应用程序,其中包括 ApplicationMaster 程序及启动 ApplicationMaster 命令2、ResourceManager 为该 ApplicationMaster 分配第一个 Container,并与对应的 NodeManager 通信,要求它在这个 Container 中启动应用程序的 ApplicationMaster3、ApplicationMaster 向ResourceManager 注册4、ApplicationMaster 为 Application 的任务申请并领取资源5、获取到资源后,要求对应的 NodeManager 在 Container 中启动任务6、NodeManager 收到 ApplicationMaster 的请求后,为任务设置好运行环境(包括环境变量、JAR 包等),将任务启动脚本写到一个脚本中,并通过运行该脚本启动任务7、各个任务通过 RPC 协议向 ApplicationMaster 汇报自己的状态和进度,以让 ApplicationMaster 随时掌握各个任务的运行状态,从而可以在失败时重启任务8、应用程序完成后,ApplicationMaster 向 ResourceManager 注销并关闭自己实际中,集群可能并没有那么多资源来满足 ApplicationMaster 的资源请求,这是 ApplicationMaster 会采用轮循的方式不断申请资源,直到申请到资源或 Application 结束

优秀的个人博客,低调大师

iOS打包ipa给客户测试流程

IOS项目开发的过程中经常会用到一个测试的问题,特别是外包的项目,客户拿了那么多钱,看不到产品时时的进度说不过去,而且UI和功能是否和符合用户需求这个很重要,需要客户的认同。 所以就需要时时给开发中的产品打包,让客户去检查是否符合需求。 接入正题: 先讲一下大概的思路,具体的步骤往下看。 1.往开发者账号里面添加测试设备 2.创建证书和配置文件(配置文件选设备和证书的时候建议都选) 3.打包 4.安装到客户的手机 具体细节: 有些外包是用外包的开发者账号,有的是用人家公司的开发者账号,其实都无所谓了。只要打包时候的开发者账号和你添加设备的开发者账号一样就行了。 1.进入开发者中心,找到证书配置文件那一页 2.创见证书(并下载到电脑上,双击添加到登录里面) 3.创建APPID 4.添加设备(主要就是UDID,要把所有测试设备的UDID都添加进来,不然将来打包安装不上,获取UDID参见:http://www.cnblogs.com/BK-12345/p/5996372.html) 5.创建配置文件(选择证书的时候建议有多少选多少,设备也一样全部选中) 6.接着就是将创建好的配置文件下载到电脑上,双击配置文件,在Xcode中选择刚才创建的配置文件即可。 7.在选择模拟器的地方调成Generic iOS Device。 8.Produc->Archive 9.Export(和正常的一样)->会有四个选项,选最后一个Save for Development Deloyment,然后next,选择刚才导入的证书,next,next ,next,Export选个地方保存一下就可以了。 10.就是将打好包安装到手机上,参考一下链接:http://www.cnblogs.com/BK-12345/p/6000124.html

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册